Annotation of libwww/Library/src/HTChannl.c, revision 2.24

2.14      frystyk     1: /*
2.1       frystyk     2: **     CONTAINS STREAMS FOR READING AND WRITING TO AND FROM A TRANSPORT
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.24    ! frystyk     6: **     @(#) $Id: HTChannl.c,v 2.23 1999/02/22 15:58:04 kahan Exp $
2.1       frystyk     7: **
                      8: **
                      9: ** HISTORY:
                     10: **     April 96  HFN   Written
                     11: */
                     12: 
                     13: /* Library Include files */
2.17      frystyk    14: #include "wwwsys.h"
2.1       frystyk    15: #include "WWWUtil.h"
                     16: #include "HTAlert.h"
2.10      frystyk    17: #include "HTHost.h"
2.1       frystyk    18: #include "HTError.h"
2.16      frystyk    19: 
                     20: #ifdef HT_MUX
                     21: #include "WWWMux.h"
                     22: #endif
                     23: 
2.1       frystyk    24: #include "HTChannl.h"                                   /* Implemented here */
                     25: 
2.22      frystyk    26: #define HASH(s)                ((s) % (HT_M_HASH_SIZE))
2.1       frystyk    27: 
2.13      frystyk    28: struct _HTInputStream {
                     29:     const HTInputStreamClass * isa;
                     30:     HTChannel *                        channel;
                     31: };
                     32: 
                     33: struct _HTOutputStream {
                     34:     const HTOutputStreamClass *        isa;
                     35:     HTChannel *                        channel;
                     36: };
                     37: 
2.1       frystyk    38: struct _HTChannel {
2.13      frystyk    39:     /* what media do we talk to? */
2.1       frystyk    40:     SOCKET             sockfd;                                    /* Socket */
2.14      frystyk    41:     FILE *             fp;                               /* File descriptor */
2.13      frystyk    42: 
                     43:     /* what streams handle the IO */
2.1       frystyk    44:     HTInputStream *    input;                               /* Input stream */
                     45:     HTOutputStream *   output;                             /* Output stream */
2.14      frystyk    46: 
2.13      frystyk    47:     /* proxy streams to dereference the above streams */
                     48:     HTInputStream      channelIStream;
                     49:     HTOutputStream     channelOStream;
                     50: 
2.1       frystyk    51:     BOOL               active;                 /* Active or passive channel */
                     52:     int                        semaphore;                         /* On channel use */
2.10      frystyk    53:     HTHost *           host;                          /* Zombie connections */
2.1       frystyk    54: };
                     55: 
