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