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