2.13      frystyk    56: PRIVATE HTList ** channels = NULL;                      /* List of channels */
2.1       frystyk    57: 
2.13      frystyk    58: /* ------------------------------------------------------------------------- */
2.1       frystyk    59: 
2.13      frystyk    60: /*
                     61: **     Skinny stream objects to pass the IO requests to the channels current IO streams.
                     62: **     This was needed because the channel's IO streams could go away after the IO streams
                     63: **     were set up for multiple requests.
                     64: */
                     65: 
                     66: PRIVATE int ChannelIStream_flush (HTInputStream * me)
                     67: {return me->channel->input ? (*me->channel->input->isa->flush)(me->channel->input) : HT_ERROR;}
                     68: PRIVATE int ChannelIStream_free (HTInputStream * me)
                     69: {return me->channel->input ? (*me->channel->input->isa->_free)(me->channel->input) : HT_ERROR;}
                     70: PRIVATE int ChannelIStream_abort (HTInputStream * me, HTList * e)
                     71: {return me->channel->input ? (*me->channel->input->isa->abort)(me->channel->input, e) : HT_ERROR;}
                     72: PRIVATE int ChannelIStream_read (HTInputStream * me)
                     73: {return me->channel->input ? (*me->channel->input->isa->read)(me->channel->input) : HT_ERROR;}
                     74: PRIVATE int ChannelIStream_close (HTInputStream * me)
                     75: {return me->channel->input ? (*me->channel->input->isa->close)(me->channel->input) : HT_ERROR;}
                     76: PUBLIC int ChannelIStream_consumed (HTInputStream * me, size_t bytes)
                     77: {return me->channel->input ? (*me->channel->input->isa->consumed)(me->channel->input, bytes) : HT_ERROR;}
                     78: PRIVATE const HTInputStreamClass ChannelIStreamIsa =
                     79: {
                     80:     "ChannelInput",
                     81:     ChannelIStream_flush,
                     82:     ChannelIStream_free,
                     83:     ChannelIStream_abort,
                     84:     ChannelIStream_read,
                     85:     ChannelIStream_close,
                     86:     ChannelIStream_consumed
                     87: }; 
                     88: 
                     89: PRIVATE int ChannelOStream_flush (HTOutputStream * me)
                     90: {return me->channel->output ? (*me->channel->output->isa->flush)(me->channel->output) : HT_ERROR;}
                     91: PRIVATE int ChannelOStream_free (HTOutputStream * me)
                     92: {return me->channel->output ? (*me->channel->output->isa->_free)(me->channel->output) : HT_ERROR;}
                     93: PRIVATE int ChannelOStream_abort (HTOutputStream * me, HTList * e)
                     94: {return me->channel->output ? (*me->channel->output->isa->abort)(me->channel->output, e) : HT_ERROR;}
                     95: PRIVATE int ChannelOStream_put_character (HTOutputStream * me, char c)
                     96: {return me->channel->output ? (*me->channel->output->isa->put_character)(me->channel->output, c) : HT_ERROR;}
                     97: PRIVATE int ChannelOStream_put_string (HTOutputStream * me, const char * s)
                     98: {return me->channel->output ? (*me->channel->output->isa->put_string)(me->channel->output, s) : HT_ERROR;}
                     99: PRIVATE int ChannelOStream_put_block (HTOutputStream * me, const char * buf, int len)
                    100: {return me->channel->output ? (*me->channel->output->isa->put_block)(me->channel->output, buf, len) : HT_ERROR;}
                    101: PRIVATE int ChannelOStream_close (HTOutputStream * me)
                    102: {return me->channel->output ? (*me->channel->output->isa->close)(me->channel->output) : HT_ERROR;}
                    103: PRIVATE const HTOutputStreamClass ChannelOStreamIsa =
                    104: {
                    105:     "ChannelOutput",
                    106:     ChannelOStream_flush,
                    107:     ChannelOStream_free,
                    108:     ChannelOStream_abort,
                    109:     ChannelOStream_put_character,
                    110:     ChannelOStream_put_string,
                    111:     ChannelOStream_put_block,
                    112:     ChannelOStream_close,
                    113: }; 
2.1       frystyk   114: 
                    115: /* ------------------------------------------------------------------------- */
                    116: 
                    117: PRIVATE void free_channel (HTChannel * ch)
                    118: {
                    119:     if (ch) {
                    120: 
                    121:        /* Close the input and output stream */
2.11      frystyk   122:        if (ch->input) {
                    123:            (*ch->input->isa->close)(ch->input);
                    124:            ch->input = NULL;
                    125:        }
                    126:        if (ch->output) {
                    127:            (*ch->output->isa->close)(ch->output);
                    128:            ch->output = NULL;
                    129:        }
2.1       frystyk   130: 
                    131:        /* Close the socket */
                    132:        if (ch->sockfd != INVSOC) {
                    133:            NETCLOSE(ch->sockfd);
2.10      frystyk   134:            HTNet_decreaseSocket();
2.24    ! frystyk   135:            HTTRACE(PROT_TRACE, "Channel..... Deleted %p, socket %d\n" _ ch _ ch->sockfd);
2.14      frystyk   136:            ch->sockfd = INVSOC;
2.1       frystyk   137:        }
                    138: 
                    139:        /* Close the file */
                    140:        if (ch->fp) {
                    141:            fclose(ch->fp);
2.24    ! frystyk   142:            HTTRACE(PROT_TRACE, "Channel..... Deleted %p, file %p\n" _ ch _ ch->fp);
2.14      frystyk   143:            ch->fp = NULL;
2.1       frystyk   144:        }
                    145:        HT_FREE(ch);
                    146:     }
                    147: }
                    148: 
                    149: /*
                    150: **     A channel is uniquely identified by a socket.
                    151: **     Note that we don't create the input and output stream - they are 
2.10      frystyk   152: **     created later.
2.1       frystyk   153: **
                    154: **     We only keep a hash on sockfd's as we don't have to look for channels
                    155: **     for ANSI file descriptors.
                    156: */
