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

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

Webmaster