Annotation of libwww/Library/src/HTChannl.c, revision 2.1
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.
! 6: ** @(#) $Id: Date Author State $
! 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"
! 17: #include "HTError.h"
! 18: #include "HTNetMan.h"
! 19: #include "HTReqMan.h"
! 20: #include "HTChannl.h" /* Implemented here */
! 21:
! 22: #define HASH_SIZE 67
! 23: #define HASH(s) ((s) % HASH_SIZE)
! 24:
! 25: struct _HTChannel {
! 26: SOCKET sockfd; /* Socket */
! 27: FILE * fp;
! 28: HTChannelMode mode; /* Mode of channel */
! 29: HTInputStream * input; /* Input stream */
! 30: HTOutputStream * output; /* Output stream */
! 31: BOOL active; /* Active or passive channel */
! 32: int semaphore; /* On channel use */
! 33: };
! 34:
! 35: struct _HTInputStream {
! 36: const HTInputStreamClass * isa;
! 37: };
! 38:
! 39: struct _HTOutputStream {
! 40: const HTOutputStreamClass * isa;
! 41: };
! 42:
! 43: PRIVATE HTList ** channels = NULL; /* List of channels */
! 44:
! 45: /* ------------------------------------------------------------------------- */
! 46:
! 47: PRIVATE void free_channel (HTChannel * ch)
! 48: {
! 49: if (ch) {
! 50:
! 51: /* Close the input and output stream */
! 52: if (ch->input) (*ch->input->isa->close)(ch->input);
! 53: if (ch->output) (*ch->output->isa->close)(ch->output);
! 54:
! 55: /* Close the socket */
! 56: if (ch->sockfd != INVSOC) {
! 57: NETCLOSE(ch->sockfd);
! 58: HTEvent_UnRegister(ch->sockfd, (SockOps) FD_ALL);
! 59: if (PROT_TRACE)
! 60: HTTrace("Channel..... Deleted %p, socket %d\n", ch,ch->sockfd);
! 61: }
! 62:
! 63: /* Close the file */
! 64: if (ch->fp) {
! 65: fclose(ch->fp);
! 66: if (PROT_TRACE)
! 67: HTTrace("Channel..... Deleted %p, file %p\n", ch, ch->fp);
! 68: }
! 69: HT_FREE(ch);
! 70: }
! 71: }
! 72:
! 73: /*
! 74: ** A channel is uniquely identified by a socket.
! 75: ** Note that we don't create the input and output stream - they are
! 76: ** created later. When a channel first is created it has the default mode
! 77: ** HT_CH_SINGLE which ensures that other connections to the same host
! 78: ** will not result in multiple parallel connections but wait and see if
! 79: ** the actual mode supported by the peer process.
! 80: **
! 81: ** We only keep a hash on sockfd's as we don't have to look for channels
! 82: ** for ANSI file descriptors.
! 83: */
! 84: PUBLIC HTChannel * HTChannel_new (HTNet * net, BOOL active)
! 85: {
! 86: if (net) {
! 87: HTList * list = NULL;
! 88: HTChannel * ch = NULL;
! 89: int hash = net->sockfd < 0 ? 0 : HASH(net->sockfd);
! 90: if (PROT_TRACE) HTTrace("Channel..... Hash value is %d\n", hash);
! 91: if (!channels) {
! 92: if (!(channels = (HTList **) HT_CALLOC(HASH_SIZE,sizeof(HTList*))))
! 93: HT_OUTOFMEM("HTChannel_new");
! 94: }
! 95: if (!channels[hash]) channels[hash] = HTList_new();
! 96: list = channels[hash];
! 97: if ((ch = (HTChannel *) HT_CALLOC(1, sizeof(HTChannel))) == NULL)
! 98: HT_OUTOFMEM("HTChannel_new");
! 99: ch->sockfd = net->sockfd;
! 100: ch->mode = HT_CH_SINGLE;
! 101: ch->active = active;
! 102: ch->semaphore = 1;
! 103: HTList_addObject(list, (void *) ch);
! 104: if (PROT_TRACE) HTTrace("Channel..... Added %p to list %p\n", ch,list);
! 105: return ch;
! 106: }
! 107: return NULL;
! 108: }
! 109:
! 110: /*
! 111: ** Look for a channel object if we for some reason should have lost it
! 112: ** Returns NULL if nothing found
! 113: */
! 114: PUBLIC HTChannel * HTChannel_find (SOCKET sockfd)
! 115: {
! 116: if (channels && sockfd != INVSOC) {
! 117: int hash = HASH(sockfd);
! 118: HTList * list = channels[hash];
! 119: if (list) {
! 120: HTChannel * ch = NULL;
! 121: while ((ch = (HTChannel *) HTList_nextObject(list)))
! 122: if (ch->sockfd == sockfd) return ch;
! 123: }
! 124: }
! 125: return NULL;
! 126: }
! 127:
! 128: /*
! 129: ** When deleting a channel we first look at if there are no more requests
! 130: ** using the channel (the semaphore is <= 0). Then, if the socket supports
! 131: ** persistent connections then we register the channel in the Host cache
! 132: ** and wait until the other end closes it or we get a time out on our side
! 133: */
! 134: PUBLIC BOOL HTChannel_delete (HTChannel * channel)
! 135: {
! 136: if (channel) {
! 137: if (PROT_TRACE) HTTrace("Channel..... Delete % with semaphore %d\n",
! 138: channel, channel->semaphore);
! 139: /*
! 140: ** We call the free methods on both the input stream and the output
! 141: ** stream so that we can free up the stream pipes. However, note that
! 142: ** this doesn't mean that we close the input stream and output stream
! 143: ** them selves - only the generic streams
! 144: */
! 145: if (channel->input) (*channel->input->isa->_free)(channel->input);
! 146: if (channel->output) (*channel->output->isa->_free)(channel->output);
! 147:
! 148: /*
! 149: ** Check whether this channel is used by other objects or we can
! 150: ** delete it and free memory.
! 151: */
! 152: if (channel->semaphore <= 0 && channels) {
! 153: int hash = HASH(channel->sockfd);
! 154: HTList * list = channels[hash];
! 155: if (list) {
! 156: HTList_removeObject(list, (void *) channel);
! 157: free_channel(channel);
! 158: return YES;
! 159: }
! 160: }
! 161: }
! 162: return NO;
! 163: }
! 164:
! 165: /* HTChannel_deleteAll
! 166: ** -------------------
! 167: ** Destroys all channels. This is called by HTLibTerminate(0
! 168: */
! 169: PUBLIC BOOL HTCannel_deleteAll (void)
! 170: {
! 171: if (channels) {
! 172: HTList * cur;
! 173: int cnt;
! 174: for (cnt=0; cnt<HASH_SIZE; cnt++) {
! 175: if ((cur = channels[cnt])) {
! 176: HTChannel * pres;
! 177: while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
! 178: free_channel(pres);
! 179: }
! 180: HTList_delete(channels[cnt]);
! 181: }
! 182: HT_FREE(channels);
! 183: }
! 184: return YES;
! 185: }
! 186:
! 187: /*
! 188: ** Set and get the mode of a channel. A channel may change mode in the
! 189: ** middle of a connection. We also return whether the channel is active
! 190: ** or passive.
! 191: */
! 192: PUBLIC HTChannelMode HTChannel_mode (HTChannel * channel, BOOL * active)
! 193: {
! 194: return channel ? channel->mode : HT_CH_SINGLE;
! 195: }
! 196:
! 197: PUBLIC BOOL HTChannel_setMode (HTChannel * channel, HTChannelMode mode)
! 198: {
! 199: if (channel) {
! 200: channel->mode = mode;
! 201: return YES;
! 202: }
! 203: return NO;
! 204: }
! 205:
! 206: /*
! 207: ** Check whether a channel is idle meaning if it is ready for a new
! 208: ** request which depends on the mode of the channel. If the channel is
! 209: ** idle, i.e. ready for use then return YES else NO.
! 210: */
! 211: PUBLIC BOOL HTChannel_idle (HTChannel * channel)
! 212: {
! 213: return (channel &&
! 214: ((channel->mode != HT_CH_SINGLE) ||
! 215: (channel->mode == HT_CH_SINGLE && channel->semaphore <= 0)));
! 216: }
! 217:
! 218: /*
! 219: ** Return the socket associated with this channel
! 220: */
! 221: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
! 222: {
! 223: return channel ? channel->sockfd : INVSOC;
! 224: }
! 225:
! 226: /*
! 227: ** Increase the semaphore for this channel
! 228: */
! 229: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
! 230: {
! 231: if (channel) {
! 232: channel->semaphore++;
! 233: if (PROT_TRACE)
! 234: HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
! 235: channel->semaphore, channel);
! 236: }
! 237: }
! 238:
! 239: /*
! 240: ** Decrease the semaphore for this channel
! 241: */
! 242: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
! 243: {
! 244: if (channel) {
! 245: channel->semaphore--;
! 246: if (channel->semaphore <= 0) channel->semaphore = 0;
! 247: if (PROT_TRACE)
! 248: HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
! 249: channel->semaphore, channel);
! 250: }
! 251: }
! 252:
! 253: /*
! 254: ** Create the input stream and bind it to the channel
! 255: ** Please read the description in the HTIOStream module on the parameters
! 256: */
! 257: PUBLIC BOOL HTChannel_setInput (HTChannel * ch,
! 258: HTInputStream * input, HTChannelMode mode)
! 259: {
! 260: if (ch) {
! 261: ch->mode = mode;
! 262: ch->input = input;
! 263: return YES;
! 264: }
! 265: return NO;
! 266: }
! 267:
! 268: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
! 269: {
! 270: return ch ? ch->input : NULL;
! 271: }
! 272:
! 273: /*
! 274: ** Create the output stream and bind it to the channel
! 275: ** Please read the description in the HTIOStream module on the parameters
! 276: */
! 277: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch,
! 278: HTOutputStream * output, HTChannelMode mode)
! 279: {
! 280: if (ch) {
! 281: ch->mode = mode;
! 282: ch->output = output;
! 283: return YES;
! 284: }
! 285: return NO;
! 286: }
! 287:
! 288: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
! 289: {
! 290: return ch ? ch->output : NULL;
! 291: }
! 292:
Webmaster