2.14      frystyk   157: PUBLIC HTChannel * HTChannel_new (SOCKET sockfd, FILE * fp, BOOL active)
2.1       frystyk   158: {
2.13      frystyk   159:     HTList * list = NULL;
                    160:     HTChannel * ch = NULL;
                    161:     int hash = sockfd < 0 ? 0 : HASH(sockfd);
2.24    ! frystyk   162:     HTTRACE(PROT_TRACE, "Channel..... Hash value is %d\n" _ hash);
2.13      frystyk   163:     if (!channels) {
2.22      frystyk   164:        if (!(channels = (HTList **) HT_CALLOC(HT_M_HASH_SIZE,sizeof(HTList*))))
2.13      frystyk   165:            HT_OUTOFMEM("HTChannel_new");
                    166:     }
                    167:     if (!channels[hash]) channels[hash] = HTList_new();
                    168:     list = channels[hash];
                    169:     if ((ch = (HTChannel *) HT_CALLOC(1, sizeof(HTChannel))) == NULL)
                    170:        HT_OUTOFMEM("HTChannel_new");       
                    171:     ch->sockfd = sockfd;
2.14      frystyk   172:     ch->fp = fp;
2.13      frystyk   173:     ch->active = active;
                    174:     ch->semaphore = 1;
                    175:     ch->channelIStream.isa = &ChannelIStreamIsa;
                    176:     ch->channelOStream.isa = &ChannelOStreamIsa;
                    177:     ch->channelIStream.channel = ch;
                    178:     ch->channelOStream.channel = ch;
                    179:     HTList_addObject(list, (void *) ch);
                    180: 
2.16      frystyk   181: #ifdef HT_MUX
                    182:            /*
                    183:            **  Create a MUX channel and do a connect on this channel with a
                    184:            **  new session.
                    185:            */
                    186:            {
                    187:                HTProtocol * protocol = HTNet_protocol(net);
                    188:                HTMuxChannel * muxch = HTMuxChannel_new(me);
                    189:                net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
                    190:            }
                    191: #endif /* HT_MUX */
                    192: 
2.24    ! frystyk   193:     HTTRACE(PROT_TRACE, "Channel..... Added %p to list %p\n" _ ch _ list);
2.13      frystyk   194:     return ch;
2.1       frystyk   195: }
                    196: 
                    197: /*
                    198: **     Look for a channel object if we for some reason should have lost it
                    199: **     Returns NULL if nothing found
                    200: */
                    201: PUBLIC HTChannel * HTChannel_find (SOCKET sockfd)
                    202: {
                    203:     if (channels && sockfd != INVSOC) {
                    204:        int hash = HASH(sockfd);
                    205:        HTList * list = channels[hash];
                    206:        if (list) {
                    207:            HTChannel * ch = NULL;
                    208:            while ((ch = (HTChannel *) HTList_nextObject(list)))
                    209:                if (ch->sockfd == sockfd) return ch;
                    210:        }
                    211:     }
                    212:     return NULL;
                    213: }
                    214: 
                    215: /*
                    216: **     When deleting a channel we first look at if there are no more requests
                    217: **     using the channel (the semaphore is <= 0). Then, if the socket supports
                    218: **     persistent connections then we register the channel in the Host cache
                    219: **     and wait until the other end closes it or we get a time out on our side
                    220: */
