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

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.25    ! frystyk     6: **     @(#) $Id: HTChannl.c,v 2.24 1999/02/22 22:10:11 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:             }
                    293:           }
                    294:         }
                    295:         return YES;
                    296:     }
                    297:     return NO;
2.1       frystyk   298: }
                    299: 
                    300: /*
2.10      frystyk   301: **     Return the socket associated with this channel
2.1       frystyk   302: */
2.10      frystyk   303: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
2.1       frystyk   304: {
2.10      frystyk   305:     return channel ? channel->sockfd : INVSOC;
2.1       frystyk   306: }
                    307: 
2.25    ! frystyk   308: PUBLIC BOOL HTChannel_setSocket (HTChannel * channel, SOCKET sockfd)
2.13      frystyk   309: {
2.14      frystyk   310:     if (channel) {
2.25    ! frystyk   311:        
        !           312:        /*
        !           313:        ** As we use the socket number as the hash entry then we have to
        !           314:        ** update the hash table as well.
        !           315:        */
        !           316:        int old_hash = HASH(channel->sockfd);
        !           317:        int new_hash = sockfd < 0 ? 0 : HASH(sockfd);
        !           318:        HTList * list = channels[old_hash];
        !           319:        if (list) HTList_removeObject(list, channel);
        !           320:        if (!channels[new_hash]) channels[new_hash] = HTList_new();
        !           321:        list = channels[new_hash];
        !           322:        HTList_addObject(list, channel);
        !           323: 
        !           324:        channel->sockfd = sockfd;
        !           325:        return YES;
2.14      frystyk   326:     }
                    327:     return NO;
2.13      frystyk   328: }
                    329: 
2.10      frystyk   330: /*
                    331: **     Return the file descriptor associated with this channel
                    332: */
                    333: PUBLIC FILE * HTChannel_file (HTChannel * channel)
2.1       frystyk   334: {
2.10      frystyk   335:     return channel ? channel->fp : NULL;
2.1       frystyk   336: }
                    337: 
2.14      frystyk   338: PUBLIC BOOL HTChannel_setFile (HTChannel * channel, FILE * fp)
                    339: {
                    340:     if (channel) {
                    341:        channel->fp = fp;
                    342:        return YES;
                    343:     }
                    344:     return NO;
                    345: }
                    346: 
2.1       frystyk   347: /*
2.10      frystyk   348: **     We keep the associated Host object in case we have a
                    349: **     sleeping connection. 
2.1       frystyk   350: */
2.10      frystyk   351: PUBLIC BOOL HTChannel_setHost (HTChannel * ch, HTHost * host)
2.1       frystyk   352: {
2.13      frystyk   353:     if (ch) {
2.10      frystyk   354:        ch->host = host;
                    355:        return YES;
                    356:     }
                    357:     return NO;
2.4       frystyk   358: }
                    359: 
2.10      frystyk   360: PUBLIC HTHost * HTChannel_host (HTChannel * ch)
2.4       frystyk   361: {
2.10      frystyk   362:     return (ch ? ch->host : NULL);
2.1       frystyk   363: }
                    364: 
                    365: /*
                    366: **     Increase the semaphore for this channel
                    367: */
                    368: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
                    369: {
                    370:     if (channel) {
                    371:        channel->semaphore++;
2.24      frystyk   372:        HTTRACE(PROT_TRACE, "Channel..... Semaphore increased to %d for channel %p\n" _ 
                    373:                    channel->semaphore _ channel);
2.16      frystyk   374: #ifdef HT_MUX
                    375:                HTMuxChannel * muxch = HTMuxChannel_find(me);
                    376:                HTProtocol * protocol = HTNet_protocol(net);
                    377:                net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
                    378: #endif /* HT_MUX */
                    379: 
2.1       frystyk   380:     }
                    381: }
                    382: 
                    383: /*
                    384: **     Decrease the semaphore for this channel
                    385: */
                    386: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
                    387: {
                    388:     if (channel) {
                    389:        channel->semaphore--;
                    390:        if (channel->semaphore <= 0) channel->semaphore = 0;
2.24      frystyk   391:        HTTRACE(PROT_TRACE, "Channel..... Semaphore decreased to %d for channel %p\n" _ 
                    392:                    channel->semaphore _ channel);
2.7       frystyk   393:     }
                    394: }
                    395: 
                    396: /*
                    397: **     Explicitly set the semaphore for this channel
                    398: */
                    399: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
                    400: {
                    401:     if (channel) {
                    402:        channel->semaphore = semaphore;
                    403:        if (channel->semaphore <= 0) channel->semaphore = 0;
2.24      frystyk   404:        HTTRACE(PROT_TRACE, "Channel..... Semaphore set to %d for channel %p\n" _ 
                    405:                    channel->semaphore _ channel);
2.1       frystyk   406:     }
                    407: }
                    408: 
                    409: /*
                    410: **     Create the input stream and bind it to the channel
                    411: **     Please read the description in the HTIOStream module on the parameters
                    412: */
