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

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.13    ! frystyk     6: **     @(#) $Id: HTChannl.c,v 2.12.2.6 1996/11/21 19:42:18 eric 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"
2.10      frystyk    17: #include "HTHost.h"
2.1       frystyk    18: #include "HTError.h"
                     19: #include "HTChannl.h"                                   /* Implemented here */
                     20: 
                     21: #define HASH_SIZE      67
                     22: #define HASH(s)                ((s) % HASH_SIZE)
                     23: 
2.13    ! frystyk    24: struct _HTInputStream {
        !            25:     const HTInputStreamClass * isa;
        !            26:     HTChannel *                        channel;
        !            27: };
        !            28: 
        !            29: struct _HTOutputStream {
        !            30:     const HTOutputStreamClass *        isa;
        !            31:     HTChannel *                        channel;
        !            32: };
        !            33: 
2.1       frystyk    34: struct _HTChannel {
2.13    ! frystyk    35:     /* what media do we talk to? */
2.1       frystyk    36:     SOCKET             sockfd;                                    /* Socket */
                     37:     FILE *             fp;
2.13    ! frystyk    38: 
        !            39:     /* what streams handle the IO */
2.1       frystyk    40:     HTInputStream *    input;                               /* Input stream */
                     41:     HTOutputStream *   output;                             /* Output stream */
2.13    ! frystyk    42:     /* proxy streams to dereference the above streams */
        !            43:     HTInputStream      channelIStream;
        !            44:     HTOutputStream     channelOStream;
        !            45: 
2.1       frystyk    46:     BOOL               active;                 /* Active or passive channel */
                     47:     int                        semaphore;                         /* On channel use */
2.10      frystyk    48:     HTHost *           host;                          /* Zombie connections */
2.1       frystyk    49: };
                     50: 
2.13    ! frystyk    51: PRIVATE HTList ** channels = NULL;                      /* List of channels */
2.1       frystyk    52: 
2.13    ! frystyk    53: /* ------------------------------------------------------------------------- */
2.1       frystyk    54: 
2.13    ! frystyk    55: /*
        !            56: **     Skinny stream objects to pass the IO requests to the channels current IO streams.
        !            57: **     This was needed because the channel's IO streams could go away after the IO streams
        !            58: **     were set up for multiple requests.
        !            59: */
        !            60: 
        !            61: PRIVATE int ChannelIStream_flush (HTInputStream * me)
        !            62: {return me->channel->input ? (*me->channel->input->isa->flush)(me->channel->input) : HT_ERROR;}
        !            63: PRIVATE int ChannelIStream_free (HTInputStream * me)
        !            64: {return me->channel->input ? (*me->channel->input->isa->_free)(me->channel->input) : HT_ERROR;}
        !            65: PRIVATE int ChannelIStream_abort (HTInputStream * me, HTList * e)
        !            66: {return me->channel->input ? (*me->channel->input->isa->abort)(me->channel->input, e) : HT_ERROR;}
        !            67: PRIVATE int ChannelIStream_read (HTInputStream * me)
        !            68: {return me->channel->input ? (*me->channel->input->isa->read)(me->channel->input) : HT_ERROR;}
        !            69: PRIVATE int ChannelIStream_close (HTInputStream * me)
        !            70: {return me->channel->input ? (*me->channel->input->isa->close)(me->channel->input) : HT_ERROR;}
        !            71: PUBLIC int ChannelIStream_consumed (HTInputStream * me, size_t bytes)
        !            72: {return me->channel->input ? (*me->channel->input->isa->consumed)(me->channel->input, bytes) : HT_ERROR;}
        !            73: PRIVATE const HTInputStreamClass ChannelIStreamIsa =
        !            74: {
        !            75:     "ChannelInput",
        !            76:     ChannelIStream_flush,
        !            77:     ChannelIStream_free,
        !            78:     ChannelIStream_abort,
        !            79:     ChannelIStream_read,
        !            80:     ChannelIStream_close,
        !            81:     ChannelIStream_consumed
        !            82: }; 
        !            83: 
        !            84: PRIVATE int ChannelOStream_flush (HTOutputStream * me)
        !            85: {return me->channel->output ? (*me->channel->output->isa->flush)(me->channel->output) : HT_ERROR;}
        !            86: PRIVATE int ChannelOStream_free (HTOutputStream * me)
        !            87: {return me->channel->output ? (*me->channel->output->isa->_free)(me->channel->output) : HT_ERROR;}
        !            88: PRIVATE int ChannelOStream_abort (HTOutputStream * me, HTList * e)
        !            89: {return me->channel->output ? (*me->channel->output->isa->abort)(me->channel->output, e) : HT_ERROR;}
        !            90: PRIVATE int ChannelOStream_put_character (HTOutputStream * me, char c)
        !            91: {return me->channel->output ? (*me->channel->output->isa->put_character)(me->channel->output, c) : HT_ERROR;}
        !            92: PRIVATE int ChannelOStream_put_string (HTOutputStream * me, const char * s)
        !            93: {return me->channel->output ? (*me->channel->output->isa->put_string)(me->channel->output, s) : HT_ERROR;}
        !            94: PRIVATE int ChannelOStream_put_block (HTOutputStream * me, const char * buf, int len)
        !            95: {return me->channel->output ? (*me->channel->output->isa->put_block)(me->channel->output, buf, len) : HT_ERROR;}
        !            96: PRIVATE int ChannelOStream_close (HTOutputStream * me)
        !            97: {return me->channel->output ? (*me->channel->output->isa->close)(me->channel->output) : HT_ERROR;}
        !            98: PRIVATE const HTOutputStreamClass ChannelOStreamIsa =
        !            99: {
        !           100:     "ChannelOutput",
        !           101:     ChannelOStream_flush,
        !           102:     ChannelOStream_free,
        !           103:     ChannelOStream_abort,
        !           104:     ChannelOStream_put_character,
        !           105:     ChannelOStream_put_string,
        !           106:     ChannelOStream_put_block,
        !           107:     ChannelOStream_close,
        !           108: }; 
2.1       frystyk   109: 
                    110: /* ------------------------------------------------------------------------- */
                    111: 
                    112: PRIVATE void free_channel (HTChannel * ch)
                    113: {
                    114:     if (ch) {
                    115: 
                    116:        /* Close the input and output stream */
2.11      frystyk   117:        if (ch->input) {
                    118:            (*ch->input->isa->close)(ch->input);
                    119:            ch->input = NULL;
                    120:        }
                    121:        if (ch->output) {
                    122:            (*ch->output->isa->close)(ch->output);
                    123:            ch->output = NULL;
                    124:        }
2.1       frystyk   125: 
                    126:        /* Close the socket */
                    127:        if (ch->sockfd != INVSOC) {
                    128:            NETCLOSE(ch->sockfd);
2.13    ! frystyk   129:            /*      HTEvent_unregister(ch->sockfd, all options); */
2.10      frystyk   130:            HTNet_decreaseSocket();
2.1       frystyk   131:            if (PROT_TRACE)
                    132:                HTTrace("Channel..... Deleted %p, socket %d\n", ch,ch->sockfd);
                    133:        }
2.13    ! frystyk   134:        ch->sockfd = INVSOC;
2.1       frystyk   135: 
                    136:        /* Close the file */
                    137:        if (ch->fp) {
                    138:            fclose(ch->fp);
                    139:            if (PROT_TRACE)
                    140:                HTTrace("Channel..... Deleted %p, file %p\n", ch, ch->fp);
                    141:        }
                    142:        HT_FREE(ch);
                    143:     }
                    144: }
                    145: 
                    146: /*
                    147: **     A channel is uniquely identified by a socket.
                    148: **     Note that we don't create the input and output stream - they are 
2.10      frystyk   149: **     created later.
2.1       frystyk   150: **
                    151: **     We only keep a hash on sockfd's as we don't have to look for channels
                    152: **     for ANSI file descriptors.
                    153: */
2.13    ! frystyk   154: PUBLIC HTChannel * HTChannel_new (SOCKET sockfd, BOOL active)
2.1       frystyk   155: {
2.13    ! frystyk   156:     HTList * list = NULL;
        !           157:     HTChannel * ch = NULL;
        !           158:     int hash = sockfd < 0 ? 0 : HASH(sockfd);
        !           159:     if (PROT_TRACE) HTTrace("Channel..... Hash value is %d\n", hash);
        !           160:     if (!channels) {
        !           161:        if (!(channels = (HTList **) HT_CALLOC(HASH_SIZE,sizeof(HTList*))))
        !           162:            HT_OUTOFMEM("HTChannel_new");
        !           163:     }
        !           164:     if (!channels[hash]) channels[hash] = HTList_new();
        !           165:     list = channels[hash];
        !           166:     if ((ch = (HTChannel *) HT_CALLOC(1, sizeof(HTChannel))) == NULL)
        !           167:        HT_OUTOFMEM("HTChannel_new");       
        !           168:     ch->sockfd = sockfd;
        !           169:     ch->active = active;
        !           170:     ch->semaphore = 1;
        !           171:     ch->channelIStream.isa = &ChannelIStreamIsa;
        !           172:     ch->channelOStream.isa = &ChannelOStreamIsa;
        !           173:     ch->channelIStream.channel = ch;
        !           174:     ch->channelOStream.channel = ch;
        !           175:     HTList_addObject(list, (void *) ch);
        !           176: 
        !           177:     if (PROT_TRACE) HTTrace("Channel..... Added %p to list %p\n", ch,list);
        !           178:     return ch;
2.1       frystyk   179: }
                    180: 
                    181: /*
                    182: **     Look for a channel object if we for some reason should have lost it
                    183: **     Returns NULL if nothing found
                    184: */
                    185: PUBLIC HTChannel * HTChannel_find (SOCKET sockfd)
                    186: {
                    187:     if (channels && sockfd != INVSOC) {
                    188:        int hash = HASH(sockfd);
                    189:        HTList * list = channels[hash];
                    190:        if (list) {
                    191:            HTChannel * ch = NULL;
                    192:            while ((ch = (HTChannel *) HTList_nextObject(list)))
                    193:                if (ch->sockfd == sockfd) return ch;
                    194:        }
                    195:     }
                    196:     return NULL;
                    197: }
                    198: 
                    199: /*
                    200: **     When deleting a channel we first look at if there are no more requests
                    201: **     using the channel (the semaphore is <= 0). Then, if the socket supports
                    202: **     persistent connections then we register the channel in the Host cache
                    203: **     and wait until the other end closes it or we get a time out on our side
                    204: */
2.6       eric      205: PUBLIC BOOL HTChannel_delete (HTChannel * channel, int status)
2.1       frystyk   206: {
                    207:     if (channel) {
2.2       frystyk   208:        if (PROT_TRACE) HTTrace("Channel..... Delete %p with semaphore %d\n",
2.1       frystyk   209:                                channel, channel->semaphore);
                    210:        /*
                    211:        **  We call the free methods on both the input stream and the output
                    212:        **  stream so that we can free up the stream pipes. However, note that
                    213:        **  this doesn't mean that we close the input stream and output stream
                    214:        **  them selves - only the generic streams
                    215:        */
2.12      frystyk   216:        if (status != HT_IGNORE) {
2.13    ! frystyk   217:            if (channel->input) {
2.12      frystyk   218:                if (status == HT_INTERRUPTED)
                    219:                    (*channel->input->isa->abort)(channel->input, NULL);
                    220:                else
                    221:                    (*channel->input->isa->_free)(channel->input);
2.13    ! frystyk   222:            }
        !           223:            if (channel->output) {
2.12      frystyk   224:                if (status == HT_INTERRUPTED)
                    225:                    (*channel->output->isa->abort)(channel->output, NULL);
                    226:                else
                    227:                    (*channel->output->isa->_free)(channel->output);
2.13    ! frystyk   228:            }
2.12      frystyk   229:        }
2.1       frystyk   230: 
                    231:        /*
                    232:        **  Check whether this channel is used by other objects or we can
                    233:        **  delete it and free memory.
                    234:        */
2.13    ! frystyk   235:        if (channel->semaphore <= 0 && channels && channel->sockfd != INVSOC) {
2.1       frystyk   236:            int hash = HASH(channel->sockfd);
                    237:            HTList * list = channels[hash];
                    238:            if (list) {
                    239:                HTList_removeObject(list, (void *) channel);
                    240:                free_channel(channel);
                    241:                return YES;
                    242:            }
2.8       frystyk   243:        } else
                    244:            HTChannel_downSemaphore(channel);
2.1       frystyk   245:     }
                    246:     return NO;
                    247: }
                    248: 
                    249: /*     HTChannel_deleteAll
                    250: **     -------------------
                    251: **     Destroys all channels. This is called by HTLibTerminate(0
                    252: */
2.9       frystyk   253: PUBLIC BOOL HTChannel_deleteAll (void)
2.1       frystyk   254: {
                    255:     if (channels) {
                    256:        HTList * cur;
                    257:        int cnt;
                    258:        for (cnt=0; cnt<HASH_SIZE; cnt++) {
                    259:            if ((cur = channels[cnt])) { 
                    260:                HTChannel * pres;
                    261:                while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
                    262:                    free_channel(pres);
                    263:            }
                    264:            HTList_delete(channels[cnt]);
                    265:        }
                    266:        HT_FREE(channels);
                    267:     }
                    268:     return YES;
                    269: }
                    270: 
                    271: /*
2.10      frystyk   272: **     Return the socket associated with this channel
2.1       frystyk   273: */
2.10      frystyk   274: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
2.1       frystyk   275: {
2.10      frystyk   276:     return channel ? channel->sockfd : INVSOC;
2.1       frystyk   277: }
                    278: 
2.13    ! frystyk   279: PUBLIC void HTChannel_setSocket (HTChannel * channel, SOCKET socket)
        !           280: {
        !           281:     if (channel)
        !           282:       channel->sockfd = socket;
        !           283: }
        !           284: 
2.10      frystyk   285: /*
                    286: **     Return the file descriptor associated with this channel
                    287: */
                    288: PUBLIC FILE * HTChannel_file (HTChannel * channel)
2.1       frystyk   289: {
2.10      frystyk   290:     return channel ? channel->fp : NULL;
2.1       frystyk   291: }
                    292: 
                    293: /*
2.10      frystyk   294: **     We keep the associated Host object in case we have a
                    295: **     sleeping connection. 
2.1       frystyk   296: */
2.10      frystyk   297: PUBLIC BOOL HTChannel_setHost (HTChannel * ch, HTHost * host)
2.1       frystyk   298: {
2.13    ! frystyk   299:     if (ch) {
2.10      frystyk   300:        ch->host = host;
                    301:        return YES;
                    302:     }
                    303:     return NO;
2.4       frystyk   304: }
                    305: 
2.10      frystyk   306: PUBLIC HTHost * HTChannel_host (HTChannel * ch)
2.4       frystyk   307: {
2.10      frystyk   308:     return (ch ? ch->host : NULL);
2.1       frystyk   309: }
                    310: 
                    311: /*
                    312: **     Increase the semaphore for this channel
                    313: */
                    314: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
                    315: {
                    316:     if (channel) {
                    317:        channel->semaphore++;
                    318:        if (PROT_TRACE)
                    319:            HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
                    320:                    channel->semaphore, channel);
                    321:     }
                    322: }
                    323: 
                    324: /*
                    325: **     Decrease the semaphore for this channel
                    326: */
                    327: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
                    328: {
                    329:     if (channel) {
                    330:        channel->semaphore--;
                    331:        if (channel->semaphore <= 0) channel->semaphore = 0;
                    332:        if (PROT_TRACE)
                    333:            HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
2.7       frystyk   334:                    channel->semaphore, channel);
                    335:     }
                    336: }
                    337: 
                    338: /*
                    339: **     Explicitly set the semaphore for this channel
                    340: */
                    341: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
                    342: {
                    343:     if (channel) {
                    344:        channel->semaphore = semaphore;
                    345:        if (channel->semaphore <= 0) channel->semaphore = 0;
                    346:        if (PROT_TRACE)
                    347:            HTTrace("Channel..... Semaphore set to %d for channel %p\n",
2.1       frystyk   348:                    channel->semaphore, channel);
                    349:     }
                    350: }
                    351: 
                    352: /*
                    353: **     Create the input stream and bind it to the channel
                    354: **     Please read the description in the HTIOStream module on the parameters
                    355: */
