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

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.26    ! kahan       6: **     @(#) $Id: HTChannl.c,v 2.25 1999/07/07 15:43:28 frystyk 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.25      frystyk   224:        HTTRACE(PROT_TRACE, "Channel..... Delete %p with semaphore %d, status %d\n" _ 
                    225:                channel _ channel->semaphore _ status);
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.25      frystyk   232:        HTChannel_deleteInput(channel, status);
                    233:        HTChannel_deleteOutput(channel, status);
2.1       frystyk   234: 
                    235:        /*
                    236:        **  Check whether this channel is used by other objects or we can
                    237:        **  delete it and free memory.
                    238:        */
2.18      frystyk   239:        if (channel->semaphore <= 0 && channels && (
                    240:            channel->sockfd != INVSOC || channel->fp != NULL)) {
2.15      frystyk   241:             int hash = HASH(channel->sockfd);
2.1       frystyk   242:            HTList * list = channels[hash];
                    243:            if (list) {
                    244:                HTList_removeObject(list, (void *) channel);
                    245:                free_channel(channel);
                    246:                return YES;
                    247:            }
2.8       frystyk   248:        } else
                    249:            HTChannel_downSemaphore(channel);
2.1       frystyk   250:     }
                    251:     return NO;
                    252: }
                    253: 
                    254: /*     HTChannel_deleteAll
                    255: **     -------------------
                    256: **     Destroys all channels. This is called by HTLibTerminate(0
                    257: */
2.9       frystyk   258: PUBLIC BOOL HTChannel_deleteAll (void)
2.1       frystyk   259: {
                    260:     if (channels) {
                    261:        HTList * cur;
                    262:        int cnt;
2.22      frystyk   263:        for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
2.1       frystyk   264:            if ((cur = channels[cnt])) { 
                    265:                HTChannel * pres;
                    266:                while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
                    267:                    free_channel(pres);
                    268:            }
                    269:            HTList_delete(channels[cnt]);
                    270:        }
                    271:        HT_FREE(channels);
                    272:     }
                    273:     return YES;
2.23      kahan     274: }
                    275: 
                    276: /*      HTChannel_safeDeleteAll
                    277: **      -------------------
                    278: **      Destroys all channels. This is called by HTLibTerminate(0
                    279: */
                    280:  
                    281: PUBLIC BOOL HTChannel_safeDeleteAll (void)
                    282: {
                    283:     if (channels) {
                    284:         HTList * cur;
                    285:         int cnt;
                    286:         for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
                    287:           if ((cur = channels[cnt])) {
                    288:             HTChannel * pres;
                    289:             while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL) {
                    290:               HTChannel_delete (pres, HT_TIMEOUT);
                    291:               cur = channels[cnt];
                    292:             }
2.26    ! kahan     293:            HTList_delete (channels[cnt]);
        !           294:            channels[cnt] = NULL;
2.23      kahan     295:           }
                    296:         }
                    297:         return YES;
                    298:     }
                    299:     return NO;
2.1       frystyk   300: }
                    301: 
                    302: /*
2.10      frystyk   303: **     Return the socket associated with this channel
2.1       frystyk   304: */
2.10      frystyk   305: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
2.1       frystyk   306: {
2.10      frystyk   307:     return channel ? channel->sockfd : INVSOC;
2.1       frystyk   308: }
                    309: 
2.25      frystyk   310: PUBLIC BOOL HTChannel_setSocket (HTChannel * channel, SOCKET sockfd)
2.13      frystyk   311: {
2.14      frystyk   312:     if (channel) {
2.25      frystyk   313:        
                    314:        /*
                    315:        ** As we use the socket number as the hash entry then we have to
                    316:        ** update the hash table as well.
                    317:        */
                    318:        int old_hash = HASH(channel->sockfd);
                    319:        int new_hash = sockfd < 0 ? 0 : HASH(sockfd);
                    320:        HTList * list = channels[old_hash];
                    321:        if (list) HTList_removeObject(list, channel);
                    322:        if (!channels[new_hash]) channels[new_hash] = HTList_new();
                    323:        list = channels[new_hash];
                    324:        HTList_addObject(list, channel);
                    325: 
                    326:        channel->sockfd = sockfd;
                    327:        return YES;
2.14      frystyk   328:     }
                    329:     return NO;
2.13      frystyk   330: }
                    331: 
2.10      frystyk   332: /*
                    333: **     Return the file descriptor associated with this channel
                    334: */
                    335: PUBLIC FILE * HTChannel_file (HTChannel * channel)
2.1       frystyk   336: {
2.10      frystyk   337:     return channel ? channel->fp : NULL;
2.1       frystyk   338: }
                    339: 
2.14      frystyk   340: PUBLIC BOOL HTChannel_setFile (HTChannel * channel, FILE * fp)
                    341: {
                    342:     if (channel) {
                    343:        channel->fp = fp;
                    344:        return YES;
                    345:     }
                    346:     return NO;
                    347: }
                    348: 
