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

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.9     ! frystyk     6: **     @(#) $Id: HTHost.c,v 2.8 1996/08/19 18:30:35 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 */
2.6       frystyk    35:     HTMethod           methods;                /* Public methods (bit-flag) */
                     36:     char *             server;                               /* Server name */
                     37:     char *             user_agent;                            /* User Agent */
2.8       frystyk    38:     HTTransportMode    mode;                              /* Supported mode */
2.1       frystyk    39:     HTChannel *                channel;                       /* Persistent channel */
2.8       frystyk    40:     HTList *           pipeline;                /* Pipe line of net objects */
                     41:     HTList *           pending;              /* List of pending Net objects */
2.1       frystyk    42:     time_t             expires;          /* Persistent channel expires time */
                     43: };
                     44: 
                     45: PRIVATE time_t HostTimeout = HOST_TIMEOUT;       /* Timeout on host entries */
                     46: PRIVATE time_t TCPTimeout = TCP_TIMEOUT;  /* Timeout on persistent channels */
                     47: 
2.8       frystyk    48: PRIVATE HTList ** HostTable = NULL;
                     49: PRIVATE HTList * PendHost = NULL;          /* List of pending host elements */
2.1       frystyk    50: 
                     51: /* ------------------------------------------------------------------------- */
                     52: 
                     53: PRIVATE void free_object (HTHost * me)
                     54: {
                     55:     if (me) {
                     56:        HT_FREE(me->hostname);
                     57:        HT_FREE(me->type);
2.3       eric       58:        if (me->channel) {
2.5       eric       59:            HTChannel_delete(me->channel, HT_OK);
2.3       eric       60:            me->channel = NULL;
                     61:        }
2.8       frystyk    62:        HTList_delete(me->pipeline);
                     63:        HTList_delete(me->pending);
2.1       frystyk    64:        HT_FREE(me);
                     65:     }
                     66: }
                     67: 
                     68: PRIVATE BOOL delete_object (HTList * list, HTHost * me)
                     69: {
2.2       frystyk    70:     if (CORE_TRACE) HTTrace("Host info... object %p from list %p\n", me, list);
2.1       frystyk    71:     HTList_removeObject(list, (void *) me);
                     72:     free_object(me);
                     73:     return YES;
                     74: }
                     75: 
                     76: /*
                     77: **     Search the host info cache for a host object or create a new one
                     78: **     and add it. Examples of host names are
                     79: **
                     80: **             www.w3.org
                     81: **             www.foo.com:8000
                     82: **             18.52.0.18
                     83: **
                     84: **     Returns Host object or NULL if error. You may get back an already
                     85: **     existing host object - you're not guaranteed a new one each time.
                     86: */
                     87: PUBLIC HTHost * HTHost_new (char * host)
                     88: {
                     89:     HTList * list = NULL;                          /* Current list in cache */
                     90:     HTHost * pres = NULL;
                     91:     if (!host) {
2.2       frystyk    92:        if (CORE_TRACE) HTTrace("Host info... Bad argument\n");
2.1       frystyk    93:        return NULL;
                     94:     }
                     95:     
                     96:     /* Find a hash for this host */
                     97:     {
                     98:        int hash = 0;
                     99:        char *ptr;
                    100:        for (ptr=host; *ptr; ptr++)
                    101:            hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HASH_SIZE);
                    102:        if (!HostTable) {
                    103:            if ((HostTable = (HTList **) HT_CALLOC(HASH_SIZE,
                    104:                                                   sizeof(HTList *))) == NULL)
                    105:                HT_OUTOFMEM("HTHost_find");
                    106:        }
                    107:        if (!HostTable[hash]) HostTable[hash] = HTList_new();
                    108:        list = HostTable[hash];
                    109:     }
                    110: 
                    111:     /* Search the cache */
                    112:     {
                    113:        HTList * cur = list;
                    114:        while ((pres = (HTHost *) HTList_nextObject(cur))) {
                    115:            if (!strcmp(pres->hostname, host)) {
2.8       frystyk   116:                if (HTHost_isIdle(pres) && time(NULL)>pres->ntime+HostTimeout){
2.2       frystyk   117:                    if (CORE_TRACE)
2.1       frystyk   118:                        HTTrace("Host info... Collecting host info %p\n",pres);
                    119:                    delete_object(list, pres);
                    120:                    pres = NULL;
                    121:                }
                    122:                break;
                    123:            }
                    124:        }
                    125:     }
                    126: 