2.10      frystyk   356: PUBLIC BOOL HTChannel_setInput (HTChannel * ch, HTInputStream * input)
2.1       frystyk   357: {
                    358:     if (ch) {
                    359:        ch->input = input;
                    360:        return YES;
                    361:     }
                    362:     return NO;
                    363: }
                    364: 
                    365: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
                    366: {
                    367:     return ch ? ch->input : NULL;
                    368: }
                    369: 
                    370: /*
                    371: **     Create the output stream and bind it to the channel
                    372: **     Please read the description in the HTIOStream module on the parameters
                    373: */
2.10      frystyk   374: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch, HTOutputStream * output)
2.1       frystyk   375: {
                    376:     if (ch) {
                    377:        ch->output = output;
                    378:        return YES;
                    379:     }
                    380:     return NO;
                    381: }
                    382: 
                    383: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
                    384: {
                    385:     return ch ? ch->output : NULL;
2.13    ! frystyk   386: }
        !           387: 
        !           388: PUBLIC HTInputStream * HTChannel_getChannelIStream (HTChannel * ch)
        !           389: {
        !           390:     if (ch)
        !           391:        return &ch->channelIStream;
        !           392:     return NULL;
        !           393: }
        !           394: 
        !           395: PUBLIC HTOutputStream * HTChannel_getChannelOStream (HTChannel * ch)
        !           396: {
        !           397:     if (ch)
        !           398:        return &ch->channelOStream;
        !           399:     return NULL;
2.1       frystyk   400: }
                    401: 

Webmaster