2.6       eric      221: PUBLIC BOOL HTChannel_delete (HTChannel * channel, int status)
2.1       frystyk   222: {
                    223:     if (channel) {
2.24    ! frystyk   224:        HTTRACE(PROT_TRACE, "Channel..... Delete %p with semaphore %d\n" _ 
        !           225:                                channel _ channel->semaphore);
2.1       frystyk   226:        /*
                    227:        **  We call the free methods on both the input stream and the output
                    228:        **  stream so that we can free up the stream pipes. However, note that
                    229:        **  this doesn't mean that we close the input stream and output stream
                    230:        **  them selves - only the generic streams
                    231:        */
2.12      frystyk   232:        if (status != HT_IGNORE) {
2.13      frystyk   233:            if (channel->input) {
2.19      frystyk   234:                 if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
2.12      frystyk   235:                    (*channel->input->isa->abort)(channel->input, NULL);
                    236:                else
                    237:                    (*channel->input->isa->_free)(channel->input);
2.13      frystyk   238:            }
                    239:            if (channel->output) {
2.19      frystyk   240:                if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
2.12      frystyk   241:                    (*channel->output->isa->abort)(channel->output, NULL);
                    242:                else
                    243:                    (*channel->output->isa->_free)(channel->output);
2.13      frystyk   244:            }
2.12      frystyk   245:        }
2.1       frystyk   246: 
                    247:        /*
                    248:        **  Check whether this channel is used by other objects or we can
                    249:        **  delete it and free memory.
                    250:        */
2.18      frystyk   251:        if (channel->semaphore <= 0 && channels && (
                    252:            channel->sockfd != INVSOC || channel->fp != NULL)) {
2.15      frystyk   253:             int hash = HASH(channel->sockfd);
2.1       frystyk   254:            HTList * list = channels[hash];
                    255:            if (list) {
                    256:                HTList_removeObject(list, (void *) channel);
                    257:                free_channel(channel);
                    258:                return YES;
                    259:            }
2.8       frystyk   260:        } else
                    261:            HTChannel_downSemaphore(channel);
2.1       frystyk   262:     }
                    263:     return NO;
                    264: }
                    265: 
                    266: /*     HTChannel_deleteAll
                    267: **     -------------------
                    268: **     Destroys all channels. This is called by HTLibTerminate(0
                    269: */
2.9       frystyk   270: PUBLIC BOOL HTChannel_deleteAll (void)
2.1       frystyk   271: {
                    272:     if (channels) {
                    273:        HTList * cur;
                    274:        int cnt;
2.22      frystyk   275:        for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
2.1       frystyk   276:            if ((cur = channels[cnt])) { 
                    277:                HTChannel * pres;
                    278:                while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
                    279:                    free_channel(pres);
                    280:            }
                    281:            HTList_delete(channels[cnt]);
                    282:        }
                    283:        HT_FREE(channels);
                    284:     }
                    285:     return YES;
2.23      kahan     286: }
                    287: 
                    288: /*      HTChannel_safeDeleteAll
                    289: **      -------------------
                    290: **      Destroys all channels. This is called by HTLibTerminate(0
                    291: */
                    292:  
                    293: PUBLIC BOOL HTChannel_safeDeleteAll (void)
                    294: {
                    295:     if (channels) {
                    296:         HTList * cur;
                    297:         int cnt;
                    298:         for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
                    299:           if ((cur = channels[cnt])) {
                    300:             HTChannel * pres;
                    301:             while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL) {
                    302:               HTChannel_delete (pres, HT_TIMEOUT);
                    303:               cur = channels[cnt];
                    304:             }
                    305:           }
                    306:         }
                    307:         return YES;
                    308:     }
                    309:     return NO;
2.1       frystyk   310: }
                    311: 
                    312: /*
2.10      frystyk   313: **     Return the socket associated with this channel
2.1       frystyk   314: */
2.10      frystyk   315: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
2.1       frystyk   316: {
2.10      frystyk   317:     return channel ? channel->sockfd : INVSOC;
2.1       frystyk   318: }
                    319: 
2.14      frystyk   320: PUBLIC BOOL HTChannel_setSocket (HTChannel * channel, SOCKET socket)
2.13      frystyk   321: {
2.14      frystyk   322:     if (channel) {
2.13      frystyk   323:       channel->sockfd = socket;
2.14      frystyk   324:       return YES;
                    325:     }
                    326:     return NO;
2.13      frystyk   327: }
                    328: 
2.10      frystyk   329: /*
                    330: **     Return the file descriptor associated with this channel
                    331: */
                    332: PUBLIC FILE * HTChannel_file (HTChannel * channel)
2.1       frystyk   333: {
2.10      frystyk   334:     return channel ? channel->fp : NULL;
2.1       frystyk   335: }
                    336: 
2.14      frystyk   337: PUBLIC BOOL HTChannel_setFile (HTChannel * channel, FILE * fp)
                    338: {
                    339:     if (channel) {
                    340:        channel->fp = fp;
                    341:        return YES;
                    342:     }
                    343:     return NO;
                    344: }
                    345: 
