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