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

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

Webmaster