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