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