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