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

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.22    ! frystyk     6: **     @(#) $Id: HTChannl.c,v 2.21 1999/01/22 14:02:19 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.1       frystyk   135:            if (PROT_TRACE)
                    136:                HTTrace("Channel..... Deleted %p, socket %d\n", ch,ch->sockfd);
2.14      frystyk   137:            ch->sockfd = INVSOC;
2.1       frystyk   138:        }
                    139: 
                    140:        /* Close the file */
                    141:        if (ch->fp) {
                    142:            fclose(ch->fp);
                    143:            if (PROT_TRACE)
                    144:                HTTrace("Channel..... Deleted %p, file %p\n", ch, ch->fp);
2.14      frystyk   145:            ch->fp = NULL;
2.1       frystyk   146:        }
                    147:        HT_FREE(ch);
                    148:     }
                    149: }
                    150: 
                    151: /*
                    152: **     A channel is uniquely identified by a socket.
                    153: **     Note that we don't create the input and output stream - they are 
2.10      frystyk   154: **     created later.
2.1       frystyk   155: **
                    156: **     We only keep a hash on sockfd's as we don't have to look for channels
                    157: **     for ANSI file descriptors.
                    158: */
2.14      frystyk   159: PUBLIC HTChannel * HTChannel_new (SOCKET sockfd, FILE * fp, BOOL active)
2.1       frystyk   160: {
2.13      frystyk   161:     HTList * list = NULL;
                    162:     HTChannel * ch = NULL;
                    163:     int hash = sockfd < 0 ? 0 : HASH(sockfd);
                    164:     if (PROT_TRACE) HTTrace("Channel..... Hash value is %d\n", hash);
                    165:     if (!channels) {
2.22    ! frystyk   166:        if (!(channels = (HTList **) HT_CALLOC(HT_M_HASH_SIZE,sizeof(HTList*))))
2.13      frystyk   167:            HT_OUTOFMEM("HTChannel_new");
                    168:     }
                    169:     if (!channels[hash]) channels[hash] = HTList_new();
                    170:     list = channels[hash];
                    171:     if ((ch = (HTChannel *) HT_CALLOC(1, sizeof(HTChannel))) == NULL)
                    172:        HT_OUTOFMEM("HTChannel_new");       
                    173:     ch->sockfd = sockfd;
2.14      frystyk   174:     ch->fp = fp;
2.13      frystyk   175:     ch->active = active;
                    176:     ch->semaphore = 1;
                    177:     ch->channelIStream.isa = &ChannelIStreamIsa;
                    178:     ch->channelOStream.isa = &ChannelOStreamIsa;
                    179:     ch->channelIStream.channel = ch;
                    180:     ch->channelOStream.channel = ch;
                    181:     HTList_addObject(list, (void *) ch);
                    182: 
2.16      frystyk   183: #ifdef HT_MUX
                    184:            /*
                    185:            **  Create a MUX channel and do a connect on this channel with a
                    186:            **  new session.
                    187:            */
                    188:            {
                    189:                HTProtocol * protocol = HTNet_protocol(net);
                    190:                HTMuxChannel * muxch = HTMuxChannel_new(me);
                    191:                net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
                    192:            }
                    193: #endif /* HT_MUX */
                    194: 
2.13      frystyk   195:     if (PROT_TRACE) HTTrace("Channel..... Added %p to list %p\n", ch,list);
                    196:     return ch;
2.1       frystyk   197: }
                    198: 
                    199: /*
                    200: **     Look for a channel object if we for some reason should have lost it
                    201: **     Returns NULL if nothing found
                    202: */
                    203: PUBLIC HTChannel * HTChannel_find (SOCKET sockfd)
                    204: {
                    205:     if (channels && sockfd != INVSOC) {
                    206:        int hash = HASH(sockfd);
                    207:        HTList * list = channels[hash];
                    208:        if (list) {
                    209:            HTChannel * ch = NULL;
                    210:            while ((ch = (HTChannel *) HTList_nextObject(list)))
                    211:                if (ch->sockfd == sockfd) return ch;
                    212:        }
                    213:     }
                    214:     return NULL;
                    215: }
                    216: 
                    217: /*
                    218: **     When deleting a channel we first look at if there are no more requests
                    219: **     using the channel (the semaphore is <= 0). Then, if the socket supports
                    220: **     persistent connections then we register the channel in the Host cache
                    221: **     and wait until the other end closes it or we get a time out on our side
                    222: */
