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

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

Webmaster