Annotation of libwww/Library/src/HTChannl.c, revision 2.7
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.7 ! frystyk 6: ** @(#) $Id: HTChannl.c,v 2.6 1996/06/03 19:25:08 eric 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: }
167: }
168: }
169: return NO;
170: }
171:
172: /* HTChannel_deleteAll
173: ** -------------------
174: ** Destroys all channels. This is called by HTLibTerminate(0
175: */
176: PUBLIC BOOL HTCannel_deleteAll (void)
177: {
178: if (channels) {
179: HTList * cur;
180: int cnt;
181: for (cnt=0; cnt<HASH_SIZE; cnt++) {
182: if ((cur = channels[cnt])) {
183: HTChannel * pres;
184: while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
185: free_channel(pres);
186: }
187: HTList_delete(channels[cnt]);
188: }
189: HT_FREE(channels);
190: }
191: return YES;
192: }
193:
194: /*
195: ** Set and get the mode of a channel. A channel may change mode in the
196: ** middle of a connection. We also return whether the channel is active
197: ** or passive.
198: */
199: PUBLIC HTChannelMode HTChannel_mode (HTChannel * channel, BOOL * active)
200: {
201: return channel ? channel->mode : HT_CH_SINGLE;
202: }
203:
204: PUBLIC BOOL HTChannel_setMode (HTChannel * channel, HTChannelMode mode)
205: {
206: if (channel) {
207: channel->mode = mode;
208: return YES;
209: }
210: return NO;
211: }
212:
213: /*
214: ** Check whether a channel is idle meaning if it is ready for a new
215: ** request which depends on the mode of the channel. If the channel is
216: ** idle, i.e. ready for use then return YES else NO.
217: */
218: PUBLIC BOOL HTChannel_idle (HTChannel * channel)
219: {
220: return (channel &&
221: ((channel->mode != HT_CH_SINGLE) ||
222: (channel->mode == HT_CH_SINGLE && channel->semaphore <= 0)));
223: }
224:
225: /*
226: ** Return the socket associated with this channel
227: */
228: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
229: {
230: return channel ? channel->sockfd : INVSOC;
2.4 frystyk 231: }
232:
233: /*
234: ** Return the file descriptor associated with this channel
235: */
236: PUBLIC FILE * HTChannel_file (HTChannel * channel)
237: {
238: return channel ? channel->fp : NULL;
2.1 frystyk 239: }
240:
241: /*
242: ** Increase the semaphore for this channel
243: */
244: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
245: {
246: if (channel) {
247: channel->semaphore++;
248: if (PROT_TRACE)
249: HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
250: channel->semaphore, channel);
251: }
252: }
253:
254: /*
255: ** Decrease the semaphore for this channel
256: */
257: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
258: {
259: if (channel) {
260: channel->semaphore--;
261: if (channel->semaphore <= 0) channel->semaphore = 0;
262: if (PROT_TRACE)
263: HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
2.7 ! frystyk 264: channel->semaphore, channel);
! 265: }
! 266: }
! 267:
! 268: /*
! 269: ** Explicitly set the semaphore for this channel
! 270: */
! 271: PUBLIC void HTChannel_setSemaphore (HTChannel * channel, int semaphore)
! 272: {
! 273: if (channel) {
! 274: channel->semaphore = semaphore;
! 275: if (channel->semaphore <= 0) channel->semaphore = 0;
! 276: if (PROT_TRACE)
! 277: HTTrace("Channel..... Semaphore set to %d for channel %p\n",
2.1 frystyk 278: channel->semaphore, channel);
279: }
280: }
281:
282: /*
283: ** Create the input stream and bind it to the channel
284: ** Please read the description in the HTIOStream module on the parameters
285: */
286: PUBLIC BOOL HTChannel_setInput (HTChannel * ch,
287: HTInputStream * input, HTChannelMode mode)
288: {
289: if (ch) {
290: ch->mode = mode;
291: ch->input = input;
292: return YES;
293: }
294: return NO;
295: }
296:
297: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
298: {
299: return ch ? ch->input : NULL;
300: }
301:
302: /*
303: ** Create the output stream and bind it to the channel
304: ** Please read the description in the HTIOStream module on the parameters
305: */
306: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch,
307: HTOutputStream * output, HTChannelMode mode)
308: {
309: if (ch) {
310: ch->mode = mode;
311: ch->output = output;
312: return YES;
313: }
314: return NO;
315: }
316:
317: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
318: {
319: return ch ? ch->output : NULL;
320: }
321:
Webmaster