2.10      frystyk   413: PUBLIC BOOL HTChannel_setInput (HTChannel * ch, HTInputStream * input)
2.1       frystyk   414: {
                    415:     if (ch) {
                    416:        ch->input = input;
                    417:        return YES;
                    418:     }
                    419:     return NO;
                    420: }
                    421: 
                    422: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
                    423: {
                    424:     return ch ? ch->input : NULL;
                    425: }
                    426: 
2.25    ! frystyk   427: PUBLIC BOOL HTChannel_deleteInput (HTChannel * channel, int status)
        !           428: {      
        !           429:     if (channel && channel->input && status != HT_IGNORE) {
        !           430:        HTTRACE(PROT_TRACE,
        !           431:                "Channel..... Delete input stream %p from channel %p\n" _ 
        !           432:                channel->input _ channel);
        !           433:        if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
        !           434:            (*channel->input->isa->abort)(channel->input, NULL);
        !           435:        else
        !           436:            (*channel->input->isa->_free)(channel->input);
        !           437:        return YES;
        !           438:     }
        !           439:     return NO;
        !           440: }
        !           441: 
2.1       frystyk   442: /*
                    443: **     Create the output stream and bind it to the channel
                    444: **     Please read the description in the HTIOStream module on the parameters
                    445: */
2.10      frystyk   446: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch, HTOutputStream * output)
2.1       frystyk   447: {
                    448:     if (ch) {
                    449:        ch->output = output;
                    450:        return YES;
                    451:     }
                    452:     return NO;
                    453: }
                    454: 
                    455: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
                    456: {
                    457:     return ch ? ch->output : NULL;
2.25    ! frystyk   458: }
        !           459: 
        !           460: PUBLIC BOOL HTChannel_deleteOutput (HTChannel * channel, int status)
        !           461: {      
        !           462:     if (channel && channel->output && status != HT_IGNORE) {
        !           463:        HTTRACE(PROT_TRACE,
        !           464:                "Channel..... Delete input stream %p from channel %p\n" _ 
        !           465:                channel->input _ channel);
        !           466:        if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
        !           467:            (*channel->output->isa->abort)(channel->output, NULL);
        !           468:        else
        !           469:            (*channel->output->isa->_free)(channel->output);
        !           470:        return YES;
        !           471:     }
        !           472:     return NO;
2.13      frystyk   473: }
                    474: 
                    475: PUBLIC HTInputStream * HTChannel_getChannelIStream (HTChannel * ch)
                    476: {
                    477:     if (ch)
                    478:        return &ch->channelIStream;
                    479:     return NULL;
                    480: }
                    481: 
                    482: PUBLIC HTOutputStream * HTChannel_getChannelOStream (HTChannel * ch)
                    483: {
                    484:     if (ch)
                    485:        return &ch->channelOStream;
                    486:     return NULL;
2.1       frystyk   487: }
                    488: 

Webmaster