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