Annotation of libwww/Library/src/HTChannl.c, revision 2.8
2.1 frystyk 1: /* HTChannl.c
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.8 ! frystyk 6: ** @(#) $Id: HTChannl.c,v 2.7 1996/07/02 22:54:17 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"
17: #include "HTError.h"
18: #include "HTChannl.h" /* Implemented here */
19:
20: #define HASH_SIZE 67
21: #define HASH(s) ((s) % HASH_SIZE)
22:
23: struct _HTChannel {
24: SOCKET sockfd; /* Socket */
25: FILE * fp;
26: HTChannelMode mode; /* Mode of channel */
27: HTInputStream * input; /* Input stream */
28: HTOutputStream * output; /* Output stream */
29: BOOL active; /* Active or passive channel */
30: int semaphore; /* On channel use */
31: };
32:
33: struct _HTInputStream {
34: const HTInputStreamClass * isa;
35: };
36:
37: struct _HTOutputStream {
38: const HTOutputStreamClass * isa;
39: };
40:
41: PRIVATE HTList ** channels = NULL; /* List of channels */
42:
43: /* ------------------------------------------------------------------------- */
44:
45: PRIVATE void free_channel (HTChannel * ch)
46: {
47: if (ch) {
48:
49: /* Close the input and output stream */
50: if (ch->input) (*ch->input->isa->close)(ch->input);
51: if (ch->output) (*ch->output->isa->close)(ch->output);
52:
53: /* Close the socket */
54: if (ch->sockfd != INVSOC) {
55: NETCLOSE(ch->sockfd);
2.3 eric 56: HTEvent_unregister(ch->sockfd, (SockOps) FD_ALL);
2.1 frystyk 57: if (PROT_TRACE)
58: HTTrace("Channel..... Deleted %p, socket %d\n", ch,ch->sockfd);
59: }
60:
61: /* Close the file */
62: if (ch->fp) {
63: fclose(ch->fp);
64: if (PROT_TRACE)
65: HTTrace("Channel..... Deleted %p, file %p\n", ch, ch->fp);
66: }
67: HT_FREE(ch);
68: }
69: }
70:
71: /*
72: ** A channel is uniquely identified by a socket.
73: ** Note that we don't create the input and output stream - they are
74: ** created later. When a channel first is created it has the default mode
75: ** HT_CH_SINGLE which ensures that other connections to the same host
76: ** will not result in multiple parallel connections but wait and see if
77: ** the actual mode supported by the peer process.
78: **
79: ** We only keep a hash on sockfd's as we don't have to look for channels
80: ** for ANSI file descriptors.
81: */
82: PUBLIC HTChannel * HTChannel_new (HTNet * net, BOOL active)
83: {
84: if (net) {
85: HTList * list = NULL;
86: HTChannel * ch = NULL;
2.5 frystyk 87: SOCKET sockfd = HTNet_socket(net);
88: int hash = sockfd < 0 ? 0 : HASH(sockfd);
2.1 frystyk 89: if (PROT_TRACE) HTTrace("Channel..... Hash value is %d\n", hash);
90: if (!channels) {
91: if (!(channels = (HTList **) HT_CALLOC(HASH_SIZE,sizeof(HTList*))))
92: HT_OUTOFMEM("HTChannel_new");
93: }
94: if (!channels[hash]) channels[hash] = HTList_new();
95: list = channels[hash];
96: if ((ch = (HTChannel *) HT_CALLOC(1, sizeof(HTChannel))) == NULL)
97: HT_OUTOFMEM("HTChannel_new");
2.5 frystyk 98: ch->sockfd = sockfd;
2.1 frystyk 99: ch->mode = HT_CH_SINGLE;
100: ch->active = active;
101: ch->semaphore = 1;
102: HTList_addObject(list, (void *) ch);
103: if (PROT_TRACE) HTTrace("Channel..... Added %p to list %p\n", ch,list);
104: return ch;
105: }
106: return NULL;
107: }
108:
109: /*
110: ** Look for a channel object if we for some reason should have lost it
111: ** Returns NULL if nothing found
112: */
113: PUBLIC HTChannel * HTChannel_find (SOCKET sockfd)
114: {
115: if (channels && sockfd != INVSOC) {
116: int hash = HASH(sockfd);
117: HTList * list = channels[hash];
118: if (list) {
119: HTChannel * ch = NULL;
120: while ((ch = (HTChannel *) HTList_nextObject(list)))
121: if (ch->sockfd == sockfd) return ch;
122: }
123: }
124: return NULL;
125: }
126:
127: /*
128: ** When deleting a channel we first look at if there are no more requests
129: ** using the channel (the semaphore is <= 0). Then, if the socket supports
130: ** persistent connections then we register the channel in the Host cache
131: ** and wait until the other end closes it or we get a time out on our side
132: */
2.6 eric 133: PUBLIC BOOL HTChannel_delete (HTChannel * channel, int status)
2.1 frystyk 134: {
135: if (channel) {
2.2 frystyk 136: if (PROT_TRACE) HTTrace("Channel..... Delete %p with semaphore %d\n",
2.1 frystyk 137: channel, channel->semaphore);
138: /*
139: ** We call the free methods on both the input stream and the output
140: ** stream so that we can free up the stream pipes. However, note that
141: ** this doesn't mean that we close the input stream and output stream
142: ** them selves - only the generic streams
143: */
2.6 eric 144: if (channel->input)
145: if (status == HT_INTERRUPTED)
146: (*channel->input->isa->abort)(channel->input, NULL);
147: else
148: (*channel->input->isa->_free)(channel->input);
149: if (channel->output)
150: if (status == HT_INTERRUPTED)
151: (*channel->output->isa->abort)(channel->output, NULL);
152: else
153: (*channel->output->isa->_free)(channel->output);
2.1 frystyk 154:
155: /*
156: ** Check whether this channel is used by other objects or we can
157: ** delete it and free memory.
158: */
159: if (channel->semaphore <= 0 && channels) {
160: int hash = HASH(channel->sockfd);
161: HTList * list = channels[hash];
162: if (list) {
163: HTList_removeObject(list, (void *) channel);
164: free_channel(channel);
165: return YES;
166: }
2.8 ! frystyk 167: } else
! 168: HTChannel_downSemaphore(channel);
2.1 frystyk 169: }
170: return NO;
171: }
172:
173: /* HTChannel_deleteAll
174: ** -------------------
175: ** Destroys all channels. This is called by HTLibTerminate(0
176: */
177: PUBLIC BOOL HTCannel_deleteAll (void)
178: {
179: if (channels) {
180: HTList * cur;
181: int cnt;
182: for (cnt=0; cnt<HASH_SIZE; cnt++) {
183: if ((cur = channels[cnt])) {
184: HTChannel * pres;
185: while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
186: free_channel(pres);
187: }
188: HTList_delete(channels[cnt]);
189: }
190: HT_FREE(channels);
191: }
192: return YES;
193: }
194:
195: /*
196: ** Set and get the mode of a channel. A channel may change mode in the
197: ** middle of a connection. We also return whether the channel is active
198: ** or passive.
199: */
200: PUBLIC HTChannelMode HTChannel_mode (HTChannel * channel, BOOL * active)
201: {
202: return channel ? channel->mode : HT_CH_SINGLE;
203: }
204:
205: PUBLIC BOOL HTChannel_setMode (HTChannel * channel, HTChannelMode mode)
206: {
207: if (channel) {
208: channel->mode = mode;
209: return YES;
210: }
211: return NO;
212: }
213:
214: /*
215: ** Check whether a channel is idle meaning if it is ready for a new
216: ** request which depends on the mode of the channel. If the channel is
217: ** idle, i.e. ready for use then return YES else NO.
218: */
219: PUBLIC BOOL HTChannel_idle (HTChannel * channel)
220: {
221: return (channel &&
222: ((channel->mode != HT_CH_SINGLE) ||
223: (channel->mode == HT_CH_SINGLE && channel->semaphore <= 0)));
224: }
225:
226: /*
227: ** Return the socket associated with this channel
228: */
229: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
230: {
231: return channel ? channel->sockfd : INVSOC;
2.4 frystyk 232: }
233:
234: /*
235: ** Return the file descriptor associated with this channel
236: */
237: PUBLIC FILE * HTChannel_file (HTChannel * channel)
238: {
239: return channel ? channel->fp : NULL;
2.1 frystyk 240: }
241:
242: /*
243: ** Increase the semaphore for this channel
244: */
245: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
246: {
247: if (channel) {
248: channel->semaphore++;
249: if (PROT_TRACE)
250: HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
251: channel->semaphore, channel);
252: }
253: }
254:
255: /*
256: ** Decrease the semaphore for this channel
257: */
258: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
259: {
260: if (channel) {
261: channel->semaphore--;
262: if (channel->semaphore <= 0) channel->semaphore = 0;
263: if (PROT_TRACE)
264: HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
2.7 frystyk 265: channel->semaphore, channel);
266: }
267: }
268:
269: /*
270: ** Explicitly set the semaphore for this channel
271: */
272: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
273: {
274: if (channel) {
275: channel->semaphore = semaphore;
276: if (channel->semaphore <= 0) channel->semaphore = 0;
277: if (PROT_TRACE)
278: HTTrace("Channel..... Semaphore set to %d for channel %p\n",
2.1 frystyk 279: channel->semaphore, channel);
280: }
281: }
282:
283: /*
284: ** Create the input stream and bind it to the channel
285: ** Please read the description in the HTIOStream module on the parameters
286: */
287: PUBLIC BOOL HTChannel_setInput (HTChannel * ch,
288: HTInputStream * input, HTChannelMode mode)
289: {
290: if (ch) {
291: ch->mode = mode;
292: ch->input = input;
293: return YES;
294: }
295: return NO;
296: }
297:
298: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
299: {
300: return ch ? ch->input : NULL;
301: }
302:
303: /*
304: ** Create the output stream and bind it to the channel
305: ** Please read the description in the HTIOStream module on the parameters
306: */
307: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch,
308: HTOutputStream * output, HTChannelMode mode)
309: {
310: if (ch) {
311: ch->mode = mode;
312: ch->output = output;
313: return YES;
314: }
315: return NO;
316: }
317:
318: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
319: {
320: return ch ? ch->output : NULL;
321: }
322:
Webmaster