2.8       frystyk   127:     /* If not found then create new Host object, else use existing one */
2.1       frystyk   128:     if (pres) {
                    129:        if (pres->channel) {
                    130:            if (pres->expires < time(NULL)) {      /* Cached channel is cold */
2.2       frystyk   131:                if (CORE_TRACE)
2.1       frystyk   132:                    HTTrace("Host info... Persistent channel %p gotten cold\n",
                    133:                            pres->channel);
2.5       eric      134:                HTChannel_delete(pres->channel, HT_OK);
2.1       frystyk   135:                pres->channel = NULL;
                    136:            } else {
2.2       frystyk   137:                if (CORE_TRACE)
2.1       frystyk   138:                    HTTrace("Host info... REUSING CHANNEL %p\n",pres->channel);
                    139:            }
                    140:        }
                    141:     } else {
                    142:        if ((pres = (HTHost *) HT_CALLOC(1, sizeof(HTHost))) == NULL)
                    143:            HT_OUTOFMEM("HTHost_add");
                    144:        StrAllocCopy(pres->hostname, host);
                    145:        pres->ntime = time(NULL);
2.8       frystyk   146:        pres->mode = HT_TP_SINGLE;
2.2       frystyk   147:        if (CORE_TRACE) 
2.1       frystyk   148:            HTTrace("Host info... added `%s\' to list %p\n", host, list);
                    149:        HTList_addObject(list, (void *) pres);
                    150:     }
                    151:     return pres;
2.9     ! frystyk   152: }
        !           153: 
        !           154: /*
        !           155: **     Search the host info cache for a host object. Examples of host names:
        !           156: **
        !           157: **             www.w3.org
        !           158: **             www.foo.com:8000
        !           159: **             18.52.0.18
        !           160: **
        !           161: **     Returns Host object or NULL if not found.
        !           162: */
        !           163: PUBLIC HTHost * HTHost_find (char * host)
        !           164: {
        !           165:     HTList * list = NULL;                          /* Current list in cache */
        !           166:     HTHost * pres = NULL;
        !           167:     if (CORE_TRACE)
        !           168:        HTTrace("Host info... Looking for `%s\'\n", host ? host : "<null>");
        !           169: 
        !           170:     /* Find a hash for this host */
        !           171:     if (host && HostTable) {
        !           172:        int hash = 0;
        !           173:        char *ptr;
        !           174:        for (ptr=host; *ptr; ptr++)
        !           175:            hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HASH_SIZE);
        !           176:        if (!HostTable[hash]) return NULL;
        !           177:        list = HostTable[hash];
        !           178: 
        !           179:        /* Search the cache */
        !           180:        {
        !           181:            HTList * cur = list;
        !           182:            while ((pres = (HTHost *) HTList_nextObject(cur))) {
        !           183:                if (!strcmp(pres->hostname, host)) {
        !           184:                    if (time(NULL) > pres->ntime + HostTimeout) {
        !           185:                        if (CORE_TRACE)
        !           186:                            HTTrace("Host info... Collecting host %p\n", pres);
        !           187:                        delete_object(list, pres);
        !           188:                        pres = NULL;
        !           189:                    } else {
        !           190:                        if (CORE_TRACE)
        !           191:                            HTTrace("Host info... Found `%s\'\n", host);
        !           192:                    }
        !           193:                    return pres;
        !           194:                }
        !           195:            }
        !           196:        }
        !           197:     }
        !           198:     return NULL;