2.1       frystyk   349: /*
2.10      frystyk   350: **     We keep the associated Host object in case we have a
                    351: **     sleeping connection. 
2.1       frystyk   352: */
2.10      frystyk   353: PUBLIC BOOL HTChannel_setHost (HTChannel * ch, HTHost * host)
2.1       frystyk   354: {
2.13      frystyk   355:     if (ch) {
2.10      frystyk   356:        ch->host = host;
                    357:        return YES;
                    358:     }
                    359:     return NO;
2.4       frystyk   360: }
                    361: 
2.10      frystyk   362: PUBLIC HTHost * HTChannel_host (HTChannel * ch)
2.4       frystyk   363: {
2.10      frystyk   364:     return (ch ? ch->host : NULL);
2.1       frystyk   365: }
                    366: 
                    367: /*
                    368: **     Increase the semaphore for this channel
                    369: */
                    370: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
                    371: {
                    372:     if (channel) {
                    373:        channel->semaphore++;
2.24      frystyk   374:        HTTRACE(PROT_TRACE, "Channel..... Semaphore increased to %d for channel %p\n" _ 
                    375:                    channel->semaphore _ channel);
2.16      frystyk   376: #ifdef HT_MUX
                    377:                HTMuxChannel * muxch = HTMuxChannel_find(me);
                    378:                HTProtocol * protocol = HTNet_protocol(net);
                    379:                net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
                    380: #endif /* HT_MUX */
                    381: 
2.1       frystyk   382:     }
                    383: }
                    384: 
                    385: /*
                    386: **     Decrease the semaphore for this channel
                    387: */
                    388: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
                    389: {
                    390:     if (channel) {
                    391:        channel->semaphore--;
                    392:        if (channel->semaphore <= 0) channel->semaphore = 0;
2.24      frystyk   393:        HTTRACE(PROT_TRACE, "Channel..... Semaphore decreased to %d for channel %p\n" _ 
                    394:                    channel->semaphore _ channel);
2.7       frystyk   395:     }
                    396: }
                    397: 
                    398: /*
                    399: **     Explicitly set the semaphore for this channel
                    400: */
                    401: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
                    402: {
                    403:     if (channel) {
                    404:        channel->semaphore = semaphore;
                    405:        if (channel->semaphore <= 0) channel->semaphore = 0;
2.24      frystyk   406:        HTTRACE(PROT_TRACE, "Channel..... Semaphore set to %d for channel %p\n" _ 
                    407:                    channel->semaphore _ channel);
2.1       frystyk   408:     }
                    409: }
                    410: 
                    411: /*
                    412: **     Create the input stream and bind it to the channel
                    413: **     Please read the description in the HTIOStream module on the parameters
                    414: */
2.10      frystyk   415: PUBLIC BOOL HTChannel_setInput (HTChannel * ch, HTInputStream * input)
2.1       frystyk   416: {
                    417:     if (ch) {
                    418:        ch->input = input;
                    419:        return YES;
                    420:     }
                    421:     return NO;
                    422: }
                    423: 
                    424: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
                    425: {
                    426:     return ch ? ch->input : NULL;
                    427: }
                    428: 
2.25      frystyk   429: PUBLIC BOOL HTChannel_deleteInput (HTChannel * channel, int status)
                    430: {      
                    431:     if (channel && channel->input && status != HT_IGNORE) {
                    432:        HTTRACE(PROT_TRACE,
                    433:                "Channel..... Delete input stream %p from channel %p\n" _ 
                    434:                channel->input _ channel);
                    435:        if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
                    436:            (*channel->input->isa->abort)(channel->input, NULL);
                    437:        else
                    438:            (*channel->input->isa->_free)(channel->input);
                    439:        return YES;
                    440:     }
                    441:     return NO;
                    442: }
                    443: 
2.1       frystyk   444: /*
                    445: **     Create the output stream and bind it to the channel
                    446: **     Please read the description in the HTIOStream module on the parameters
                    447: */
2.10      frystyk   448: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch, HTOutputStream * output)
2.1       frystyk   449: {
                    450:     if (ch) {
                    451:        ch->output = output;
                    452:        return YES;
                    453:     }
                    454:     return NO;
                    455: }
                    456: 
                    457: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
                    458: {
                    459:     return ch ? ch->output : NULL;
2.25      frystyk   460: }
                    461: 
                    462: PUBLIC BOOL HTChannel_deleteOutput (HTChannel * channel, int status)
                    463: {      
                    464:     if (channel && channel->output && status != HT_IGNORE) {
                    465:        HTTRACE(PROT_TRACE,
                    466:                "Channel..... Delete input stream %p from channel %p\n" _ 
                    467:                channel->input _ channel);
                    468:        if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
                    469:            (*channel->output->isa->abort)(channel->output, NULL);
                    470:        else
                    471:            (*channel->output->isa->_free)(channel->output);
                    472:        return YES;
                    473:     }
                    474:     return NO;
2.13      frystyk   475: }
                    476: 
                    477: PUBLIC HTInputStream * HTChannel_getChannelIStream (HTChannel * ch)
                    478: {
                    479:     if (ch)
                    480:        return &ch->channelIStream;
                    481:     return NULL;
                    482: }
                    483: 
                    484: PUBLIC HTOutputStream * HTChannel_getChannelOStream (HTChannel * ch)
                    485: {
                    486:     if (ch)
                    487:        return &ch->channelOStream;
                    488:     return NULL;
2.1       frystyk   489: }
                    490: 

Webmaster