Annotation of libwww/Library/src/HTHost.c, revision 2.7
2.1 frystyk 1: /* HTHost.c
2: ** REMOTE HOST INFORMATION
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.7 ! frystyk 6: ** @(#) $Id: HTHost.c,v 2.6 1996/07/02 22:54:32 frystyk Exp $
2.1 frystyk 7: **
8: ** This object manages the information that we know about a remote host.
9: ** This can for example be what type of host it is, and what version
10: ** it is using. We also keep track of persistent connections
11: **
12: ** April 96 HFN Written
13: */
14:
15: /* Library include files */
16: #include "sysdep.h"
17: #include "WWWUtil.h"
18: #include "HTParse.h"
19: #include "HTAlert.h"
20: #include "HTError.h"
21: #include "HTNetMan.h"
22: #include "HTTrans.h"
23: #include "HTHost.h" /* Implemented here */
24:
25: #define HOST_TIMEOUT 43200L /* Default host timeout is 12 h */
26: #define TCP_TIMEOUT 3600L /* Default TCP timeout i 1 h */
27: #define HASH_SIZE 67
28:
29: /* Type definitions and global variables etc. local to this module */
30: struct _HTHost {
31: char * hostname; /* name of host + optional port */
32: time_t ntime; /* Creation time */
33: char * type; /* Peer type */
34: int version; /* Peer version */
2.6 frystyk 35: HTMethod methods; /* Public methods (bit-flag) */
36: char * server; /* Server name */
37: char * user_agent; /* User Agent */
2.1 frystyk 38: HTChannelMode mode; /* Supported mode */
39: HTChannel * channel; /* Persistent channel */
40: time_t expires; /* Persistent channel expires time */
41: };
42:
43: PRIVATE HTList ** HostTable = NULL;
44: PRIVATE time_t HostTimeout = HOST_TIMEOUT; /* Timeout on host entries */
45: PRIVATE time_t TCPTimeout = TCP_TIMEOUT; /* Timeout on persistent channels */
46:
47: PRIVATE HTList * Persistent = NULL; /* List of persistent sockets */
48:
49: /* ------------------------------------------------------------------------- */
50:
51: PRIVATE void free_object (HTHost * me)
52: {
53: if (me) {
54: HT_FREE(me->hostname);
55: HT_FREE(me->type);
2.3 eric 56: if (me->channel) {
2.5 eric 57: HTChannel_delete(me->channel, HT_OK);
2.3 eric 58: me->channel = NULL;
59: }
2.1 frystyk 60: HT_FREE(me);
61: }
62: }
63:
64: PRIVATE BOOL delete_object (HTList * list, HTHost * me)
65: {
2.2 frystyk 66: if (CORE_TRACE) HTTrace("Host info... object %p from list %p\n", me, list);
2.1 frystyk 67: HTList_removeObject(list, (void *) me);
68: free_object(me);
69: return YES;
70: }
71:
72: /*
73: ** Search the host info cache for a host object or create a new one
74: ** and add it. Examples of host names are
75: **
76: ** www.w3.org
77: ** www.foo.com:8000
78: ** 18.52.0.18
79: **
80: ** Returns Host object or NULL if error. You may get back an already
81: ** existing host object - you're not guaranteed a new one each time.
82: */
83: PUBLIC HTHost * HTHost_new (char * host)
84: {
85: HTList * list = NULL; /* Current list in cache */
86: HTHost * pres = NULL;
87: if (!host) {
2.2 frystyk 88: if (CORE_TRACE) HTTrace("Host info... Bad argument\n");
2.1 frystyk 89: return NULL;
90: }
91:
92: /* Find a hash for this host */
93: {
94: int hash = 0;
95: char *ptr;
96: for (ptr=host; *ptr; ptr++)
97: hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HASH_SIZE);
98: if (!HostTable) {
99: if ((HostTable = (HTList **) HT_CALLOC(HASH_SIZE,
100: sizeof(HTList *))) == NULL)
101: HT_OUTOFMEM("HTHost_find");
102: }
103: if (!HostTable[hash]) HostTable[hash] = HTList_new();
104: list = HostTable[hash];
105: }
106:
107: /* Search the cache */
108: {
109: HTList * cur = list;
110: while ((pres = (HTHost *) HTList_nextObject(cur))) {
111: if (!strcmp(pres->hostname, host)) {
112: if (time(NULL) > pres->ntime + HostTimeout) {
2.2 frystyk 113: if (CORE_TRACE)
2.1 frystyk 114: HTTrace("Host info... Collecting host info %p\n",pres);
115: delete_object(list, pres);
116: pres = NULL;
117: }
118: break;
119: }
120: }
121: }
122:
123: /* If not found then create new Host object */
124: if (pres) {
125: if (pres->channel) {
126: if (pres->expires < time(NULL)) { /* Cached channel is cold */
2.2 frystyk 127: if (CORE_TRACE)
2.1 frystyk 128: HTTrace("Host info... Persistent channel %p gotten cold\n",
129: pres->channel);
2.5 eric 130: HTChannel_delete(pres->channel, HT_OK);
2.1 frystyk 131: pres->channel = NULL;
132: } else {
2.2 frystyk 133: if (CORE_TRACE)
2.1 frystyk 134: HTTrace("Host info... REUSING CHANNEL %p\n",pres->channel);
135: }
136: }
137: } else {
138: if ((pres = (HTHost *) HT_CALLOC(1, sizeof(HTHost))) == NULL)
139: HT_OUTOFMEM("HTHost_add");
140: StrAllocCopy(pres->hostname, host);
141: pres->ntime = time(NULL);
2.2 frystyk 142: if (CORE_TRACE)
2.1 frystyk 143: HTTrace("Host info... added `%s\' to list %p\n", host, list);
144: HTList_addObject(list, (void *) pres);
145: }
146: return pres;
147: }
148:
149: /*
150: ** Get and set the type class of the remote host
151: */
152: PUBLIC char * HTHost_class (HTHost * host)
153: {
154: return host ? host->type : NULL;
155: }
156:
157: PUBLIC void HTHost_setClass (HTHost * host, char * s_class)
158: {
159: if (host && s_class) StrAllocCopy(host->type, s_class);
160: }
161:
162: /*
163: ** Get and set the version of the remote host
164: */
165: PUBLIC int HTHost_version (HTHost *host)
166: {
167: return host ? host->version : 0;
168: }
169:
170: PUBLIC void HTHost_setVersion (HTHost * host, int version)
171: {
172: if (host) host->version = version;
173: }
174:
175: /*
176: ** Get and set the cache timeout for persistent entries.
177: ** The default value is TCP_TIMEOUT
178: */
179: PUBLIC void HTHost_setPersistTimeout (time_t timeout)
180: {
181: TCPTimeout = timeout;
182: }
183:
184: PUBLIC time_t HTHost_persistTimeout (time_t timeout)
185: {
186: return TCPTimeout;
187: }
188:
189: /* Persistent Connection Expiration
190: ** --------------------------------
191: ** Should normally not be used. If, then use calendar time.
192: */
193: PUBLIC void HTHost_setPersistExpires (HTHost * host, time_t expires)
194: {
195: if (host) host->expires = expires;
196: }
197:
198: PUBLIC time_t HTHost_persistExpires (HTHost * host)
199: {
200: return host ? host->expires : -1;
201: }
202:
203: /*
2.6 frystyk 204: ** Public methods for this host
205: */
206: PUBLIC HTMethod HTHost_publicMethods (HTHost * me)
207: {
208: return me ? me->methods : METHOD_INVALID;
209: }
210:
211: PUBLIC void HTHost_setPublicMethods (HTHost * me, HTMethod methodset)
212: {
213: if (me) me->methods = methodset;
214: }
215:
216: PUBLIC void HTHost_appendPublicMethods (HTHost * me, HTMethod methodset)
217: {
218: if (me) me->methods |= methodset;
219: }
220:
221: /*
222: ** Get and set the server name of the remote host
223: */
224: PUBLIC char * HTHost_server (HTHost * host)
225: {
226: return host ? host->server : NULL;
227: }
228:
229: PUBLIC BOOL HTHost_setServer (HTHost * host, const char * server)
230: {
231: if (host && server) {
232: StrAllocCopy(host->server, server);
233: return YES;
234: }
235: return NO;
236: }
237:
238: /*
239: ** Get and set the userAgent name of the remote host
240: */
241: PUBLIC char * HTHost_userAgent (HTHost * host)
242: {
243: return host ? host->user_agent : NULL;
244: }
245:
246: PUBLIC BOOL HTHost_setUserAgent (HTHost * host, const char * userAgent)
247: {
248: if (host && userAgent) {
249: StrAllocCopy(host->user_agent, userAgent);
250: return YES;
251: }
252: return NO;
253: }
254:
255: /*
2.1 frystyk 256: ** Searches the list of persistent connections for a host object
257: ** associated with this channel
258: */
259: PRIVATE HTHost * HTHost_findPersistent (HTChannel * ch)
260: {
261: if (Persistent && ch) {
262: HTList * cur = Persistent;
263: HTHost * pres;
264: while ((pres = (HTHost *) HTList_nextObject(cur)))
265: if (pres->channel == ch) return pres;
266: }
267: return NULL;
268: }
269:
270: /* HTHost_catchClose
271: ** -----------------
272: ** This function is registered when the socket is idle so that we get
273: ** a notification if the socket closes at the other end. At this point
274: ** we can't use the request object as it might have been freed a long
275: ** time ago.
276: */
277: PUBLIC int HTHost_catchClose (SOCKET soc, HTRequest * request, SockOps ops)
278: {
2.2 frystyk 279: if (CORE_TRACE)
2.1 frystyk 280: HTTrace("Catch Close. called with socket %d with ops %x\n",
281: soc, (unsigned) ops);
282: if (ops == FD_READ) {
283: HTChannel * ch = HTChannel_find(soc); /* Find associated channel */
284: HTHost * host = HTHost_findPersistent(ch);
285: if (ch && host) {
2.2 frystyk 286: if (CORE_TRACE) HTTrace("Catch Close. CLOSING socket %d\n", soc);
2.1 frystyk 287: HTHost_clearChannel(host);
288: } else {
2.2 frystyk 289: if (CORE_TRACE) HTTrace("Catch Close. socket %d NOT FOUND!\n",soc);
2.1 frystyk 290: }
291: }
2.4 eric 292: HTEvent_unregister(soc, (SockOps) FD_ALL);
2.1 frystyk 293: return HT_OK;
294: }
295:
296: /*
297: ** As soon as we know that this host accepts persistent connections,
298: ** we associated the channel with the host.
299: ** We don't want more than MaxSockets-2 connections to be persistent in
300: ** order to avoid deadlock.
301: */
302: PUBLIC BOOL HTHost_setChannel (HTHost * host, HTChannel * channel)
303: {
2.6 frystyk 304: if (!host || !channel) return NO;
2.2 frystyk 305: if (host->channel) {
306: if (CORE_TRACE) HTTrace("Host info... %p already persistent\n", host);
307: return YES;
308: } else {
2.1 frystyk 309: SOCKET sockfd = HTChannel_socket(channel);
310: if (!Persistent) Persistent = HTList_new();
311: if (sockfd != INVSOC && HTList_count(Persistent)<HTNet_maxSocket()-2) {
312: host->channel = channel;
313: host->expires = time(NULL) + TCPTimeout; /* Default timeout */
314: HTList_addObject(Persistent, host);
2.2 frystyk 315: if (CORE_TRACE)
2.1 frystyk 316: HTTrace("Host info... added host %p as persistent\n", host);
317: return YES;
318: } else {
2.2 frystyk 319: if (CORE_TRACE)
320: HTTrace("Host info... no room for persistent socket %d\n",
2.7 ! frystyk 321: sockfd);
2.1 frystyk 322: }
323: }
324: return NO;
325: }
326:
327: /*
328: ** Find persistent channel associated with this host.
329: */
330: PUBLIC HTChannel * HTHost_channel (HTHost * host)
331: {
332: return host ? host->channel : NULL;
333: }
334:
335: /*
336: ** Clear the persistent entry by deleting the channel object. Note that
337: ** the channel object is only deleted if it's not used anymore.
338: */
339: PUBLIC BOOL HTHost_clearChannel (HTHost * host)
340: {
341: if (host && host->channel) {
2.5 eric 342: HTChannel_delete(host->channel, HT_OK);
2.1 frystyk 343: host->expires = 0;
344: host->channel = NULL;
2.2 frystyk 345: if (CORE_TRACE)
346: HTTrace("Host info... removed host %p as persistent\n", host);
2.1 frystyk 347: HTList_removeObject(Persistent, host);
348: return YES;
349: }
350: return NO;
351: }
352:
353: /*
354: ** Check whether we have a persistent channel or not
355: */
356: PUBLIC BOOL HTHost_isPersistent (HTHost * host)
357: {
358: return host && host->channel;
359: }
360:
Webmaster