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

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.23    ! kahan       6: **     @(#) $Id: HTChannl.c,v 2.22 1999/02/07 18:20:31 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;
2.23    ! kahan     288: }
        !           289: 
        !           290: /*      HTChannel_safeDeleteAll
        !           291: **      -------------------
        !           292: **      Destroys all channels. This is called by HTLibTerminate(0
        !           293: */
        !           294:  
        !           295: PUBLIC BOOL HTChannel_safeDeleteAll (void)
        !           296: {
        !           297:     if (channels) {
        !           298:         HTList * cur;
        !           299:         int cnt;
        !           300:         for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
        !           301:           if ((cur = channels[cnt])) {
        !           302:             HTChannel * pres;
        !           303:             while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL) {
        !           304:               HTChannel_delete (pres, HT_TIMEOUT);
        !           305:               cur = channels[cnt];
        !           306:             }
        !           307:           }
        !           308:         }
        !           309:         return YES;
        !           310:     }
        !           311:     return NO;
2.1       frystyk   312: }
                    313: 
                    314: /*
2.10      frystyk   315: **     Return the socket associated with this channel
2.1       frystyk   316: */
2.10      frystyk   317: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
2.1       frystyk   318: {
2.10      frystyk   319:     return channel ? channel->sockfd : INVSOC;
2.1       frystyk   320: }
                    321: 
2.14      frystyk   322: PUBLIC BOOL HTChannel_setSocket (HTChannel * channel, SOCKET socket)
2.13      frystyk   323: {
2.14      frystyk   324:     if (channel) {
2.13      frystyk   325:       channel->sockfd = socket;
2.14      frystyk   326:       return YES;
                    327:     }
                    328:     return NO;
2.13      frystyk   329: }
                    330: 
2.10      frystyk   331: /*
                    332: **     Return the file descriptor associated with this channel
                    333: */
                    334: PUBLIC FILE * HTChannel_file (HTChannel * channel)
2.1       frystyk   335: {
2.10      frystyk   336:     return channel ? channel->fp : NULL;
2.1       frystyk   337: }
                    338: 
2.14      frystyk   339: PUBLIC BOOL HTChannel_setFile (HTChannel * channel, FILE * fp)
                    340: {
                    341:     if (channel) {
                    342:        channel->fp = fp;
                    343:        return YES;
                    344:     }
                    345:     return NO;
                    346: }
                    347: 
2.1       frystyk   348: /*
2.10      frystyk   349: **     We keep the associated Host object in case we have a
                    350: **     sleeping connection. 
2.1       frystyk   351: */
2.10      frystyk   352: PUBLIC BOOL HTChannel_setHost (HTChannel * ch, HTHost * host)
2.1       frystyk   353: {
2.13      frystyk   354:     if (ch) {
2.10      frystyk   355:        ch->host = host;
                    356:        return YES;
                    357:     }
                    358:     return NO;
2.4       frystyk   359: }
                    360: 
2.10      frystyk   361: PUBLIC HTHost * HTChannel_host (HTChannel * ch)
2.4       frystyk   362: {
2.10      frystyk   363:     return (ch ? ch->host : NULL);
2.1       frystyk   364: }
                    365: 
                    366: /*
                    367: **     Increase the semaphore for this channel
                    368: */
                    369: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
                    370: {
                    371:     if (channel) {
                    372:        channel->semaphore++;
                    373:        if (PROT_TRACE)
                    374:            HTTrace("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;
                    393:        if (PROT_TRACE)
                    394:            HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
2.7       frystyk   395:                    channel->semaphore, channel);
                    396:     }
                    397: }
                    398: 
                    399: /*
                    400: **     Explicitly set the semaphore for this channel
                    401: */
                    402: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
                    403: {
                    404:     if (channel) {
                    405:        channel->semaphore = semaphore;
                    406:        if (channel->semaphore <= 0) channel->semaphore = 0;
                    407:        if (PROT_TRACE)
                    408:            HTTrace("Channel..... Semaphore set to %d for channel %p\n",
2.1       frystyk   409:                    channel->semaphore, channel);
                    410:     }
                    411: }
                    412: 
                    413: /*
                    414: **     Create the input stream and bind it to the channel
                    415: **     Please read the description in the HTIOStream module on the parameters
                    416: */
2.10      frystyk   417: PUBLIC BOOL HTChannel_setInput (HTChannel * ch, HTInputStream * input)
2.1       frystyk   418: {
                    419:     if (ch) {
                    420:        ch->input = input;
                    421:        return YES;
                    422:     }
                    423:     return NO;
                    424: }
                    425: 
                    426: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
                    427: {
                    428:     return ch ? ch->input : NULL;
                    429: }
                    430: 
                    431: /*
                    432: **     Create the output stream and bind it to the channel
                    433: **     Please read the description in the HTIOStream module on the parameters
                    434: */
2.10      frystyk   435: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch, HTOutputStream * output)
2.1       frystyk   436: {
                    437:     if (ch) {
                    438:        ch->output = output;
                    439:        return YES;
                    440:     }
                    441:     return NO;
                    442: }
                    443: 
                    444: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
                    445: {
                    446:     return ch ? ch->output : NULL;
2.13      frystyk   447: }
                    448: 
                    449: PUBLIC HTInputStream * HTChannel_getChannelIStream (HTChannel * ch)
                    450: {
                    451:     if (ch)
                    452:        return &ch->channelIStream;
                    453:     return NULL;
                    454: }
                    455: 
                    456: PUBLIC HTOutputStream * HTChannel_getChannelOStream (HTChannel * ch)
                    457: {
                    458:     if (ch)
                    459:        return &ch->channelOStream;
                    460:     return NULL;
2.1       frystyk   461: }
                    462: 

Webmaster