2.1       frystyk   346: /*
2.10      frystyk   347: **     We keep the associated Host object in case we have a
                    348: **     sleeping connection. 
2.1       frystyk   349: */
2.10      frystyk   350: PUBLIC BOOL HTChannel_setHost (HTChannel * ch, HTHost * host)
2.1       frystyk   351: {
2.13      frystyk   352:     if (ch) {
2.10      frystyk   353:        ch->host = host;
                    354:        return YES;
                    355:     }
                    356:     return NO;
2.4       frystyk   357: }
                    358: 
2.10      frystyk   359: PUBLIC HTHost * HTChannel_host (HTChannel * ch)
2.4       frystyk   360: {
2.10      frystyk   361:     return (ch ? ch->host : NULL);
2.1       frystyk   362: }
                    363: 
                    364: /*
                    365: **     Increase the semaphore for this channel
                    366: */
                    367: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
                    368: {
                    369:     if (channel) {
                    370:        channel->semaphore++;
2.24    ! frystyk   371:        HTTRACE(PROT_TRACE, "Channel..... Semaphore increased to %d for channel %p\n" _ 
        !           372:                    channel->semaphore _ channel);
2.16      frystyk   373: #ifdef HT_MUX
                    374:                HTMuxChannel * muxch = HTMuxChannel_find(me);
                    375:                HTProtocol * protocol = HTNet_protocol(net);
                    376:                net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
                    377: #endif /* HT_MUX */
                    378: 
2.1       frystyk   379:     }
                    380: }
                    381: 
                    382: /*
                    383: **     Decrease the semaphore for this channel
                    384: */
                    385: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
                    386: {
                    387:     if (channel) {
                    388:        channel->semaphore--;
                    389:        if (channel->semaphore <= 0) channel->semaphore = 0;
2.24    ! frystyk   390:        HTTRACE(PROT_TRACE, "Channel..... Semaphore decreased to %d for channel %p\n" _ 
        !           391:                    channel->semaphore _ channel);
2.7       frystyk   392:     }
                    393: }
                    394: 
                    395: /*
                    396: **     Explicitly set the semaphore for this channel
                    397: */
                    398: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
                    399: {
                    400:     if (channel) {
                    401:        channel->semaphore = semaphore;
                    402:        if (channel->semaphore <= 0) channel->semaphore = 0;
2.24    ! frystyk   403:        HTTRACE(PROT_TRACE, "Channel..... Semaphore set to %d for channel %p\n" _ 
        !           404:                    channel->semaphore _ channel);
2.1       frystyk   405:     }
                    406: }
                    407: 
                    408: /*
                    409: **     Create the input stream and bind it to the channel
                    410: **     Please read the description in the HTIOStream module on the parameters
                    411: */
2.10      frystyk   412: PUBLIC BOOL HTChannel_setInput (HTChannel * ch, HTInputStream * input)
2.1       frystyk   413: {
                    414:     if (ch) {
                    415:        ch->input = input;
                    416:        return YES;
                    417:     }
                    418:     return NO;
                    419: }
                    420: 
                    421: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
                    422: {
                    423:     return ch ? ch->input : NULL;
                    424: }
                    425: 
                    426: /*
                    427: **     Create the output stream and bind it to the channel
                    428: **     Please read the description in the HTIOStream module on the parameters
                    429: */
2.10      frystyk   430: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch, HTOutputStream * output)
2.1       frystyk   431: {
                    432:     if (ch) {
                    433:        ch->output = output;
                    434:        return YES;
                    435:     }
                    436:     return NO;
                    437: }
                    438: 
                    439: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
                    440: {
                    441:     return ch ? ch->output : NULL;
2.13      frystyk   442: }
                    443: 
                    444: PUBLIC HTInputStream * HTChannel_getChannelIStream (HTChannel * ch)
                    445: {
                    446:     if (ch)
                    447:        return &ch->channelIStream;
                    448:     return NULL;
                    449: }
                    450: 
                    451: PUBLIC HTOutputStream * HTChannel_getChannelOStream (HTChannel * ch)
                    452: {
                    453:     if (ch)
                    454:        return &ch->channelOStream;
                    455:     return NULL;
2.1       frystyk   456: }
                    457: 

Webmaster