Annotation of libwww/Library/src/HTChannl.c, revision 2.5
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.5 ! frystyk 6: ** @(#) $Id: HTChannl.c,v 2.4 1996/05/20 15:06:28 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: */
133: PUBLIC BOOL HTChannel_delete (HTChannel * channel)
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: */
144: if (channel->input) (*channel->input->isa->_free)(channel->input);
145: if (channel->output) (*channel->output->isa->_free)(channel->output);
146:
147: /*
148: ** Check whether this channel is used by other objects or we can
149: ** delete it and free memory.
150: */
151: if (channel->semaphore <= 0 && channels) {
152: int hash = HASH(channel->sockfd);
153: HTList * list = channels[hash];
154: if (list) {
155: HTList_removeObject(list, (void *) channel);
156: free_channel(channel);
157: return YES;
158: }
159: }
160: }
161: return NO;
162: }
163:
164: /* HTChannel_deleteAll
165: ** -------------------
166: ** Destroys all channels. This is called by HTLibTerminate(0
167: */
168: PUBLIC BOOL HTCannel_deleteAll (void)
169: {
170: if (channels) {
171: HTList * cur;
172: int cnt;
173: for (cnt=0; cnt<HASH_SIZE; cnt++) {
174: if ((cur = channels[cnt])) {
175: HTChannel * pres;
176: while ((pres = (HTChannel *) HTList_nextObject(cur)) != NULL)
177: free_channel(pres);
178: }
179: HTList_delete(channels[cnt]);
180: }
181: HT_FREE(channels);
182: }
183: return YES;
184: }
185:
186: /*
187: ** Set and get the mode of a channel. A channel may change mode in the
188: ** middle of a connection. We also return whether the channel is active
189: ** or passive.
190: */
191: PUBLIC HTChannelMode HTChannel_mode (HTChannel * channel, BOOL * active)
192: {
193: return channel ? channel->mode : HT_CH_SINGLE;
194: }
195:
196: PUBLIC BOOL HTChannel_setMode (HTChannel * channel, HTChannelMode mode)
197: {
198: if (channel) {
199: channel->mode = mode;
200: return YES;
201: }
202: return NO;
203: }
204:
205: /*
206: ** Check whether a channel is idle meaning if it is ready for a new
207: ** request which depends on the mode of the channel. If the channel is
208: ** idle, i.e. ready for use then return YES else NO.
209: */
210: PUBLIC BOOL HTChannel_idle (HTChannel * channel)
211: {
212: return (channel &&
213: ((channel->mode != HT_CH_SINGLE) ||
214: (channel->mode == HT_CH_SINGLE && channel->semaphore <= 0)));
215: }
216:
217: /*
218: ** Return the socket associated with this channel
219: */
220: PUBLIC SOCKET HTChannel_socket (HTChannel * channel)
221: {
222: return channel ? channel->sockfd : INVSOC;
2.4 frystyk 223: }
224:
225: /*
226: ** Return the file descriptor associated with this channel
227: */
228: PUBLIC FILE * HTChannel_file (HTChannel * channel)
229: {
230: return channel ? channel->fp : NULL;
2.1 frystyk 231: }
232:
233: /*
234: ** Increase the semaphore for this channel
235: */
236: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
237: {
238: if (channel) {
239: channel->semaphore++;
240: if (PROT_TRACE)
241: HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
242: channel->semaphore, channel);
243: }
244: }
245:
246: /*
247: ** Decrease the semaphore for this channel
248: */
249: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
250: {
251: if (channel) {
252: channel->semaphore--;
253: if (channel->semaphore <= 0) channel->semaphore = 0;
254: if (PROT_TRACE)
255: HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
256: channel->semaphore, channel);
257: }
258: }
259:
260: /*
261: ** Create the input stream and bind it to the channel
262: ** Please read the description in the HTIOStream module on the parameters
263: */
264: PUBLIC BOOL HTChannel_setInput (HTChannel * ch,
265: HTInputStream * input, HTChannelMode mode)
266: {
267: if (ch) {
268: ch->mode = mode;
269: ch->input = input;
270: return YES;
271: }
272: return NO;
273: }
274:
275: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
276: {
277: return ch ? ch->input : NULL;
278: }
279:
280: /*
281: ** Create the output stream and bind it to the channel
282: ** Please read the description in the HTIOStream module on the parameters
283: */
284: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch,
285: HTOutputStream * output, HTChannelMode mode)
286: {
287: if (ch) {
288: ch->mode = mode;
289: ch->output = output;
290: return YES;
291: }
292: return NO;
293: }
294:
295: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
296: {
297: return ch ? ch->output : NULL;
298: }
299:
Webmaster