2.6       eric      223: PUBLIC BOOL HTChannel_delete (HTChannel * channel, int status)
2.1       frystyk   224: {
                    225:     if (channel) {
2.2       frystyk   226:        if (PROT_TRACE) HTTrace("Channel..... Delete %p with semaphore %d\n",
2.1       frystyk   227:                                channel, channel->semaphore);
                    228:        /*
                    229:        **  We call the free methods on both the input stream and the output
                    230:        **  stream so that we can free up the stream pipes. However, note that
                    231:        **  this doesn't mean that we close the input stream and output stream
                    232:        **  them selves - only the generic streams
                    233:        */
2.12      frystyk   234:        if (status != HT_IGNORE) {
2.13      frystyk   235:            if (channel->input) {
2.19      frystyk   236:                 if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
2.12      frystyk   237:                    (*channel->input->isa->abort)(channel->input, NULL);
                    238:                else
                    239:                    (*channel->input->isa->_free)(channel->input);
2.13      frystyk   240:            }
                    241:            if (channel->output) {
2.19      frystyk   242:                if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
2.12      frystyk   243:                    (*channel->output->isa->abort)(channel->output, NULL);
                    244:                else
                    245:                    (*channel->output->isa->_free)(channel->output);
2.13      frystyk   246:            }
2.12      frystyk   247:        }
2.1       frystyk   248: 
                    249:        /*
                    250:        **  Check whether this channel is used by other objects or we can
                    251:        **  delete it and free memory.
                    252:        */
2.18      frystyk   253:        if (channel->semaphore <= 0 && channels && (
                    254:            channel->sockfd != INVSOC || channel->fp != NULL)) {
2.15      frystyk   255:             int hash = HASH(channel->sockfd);
2.1       frystyk   256:            HTList * list = channels[hash];
                    257:            if (list) {
                    258:                HTList_removeObject(list, (void *) channel);
                    259:                free_channel(channel);
                    260:                return YES;
                    261:            }
2.8       frystyk   262:        } else
                    263:            HTChannel_downSemaphore(channel);
2.1       frystyk   264:     }
                    265:     return NO;
                    266: }
                    267: 
                    268: /*     HTChannel_deleteAll
                    269: **     -------------------
                    270: **     Destroys all channels. This is called by HTLibTerminate(0
                    271: */
2.9       frystyk   272: PUBLIC BOOL HTChannel_deleteAll (void)
2.1       frystyk   273: {
                    274:     if (channels) {
                    275:        HTList * cur;
                    276:        int cnt;
2.22    ! frystyk   277:        for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
2.1       frystyk   278:            if ((cur = channels[cnt])) { 
                    279:                HTChannel * pres;
                    280:                while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
                    281:                    free_channel(pres);
                    282:            }
                    283:            HTList_delete(channels[cnt]);
                    284:        }
                    285:        HT_FREE(channels);
                    286:     }
                    287:     return YES;
                    288: }
                    289: 
                    290: /*
2.10      frystyk   291: **     Return the socket associated with this channel
2.1       frystyk   292: */
2.10      frystyk   293: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
2.1       frystyk   294: {
2.10      frystyk   295:     return channel ? channel->sockfd : INVSOC;
2.1       frystyk   296: }
                    297: 
2.14      frystyk   298: PUBLIC BOOL HTChannel_setSocket (HTChannel * channel, SOCKET socket)
2.13      frystyk   299: {
2.14      frystyk   300:     if (channel) {
2.13      frystyk   301:       channel->sockfd = socket;
2.14      frystyk   302:       return YES;
                    303:     }
                    304:     return NO;
2.13      frystyk   305: }
                    306: 
2.10      frystyk   307: /*
                    308: **     Return the file descriptor associated with this channel
                    309: */
                    310: PUBLIC FILE * HTChannel_file (HTChannel * channel)
2.1       frystyk   311: {
2.10      frystyk   312:     return channel ? channel->fp : NULL;
2.1       frystyk   313: }
                    314: 
