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

2.1     ! frystyk     1: /*                                                                  HTChannl.c
        !             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.
        !             6: **     @(#) $Id: Date Author State $
        !             7: **
        !             8: **
        !             9: ** HISTORY:
        !            10: **     April 96  HFN   Written
        !            11: */
        !            12: 
        !            13: /* Library Include files */
        !            14: #include "sysdep.h"
        !            15: #include "WWWUtil.h"
        !            16: #include "HTAlert.h"
        !            17: #include "HTError.h"
        !            18: #include "HTNetMan.h"
        !            19: #include "HTReqMan.h"
        !            20: #include "HTChannl.h"                                   /* Implemented here */
        !            21: 
        !            22: #define HASH_SIZE      67
        !            23: #define HASH(s)                ((s) % HASH_SIZE)
        !            24: 
        !            25: struct _HTChannel {
        !            26:     SOCKET             sockfd;                                    /* Socket */
        !            27:     FILE *             fp;
        !            28:     HTChannelMode      mode;                             /* Mode of channel */
        !            29:     HTInputStream *    input;                               /* Input stream */
        !            30:     HTOutputStream *   output;                             /* Output stream */
        !            31:     BOOL               active;                 /* Active or passive channel */
        !            32:     int                        semaphore;                         /* On channel use */
        !            33: };
        !            34: 
        !            35: struct _HTInputStream {
        !            36:     const HTInputStreamClass * isa;    
        !            37: };
        !            38: 
        !            39: struct _HTOutputStream {
        !            40:     const HTOutputStreamClass *        isa;    
        !            41: };
        !            42: 
        !            43: PRIVATE HTList ** channels = NULL;                      /* List of channels */
        !            44: 
        !            45: /* ------------------------------------------------------------------------- */
        !            46: 
        !            47: PRIVATE void free_channel (HTChannel * ch)
        !            48: {
        !            49:     if (ch) {
        !            50: 
        !            51:        /* Close the input and output stream */
        !            52:        if (ch->input) (*ch->input->isa->close)(ch->input);
        !            53:        if (ch->output) (*ch->output->isa->close)(ch->output);
        !            54: 
        !            55:        /* Close the socket */
        !            56:        if (ch->sockfd != INVSOC) {
        !            57:            NETCLOSE(ch->sockfd);
        !            58:            HTEvent_UnRegister(ch->sockfd, (SockOps) FD_ALL);
        !            59:            if (PROT_TRACE)
        !            60:                HTTrace("Channel..... Deleted %p, socket %d\n", ch,ch->sockfd);
        !            61:        }
        !            62: 
        !            63:        /* Close the file */
        !            64:        if (ch->fp) {
        !            65:            fclose(ch->fp);
        !            66:            if (PROT_TRACE)
        !            67:                HTTrace("Channel..... Deleted %p, file %p\n", ch, ch->fp);
        !            68:        }
        !            69:        HT_FREE(ch);
        !            70:     }
        !            71: }
        !            72: 
        !            73: /*
        !            74: **     A channel is uniquely identified by a socket.
        !            75: **     Note that we don't create the input and output stream - they are 
        !            76: **     created later. When a channel first is created it has the default mode
        !            77: **     HT_CH_SINGLE which ensures that other connections to the same host
        !            78: **     will not result in multiple parallel connections but wait and see if
        !            79: **     the actual mode supported by the peer process.
        !            80: **
        !            81: **     We only keep a hash on sockfd's as we don't have to look for channels
        !            82: **     for ANSI file descriptors.
        !            83: */
        !            84: PUBLIC HTChannel * HTChannel_new (HTNet * net, BOOL active)
        !            85: {
        !            86:     if (net) {
        !            87:        HTList * list = NULL;
        !            88:        HTChannel * ch = NULL;
        !            89:        int hash = net->sockfd < 0 ? 0 : HASH(net->sockfd);
        !            90:        if (PROT_TRACE) HTTrace("Channel..... Hash value is %d\n", hash);
        !            91:        if (!channels) {
        !            92:            if (!(channels = (HTList **) HT_CALLOC(HASH_SIZE,sizeof(HTList*))))
        !            93:                HT_OUTOFMEM("HTChannel_new");
        !            94:        }
        !            95:        if (!channels[hash]) channels[hash] = HTList_new();
        !            96:        list = channels[hash];
        !            97:        if ((ch = (HTChannel *) HT_CALLOC(1, sizeof(HTChannel))) == NULL)
        !            98:            HT_OUTOFMEM("HTChannel_new");           
        !            99:        ch->sockfd = net->sockfd;
        !           100:        ch->mode = HT_CH_SINGLE;
        !           101:        ch->active = active;
        !           102:        ch->semaphore = 1;
        !           103:        HTList_addObject(list, (void *) ch);
        !           104:        if (PROT_TRACE) HTTrace("Channel..... Added %p to list %p\n", ch,list);
        !           105:        return ch;
        !           106:     }
        !           107:     return NULL;
        !           108: }
        !           109: 
        !           110: /*
        !           111: **     Look for a channel object if we for some reason should have lost it
        !           112: **     Returns NULL if nothing found
        !           113: */
        !           114: PUBLIC HTChannel * HTChannel_find (SOCKET sockfd)
        !           115: {
        !           116:     if (channels && sockfd != INVSOC) {
        !           117:        int hash = HASH(sockfd);
        !           118:        HTList * list = channels[hash];
        !           119:        if (list) {
        !           120:            HTChannel * ch = NULL;
        !           121:            while ((ch = (HTChannel *) HTList_nextObject(list)))
        !           122:                if (ch->sockfd == sockfd) return ch;
        !           123:        }
        !           124:     }
        !           125:     return NULL;
        !           126: }
        !           127: 
        !           128: /*
        !           129: **     When deleting a channel we first look at if there are no more requests
        !           130: **     using the channel (the semaphore is <= 0). Then, if the socket supports
        !           131: **     persistent connections then we register the channel in the Host cache
        !           132: **     and wait until the other end closes it or we get a time out on our side
        !           133: */
        !           134: PUBLIC BOOL HTChannel_delete (HTChannel * channel)
        !           135: {
        !           136:     if (channel) {
        !           137:        if (PROT_TRACE) HTTrace("Channel..... Delete % with semaphore %d\n",
        !           138:                                channel, channel->semaphore);
        !           139:        /*
        !           140:        **  We call the free methods on both the input stream and the output
        !           141:        **  stream so that we can free up the stream pipes. However, note that
        !           142:        **  this doesn't mean that we close the input stream and output stream
        !           143:        **  them selves - only the generic streams
        !           144:        */
        !           145:        if (channel->input) (*channel->input->isa->_free)(channel->input);
        !           146:        if (channel->output) (*channel->output->isa->_free)(channel->output);
        !           147: 
        !           148:        /*
        !           149:        **  Check whether this channel is used by other objects or we can
        !           150:        **  delete it and free memory.
        !           151:        */
        !           152:        if (channel->semaphore <= 0 && channels) {
        !           153:            int hash = HASH(channel->sockfd);
        !           154:            HTList * list = channels[hash];
        !           155:            if (list) {
        !           156:                HTList_removeObject(list, (void *) channel);
        !           157:                free_channel(channel);
        !           158:                return YES;
        !           159:            }
        !           160:        }
        !           161:     }
        !           162:     return NO;
        !           163: }
        !           164: 
        !           165: /*     HTChannel_deleteAll
        !           166: **     -------------------
        !           167: **     Destroys all channels. This is called by HTLibTerminate(0
        !           168: */
        !           169: PUBLIC BOOL HTCannel_deleteAll (void)
        !           170: {
        !           171:     if (channels) {
        !           172:        HTList * cur;
        !           173:        int cnt;
        !           174:        for (cnt=0; cnt<HASH_SIZE; cnt++) {
        !           175:            if ((cur = channels[cnt])) { 
        !           176:                HTChannel * pres;
        !           177:                while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
        !           178:                    free_channel(pres);
        !           179:            }
        !           180:            HTList_delete(channels[cnt]);
        !           181:        }
        !           182:        HT_FREE(channels);
        !           183:     }
        !           184:     return YES;
        !           185: }
        !           186: 
        !           187: /*
        !           188: **     Set and get the mode of a channel. A channel may change mode in the 
        !           189: **     middle of a connection. We also return whether the channel is active
        !           190: **     or passive.
        !           191: */
        !           192: PUBLIC HTChannelMode HTChannel_mode (HTChannel * channel, BOOL * active)
        !           193: {
        !           194:     return channel ? channel->mode : HT_CH_SINGLE;
        !           195: }
        !           196: 
        !           197: PUBLIC BOOL HTChannel_setMode (HTChannel * channel, HTChannelMode mode)
        !           198: {
        !           199:     if (channel) {
        !           200:        channel->mode = mode;
        !           201:        return YES;
        !           202:     }
        !           203:     return NO;
        !           204: }
        !           205: 
        !           206: /*
        !           207: **     Check whether a channel is idle meaning if it is ready for a new
        !           208: **     request which depends on the mode of the channel. If the channel is 
        !           209: **     idle, i.e. ready for use then return YES else NO.
        !           210: */
        !           211: PUBLIC BOOL HTChannel_idle (HTChannel * channel)
        !           212: {
        !           213:     return (channel &&
        !           214:            ((channel->mode != HT_CH_SINGLE) ||
        !           215:             (channel->mode == HT_CH_SINGLE && channel->semaphore <= 0)));
        !           216: }
        !           217: 
        !           218: /*
        !           219: **     Return the socket associated with this channel
        !           220: */
        !           221: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
        !           222: {
        !           223:     return channel ? channel->sockfd : INVSOC;
        !           224: }
        !           225: 
        !           226: /*
        !           227: **     Increase the semaphore for this channel
        !           228: */
        !           229: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
        !           230: {
        !           231:     if (channel) {
        !           232:        channel->semaphore++;
        !           233:        if (PROT_TRACE)
        !           234:            HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
        !           235:                    channel->semaphore, channel);
        !           236:     }
        !           237: }
        !           238: 
        !           239: /*
        !           240: **     Decrease the semaphore for this channel
        !           241: */
        !           242: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
        !           243: {
        !           244:     if (channel) {
        !           245:        channel->semaphore--;
        !           246:        if (channel->semaphore <= 0) channel->semaphore = 0;
        !           247:        if (PROT_TRACE)
        !           248:            HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
        !           249:                    channel->semaphore, channel);
        !           250:     }
        !           251: }
        !           252: 
        !           253: /*
        !           254: **     Create the input stream and bind it to the channel
        !           255: **     Please read the description in the HTIOStream module on the parameters
        !           256: */
        !           257: PUBLIC BOOL HTChannel_setInput (HTChannel * ch,
        !           258:                                HTInputStream * input, HTChannelMode mode)
        !           259: {
        !           260:     if (ch) {
        !           261:        ch->mode = mode;
        !           262:        ch->input = input;
        !           263:        return YES;
        !           264:     }
        !           265:     return NO;
        !           266: }
        !           267: 
        !           268: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
        !           269: {
        !           270:     return ch ? ch->input : NULL;
        !           271: }
        !           272: 
        !           273: /*
        !           274: **     Create the output stream and bind it to the channel
        !           275: **     Please read the description in the HTIOStream module on the parameters
        !           276: */
        !           277: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch,
        !           278:                                 HTOutputStream * output, HTChannelMode mode)
        !           279: {
        !           280:     if (ch) {
        !           281:        ch->mode = mode;
        !           282:        ch->output = output;
        !           283:        return YES;
        !           284:     }
        !           285:     return NO;
        !           286: }
        !           287: 
        !           288: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
        !           289: {
        !           290:     return ch ? ch->output : NULL;
        !           291: }
        !           292: 

Webmaster