Annotation of libwww/Library/src/HTChannl.c, revision 2.23
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.23 ! kahan 6: ** @(#) $Id: HTChannl.c,v 2.22 1999/02/07 18:20:31 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;
2.23 ! kahan 288: }
! 289:
! 290: /* HTChannel_safeDeleteAll
! 291: ** -------------------
! 292: ** Destroys all channels. This is called by HTLibTerminate(0
! 293: */
! 294:
! 295: PUBLIC BOOL HTChannel_safeDeleteAll (void)
! 296: {
! 297: if (channels) {
! 298: HTList * cur;
! 299: int cnt;
! 300: for (cnt=0; cnt<HT_M_HASH_SIZE; cnt++) {
! 301: if ((cur = channels[cnt])) {
! 302: HTChannel * pres;
! 303: while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL) {
! 304: HTChannel_delete (pres, HT_TIMEOUT);
! 305: cur = channels[cnt];
! 306: }
! 307: }
! 308: }
! 309: return YES;
! 310: }
! 311: return NO;
2.1 frystyk 312: }
313:
314: /*
2.10 frystyk 315: ** Return the socket associated with this channel
2.1 frystyk 316: */
2.10 frystyk 317: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
2.1 frystyk 318: {
2.10 frystyk 319: return channel ? channel->sockfd : INVSOC;
2.1 frystyk 320: }
321:
2.14 frystyk 322: PUBLIC BOOL HTChannel_setSocket (HTChannel * channel, SOCKET socket)
2.13 frystyk 323: {
2.14 frystyk 324: if (channel) {
2.13 frystyk 325: channel->sockfd = socket;
2.14 frystyk 326: return YES;
327: }
328: return NO;
2.13 frystyk 329: }
330:
2.10 frystyk 331: /*
332: ** Return the file descriptor associated with this channel
333: */
334: PUBLIC FILE * HTChannel_file (HTChannel * channel)
2.1 frystyk 335: {
2.10 frystyk 336: return channel ? channel->fp : NULL;
2.1 frystyk 337: }
338:
2.14 frystyk 339: PUBLIC BOOL HTChannel_setFile (HTChannel * channel, FILE * fp)
340: {
341: if (channel) {
342: channel->fp = fp;
343: return YES;
344: }
345: return NO;
346: }
347:
2.1 frystyk 348: /*
2.10 frystyk 349: ** We keep the associated Host object in case we have a
350: ** sleeping connection.
2.1 frystyk 351: */
2.10 frystyk 352: PUBLIC BOOL HTChannel_setHost (HTChannel * ch, HTHost * host)
2.1 frystyk 353: {
2.13 frystyk 354: if (ch) {
2.10 frystyk 355: ch->host = host;
356: return YES;
357: }
358: return NO;
2.4 frystyk 359: }
360:
2.10 frystyk 361: PUBLIC HTHost * HTChannel_host (HTChannel * ch)
2.4 frystyk 362: {
2.10 frystyk 363: return (ch ? ch->host : NULL);
2.1 frystyk 364: }
365:
366: /*
367: ** Increase the semaphore for this channel
368: */
369: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
370: {
371: if (channel) {
372: channel->semaphore++;
373: if (PROT_TRACE)
374: HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
375: channel->semaphore, channel);
2.16 frystyk 376: #ifdef HT_MUX
377: HTMuxChannel * muxch = HTMuxChannel_find(me);
378: HTProtocol * protocol = HTNet_protocol(net);
379: net->session = HTMuxSession_connect(muxch, net, HTProtocol_id(protocol));
380: #endif /* HT_MUX */
381:
2.1 frystyk 382: }
383: }
384:
385: /*
386: ** Decrease the semaphore for this channel
387: */
388: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
389: {
390: if (channel) {
391: channel->semaphore--;
392: if (channel->semaphore <= 0) channel->semaphore = 0;
393: if (PROT_TRACE)
394: HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
2.7 frystyk 395: channel->semaphore, channel);
396: }
397: }
398:
399: /*
400: ** Explicitly set the semaphore for this channel
401: */
402: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
403: {
404: if (channel) {
405: channel->semaphore = semaphore;
406: if (channel->semaphore <= 0) channel->semaphore = 0;
407: if (PROT_TRACE)
408: HTTrace("Channel..... Semaphore set to %d for channel %p\n",
2.1 frystyk 409: channel->semaphore, channel);
410: }
411: }
412:
413: /*
414: ** Create the input stream and bind it to the channel
415: ** Please read the description in the HTIOStream module on the parameters
416: */
2.10 frystyk 417: PUBLIC BOOL HTChannel_setInput (HTChannel * ch, HTInputStream * input)
2.1 frystyk 418: {
419: if (ch) {
420: ch->input = input;
421: return YES;
422: }
423: return NO;
424: }
425:
426: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
427: {
428: return ch ? ch->input : NULL;
429: }
430:
431: /*
432: ** Create the output stream and bind it to the channel
433: ** Please read the description in the HTIOStream module on the parameters
434: */
2.10 frystyk 435: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch, HTOutputStream * output)
2.1 frystyk 436: {
437: if (ch) {
438: ch->output = output;
439: return YES;
440: }
441: return NO;
442: }
443:
444: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
445: {
446: return ch ? ch->output : NULL;
2.13 frystyk 447: }
448:
449: PUBLIC HTInputStream * HTChannel_getChannelIStream (HTChannel * ch)
450: {
451: if (ch)
452: return &ch->channelIStream;
453: return NULL;
454: }
455:
456: PUBLIC HTOutputStream * HTChannel_getChannelOStream (HTChannel * ch)
457: {
458: if (ch)
459: return &ch->channelOStream;
460: return NULL;
2.1 frystyk 461: }
462:
Webmaster