2.1       frystyk   199: }
                    200: 
                    201: /*
2.8       frystyk   202: **     Get and set the hostname of the remote host
                    203: */
                    204: PUBLIC char * HTHost_name (HTHost * host)
                    205: {
                    206:      return host ? host->hostname : NULL;
                    207: }
                    208: 
                    209: /*
2.1       frystyk   210: **     Get and set the type class of the remote host
                    211: */
                    212: PUBLIC char * HTHost_class (HTHost * host)
                    213: {
                    214:      return host ? host->type : NULL;
                    215: }
                    216: 
                    217: PUBLIC void HTHost_setClass (HTHost * host, char * s_class)
                    218: {
                    219:     if (host && s_class) StrAllocCopy(host->type, s_class);
                    220: }
                    221: 
                    222: /*
                    223: **     Get and set the version of the remote host
                    224: */
                    225: PUBLIC int HTHost_version (HTHost *host)
                    226: {
                    227:      return host ? host->version : 0;
                    228: }
                    229: 
                    230: PUBLIC void HTHost_setVersion (HTHost * host, int version)
                    231: {
                    232:     if (host) host->version = version;
                    233: }
                    234: 
                    235: /*
                    236: **     Get and set the cache timeout for persistent entries.
                    237: **     The default value is TCP_TIMEOUT
                    238: */
                    239: PUBLIC void HTHost_setPersistTimeout (time_t timeout)
                    240: {
                    241:     TCPTimeout = timeout;
                    242: }
                    243: 
                    244: PUBLIC time_t HTHost_persistTimeout (time_t timeout)
                    245: {
                    246:     return TCPTimeout;
                    247: }
                    248: 
                    249: /*     Persistent Connection Expiration
                    250: **     --------------------------------
                    251: **     Should normally not be used. If, then use calendar time.
                    252: */
                    253: PUBLIC void HTHost_setPersistExpires (HTHost * host, time_t expires)
                    254: {
                    255:     if (host) host->expires = expires;
                    256: }
                    257: 
                    258: PUBLIC time_t HTHost_persistExpires (HTHost * host)
                    259: {
                    260:     return host ? host->expires : -1;
                    261: }
                    262: 
                    263: /*
2.6       frystyk   264: **     Public methods for this host
                    265: */
                    266: PUBLIC HTMethod HTHost_publicMethods (HTHost * me)
                    267: {
                    268:     return me ? me->methods : METHOD_INVALID;
                    269: }
                    270: 
                    271: PUBLIC void HTHost_setPublicMethods (HTHost * me, HTMethod methodset)
                    272: {
                    273:     if (me) me->methods = methodset;
                    274: }
                    275: 
                    276: PUBLIC void HTHost_appendPublicMethods (HTHost * me, HTMethod methodset)
                    277: {
                    278:     if (me) me->methods |= methodset;
                    279: }
                    280: 
                    281: /*
                    282: **     Get and set the server name of the remote host
                    283: */
                    284: PUBLIC char * HTHost_server (HTHost * host)
                    285: {
                    286:      return host ? host->server : NULL;
                    287: }
                    288: 
                    289: PUBLIC BOOL HTHost_setServer (HTHost * host, const char * server)
                    290: {
                    291:     if (host && server) {
                    292:        StrAllocCopy(host->server, server);
                    293:        return YES;
                    294:     }
                    295:     return NO;
                    296: }
                    297: 
                    298: /*
                    299: **     Get and set the userAgent name of the remote host
                    300: */
                    301: PUBLIC char * HTHost_userAgent (HTHost * host)
                    302: {
                    303:      return host ? host->user_agent : NULL;
                    304: }
                    305: 
                    306: PUBLIC BOOL HTHost_setUserAgent (HTHost * host, const char * userAgent)
                    307: {
                    308:     if (host && userAgent) {
                    309:        StrAllocCopy(host->user_agent, userAgent);
                    310:        return YES;
                    311:     }
                    312:     return NO;
                    313: }
                    314: 
