Annotation of libwww/Library/src/HTChannl.c, revision 2.4
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.4 ! frystyk 6: ** @(#) $Id: HTChannl.c,v 2.3 1996/05/15 22:34:00 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 "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);
2.3 eric 58: HTEvent_unregister(ch->sockfd, (SockOps) FD_ALL);
2.1 frystyk 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;
2.4 ! frystyk 224: }
! 225:
! 226: /*
! 227: ** Return the file descriptor associated with this channel
! 228: */
! 229: PUBLIC FILE * HTChannel_file (HTChannel * channel)
! 230: {
! 231: return channel ? channel->fp : NULL;
2.1 frystyk 232: }
233:
234: /*
235: ** Increase the semaphore for this channel
236: */
237: PUBLIC void HTChannel_upSemaphore (HTChannel * channel)
238: {
239: if (channel) {
240: channel->semaphore++;
241: if (PROT_TRACE)
242: HTTrace("Channel..... Semaphore increased to %d for channel %p\n",
243: channel->semaphore, channel);
244: }
245: }
246:
247: /*
248: ** Decrease the semaphore for this channel
249: */
250: PUBLIC void HTChannel_downSemaphore (HTChannel * channel)
251: {
252: if (channel) {
253: channel->semaphore--;
254: if (channel->semaphore <= 0) channel->semaphore = 0;
255: if (PROT_TRACE)
256: HTTrace("Channel..... Semaphore decreased to %d for channel %p\n",
257: channel->semaphore, channel);
258: }
259: }
260:
261: /*
262: ** Create the input stream and bind it to the channel
263: ** Please read the description in the HTIOStream module on the parameters
264: */
265: PUBLIC BOOL HTChannel_setInput (HTChannel * ch,
266: HTInputStream * input, HTChannelMode mode)
267: {
268: if (ch) {
269: ch->mode = mode;
270: ch->input = input;
271: return YES;
272: }
273: return NO;
274: }
275:
276: PUBLIC HTInputStream * HTChannel_input (HTChannel * ch)
277: {
278: return ch ? ch->input : NULL;
279: }
280:
281: /*
282: ** Create the output stream and bind it to the channel
283: ** Please read the description in the HTIOStream module on the parameters
284: */
285: PUBLIC BOOL HTChannel_setOutput (HTChannel * ch,
286: HTOutputStream * output, HTChannelMode mode)
287: {
288: if (ch) {
289: ch->mode = mode;
290: ch->output = output;
291: return YES;
292: }
293: return NO;
294: }
295:
296: PUBLIC HTOutputStream * HTChannel_output (HTChannel * ch)
297: {
298: return ch ? ch->output : NULL;
299: }
300:
Webmaster