Annotation of libwww/Library/src/HTHost.c, revision 2.1
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.
! 6: ** @(#) $Id: Date Author State $
! 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: {
! 60: if (PROT_TRACE) HTTrace("Host info... object %p from list %p\n", me, list);
! 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) {
! 82: if (PROT_TRACE) HTTrace("Host info... Bad argument\n");
! 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) {
! 107: if (PROT_TRACE)
! 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 */
! 121: if (PROT_TRACE)
! 122: HTTrace("Host info... Persistent channel %p gotten cold\n",
! 123: pres->channel);
! 124: HTChannel_delete(pres->channel);
! 125: pres->channel = NULL;
! 126: } else {
! 127: if (PROT_TRACE)
! 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);
! 136: if (PROT_TRACE)
! 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: {
! 221: if (PROT_TRACE)
! 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) {
! 228: if (PROT_TRACE) HTTrace("Catch Close. CLOSING socket %d\n", soc);
! 229: HTHost_clearChannel(host);
! 230: } else {
! 231: if (PROT_TRACE) HTTrace("Catch Close. socket %d NOT FOUND!\n",soc);
! 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: {
! 246: if (host && channel) {
! 247: SOCKET sockfd = HTChannel_socket(channel);
! 248: if (!Persistent) Persistent = HTList_new();
! 249: if (sockfd != INVSOC && HTList_count(Persistent)<HTNet_maxSocket()-2) {
! 250: host->channel = channel;
! 251: host->expires = time(NULL) + TCPTimeout; /* Default timeout */
! 252: HTList_addObject(Persistent, host);
! 253: if (PROT_TRACE)
! 254: HTTrace("Host info... added host %p as persistent\n", host);
! 255: return YES;
! 256: } else {
! 257: if (PROT_TRACE)
! 258: HTTrace("Host info... no room for persistent cocket %d\n",
! 259: socket);
! 260: }
! 261: }
! 262: return NO;
! 263: }
! 264:
! 265: /*
! 266: ** Find persistent channel associated with this host.
! 267: */
! 268: PUBLIC HTChannel * HTHost_channel (HTHost * host)
! 269: {
! 270: return host ? host->channel : NULL;
! 271: }
! 272:
! 273: /*
! 274: ** Clear the persistent entry by deleting the channel object. Note that
! 275: ** the channel object is only deleted if it's not used anymore.
! 276: */
! 277: PUBLIC BOOL HTHost_clearChannel (HTHost * host)
! 278: {
! 279: if (host && host->channel) {
! 280: HTChannel_delete(host->channel);
! 281: host->expires = 0;
! 282: host->channel = NULL;
! 283: HTList_removeObject(Persistent, host);
! 284: return YES;
! 285: }
! 286: return NO;
! 287: }
! 288:
! 289: /*
! 290: ** Check whether we have a persistent channel or not
! 291: */
! 292: PUBLIC BOOL HTHost_isPersistent (HTHost * host)
! 293: {
! 294: return host && host->channel;
! 295: }
! 296:
Webmaster