2.14      frystyk   315: PUBLIC BOOL HTChannel_setFile (HTChannel * channel, FILE * fp)
                    316: {
                    317:     if (channel) {
                    318:        channel->fp = fp;
                    319:        return YES;
                    320:     }
                    321:     return NO;
                    322: }
                    323: 
2.1       frystyk   324: /*
2.10      frystyk   325: **     We keep the associated Host object in case we have a
                    326: **     sleeping connection. 
2.1       frystyk   327: */
2.10      frystyk   328: PUBLIC BOOL HTChannel_setHost (HTChannel * ch, HTHost * host)
2.1       frystyk   329: {
2.13      frystyk   330:     if (ch) {
2.10      frystyk   331:        ch->host = host;
                    332:        return YES;
                    333:     }
                    334:     return NO;
2.4       frystyk   335: }
                    336: 
2.10      frystyk   337: PUBLIC HTHost * HTChannel_host (HTChannel * ch)
2.4       frystyk   338: {
2.10      frystyk   339:     return (ch ? ch->host : NULL);
2.1       frystyk   340: }
                    341: 
                    342: /*
                    343: **     Increase the semaphore for this channel
                    344: */
                    345: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
                    346: {
                    347:     if (channel) {
                    348:        channel->semaphore++;
                    349:        if (PROT_TRACE)
                    350:            HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
                    351:                    channel->semaphore, channel);
2.16      frystyk   352: #ifdef HT_MUX
                    353:                HTMuxChannel * muxch = HTMuxChannel_find(me);
                    354:                HTProtocol * protocol = HTNet_protocol(net);
                    355:                net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
                    356: #endif /* HT_MUX */
                    357: 
2.1       frystyk   358:     }
                    359: }
                    360: 
                    361: /*
                    362: **     Decrease the semaphore for this channel
                    363: */
                    364: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
                    365: {
                    366:     if (channel) {
                    367:        channel->semaphore--;
                    368:        if (channel->semaphore <= 0) channel->semaphore = 0;
                    369:        if (PROT_TRACE)
                    370:            HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
2.7       frystyk   371:                    channel->semaphore, channel);
                    372:     }
                    373: }
                    374: 
                    375: /*
                    376: **     Explicitly set the semaphore for this channel
                    377: */
                    378: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
                    379: {
                    380:     if (channel) {
                    381:        channel->semaphore = semaphore;
                    382:        if (channel->semaphore <= 0) channel->semaphore = 0;
                    383:        if (PROT_TRACE)
                    384:            HTTrace("Channel..... Semaphore set to %d for channel %p\n",
2.1       frystyk   385:                    channel->semaphore, channel);
                    386:     }
                    387: }
                    388: 
                    389: /*
                    390: **     Create the input stream and bind it to the channel
                    391: **     Please read the description in the HTIOStream module on the parameters
                    392: */
2.10      frystyk   393: PUBLIC BOOL HTChannel_setInput (HTChannel * ch, HTInputStream * input)
2.1       frystyk   394: {
                    395:     if (ch) {
                    396:        ch->input = input;
                    397:        return YES;
                    398:     }
                    399:     return NO;
                    400: }
                    401: 
                    402: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
                    403: {
                    404:     return ch ? ch->input : NULL;
                    405: }
                    406: 
                    407: /*
                    408: **     Create the output stream and bind it to the channel
                    409: **     Please read the description in the HTIOStream module on the parameters
                    410: */
2.10      frystyk   411: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch, HTOutputStream * output)
2.1       frystyk   412: {
                    413:     if (ch) {
                    414:        ch->output = output;
                    415:        return YES;
                    416:     }
                    417:     return NO;
                    418: }
                    419: 
                    420: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
                    421: {
                    422:     return ch ? ch->output : NULL;
2.13      frystyk   423: }
                    424: 
                    425: PUBLIC HTInputStream * HTChannel_getChannelIStream (HTChannel * ch)
                    426: {
                    427:     if (ch)
                    428:        return &ch->channelIStream;
                    429:     return NULL;
                    430: }
                    431: 
                    432: PUBLIC HTOutputStream * HTChannel_getChannelOStream (HTChannel * ch)
                    433: {
                    434:     if (ch)
                    435:        return &ch->channelOStream;
                    436:     return NULL;
2.1       frystyk   437: }
                    438: 

Webmaster