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

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

Webmaster