Annotation of libwww/Library/src/HTChannl.c, revision 2.25
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.25 ! frystyk 6: ** @(#) $Id: HTChannl.c,v 2.24 1999/02/22 22:10:11 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.24 frystyk 135: HTTRACE(PROT_TRACE, "Channel..... Deleted %p, socket %d\n" _ ch _ ch->sockfd);
2.14 frystyk 136: ch->sockfd = INVSOC;
2.1 frystyk 137: }
138:
139: /* Close the file */
140: if (ch->fp) {
141: fclose(ch->fp);
2.24 frystyk 142: HTTRACE(PROT_TRACE, "Channel..... Deleted %p, file %p\n" _ ch _ ch->fp);
2.14 frystyk 143: ch->fp = NULL;
2.1 frystyk 144: }
145: HT_FREE(ch);
146: }
147: }
148:
149: /*
150: ** A channel is uniquely identified by a socket.
151: ** Note that we don't create the input and output stream - they are
2.10 frystyk 152: ** created later.
2.1 frystyk 153: **
154: ** We only keep a hash on sockfd's as we don't have to look for channels
155: ** for ANSI file descriptors.
156: */
2.14 frystyk 157: PUBLIC HTChannel * HTChannel_new (SOCKET sockfd, FILE * fp, BOOL active)
2.1 frystyk 158: {
2.13 frystyk 159: HTList * list = NULL;
160: HTChannel * ch = NULL;
161: int hash = sockfd < 0 ? 0 : HASH(sockfd);
2.24 frystyk 162: HTTRACE(PROT_TRACE, "Channel..... Hash value is %d\n" _ hash);
2.13 frystyk 163: if (!channels) {
2.22 frystyk 164: if (!(channels = (HTList **) HT_CALLOC(HT_M_HASH_SIZE,sizeof(HTList*))))
2.13 frystyk 165: HT_OUTOFMEM("HTChannel_new");
166: }
167: if (!channels[hash]) channels[hash] = HTList_new();
168: list = channels[hash];
169: if ((ch = (HTChannel *) HT_CALLOC(1, sizeof(HTChannel))) == NULL)
170: HT_OUTOFMEM("HTChannel_new");
171: ch->sockfd = sockfd;
2.14 frystyk 172: ch->fp = fp;
2.13 frystyk 173: ch->active = active;
174: ch->semaphore = 1;
175: ch->channelIStream.isa = &ChannelIStreamIsa;
176: ch->channelOStream.isa = &ChannelOStreamIsa;
177: ch->channelIStream.channel = ch;
178: ch->channelOStream.channel = ch;
179: HTList_addObject(list, (void *) ch);
180:
2.16 frystyk 181: #ifdef HT_MUX
182: /*
183: ** Create a MUX channel and do a connect on this channel with a
184: ** new session.
185: */
186: {
187: HTProtocol * protocol = HTNet_protocol(net);
188: HTMuxChannel * muxch = HTMuxChannel_new(me);
189: net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
190: }
191: #endif /* HT_MUX */
192:
2.24 frystyk 193: HTTRACE(PROT_TRACE, "Channel..... Added %p to list %p\n" _ ch _ list);
2.13 frystyk 194: return ch;
2.1 frystyk 195: }
196:
197: /*
198: ** Look for a channel object if we for some reason should have lost it
199: ** Returns NULL if nothing found
200: */
201: PUBLIC HTChannel * HTChannel_find (SOCKET sockfd)
202: {
203: if (channels && sockfd != INVSOC) {
204: int hash = HASH(sockfd);
205: HTList * list = channels[hash];
206: if (list) {
207: HTChannel * ch = NULL;
208: while ((ch = (HTChannel *) HTList_nextObject(list)))
209: if (ch->sockfd == sockfd) return ch;
210: }
211: }
212: return NULL;
213: }
214:
215: /*
216: ** When deleting a channel we first look at if there are no more requests
217: ** using the channel (the semaphore is <= 0). Then, if the socket supports
218: ** persistent connections then we register the channel in the Host cache
219: ** and wait until the other end closes it or we get a time out on our side
220: */
2.6 eric 221: PUBLIC BOOL HTChannel_delete (HTChannel * channel, int status)
2.1 frystyk 222: {
223: if (channel) {
2.25 ! frystyk 224: HTTRACE(PROT_TRACE, "Channel..... Delete %p with semaphore %d, status %d\n" _
! 225: channel _ channel->semaphore _ status);
2.1 frystyk 226: /*
227: ** We call the free methods on both the input stream and the output
228: ** stream so that we can free up the stream pipes. However, note that
229: ** this doesn't mean that we close the input stream and output stream
230: ** them selves - only the generic streams
231: */
2.25 ! frystyk 232: HTChannel_deleteInput(channel, status);
! 233: HTChannel_deleteOutput(channel, status);
2.1 frystyk 234:
235: /*
236: ** Check whether this channel is used by other objects or we can
237: ** delete it and free memory.
238: */
2.18 frystyk 239: if (channel->semaphore <= 0 && channels && (
240: channel->sockfd != INVSOC || channel->fp != NULL)) {
2.15 frystyk 241: int hash = HASH(channel->sockfd);
2.1 frystyk 242: HTList * list = channels[hash];
243: if (list) {
244: HTList_removeObject(list, (void *) channel);
245: free_channel(channel);
246: return YES;
247: }
2.8 frystyk 248: } else
249: HTChannel_downSemaphore(channel);
2.1 frystyk 250: }
251: return NO;
252: }
253:
254: /* HTChannel_deleteAll
255: ** -------------------
256: ** Destroys all channels. This is called by HTLibTerminate(0
257: */
2.9 frystyk 258: PUBLIC BOOL HTChannel_deleteAll (void)
2.1 frystyk 259: {
260: if (channels) {
261: HTList * cur;
262: int cnt;
2.22 frystyk 263: for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
2.1 frystyk 264: if ((cur = channels[cnt])) {
265: HTChannel * pres;
266: while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
267: free_channel(pres);
268: }
269: HTList_delete(channels[cnt]);
270: }
271: HT_FREE(channels);
272: }
273: return YES;
2.23 kahan 274: }
275:
276: /* HTChannel_safeDeleteAll
277: ** -------------------
278: ** Destroys all channels. This is called by HTLibTerminate(0
279: */
280:
281: PUBLIC BOOL HTChannel_safeDeleteAll (void)
282: {
283: if (channels) {
284: HTList * cur;
285: int cnt;
286: for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
287: if ((cur = channels[cnt])) {
288: HTChannel * pres;
289: while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL) {
290: HTChannel_delete (pres, HT_TIMEOUT);
291: cur = channels[cnt];
292: }
293: }
294: }
295: return YES;
296: }
297: return NO;
2.1 frystyk 298: }
299:
300: /*
2.10 frystyk 301: ** Return the socket associated with this channel
2.1 frystyk 302: */
2.10 frystyk 303: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
2.1 frystyk 304: {
2.10 frystyk 305: return channel ? channel->sockfd : INVSOC;
2.1 frystyk 306: }
307:
2.25 ! frystyk 308: PUBLIC BOOL HTChannel_setSocket (HTChannel * channel, SOCKET sockfd)
2.13 frystyk 309: {
2.14 frystyk 310: if (channel) {
2.25 ! frystyk 311:
! 312: /*
! 313: ** As we use the socket number as the hash entry then we have to
! 314: ** update the hash table as well.
! 315: */
! 316: int old_hash = HASH(channel->sockfd);
! 317: int new_hash = sockfd < 0 ? 0 : HASH(sockfd);
! 318: HTList * list = channels[old_hash];
! 319: if (list) HTList_removeObject(list, channel);
! 320: if (!channels[new_hash]) channels[new_hash] = HTList_new();
! 321: list = channels[new_hash];
! 322: HTList_addObject(list, channel);
! 323:
! 324: channel->sockfd = sockfd;
! 325: return YES;
2.14 frystyk 326: }
327: return NO;
2.13 frystyk 328: }
329:
2.10 frystyk 330: /*
331: ** Return the file descriptor associated with this channel
332: */
333: PUBLIC FILE * HTChannel_file (HTChannel * channel)
2.1 frystyk 334: {
2.10 frystyk 335: return channel ? channel->fp : NULL;
2.1 frystyk 336: }
337:
2.14 frystyk 338: PUBLIC BOOL HTChannel_setFile (HTChannel * channel, FILE * fp)
339: {
340: if (channel) {
341: channel->fp = fp;
342: return YES;
343: }
344: return NO;
345: }
346:
2.1 frystyk 347: /*
2.10 frystyk 348: ** We keep the associated Host object in case we have a
349: ** sleeping connection.
2.1 frystyk 350: */
2.10 frystyk 351: PUBLIC BOOL HTChannel_setHost (HTChannel * ch, HTHost * host)
2.1 frystyk 352: {
2.13 frystyk 353: if (ch) {
2.10 frystyk 354: ch->host = host;
355: return YES;
356: }
357: return NO;
2.4 frystyk 358: }
359:
2.10 frystyk 360: PUBLIC HTHost * HTChannel_host (HTChannel * ch)
2.4 frystyk 361: {
2.10 frystyk 362: return (ch ? ch->host : NULL);
2.1 frystyk 363: }
364:
365: /*
366: ** Increase the semaphore for this channel
367: */
368: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
369: {
370: if (channel) {
371: channel->semaphore++;
2.24 frystyk 372: HTTRACE(PROT_TRACE, "Channel..... Semaphore increased to %d for channel %p\n" _
373: channel->semaphore _ channel);
2.16 frystyk 374: #ifdef HT_MUX
375: HTMuxChannel * muxch = HTMuxChannel_find(me);
376: HTProtocol * protocol = HTNet_protocol(net);
377: net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
378: #endif /* HT_MUX */
379:
2.1 frystyk 380: }
381: }
382:
383: /*
384: ** Decrease the semaphore for this channel
385: */
386: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
387: {
388: if (channel) {
389: channel->semaphore--;
390: if (channel->semaphore <= 0) channel->semaphore = 0;
2.24 frystyk 391: HTTRACE(PROT_TRACE, "Channel..... Semaphore decreased to %d for channel %p\n" _
392: channel->semaphore _ channel);
2.7 frystyk 393: }
394: }
395:
396: /*
397: ** Explicitly set the semaphore for this channel
398: */
399: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
400: {
401: if (channel) {
402: channel->semaphore = semaphore;
403: if (channel->semaphore <= 0) channel->semaphore = 0;
2.24 frystyk 404: HTTRACE(PROT_TRACE, "Channel..... Semaphore set to %d for channel %p\n" _
405: channel->semaphore _ channel);
2.1 frystyk 406: }
407: }
408:
409: /*
410: ** Create the input 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_setInput (HTChannel * ch, HTInputStream * input)
2.1 frystyk 414: {
415: if (ch) {
416: ch->input = input;
417: return YES;
418: }
419: return NO;
420: }
421:
422: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
423: {
424: return ch ? ch->input : NULL;
425: }
426:
2.25 ! frystyk 427: PUBLIC BOOL HTChannel_deleteInput (HTChannel * channel, int status)
! 428: {
! 429: if (channel && channel->input && status != HT_IGNORE) {
! 430: HTTRACE(PROT_TRACE,
! 431: "Channel..... Delete input stream %p from channel %p\n" _
! 432: channel->input _ channel);
! 433: if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
! 434: (*channel->input->isa->abort)(channel->input, NULL);
! 435: else
! 436: (*channel->input->isa->_free)(channel->input);
! 437: return YES;
! 438: }
! 439: return NO;
! 440: }
! 441:
2.1 frystyk 442: /*
443: ** Create the output stream and bind it to the channel
444: ** Please read the description in the HTIOStream module on the parameters
445: */
2.10 frystyk 446: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch, HTOutputStream * output)
2.1 frystyk 447: {
448: if (ch) {
449: ch->output = output;
450: return YES;
451: }
452: return NO;
453: }
454:
455: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
456: {
457: return ch ? ch->output : NULL;
2.25 ! frystyk 458: }
! 459:
! 460: PUBLIC BOOL HTChannel_deleteOutput (HTChannel * channel, int status)
! 461: {
! 462: if (channel && channel->output && status != HT_IGNORE) {
! 463: HTTRACE(PROT_TRACE,
! 464: "Channel..... Delete input stream %p from channel %p\n" _
! 465: channel->input _ channel);
! 466: if (status==HT_INTERRUPTED || status==HT_TIMEOUT)
! 467: (*channel->output->isa->abort)(channel->output, NULL);
! 468: else
! 469: (*channel->output->isa->_free)(channel->output);
! 470: return YES;
! 471: }
! 472: return NO;
2.13 frystyk 473: }
474:
475: PUBLIC HTInputStream * HTChannel_getChannelIStream (HTChannel * ch)
476: {
477: if (ch)
478: return &ch->channelIStream;
479: return NULL;
480: }
481:
482: PUBLIC HTOutputStream * HTChannel_getChannelOStream (HTChannel * ch)
483: {
484: if (ch)
485: return &ch->channelOStream;
486: return NULL;
2.1 frystyk 487: }
488:
Webmaster