2.1       frystyk   315: /*     HTHost_catchClose
                    316: **     -----------------
                    317: **     This function is registered when the socket is idle so that we get
                    318: **     a notification if the socket closes at the other end. At this point
                    319: **     we can't use the request object as it might have been freed a long
                    320: **     time ago.
                    321: */
                    322: PUBLIC int HTHost_catchClose (SOCKET soc, HTRequest * request, SockOps ops)
                    323: {
2.2       frystyk   324:     if (CORE_TRACE)
2.1       frystyk   325:        HTTrace("Catch Close. called with socket %d with ops %x\n",
                    326:                soc, (unsigned) ops);
                    327:     if (ops == FD_READ) {
                    328:        HTChannel * ch = HTChannel_find(soc);     /* Find associated channel */
2.8       frystyk   329:        HTHost * host = HTChannel_host(ch);           /* and associated host */
2.1       frystyk   330:        if (ch && host) {           
2.2       frystyk   331:            if (CORE_TRACE) HTTrace("Catch Close. CLOSING socket %d\n", soc);
2.8       frystyk   332:            HTHost_clearChannel(host, HT_OK);
2.1       frystyk   333:        } else {
2.2       frystyk   334:            if (CORE_TRACE) HTTrace("Catch Close. socket %d NOT FOUND!\n",soc);
2.1       frystyk   335:        }
                    336:     }
2.4       eric      337:     HTEvent_unregister(soc, (SockOps) FD_ALL);
2.1       frystyk   338:     return HT_OK;
                    339: }
                    340: 
                    341: /*
                    342: **     As soon as we know that this host accepts persistent connections,
                    343: **     we associated the channel with the host. 
                    344: **     We don't want more than MaxSockets-2 connections to be persistent in
                    345: **     order to avoid deadlock.
                    346: */
2.8       frystyk   347: PUBLIC BOOL HTHost_setChannel (HTHost *                host,
                    348:                               HTChannel *      channel,
                    349:                               HTTransportMode  mode)
2.1       frystyk   350: {
2.6       frystyk   351:     if (!host || !channel) return NO;
2.2       frystyk   352:     if (host->channel) {
                    353:        if (CORE_TRACE) HTTrace("Host info... %p already persistent\n", host);
                    354:        return YES;
                    355:     } else {
2.1       frystyk   356:        SOCKET sockfd = HTChannel_socket(channel);
2.8       frystyk   357:        if (sockfd != INVSOC && HTNet_availablePersistentSockets() > 0) {
2.1       frystyk   358:            host->channel = channel;
2.8       frystyk   359:            host->mode = mode;
2.1       frystyk   360:            host->expires = time(NULL) + TCPTimeout;      /* Default timeout */
2.8       frystyk   361:            HTChannel_setHost(channel, host); 
                    362:            HTNet_increasePersistentSocket();
2.2       frystyk   363:            if (CORE_TRACE)
2.1       frystyk   364:                HTTrace("Host info... added host %p as persistent\n", host);
                    365:            return YES;
                    366:        } else {
2.2       frystyk   367:            if (CORE_TRACE)
                    368:                HTTrace("Host info... no room for persistent socket %d\n",
2.7       frystyk   369:                        sockfd);
2.1       frystyk   370:        }
                    371:     }
                    372:     return NO;
                    373: }
                    374: 
                    375: /*
                    376: **     Find persistent channel associated with this host.
                    377: */
                    378: PUBLIC HTChannel * HTHost_channel (HTHost * host)
                    379: {
                    380:     return host ? host->channel : NULL;
                    381: }
                    382: 
                    383: /*
                    384: **     Clear the persistent entry by deleting the channel object. Note that
                    385: **     the channel object is only deleted if it's not used anymore.
                    386: */
