Annotation of libwww/Library/src/HTHost.c, revision 2.4

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.4     ! eric        6: **     @(#) $Id: HTHost.c,v 2.3 1996/05/01 12:40:34 eric 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:     }
2.4     ! eric      237:     HTEvent_unregister(soc, (SockOps) FD_ALL);
2.1       frystyk   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