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

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

Webmaster