Annotation of libwww/Library/src/HTHost.c, revision 2.3
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.3 ! eric 6: ** @(#) $Id: HTHost.c,v 2.2 1996/04/14 01:23:07 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 */
35: HTChannelMode mode; /* Supported mode */
36: HTChannel * channel; /* Persistent channel */
37: time_t expires; /* Persistent channel expires time */
38: };
39:
40: PRIVATE HTList ** HostTable = NULL;
41: PRIVATE time_t HostTimeout = HOST_TIMEOUT; /* Timeout on host entries */
42: PRIVATE time_t TCPTimeout = TCP_TIMEOUT; /* Timeout on persistent channels */
43:
44: PRIVATE HTList * Persistent = NULL; /* List of persistent sockets */
45:
46: /* ------------------------------------------------------------------------- */
47:
48: PRIVATE void free_object (HTHost * me)
49: {
50: if (me) {
51: HT_FREE(me->hostname);
52: HT_FREE(me->type);
2.3 ! eric 53: if (me->channel) {
! 54: HTChannel_delete(me->channel);
! 55: me->channel = NULL;
! 56: }
2.1 frystyk 57: HT_FREE(me);
58: }
59: }
60:
61: PRIVATE BOOL delete_object (HTList * list, HTHost * me)
62: {
2.2 frystyk 63: if (CORE_TRACE) HTTrace("Host info... object %p from list %p\n", me, list);
2.1 frystyk 64: HTList_removeObject(list, (void *) me);
65: free_object(me);
66: return YES;
67: }
68:
69: /*
70: ** Search the host info cache for a host object or create a new one
71: ** and add it. Examples of host names are
72: **
73: ** www.w3.org
74: ** www.foo.com:8000
75: ** 18.52.0.18
76: **
77: ** Returns Host object or NULL if error. You may get back an already
78: ** existing host object - you're not guaranteed a new one each time.
79: */
80: PUBLIC HTHost * HTHost_new (char * host)
81: {
82: HTList * list = NULL; /* Current list in cache */
83: HTHost * pres = NULL;
84: if (!host) {
2.2 frystyk 85: if (CORE_TRACE) HTTrace("Host info... Bad argument\n");
2.1 frystyk 86: return NULL;
87: }
88:
89: /* Find a hash for this host */
90: {
91: int hash = 0;
92: char *ptr;
93: for (ptr=host; *ptr; ptr++)
94: hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HASH_SIZE);
95: if (!HostTable) {
96: if ((HostTable = (HTList **) HT_CALLOC(HASH_SIZE,
97: sizeof(HTList *))) == NULL)
98: HT_OUTOFMEM("HTHost_find");
99: }
100: if (!HostTable[hash]) HostTable[hash] = HTList_new();
101: list = HostTable[hash];
102: }
103:
104: /* Search the cache */
105: {
106: HTList * cur = list;
107: while ((pres = (HTHost *) HTList_nextObject(cur))) {
108: if (!strcmp(pres->hostname, host)) {
109: if (time(NULL) > pres->ntime + HostTimeout) {
2.2 frystyk 110: if (CORE_TRACE)
2.1 frystyk 111: HTTrace("Host info... Collecting host info %p\n",pres);
112: delete_object(list, pres);
113: pres = NULL;
114: }
115: break;
116: }
117: }
118: }
119:
120: /* If not found then create new Host object */
121: if (pres) {
122: if (pres->channel) {
123: if (pres->expires < time(NULL)) { /* Cached channel is cold */
2.2 frystyk 124: if (CORE_TRACE)
2.1 frystyk 125: HTTrace("Host info... Persistent channel %p gotten cold\n",
126: pres->channel);
127: HTChannel_delete(pres->channel);
128: pres->channel = NULL;
129: } else {
2.2 frystyk 130: if (CORE_TRACE)
2.1 frystyk 131: HTTrace("Host info... REUSING CHANNEL %p\n",pres->channel);
132: }
133: }
134: } else {
135: if ((pres = (HTHost *) HT_CALLOC(1, sizeof(HTHost))) == NULL)
136: HT_OUTOFMEM("HTHost_add");
137: StrAllocCopy(pres->hostname, host);
138: pres->ntime = time(NULL);
2.2 frystyk 139: if (CORE_TRACE)
2.1 frystyk 140: HTTrace("Host info... added `%s\' to list %p\n", host, list);
141: HTList_addObject(list, (void *) pres);
142: }
143: return pres;
144: }
145:
146: /*
147: ** Get and set the type class of the remote host
148: */
149: PUBLIC char * HTHost_class (HTHost * host)
150: {
151: return host ? host->type : NULL;
152: }
153:
154: PUBLIC void HTHost_setClass (HTHost * host, char * s_class)
155: {
156: if (host && s_class) StrAllocCopy(host->type, s_class);
157: }
158:
159: /*
160: ** Get and set the version of the remote host
161: */
162: PUBLIC int HTHost_version (HTHost *host)
163: {
164: return host ? host->version : 0;
165: }
166:
167: PUBLIC void HTHost_setVersion (HTHost * host, int version)
168: {
169: if (host) host->version = version;
170: }
171:
172: /*
173: ** Get and set the cache timeout for persistent entries.
174: ** The default value is TCP_TIMEOUT
175: */
176: PUBLIC void HTHost_setPersistTimeout (time_t timeout)
177: {
178: TCPTimeout = timeout;
179: }
180:
181: PUBLIC time_t HTHost_persistTimeout (time_t timeout)
182: {
183: return TCPTimeout;
184: }
185:
186: /* Persistent Connection Expiration
187: ** --------------------------------
188: ** Should normally not be used. If, then use calendar time.
189: */
190: PUBLIC void HTHost_setPersistExpires (HTHost * host, time_t expires)
191: {
192: if (host) host->expires = expires;
193: }
194:
195: PUBLIC time_t HTHost_persistExpires (HTHost * host)
196: {
197: return host ? host->expires : -1;
198: }
199:
200: /*
201: ** Searches the list of persistent connections for a host object
202: ** associated with this channel
203: */
204: PRIVATE HTHost * HTHost_findPersistent (HTChannel * ch)
205: {
206: if (Persistent && ch) {
207: HTList * cur = Persistent;
208: HTHost * pres;
209: while ((pres = (HTHost *) HTList_nextObject(cur)))
210: if (pres->channel == ch) return pres;
211: }
212: return NULL;
213: }
214:
215: /* HTHost_catchClose
216: ** -----------------
217: ** This function is registered when the socket is idle so that we get
218: ** a notification if the socket closes at the other end. At this point
219: ** we can't use the request object as it might have been freed a long
220: ** time ago.
221: */
222: PUBLIC int HTHost_catchClose (SOCKET soc, HTRequest * request, SockOps ops)
223: {
2.2 frystyk 224: if (CORE_TRACE)
2.1 frystyk 225: HTTrace("Catch Close. called with socket %d with ops %x\n",
226: soc, (unsigned) ops);
227: if (ops == FD_READ) {
228: HTChannel * ch = HTChannel_find(soc); /* Find associated channel */
229: HTHost * host = HTHost_findPersistent(ch);
230: if (ch && host) {
2.2 frystyk 231: if (CORE_TRACE) HTTrace("Catch Close. CLOSING socket %d\n", soc);
2.1 frystyk 232: HTHost_clearChannel(host);
233: } else {
2.2 frystyk 234: if (CORE_TRACE) HTTrace("Catch Close. socket %d NOT FOUND!\n",soc);
2.1 frystyk 235: }
236: }
237: HTEvent_UnRegister(soc, (SockOps) FD_ALL);
238: return HT_OK;
239: }
240:
241: /*
242: ** As soon as we know that this host accepts persistent connections,
243: ** we associated the channel with the host.
244: ** We don't want more than MaxSockets-2 connections to be persistent in
245: ** order to avoid deadlock.
246: */
247: PUBLIC BOOL HTHost_setChannel (HTHost * host, HTChannel * channel)
248: {
2.2 frystyk 249: if (!host && !channel) return NO;
250: if (host->channel) {
251: if (CORE_TRACE) HTTrace("Host info... %p already persistent\n", host);
252: return YES;
253: } else {
2.1 frystyk 254: SOCKET sockfd = HTChannel_socket(channel);
255: if (!Persistent) Persistent = HTList_new();
256: if (sockfd != INVSOC && HTList_count(Persistent)<HTNet_maxSocket()-2) {
257: host->channel = channel;
258: host->expires = time(NULL) + TCPTimeout; /* Default timeout */
259: HTList_addObject(Persistent, host);
2.2 frystyk 260: if (CORE_TRACE)
2.1 frystyk 261: HTTrace("Host info... added host %p as persistent\n", host);
262: return YES;
263: } else {
2.2 frystyk 264: if (CORE_TRACE)
265: HTTrace("Host info... no room for persistent socket %d\n",
2.1 frystyk 266: socket);
267: }
268: }
269: return NO;
270: }
271:
272: /*
273: ** Find persistent channel associated with this host.
274: */
275: PUBLIC HTChannel * HTHost_channel (HTHost * host)
276: {
277: return host ? host->channel : NULL;
278: }
279:
280: /*
281: ** Clear the persistent entry by deleting the channel object. Note that
282: ** the channel object is only deleted if it's not used anymore.
283: */
284: PUBLIC BOOL HTHost_clearChannel (HTHost * host)
285: {
286: if (host && host->channel) {
287: HTChannel_delete(host->channel);
288: host->expires = 0;
289: host->channel = NULL;
2.2 frystyk 290: if (CORE_TRACE)
291: HTTrace("Host info... removed host %p as persistent\n", host);
2.1 frystyk 292: HTList_removeObject(Persistent, host);
293: return YES;
294: }
295: return NO;
296: }
297:
298: /*
299: ** Check whether we have a persistent channel or not
300: */
301: PUBLIC BOOL HTHost_isPersistent (HTHost * host)
302: {
303: return host && host->channel;
304: }
305:
Webmaster