2.8       frystyk   387: PUBLIC BOOL HTHost_clearChannel (HTHost * host, int status)
2.1       frystyk   388: {
                    389:     if (host && host->channel) {
2.8       frystyk   390:        HTChannel_setHost(host->channel, NULL);
                    391:        HTChannel_delete(host->channel, status);
2.1       frystyk   392:        host->expires = 0;
                    393:        host->channel = NULL;
2.8       frystyk   394:        HTNet_decreasePersistentSocket();
2.2       frystyk   395:        if (CORE_TRACE)
                    396:            HTTrace("Host info... removed host %p as persistent\n", host);
2.1       frystyk   397:        return YES;
                    398:     }
                    399:     return NO;
                    400: }
                    401: 
                    402: /*
                    403: **     Check whether we have a persistent channel or not
                    404: */
                    405: PUBLIC BOOL HTHost_isPersistent (HTHost * host)
                    406: {
                    407:     return host && host->channel;
2.8       frystyk   408: }
                    409: 
                    410: /*
                    411: **     Handle the connection mode. The mode may change mode in the 
                    412: **     middle of a connection.
                    413: */
                    414: PUBLIC HTTransportMode HTHost_mode (HTHost * host, BOOL * active)
                    415: {
                    416:     return host ? host->mode : HT_TP_SINGLE;
                    417: }
                    418: 
                    419: /*
                    420: **     If the new mode is lower than the old mode then adjust the pipeline
                    421: **     accordingly. That is, if we are going into single mode then move
                    422: **     all entries in the pipeline and move the rest to the pending
                    423: **     queue. They will get launched at a later point in time.
                    424: */
                    425: PUBLIC BOOL HTHost_setMode (HTHost * host, HTTransportMode mode)
                    426: {
                    427:     if (host) {
                    428:        /*
                    429:        **  Check the new mode and see if we must adjust the queues.
                    430:        */
                    431:        if (mode == HT_TP_SINGLE && host->mode > mode) {
                    432:            int piped = HTList_count(host->pipeline);
                    433:            if (piped > 0) {
                    434:                int cnt;
                    435:                if (CORE_TRACE)
                    436:                    HTTrace("Host info... Moving %d Net objects from pipe line to pending queue\n", piped);
                    437:                if (!host->pending) host->pending = HTList_new();
                    438:                for (cnt=0; cnt<piped; cnt++) {
                    439:                    HTNet * net = HTList_removeFirstObject(host->pipeline);
                    440:                    HTList_appendObject(host->pending, net);
                    441:                }
                    442:            }
                    443:        }
                    444:        host->mode = mode;
                    445:        return YES;
                    446:     }
                    447:     return NO;
                    448: }
                    449: 
                    450: /*
                    451: **     Check whether a host is idle meaning if it is ready for a new
                    452: **     request which depends on the mode of the host. If the host is 
                    453: **     idle, i.e. ready for use then return YES else NO. If the host supports
                    454: **     persistent connections then still only return idle if no requests are
                    455: **     ongoing. 
                    456: */
                    457: PUBLIC BOOL HTHost_isIdle (HTHost * host)
                    458: {
                    459:     return (host && HTList_count(host->pipeline) <= 0);
                    460: }
                    461: 
                    462: /*
                    463: **     Add a net object to the host object. If the host
                    464: **     is idle then add to active list (pipeline) else add
                    465: **     it to the pending list
                    466: **     Return HT_PENDING if we must pend, HT_OK, or HT_ERROR
                    467: */
                    468: PUBLIC int HTHost_addNet (HTHost * host, HTNet * net)
                    469: {
                    470:     if (host && net) {
                    471:        int status = HT_OK;
                    472: 
                    473:        /* Check to see if we can get a socket */
                    474:        if (HTNet_availableSockets() <= 0) {
                    475:            if (!PendHost) PendHost = HTList_new();
                    476:            if (CORE_TRACE)
                    477:                HTTrace("Host info... Add Host %p as pending\n", host);
                    478:            HTList_addObject(PendHost, host);
                    479:            status = HT_PENDING;
                    480:        }
                    481: 
                    482:        /* Add to either active or pending queue */
                    483:        if (HTHost_isIdle(host)) {
                    484:            if (CORE_TRACE) HTTrace("Host info... Add Net %p to pipeline of host %p\n", net, host);
                    485:            if (!host->pipeline) host->pipeline = HTList_new();
                    486:            HTList_addObject(host->pipeline, net);
                    487:            
                    488:            /*
                    489:            **  We have been idle and must hence unregister our catch close
                    490:            **  event handler
                    491:            */
                    492:            if (host->channel) {
                    493:                SOCKET sockfd = HTChannel_socket(host->channel);
                    494:                HTEvent_unregister(sockfd, (SockOps) FD_CLOSE);
                    495:            }
                    496:        } else {
                    497:            if (CORE_TRACE) HTTrace("Host info... Add Net %p as pending\n", net);
                    498:            if (!host->pending) host->pending = HTList_new();
                    499:            HTList_addObject(host->pending, net);
                    500:            status = HT_PENDING;
                    501:        }
                    502:        return status;
                    503:     }
                    504:     return HT_ERROR;
                    505: }
                    506: 
                    507: PUBLIC BOOL HTHost_deleteNet (HTHost * host, HTNet * net)
                    508: {
                    509:     if (host && net) {
                    510:        if (CORE_TRACE)
                    511:            HTTrace("Host info... Remove Net %p from pipe line\n", net);
                    512:        HTList_removeObject(host->pipeline, net);
                    513:        HTList_removeObject(host->pending, net);
                    514:        return YES;
                    515:     }
                    516:     return NO;
                    517: }
                    518: 
                    519: /*
                    520: **     Handle pending host objects.
                    521: **     There are two ways we can end up with pending reqyests:
                    522: **      1) If we are out of sockets then register new host objects as pending.
                    523: **      2) If we are pending on a connection then register new net objects as
                    524: **         pending
                    525: **     This set of functions handles pending host objects and can start new
                    526: **     requests as resources get available
                    527: */
                    528: 
                    529: /*
                    530: **     Check this host object for any pending requests and return the next
                    531: **     registered Net object.
                    532: */
                    533: PUBLIC HTNet * HTHost_nextPendingNet (HTHost * host)
                    534: {
                    535:     HTNet * net = NULL;
                    536:     if (host && host->pending && host->pipeline) {
                    537:        if ((net = (HTNet *) HTList_removeFirstObject(host->pending)) != NULL)
                    538:            if (PROT_TRACE)
                    539:                HTTrace("Host info... Popping %p from pending net queue\n",
                    540:                        net);
                    541:        HTList_addObject(host->pipeline, net);
                    542:     }
                    543:     return net;
                    544: }
                    545: 
                    546: /*
                    547: **     Return the current list of pending host obejcts waiting for a socket
                    548: */
                    549: PUBLIC HTHost * HTHost_nextPendingHost (void)
                    550: {
                    551:     HTHost * host = NULL;
                    552:     if (PendHost) {
                    553:        if ((host = (HTHost *) HTList_removeFirstObject(PendHost)) != NULL)
                    554:            if (PROT_TRACE)
                    555:                HTTrace("Host info... Poping %p from pending host queue\n",
                    556:                        host);
                    557:     }
                    558:     return host;
                    559: }
                    560: 
                    561: /*
                    562: **     Start the next pending request if any. First we look for pending
                    563: **     requests for the same host and then we check for any other pending
                    564: **     hosts
                    565: */
                    566: PUBLIC BOOL HTHost_launchPending (HTHost * host)
                    567: {
                    568:     int available = HTNet_availableSockets();
                    569: 
                    570:     if (!host) {
                    571:        if (PROT_TRACE) HTTrace("Host info... Bad arguments\n");
                    572:        return NO;
                    573:     }
                    574: 
                    575:     /*
                    576:     **  Check if we do have resources available for a new request
                    577:     **  This can either be reusing an existing connection or opening a new one
                    578:     */
                    579:     if (available > 0 || host->mode >= HT_TP_PIPELINE) {
                    580: 
                    581:        /*
                    582:        **  Check the current Host obejct for pending Net objects
                    583:        */
                    584:        if (host) {
                    585:            HTNet * net = HTHost_nextPendingNet(host);
                    586:            if (net) return HTNet_start(net);
                    587:        }
                    588: 
                    589:        /*
                    590:        **  Check for other pending Host objects
                    591:        */
                    592:        {
                    593:            HTHost * pending = HTHost_nextPendingHost();
                    594:            if (pending) {
                    595:                HTNet * net = HTHost_nextPendingNet(pending);
                    596:                if (net) return HTNet_start(net);
                    597:            }
                    598:        }
                    599: 
                    600:        /*
                    601:        **  If nothing pending then register our catch close event handler to
                    602:        **  have something catching the socket if the remote server closes the
                    603:        **  connection, for example due to timeout.
                    604:        */
                    605:        if (PROT_TRACE) HTTrace("Host info... Nothing pending\n");
                    606:        if (host->channel) {
                    607:            SOCKET sockfd = HTChannel_socket(host->channel);
                    608:            HTEvent_register(sockfd, 0, (SockOps) FD_CLOSE,
                    609:                             HTHost_catchClose,  HT_PRIORITY_MAX);
                    610:        }
                    611:     } else
                    612:        if (PROT_TRACE) HTTrace("Host info... No available sockets\n");
                    613:     return NO;
2.1       frystyk   614: }
                    615: 

Webmaster