Annotation of libwww/Library/src/HTTCP.c, revision 2.34

2.31      frystyk     1: /*                                                                     HTTCP.c
                      2: **     GENERIC COMMUNICATION CODE
                      3: **
                      4: **     (c) COPYRIGHT CERN 1994.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
1.1       timbl       6: **
                      7: **     This code is in common between client and server sides.
                      8: **
                      9: **     16 Jan 92  TBL  Fix strtol() undefined on CMU Mach.
                     10: **     25 Jun 92  JFG  Added DECNET option through TCP socket emulation.
2.7       duns       11: **     13 Sep 93  MD   Added correct return of vmserrorno for HTInetStatus.
                     12: **                     Added decoding of vms error message for MULTINET.
2.13      frystyk    13: **     31 May 94  HF   Added cache on host id's; now use inet_ntoa() to
                     14: **                     HTInetString and some other fixes. Added HTDoConnect
                     15: **                     and HTDoAccept
1.1       timbl      16: */
                     17: 
2.34    ! roeber     18: #include "sysdep.h"
2.19      frystyk    19: 
2.13      frystyk    20: #include "HTUtils.h"
                     21: #include "HTAtom.h"
                     22: #include "HTList.h"
                     23: #include "HTParse.h"
                     24: #include "HTAccess.h"
                     25: #include "HTError.h"
2.29      frystyk    26: 
                     27: #ifdef EVENT_LOOP
2.27      frystyk    28: #include "HTThread.h"
2.29      frystyk    29: #endif /* EVENT_LOOP */
                     30: 
2.24      frystyk    31: #include "HTTCP.h"                                      /* Implemented here */
1.1       timbl      32: 
                     33: #ifdef SHORT_NAMES
                     34: #define HTInetStatus           HTInStat
2.12      luotonen   35: #define HTErrnoString          HTErrnoS
1.1       timbl      36: #define HTInetString           HTInStri
                     37: #define HTParseInet            HTPaInet
                     38: #endif
                     39: 
2.13      frystyk    40: /* Macros and other defines */
2.24      frystyk    41: /* x seconds penalty on a multi-homed host if IP-address is down */
                     42: #define TCP_PENALTY            1200
                     43: 
                     44: /* x seconds penalty on a multi-homed host if IP-address is timed out */
                     45: #define TCP_DELAY              600
                     46: 
                     47: /* Max number of non-blocking accepts */
2.13      frystyk    48: #define MAX_ACCEPT_POLL                30
                     49: #define FCNTL(r, s, t)         fcntl(r, s, t)
                     50: 
                     51: /* Globals */
                     52: PUBLIC unsigned int    HTConCacheSize = 512;    /* Number of cached servers */
                     53: 
                     54: /* Type definitions and global variables etc. local to this module */
                     55: 
                     56: /* This structure is a cache of hosts to whom we have connected over time.
                     57:    The structure contains the necessary parts from hostent. For Internet host
                     58:    hostent->h_addr_list is not an array of char pointers but an array of 
                     59:    pointers of type in_addr. */
                     60: typedef struct _host_info {
                     61:     HTAtom *           hostname;                   /* Official name of host */
                     62:     int                        hits;           /* Total number of hits on this host */
                     63:     int                        addrlength;            /* Length of address in bytes */
2.24      frystyk    64:     int                        homes;         /* Number of IP addresses on the host */
2.13      frystyk    65:     int                        offset;         /* Offset value of active IP address */
                     66:     char **            addrlist;      /* List of addresses from name server */
                     67:     float *            weight;                    /* Weight on each address */
                     68: } host_info;
                     69: 
                     70: PRIVATE char *hostname = NULL;                     /* The name of this host */
2.19      frystyk    71: PRIVATE char *mailaddress = NULL;                   /* Current mail address */
2.13      frystyk    72: PRIVATE HTList *hostcache = NULL;  /* List of servers that we have talked to */
                     73: PRIVATE unsigned int HTCacheSize = 0;              /* Current size of cache */
2.11      duns       74: 
2.13      frystyk    75: /* ------------------------------------------------------------------------- */
2.27      frystyk    76: /* TEMPORARY STUFF */
                     77: #define IOCTL ioctl
                     78: /* ------------------------------------------------------------------------- */
1.1       timbl      79: 
                     80: /*     Encode INET status (as in sys/errno.h)                    inet_status()
                     81: **     ------------------
                     82: **
                     83: ** On entry,
                     84: **     where           gives a description of what caused the error
                     85: **     global errno    gives the error number in the unix way.
                     86: **
                     87: ** On return,
                     88: **     returns         a negative status in the unix way.
                     89: */
2.34    ! roeber     90: #if 0 /* Is this needed? --fgmr */
        !            91: #ifdef HAVE_SOCKET_ERRNO
        !            92: extern volatile noshare int socket_errno;
        !            93: #endif
2.11      duns       94: 
1.1       timbl      95: #ifndef errno
2.34    ! roeber     96: extern volatile noshare int errno; 
        !            97: #endif
        !            98: #endif
1.1       timbl      99: 
2.34    ! roeber    100: #ifdef HAVE_SYS_ERRLIST
        !           101: #ifdef NEED_SYS_ERRLIST_DECLARED
1.1       timbl     102: extern char *sys_errlist[];            /* see man perror on cernvax */
2.34    ! roeber    103: #endif
        !           104: #endif
        !           105: 
        !           106: #ifdef HAVE_SYS_NERR
        !           107: #ifdef NEED_SYS_NERR_DECLARED
1.1       timbl     108: extern int sys_nerr;
2.34    ! roeber    109: #endif
        !           110: #endif
2.12      luotonen  111: 
                    112: /*
                    113:  *     Returns the string equivalent of the current errno.
                    114:  */
                    115: PUBLIC CONST char * HTErrnoString NOARGS
1.1       timbl     116: {
2.34    ! roeber    117: #ifdef HAVE_STRERROR
2.12      luotonen  118:     return strerror(errno);
2.34    ! roeber    119: #else
2.12      luotonen  120: 
2.34    ! roeber    121: #ifdef HAVE_SYS_ERRLIST
        !           122: # ifdef HAVE_SYS_NERR
2.12      luotonen  123:     return (errno < sys_nerr ? sys_errlist[errno] : "Unknown error");
2.34    ! roeber    124: # else
        !           125:     return sys_errlist[errno];
        !           126: # endif
1.1       timbl     127: #endif
                    128: 
2.34    ! roeber    129: #ifdef HAVE_VAXC_ERRNO
2.12      luotonen  130:     static char buf[60];
                    131:     sprintf(buf,"Unix errno = %ld dec, VMS error = %lx hex",errno,vaxc$errno);
                    132:     return buf;
2.34    ! roeber    133: #endif
2.12      luotonen  134: 
2.34    ! roeber    135:     return "(Error number not translated)";
1.1       timbl     136: #endif
2.12      luotonen  137: }
                    138: 
                    139: /*     Report Internet Error
                    140: **     ---------------------
                    141: */
                    142: PUBLIC int HTInetStatus ARGS1(char *, where)
                    143: {
2.34    ! roeber    144: #ifndef HAVE_VAXC_ERRNO
2.12      luotonen  145: 
2.27      frystyk   146:     if (PROT_TRACE)
                    147:        fprintf(stderr, "TCP errno... %d after call to %s() failed.\n............ %s\n", errno, where, HTErrnoString());
1.1       timbl     148: 
2.34    ! roeber    149: #else /* HAVE_VAXC_ERRNO */
2.12      luotonen  150: 
2.27      frystyk   151:     if (PROT_TRACE) fprintf(stderr, "         Unix error number          = %ld dec\n", errno);
                    152:     if (PROT_TRACE) fprintf(stderr, "         VMS error                  = %lx hex\n", vaxc$errno);
2.12      luotonen  153: 
2.34    ! roeber    154: #ifdef HAVE_SOCKET_ERRNO
2.27      frystyk   155:     if (PROT_TRACE) fprintf(stderr, "         Multinet error             = %lx hex\n", socket_errno); 
2.34    ! roeber    156: #endif
        !           157: #ifdef HAVE_VMS_ERRNO_STRING
2.27      frystyk   158:     if (PROT_TRACE) fprintf(stderr, "         Error String               = %s\n", vms_errno_string());
2.34    ! roeber    159: #endif
2.12      luotonen  160: 
2.34    ! roeber    161: #endif /* HAVE_VAXC_ERRNO */
2.7       duns      162: 
2.34    ! roeber    163: #ifdef HAVE_VAXC_ERRNO
2.11      duns      164:     /* errno happen to be zero if vaxc$errno <> 0 */
                    165:     return -vaxc$errno;
2.7       duns      166: #else
1.1       timbl     167:     return -errno;
2.7       duns      168: #endif
1.1       timbl     169: }
                    170: 
                    171: 
                    172: /*     Parse a cardinal value                                 parse_cardinal()
                    173: **     ----------------------
                    174: **
                    175: ** On entry,
                    176: **     *pp         points to first character to be interpreted, terminated by
                    177: **                 non 0:9 character.
                    178: **     *pstatus    points to status already valid
                    179: **     maxvalue    gives the largest allowable value.
                    180: **
                    181: ** On exit,
                    182: **     *pp         points to first unread character
                    183: **     *pstatus    points to status updated iff bad
                    184: */
                    185: 
                    186: PUBLIC unsigned int HTCardinal ARGS3
                    187:        (int *,         pstatus,
                    188:        char **,        pp,
                    189:        unsigned int,   max_value)
                    190: {
                    191:     int   n;
                    192:     if ( (**pp<'0') || (**pp>'9')) {       /* Null string is error */
                    193:        *pstatus = -3;  /* No number where one expeceted */
                    194:        return 0;
                    195:     }
                    196: 
                    197:     n=0;
                    198:     while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
                    199: 
                    200:     if (n>max_value) {
                    201:        *pstatus = -4;  /* Cardinal outside range */
                    202:        return 0;
                    203:     }
                    204: 
                    205:     return n;
                    206: }
                    207: 
2.19      frystyk   208: /* ------------------------------------------------------------------------- */
2.27      frystyk   209: /*                             SIGNAL HANDLING                              */
                    210: /* ------------------------------------------------------------------------- */
                    211: 
                    212: #ifdef WWWLIB_SIG
                    213: /*                                                                 HTSetSignal
                    214: **  This function sets up signal handlers. This might not be necessary to
                    215: **  call if the application has its own handlers.
                    216: */
                    217: #include <signal.h>
                    218: PUBLIC void HTSetSignal NOARGS
                    219: {
                    220:     /* On some systems (SYSV) it is necessary to catch the SIGPIPE signal
                    221:     ** when attemting to connect to a remote host where you normally should
                    222:     ** get `connection refused' back
                    223:     */
                    224:     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
                    225:        if (PROT_TRACE) fprintf(stderr, "HTSignal.... Can't catch SIGPIPE\n");
                    226:     } else {
                    227:        if (PROT_TRACE) fprintf(stderr, "HTSignal.... Ignoring SIGPIPE\n");
                    228:     }
                    229: }
                    230: #endif /* WWWLIB_SIG */
                    231: 
                    232: /* ------------------------------------------------------------------------- */
2.19      frystyk   233: /*                          HOST CACHE MANAGEMENT                           */
                    234: /* ------------------------------------------------------------------------- */
1.1       timbl     235: 
2.27      frystyk   236: /*                                                             HTTCPCacheRemoveElement
2.13      frystyk   237: **
                    238: **     Remove the element specified from the cache
                    239: */
                    240: PRIVATE void HTTCPCacheRemoveElement ARGS1(host_info *, element)
                    241: {
                    242:     if (!hostcache) {
2.27      frystyk   243:         if (PROT_TRACE)
2.13      frystyk   244:             fprintf(stderr, "HostCache... Remove not done, no cache\n");
                    245:         return;
                    246:     }
2.27      frystyk   247:     if (PROT_TRACE) fprintf(stderr, "HostCache... Remove `%s' from cache\n",
                    248:                            HTAtom_name(element->hostname));
                    249:     HTList_removeObject(hostcache, (void *) element);
2.22      frystyk   250:     if (*element->addrlist)
                    251:        free(*element->addrlist);
2.13      frystyk   252:     if (element->addrlist)
                    253:        free(element->addrlist);
                    254:     if (element->weight)
                    255:        free(element->weight);
                    256:     free(element);
                    257: }
                    258: 
                    259: 
2.32      frystyk   260: /*                                                             HTTCPCacheRemoveAll
                    261: **
                    262: **     Cleans up the memory. Called by HTLibTerminate
                    263: */
                    264: PUBLIC void HTTCPCacheRemoveAll NOARGS
                    265: {
                    266:     if (hostcache) {
                    267:        HTList *cur = hostcache;
                    268:        host_info *pres;
                    269:        while ((pres = (host_info *) HTList_nextObject(cur))) {
                    270:            if (*pres->addrlist)
                    271:                free(*pres->addrlist);
                    272:            if (pres->addrlist)
                    273:                free(pres->addrlist);
                    274:            if (pres->weight)
                    275:                free(pres->weight);
                    276:            free(pres);
                    277:        }
                    278:        HTList_delete(hostcache);
                    279:        hostcache = NULL;
                    280:     }
                    281: }
                    282: 
                    283: 
2.13      frystyk   284: /*                                                     HTTCPCacheRemoveHost
                    285: **
                    286: **     Removes the corresponding entrance in the cache
                    287: */
                    288: PRIVATE void HTTCPCacheRemoveHost ARGS1(char *, host)
                    289: {
                    290:     HTAtom *hostatom = HTAtom_for(host);
                    291:     HTList *cur = hostcache;
                    292:     host_info *pres = NULL;
                    293:     if (!hostcache) {
                    294:        fprintf(stderr, "HostCache... Remove host not done, no cache\n");
                    295:        return;
                    296:     }
                    297:     while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
                    298:        if (pres->hostname == hostatom) {
                    299:            break;
                    300:        }
                    301:     }
                    302:     if (pres)
                    303:        HTTCPCacheRemoveElement(pres);
                    304: }
                    305: 
                    306: 
                    307: /*                                                     HTTCPCacheGarbage
                    308: **
                    309: **     Remove the element with the lowest hit rate
                    310: */
                    311: PRIVATE void HTTCPCacheGarbage NOARGS
                    312: {
                    313:     HTList *cur = hostcache;
                    314:     host_info *pres, *worst_match = NULL;
                    315:     unsigned int worst_hits = 30000;             /* Should use UINT_MAX :-( */
                    316:     if (!hostcache) {
2.27      frystyk   317:        if (PROT_TRACE)
2.13      frystyk   318:            fprintf(stderr, "HostCache... Garbage collection not done, no cache\n");
                    319:        return;
                    320:     }
                    321: 
                    322:     /* Seek for worst element */
                    323:     while ((pres = (host_info *) HTList_nextObject(cur))) {
                    324:        if (!worst_match || pres->hits <= worst_hits) {
                    325:            worst_match = pres;
                    326:            worst_hits = pres->hits;
                    327:        }
                    328:     }
                    329:     if (worst_match)
                    330:        HTTCPCacheRemoveElement(worst_match);
                    331: }
                    332: 
                    333: 
                    334: /*                                                     HTTCPCacheAddElement
                    335: **
                    336: **     Add an element to the cache of visited hosts. Note that this function
                    337: **     requires the system implemented structure hostent and not our own
2.24      frystyk   338: **     host_info. The homes variable indicates the number of
                    339: **     IP addresses found.
2.13      frystyk   340: **
                    341: **      Returns new element if OK NULL if error
                    342: */
                    343: PRIVATE host_info *HTTCPCacheAddElement ARGS2(HTAtom *, host,
                    344:                                              struct hostent *, element)
                    345: {
2.25      frystyk   346:     host_info *newhost;
2.22      frystyk   347:     char *addr;
                    348:     char **index = element->h_addr_list;
                    349:     int cnt = 1;
2.13      frystyk   350:     if (!host || !element) {
2.27      frystyk   351:        if (PROT_TRACE)
2.13      frystyk   352:            fprintf(stderr, "HostCache... Bad argument to add to cache\n");
                    353:        return NULL;
                    354:     }
2.22      frystyk   355:     while(*index++)
                    356:        cnt++;
2.25      frystyk   357:     if ((newhost = (host_info *) calloc(1, sizeof(host_info))) == NULL ||
                    358:        (newhost->addrlist = (char **) calloc(1, cnt*sizeof(char*))) == NULL ||
2.22      frystyk   359:        (addr = (char *) calloc(1, cnt*element->h_length)) == NULL)
2.18      frystyk   360:        outofmem(__FILE__, "HTTCPCacheAddElement");
2.25      frystyk   361:     newhost->hostname = host;
2.22      frystyk   362:     index = element->h_addr_list;
                    363:     cnt = 0;
                    364:     while (*index) {
2.25      frystyk   365:        *(newhost->addrlist+cnt) = addr+cnt*element->h_length;
                    366:        memcpy((void *) *(newhost->addrlist+cnt++), *index++,
                    367:               element->h_length);
2.22      frystyk   368:     }
2.25      frystyk   369:     newhost->homes = cnt;
                    370:     if ((newhost->weight = (float *) calloc(newhost->homes,
                    371:                                            sizeof(float))) == NULL)
2.24      frystyk   372:        outofmem(__FILE__, "HTTCPCacheAddElement");
                    373: 
2.25      frystyk   374:     newhost->addrlength = element->h_length;
2.13      frystyk   375:     if (!hostcache)
                    376:        hostcache = HTList_new();
                    377: 
2.27      frystyk   378:     if (PROT_TRACE) {
2.25      frystyk   379:        if (newhost->homes == 1)
2.24      frystyk   380:            fprintf(stderr, "HostCache... Adding single-homed host `%s'\n",
                    381:                    HTAtom_name(host));
2.13      frystyk   382:        else
2.24      frystyk   383:            fprintf(stderr, "HostCache... Adding host `%s' with %d homes\n",
2.25      frystyk   384:                    HTAtom_name(host), newhost->homes);
2.13      frystyk   385:     }
2.25      frystyk   386:     HTList_addObject(hostcache, (void *) newhost);
2.13      frystyk   387:     HTCacheSize++;                             /* Update number of elements */
2.25      frystyk   388:     return newhost;
2.13      frystyk   389: }
                    390: 
                    391: 
                    392: /*                                                                   HTTCPAddrWeights
                    393: **
                    394: **     This function calculates the weights of the different IP addresses
                    395: **     on a multi homed host. Each weight is calculated as
                    396: **
                    397: **             w(n+1) = w(n)*a + (1-a) * deltatime
                    398: **             a = exp(-1/Neff)
                    399: **             Neff is the effective number of samples used
                    400: **             deltatime is time spend on making a connection
                    401: **
                    402: **     A short window (low Neff) gives a high sensibility, but this is
                    403: **     required as we can't expect a lot of data to test on.
                    404: **
                    405: */
                    406: PUBLIC void HTTCPAddrWeights ARGS2(char *, host, time_t, deltatime)
                    407: {
                    408:     HTAtom *hostatom = HTAtom_for(host);
                    409:     HTList *cur = hostcache;
                    410:     host_info *pres = NULL;
                    411:     if (!hostcache) {
                    412:        fprintf(stderr, "HostCache... Weights not calculated, no cache\n");
                    413:        return;
                    414:     }
2.24      frystyk   415:     /* Skip any port number from host name */
                    416:     if (strchr(host, ':')) {
                    417:        char *newhost = NULL;
                    418:        char *strptr;
                    419:        StrAllocCopy(newhost, host);
                    420:        strptr = strchr(newhost, ':');
                    421:        *strptr = '\0';
                    422:        hostatom = HTAtom_for(newhost);
                    423:        free(newhost);
                    424:     } else
                    425:        hostatom = HTAtom_for(host);
                    426:     
2.13      frystyk   427:     while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
                    428:        if (pres->hostname == hostatom) {
                    429:            break;
                    430:        }
                    431:     }
2.24      frystyk   432:     if (pres) {
2.13      frystyk   433:        int cnt;
2.14      frystyk   434:        CONST float passive = 0.9;        /* Factor for all passive IP_addrs */
2.13      frystyk   435: #if 0
2.14      frystyk   436:        CONST int Neff = 3;
                    437:        CONST float alpha = exp(-1.0/Neff);
2.13      frystyk   438: #else
2.24      frystyk   439:        CONST float alpha = 0.716531310574;     /* Doesn't need the math lib */
2.13      frystyk   440: #endif
2.24      frystyk   441:        for (cnt=0; cnt<pres->homes; cnt++) {
2.13      frystyk   442:            if (cnt == pres->offset) {
                    443:                *(pres->weight+pres->offset) = *(pres->weight+pres->offset)*alpha + (1.0-alpha)*deltatime;
                    444:            } else {
                    445:                *(pres->weight+cnt) = *(pres->weight+cnt) * passive;
                    446:            }
2.24      frystyk   447:            if (PROT_TRACE)
                    448:                fprintf(stderr, "AddrWeights. Home %d has weight %4.2f\n", cnt,
                    449:                        *(pres->weight+cnt));
2.13      frystyk   450:        }
2.27      frystyk   451:     } else if (PROT_TRACE) {
2.24      frystyk   452:        fprintf(stderr, "HostCache... Weights not calculated, host not found in cache: `%s\'\n", host);
2.13      frystyk   453:     }
                    454: }
                    455: 
2.19      frystyk   456: /* ------------------------------------------------------------------------- */
                    457: /*                          HOST NAME FUNCTIONS                             */
                    458: /* ------------------------------------------------------------------------- */
                    459: 
                    460: #ifndef DECNET  /* Function only used below for a trace message */
                    461: 
                    462: /*     Produce a string for an Internet address
                    463: **     ----------------------------------------
                    464: **
                    465: ** On exit,
                    466: **     returns a pointer to a static string which must be copied if
                    467: **             it is to be kept.
                    468: */
                    469: 
                    470: PUBLIC CONST char * HTInetString ARGS1(SockA *, sin)
                    471: {
                    472: #if 0
2.24      frystyk   473:     /* This dumps core on some Sun systems :-(. The problem is now, that 
2.19      frystyk   474:        the current implememtation only works for IP-addresses and not in
                    475:        other address spaces. */
                    476:     return inet_ntoa(sin->sin_addr);
                    477: #endif
                    478:     static char string[16];
                    479:     sprintf(string, "%d.%d.%d.%d",
                    480:            (int)*((unsigned char *)(&sin->sin_addr)+0),
                    481:            (int)*((unsigned char *)(&sin->sin_addr)+1),
                    482:            (int)*((unsigned char *)(&sin->sin_addr)+2),
                    483:            (int)*((unsigned char *)(&sin->sin_addr)+3));
                    484:     return string;
                    485: }
                    486: #endif /* Decnet */
                    487: 
2.13      frystyk   488: 
                    489: /*                                                          HTGetHostByName
                    490: **
                    491: **     Searched first the local cache then asks the DNS for an address of
                    492: **     the host specified.
                    493: **
2.24      frystyk   494: **      Returns:       >0 if OK the number of homes are returned
                    495: **                     -1 if error
2.13      frystyk   496: */
2.24      frystyk   497: PUBLIC int HTGetHostByName ARGS3(char *, host, SockA *, sin,
                    498:                                 BOOL, use_cur)
2.13      frystyk   499: {
                    500:     HTAtom *hostatom = HTAtom_for(host);
                    501:     host_info *pres = NULL;
                    502:     if (!hostcache)
                    503:        hostcache = HTList_new();                      /* First time through */
                    504:     else {
                    505:        HTList *cur = hostcache;                             /* Search cache */
                    506:        while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
                    507:            if (pres->hostname == hostatom) {
2.27      frystyk   508:                if (PROT_TRACE)
2.18      frystyk   509:                    fprintf(stderr, "HostByName.. Host `%s\' found in cache.\n", host);
2.13      frystyk   510:                break;
                    511:            }
                    512:        }
                    513:     }
                    514:     
                    515:     /* If the host was not found in the cache, then do gethostbyname.
2.24      frystyk   516:        If we are talking to a multi homed host then take the IP address with
                    517:        the lowest weight. If `use_cur'=YES then use current IP-address */
2.13      frystyk   518:     if (pres) {
2.24      frystyk   519:        if (pres->homes > 1 && !use_cur) {
2.13      frystyk   520:            int cnt;
                    521:            float best_weight = 1e30;               /* Should be FLT_MAX :-( */
2.24      frystyk   522:            for (cnt=0; cnt<pres->homes; cnt++) {
2.13      frystyk   523:                if (*(pres->weight+cnt) < best_weight) {
                    524:                    best_weight = *(pres->weight+cnt);
                    525:                    pres->offset = cnt;
                    526:                }
                    527:            }
2.24      frystyk   528:        }
                    529:        pres->hits++;            /* Update total number of hits on this host */
2.13      frystyk   530:     } else {                                           /* Go and ask for it */
                    531:        struct hostent *hostelement;                          /* see netdb.h */
                    532: #ifdef MVS     /* Outstanding problem with crash in MVS gethostbyname */
2.27      frystyk   533:        if (PROT_TRACE)
2.24      frystyk   534:            fprintf(stderr, "HTTCP on MVS gethostbyname(%s)\n", host);
2.13      frystyk   535: #endif
                    536:        if ((hostelement = gethostbyname(host)) == NULL) {
2.27      frystyk   537:            if (PROT_TRACE)
                    538:                fprintf(stderr, "HostByName.. Can't find internet node name `%s'.\n", host);
2.13      frystyk   539:            return -1;
                    540:        }
                    541:        
                    542:        /* Add element to the cache and maybe do garbage collection */
                    543:        if (HTCacheSize >= HTConCacheSize)
                    544:            HTTCPCacheGarbage();
                    545:        if ((pres = HTTCPCacheAddElement(hostatom, hostelement)) == NULL) {
                    546:            return -1;
                    547:        }
                    548:     }
                    549:     
                    550:     /* Update socket structure using the element with the lowest weight. On
                    551:        single homed hosts it means the first value */
                    552:     memcpy(&sin->sin_addr, *(pres->addrlist+pres->offset), pres->addrlength);
2.24      frystyk   553:     return pres->homes;
2.13      frystyk   554: }
                    555: 
                    556: 
2.19      frystyk   557: /*
                    558: **     Get host name of the machine on the other end of a socket.
                    559: **
                    560: */
                    561: PUBLIC char * HTGetHostBySock ARGS1(int, soc)
                    562: {
                    563:     struct sockaddr addr;
                    564:     int len = sizeof(struct sockaddr);
                    565:     struct in_addr *iaddr;
                    566:     struct hostent * phost;            /* Pointer to host -- See netdb.h */
                    567:     char *name = NULL;
                    568: 
                    569: #ifdef DECNET  /* Decnet ain't got no damn name server 8#OO */
                    570:     return NULL;
                    571: #else
                    572:     if (getpeername(soc, &addr, &len) < 0)
                    573:        return NULL;
                    574: 
                    575:     iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
                    576:     phost=gethostbyaddr((char*)iaddr,
                    577:                        sizeof(struct in_addr),
                    578:                        AF_INET);
                    579:     if (!phost) {
2.27      frystyk   580:        if (PROT_TRACE)
                    581:            fprintf(stderr, "TCP......... Can't find internet node name for peer!!\n");
2.19      frystyk   582:        return NULL;
                    583:     }
                    584:     StrAllocCopy(name, phost->h_name);
2.27      frystyk   585:     if (PROT_TRACE) fprintf(stderr, "TCP......... Peer name is `%s'\n", name);
2.19      frystyk   586: 
                    587:     return name;
                    588: 
                    589: #endif /* not DECNET */
                    590: }
                    591: 
                    592: 
1.1       timbl     593: /*     Parse a network node address and port
                    594: **     -------------------------------------
                    595: **
                    596: ** On entry,
                    597: **     str     points to a string with a node name or number,
                    598: **             with optional trailing colon and port number.
                    599: **     sin     points to the binary internet or decnet address field.
                    600: **
2.24      frystyk   601: ** On exit,    -1      If error
                    602: **             >0      If OK the number of homes on the host
1.1       timbl     603: **     *sin    is filled in. If no port is specified in str, that
                    604: **             field is left unchanged in *sin.
2.13      frystyk   605: **
                    606: ** NOTE:       It is assumed that any portnumber and numeric host address
                    607: **             is given in decimal notation. Separation character is '.'
1.1       timbl     608: */
2.24      frystyk   609: PUBLIC int HTParseInet ARGS3(SockA *, sin, CONST char *, str,
                    610:                             BOOL, use_cur)
1.1       timbl     611: {
2.13      frystyk   612:     char *host = NULL;
2.24      frystyk   613:     int status = 0;
2.13      frystyk   614:     StrAllocCopy(host, str);                 /* Take a copy we can mutilate */
1.1       timbl     615: 
2.13      frystyk   616:     /* Parse port number if present. */    
                    617:     {
                    618:        char *port;
                    619:        if ((port=strchr(host, ':'))) {
                    620:            *port++ = 0;                                    /* Chop off port */
                    621:            if (isdigit(*port)) {
2.27      frystyk   622: 
1.1       timbl     623: #ifdef DECNET
2.13      frystyk   624:                sin->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10));
                    625: #else /* Internet */
                    626:                sin->sin_port = htons(atol(port));
1.1       timbl     627: #endif
2.13      frystyk   628:            } else {
2.24      frystyk   629:                if (PROT_TRACE)
                    630:                    fprintf(stderr, "ParseInet... No port indicated\n");
                    631:                free(host);
                    632:                return -1;
2.13      frystyk   633:            }
1.1       timbl     634:        }
2.13      frystyk   635:     }
1.1       timbl     636: 
2.13      frystyk   637:     /* Parse Internet host */
1.1       timbl     638: #ifdef DECNET
                    639:     /* read Decnet node name. @@ Should know about DECnet addresses, but it's
                    640:        probably worth waiting until the Phase transition from IV to V. */
                    641: 
                    642:     sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host));  /* <=6 in phase 4 */
                    643:     strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
                    644: 
2.27      frystyk   645:     if (PROT_TRACE) fprintf(stderr,  
1.1       timbl     646:        "DECnet: Parsed address as object number %d on host %.6s...\n",
                    647:                      sin->sdn_objnum, host);
                    648: 
2.13      frystyk   649: #else /* Internet */
1.1       timbl     650: 
2.13      frystyk   651:     /* Parse host number if present */
                    652:     {
                    653:        BOOL numeric = YES;
                    654:        char *strptr = host;
                    655:        while (*strptr) {
                    656:            if (!isdigit(*strptr) && *strptr != '.') {
                    657:                numeric = NO;
                    658:                break;
                    659:            }
                    660:            ++strptr;
                    661:        }
                    662:        if (numeric) {
                    663:            sin->sin_addr.s_addr = inet_addr(host);       /* See arpa/inet.h */
                    664:        } else {
2.24      frystyk   665:            if ((status = HTGetHostByName(host, sin, use_cur)) < 0) {
2.13      frystyk   666:                free(host);
                    667:                return -1;
                    668:            }
                    669:        }
2.27      frystyk   670:        if (PROT_TRACE) {
2.13      frystyk   671:            fprintf(stderr, "ParseInet... Parsed address as port %d on %s\n",
                    672:                    (int) ntohs(sin->sin_port),
                    673:                    HTInetString(sin));
1.1       timbl     674:        }
                    675:     }
                    676: #endif  /* Internet vs. Decnet */
2.13      frystyk   677:     free(host);
2.24      frystyk   678:     return status;
1.1       timbl     679: }
                    680: 
                    681: 
2.16      frystyk   682: #ifdef OLD_CODE
1.1       timbl     683: /*     Derive the name of the host on which we are
                    684: **     -------------------------------------------
                    685: **
                    686: */
2.8       luotonen  687: PRIVATE void get_host_details NOARGS
1.1       timbl     688: 
                    689: {
                    690:     char name[MAXHOSTNAMELEN+1];       /* The name of this host */
                    691:     struct hostent * phost;            /* Pointer to host -- See netdb.h */
                    692:     int namelength = sizeof(name);
                    693:     
                    694:     if (hostname) return;              /* Already done */
                    695:     gethostname(name, namelength);     /* Without domain */
2.27      frystyk   696:     if (PROT_TRACE) fprintf(stderr, "TCP......... Local host name is %s\n", name);
1.1       timbl     697:     StrAllocCopy(hostname, name);
                    698: 
                    699: #ifndef DECNET  /* Decnet ain't got no damn name server 8#OO */
                    700:     phost=gethostbyname(name);         /* See netdb.h */
                    701:     if (!phost) {
2.27      frystyk   702:        if (PROT_TRACE) fprintf(stderr, 
2.9       luotonen  703:                "TCP......... Can't find my own internet node address for `%s'!!\n",
1.1       timbl     704:                name);
                    705:        return;  /* Fail! */
                    706:     }
                    707:     StrAllocCopy(hostname, phost->h_name);
2.27      frystyk   708:     if (PROT_TRACE)
2.18      frystyk   709:        fprintf(stderr, "TCP......... Full local host name is %s\n", hostname);
2.8       luotonen  710: 
                    711: #ifdef NEED_HOST_ADDRESS               /* no -- needs name server! */
1.1       timbl     712:     memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
2.27      frystyk   713:     if (PROT_TRACE) fprintf(stderr, "     Name server says that I am `%s' = %s\n",
1.1       timbl     714:            hostname, HTInetString(&HTHostAddress));
2.8       luotonen  715: #endif /* NEED_HOST_ADDRESS */
1.1       timbl     716: 
                    717: #endif /* not Decnet */
                    718: }
2.16      frystyk   719: #endif /* OLD_CODE */
1.1       timbl     720: 
2.19      frystyk   721: 
2.24      frystyk   722: /*                                                             HTGetDomainName
                    723: **     Returns the current domain name without the local host name.
                    724: **     The response is pointing to a static area that might be changed
                    725: **     using HTSetHostName(). Returns NULL on error
                    726: */
                    727: PUBLIC CONST char *HTGetDomainName NOARGS
                    728: {
                    729:     CONST char *host = HTGetHostName();
                    730:     char *domain;
                    731:     if (host && *host) {
                    732:        if ((domain = strchr(host, '.')) != NULL)
                    733:            return ++domain;
                    734:        else
                    735:            return host;
                    736:     } else
                    737:        return NULL;
                    738: }
                    739: 
                    740: 
                    741: 
2.19      frystyk   742: /*                                                             HTSetHostName
                    743: **     Sets the current hostname inclusive domain name.
                    744: **     If this is not set then the default approach is used using
                    745: **     HTGetHostname().
                    746: */
                    747: PUBLIC void HTSetHostName ARGS1(char *, host)
                    748: {
2.24      frystyk   749:     if (host && *host) {
                    750:        char *strptr;
2.19      frystyk   751:        StrAllocCopy(hostname, host);
2.24      frystyk   752:        strptr = hostname;
                    753:        while (*strptr) {
                    754:            *strptr = TOLOWER(*strptr);
                    755:            strptr++;
                    756:        }
                    757:        if (*(hostname+strlen(hostname)-1) == '.')    /* Remove trailing dot */
                    758:            *(hostname+strlen(hostname)-1) = '\0';
                    759:     } else {
2.27      frystyk   760:        if (PROT_TRACE) fprintf(stderr, "SetHostName. Bad argument ignored\n");
2.19      frystyk   761:     }
                    762: }
                    763: 
                    764: 
                    765: /*                                                             HTGetHostName
2.18      frystyk   766: **     Returns the name of this host. It uses the following algoritm:
                    767: **
                    768: **     1) gethostname()
                    769: **     2) if the hostname doesn't contain any '.' try to read
                    770: **        /etc/resolv.conf. If there is no domain line in this file then
                    771: **     3) Try getdomainname and do as the man pages say for resolv.conf (sun)
                    772: **             If there is no domain line in this file, then it is derived
                    773: **             from the domain name set by the domainname(1) command, usually
                    774: **             by removing the first component. For example, if the domain-
                    775: **             name is set to ``foo.podunk.edu'' then the default domain name
                    776: **             used will be ``pudunk.edu''.
                    777: **
                    778: **     This is the same procedure as used by res_init() and sendmail.
2.16      frystyk   779: **
                    780: **     Return: hostname on success else NULL
                    781: */
2.19      frystyk   782: PUBLIC CONST char * HTGetHostName NOARGS
1.1       timbl     783: {
2.18      frystyk   784:     BOOL got_it = NO;
                    785:     FILE *fp;
2.16      frystyk   786:     char name[MAXHOSTNAMELEN+1];
2.18      frystyk   787:     if (hostname) {                                      /* If already done */
                    788:        if (*hostname)
                    789:            return hostname;
                    790:        else
                    791:            return NULL;                    /* We couldn't get the last time */
                    792:     }
2.16      frystyk   793:     *(name+MAXHOSTNAMELEN) = '\0';
                    794:     if (gethostname(name, MAXHOSTNAMELEN)) {        /* Maybe without domain */
2.27      frystyk   795:        if (PROT_TRACE)
2.16      frystyk   796:            fprintf(stderr, "HostName.... Can't get host name\n");
                    797:        return NULL;
                    798:     }
2.27      frystyk   799:     if (PROT_TRACE)
2.24      frystyk   800:        fprintf(stderr, "HostName.... Local host name is  `%s\'\n", name);
2.16      frystyk   801:     StrAllocCopy(hostname, name);
2.24      frystyk   802:     {
                    803:        char *strptr = strchr(hostname, '.');
                    804:        if (strptr != NULL)                                /* We have it all */
                    805:            got_it = YES;
                    806:     }
2.16      frystyk   807: 
2.34    ! roeber    808: #ifdef RESOLV_CONF
2.18      frystyk   809:     /* Now try the resolver config file */
2.24      frystyk   810:     if (!got_it && (fp = fopen(RESOLV_CONF, "r")) != NULL) {
2.18      frystyk   811:        char buffer[80];
                    812:        *(buffer+79) = '\0';
                    813:        while (fgets(buffer, 79, fp)) {
                    814:            if (!strncasecomp(buffer, "domain", 6)) {   
                    815:                char *domainstr = buffer+6;
                    816:                char *end;
                    817:                while (*domainstr == ' ' || *domainstr == '\t')
                    818:                    domainstr++;
                    819:                end = domainstr;
                    820:                while (*end && !isspace(*end))
                    821:                    end++;
                    822:                *end = '\0';
                    823:                if (*domainstr) {
                    824:                    StrAllocCat(hostname, ".");
                    825:                    StrAllocCat(hostname, domainstr);
                    826:                    got_it = YES;
                    827:                    break;
                    828:                }
                    829:            }
                    830:        }
                    831:        fclose(fp);
2.16      frystyk   832:     }
2.34    ! roeber    833: #endif /* RESOLV_CONF */
2.16      frystyk   834: 
2.18      frystyk   835:     /* If everything else has failed then try getdomainname */
2.34    ! roeber    836: #ifdef HAVE_GETDOMAINNAME
2.18      frystyk   837:     if (!got_it) {
                    838:        if (getdomainname(name, MAXHOSTNAMELEN)) {
2.27      frystyk   839:            if (PROT_TRACE)
2.18      frystyk   840:                fprintf(stderr, "HostName.... Can't get domain name\n");
2.24      frystyk   841:            StrAllocCopy(hostname, "");
2.18      frystyk   842:            return NULL;
                    843:        }
                    844: 
                    845:        /* If the host name and the first part of the domain name are different
                    846:           then use the former as it is more exact (I guess) */
                    847:        if (strncmp(name, hostname, (int) strlen(hostname))) {
                    848:            char *domain = strchr(name, '.');
                    849:            if (!domain)
                    850:                domain = name;
2.26      frystyk   851:            StrAllocCat(hostname, ".");
2.18      frystyk   852:            StrAllocCat(hostname, domain);
                    853:        }
2.16      frystyk   854:     }
2.34    ! roeber    855: #endif /* HAVE_GETDOMAINNAME */
2.23      duns      856: 
2.24      frystyk   857:     {
                    858:        char *strptr = hostname;
                    859:        while (*strptr) {           
                    860:            *strptr = TOLOWER(*strptr);
                    861:            strptr++;
                    862:        }
                    863:        if (*(hostname+strlen(hostname)-1) == '.')    /* Remove trailing dot */
                    864:            *(hostname+strlen(hostname)-1) = '\0';
                    865:     }
2.27      frystyk   866:     if (PROT_TRACE)
2.24      frystyk   867:        fprintf(stderr, "HostName.... Full host name is `%s\'\n", hostname);
2.18      frystyk   868:     return hostname;
                    869: 
                    870: #ifndef DECNET  /* Decnet ain't got no damn name server 8#OO */
                    871: #ifdef OLD_CODE
                    872:                              /* Now we try to get information on the domain */
2.16      frystyk   873:     {
                    874:        struct hostent *hostelement;
                    875:        if ((hostelement = gethostbyname(hostname)) == NULL) {
2.27      frystyk   876:            if (PROT_TRACE)
2.16      frystyk   877:                fprintf(stderr, "HostName.... Can't find host name on DNS\n");
                    878:            FREE(hostname);
                    879:            return NULL;
                    880:        }
2.17      frystyk   881:        StrAllocCopy(hostname, (char *) hostelement->h_name);
2.16      frystyk   882:     }
2.18      frystyk   883: #endif /* OLD_CODE */
2.16      frystyk   884: #endif /* not Decnet */
2.13      frystyk   885: }
                    886: 
2.19      frystyk   887: 
2.32      frystyk   888: /*
                    889: **     Free the host name. Called from HTLibTerminate
                    890: */
                    891: PUBLIC void HTFreeHostName NOARGS
                    892: {
                    893:     FREE(hostname);
                    894: }
                    895: 
                    896: 
2.19      frystyk   897: /*                                                            HTSetMailAddress
                    898: **     Sets the current mail address plus host name and domain name.
                    899: **     If this is not set then the default approach is used using
2.27      frystyk   900: **     HTGetMailAddress(). If the argument is NULL or "" then HTGetMailAddress
                    901: **     returns NULL on a succeding request.
2.19      frystyk   902: */
                    903: PUBLIC void HTSetMailAddress ARGS1(char *, address)
                    904: {
2.27      frystyk   905:     if (!address || !*address)
                    906:        StrAllocCopy(mailaddress, "");
                    907:     else
2.19      frystyk   908:        StrAllocCopy(mailaddress, address);
2.27      frystyk   909:     if (TRACE)
                    910:        fprintf(stderr, "SetMailAdr.. Set mail address to `%s\'\n",
                    911:                mailaddress);
2.19      frystyk   912: }
                    913: 
                    914: 
                    915: /*                                                            HTGetMailAddress
                    916: **
                    917: **     Get the mail address of the current user on the current host. The
                    918: **     domain name used is the one initialized in HTSetHostName or
                    919: **     HTGetHostName. The login name is determined using (ordered):
                    920: **
                    921: **             getlogin
                    922: **             getpwuid(getuid())
                    923: **
                    924: **     The weakness about the last attempt is if the user has multiple
                    925: **     login names each with the same user ID. If this fails as well then:
                    926: **
                    927: **             LOGNAME environment variable
                    928: **             USER environment variable
                    929: **
                    930: **     Returns NULL if error else pointer to static string
                    931: */
                    932: PUBLIC CONST char * HTGetMailAddress NOARGS
                    933: {
                    934:     char *login;
                    935:     CONST char *domain;
2.34    ! roeber    936: #ifdef HAVE_PWD_H
2.19      frystyk   937:     struct passwd *pw_info;
2.34    ! roeber    938: #endif
2.21      frystyk   939:     if (mailaddress) {
                    940:        if (*mailaddress)
                    941:            return mailaddress;
                    942:        else
                    943:            return NULL;       /* No luck the last time so we wont try again */
                    944:     }
2.23      duns      945: 
2.34    ! roeber    946: #ifdef HAVE_CUSERID
2.23      duns      947:     if ((login = (char *) cuserid(NULL)) == NULL) {
2.27      frystyk   948:         if (PROT_TRACE) fprintf(stderr, "MailAddress. cuserid returns NULL\n");
2.34    ! roeber    949:     } else goto ok;
        !           950: #endif
        !           951: #ifdef HAVE_GETLOGIN
        !           952:     if ((login = (char *) getlogin()) == NULL) {
        !           953:        if (PROT_TRACE) fprintf(stderr, "MailAddress. getlogin returns NULL\n");
        !           954:     } else goto ok;
        !           955: #endif
        !           956: #ifdef HAVE_PWD_H
        !           957:     if ((pw_info = getpwuid(getuid())) == NULL) {
        !           958:         if (PROT_TRACE) fprintf(stderr, "MailAddress. getpwid returns NULL\n");
        !           959:     } else {
        !           960:         login = pw_info->pw_name;
        !           961:         goto ok;
2.23      duns      962:     }
2.34    ! roeber    963: #endif
        !           964: 
        !           965:     if ((login = getenv("LOGNAME")) == NULL) {
        !           966:        if (PROT_TRACE) fprintf(stderr, "MailAddress. LOGNAME not found\n");
        !           967:     } else goto ok;
2.23      duns      968: 
2.34    ! roeber    969:     if ((login = getenv("USER")) == NULL) {
        !           970:         if (PROT_TRACE) fprintf(stderr,"MailAddress. USER not found\n");
        !           971:     } else goto ok;
        !           972: 
        !           973:     return NULL;               /* I GIVE UP */
2.23      duns      974: 
2.34    ! roeber    975:   ok:
2.19      frystyk   976:     if (login) {
                    977:        StrAllocCopy(mailaddress, login);
                    978:        StrAllocCat(mailaddress, "@");
                    979:        if ((domain = HTGetHostName()) != NULL)
                    980:            StrAllocCat(mailaddress, domain);
2.21      frystyk   981:        else {
                    982:            *mailaddress = '\0';
                    983:            return NULL;                        /* Domain name not available */
                    984:        }
2.19      frystyk   985:        return mailaddress;
                    986:     }
                    987:     return NULL;
                    988: }
2.32      frystyk   989: 
                    990: 
                    991: /*
                    992: **     Free the mail address. Called from HTLibTerminate
                    993: */
                    994: PUBLIC void HTFreeMailAddress NOARGS
                    995: {
                    996:     FREE(mailaddress);
                    997: }
                    998: 
2.19      frystyk   999: 
                   1000: /* ------------------------------------------------------------------------- */
                   1001: /*                   CONNECTION ESTABLISHMENT MANAGEMENT                    */
                   1002: /* ------------------------------------------------------------------------- */
2.13      frystyk  1003: 
                   1004: /*                                                             HTDoConnect()
                   1005: **
                   1006: **     Note: Any port indication in URL, e.g., as `host:port' overwrites
                   1007: **     the default_port value.
                   1008: **
                   1009: **     Returns 0 if OK, -1 on error
                   1010: */
2.24      frystyk  1011: PUBLIC int HTDoConnect ARGS5(HTNetInfo *, net, char *, url,
                   1012:                             u_short, default_port, u_long *, addr,
                   1013:                             BOOL, use_cur)
2.13      frystyk  1014: {
                   1015:     int status;
                   1016:     char *p1 = HTParse(url, "", PARSE_HOST);
                   1017:     char *at_sign;
                   1018:     char *host;
                   1019: 
                   1020:     /* if theres an @ then use the stuff after it as a hostname */
2.27      frystyk  1021:     if((at_sign = strchr(p1, '@')) != NULL)
2.13      frystyk  1022:        host = at_sign+1;
                   1023:     else
                   1024:        host = p1;
2.24      frystyk  1025:     if (!*host) {
                   1026:        HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_HOST,
                   1027:                   NULL, 0, "HTDoConnect");
                   1028:        free(p1);
                   1029:        return -1;
2.27      frystyk  1030:     } else {
                   1031:        if (PROT_TRACE)
                   1032:            fprintf(stderr, "HTDoConnect. Looking up `%s\'\n", host);
                   1033:     }
2.13      frystyk  1034: 
                   1035:    /* Set up defaults */
2.27      frystyk  1036:     if (net->sockfd < 0) {
                   1037:        memset((void *) &net->sock_addr, '\0', sizeof(net->sock_addr));
2.13      frystyk  1038: #ifdef DECNET
2.27      frystyk  1039:        net->sock_addr.sdn_family = AF_DECnet;/* Family = DECnet, host order */
                   1040:        net->sock_addr.sdn_objnum = DNP_OBJ;  /* Default: http object number */
2.13      frystyk  1041: #else  /* Internet */
2.27      frystyk  1042:        net->sock_addr.sin_family = AF_INET;
                   1043:        net->sock_addr.sin_port = htons(default_port);
2.13      frystyk  1044: #endif
2.27      frystyk  1045:     }
2.13      frystyk  1046: 
2.24      frystyk  1047:     /* If we are trying to connect to a multi-homed host then loop here until
                   1048:        success or we have tried all IP-addresses */
                   1049:     do {
2.27      frystyk  1050:        if (net->sockfd < 0) {
                   1051:            int hosts;
                   1052:            if ((hosts = HTParseInet(&net->sock_addr, host, use_cur)) < 0) {
                   1053:                if (PROT_TRACE)
                   1054:                    fprintf(stderr, "HTDoConnect. Can't locate remote host `%s\'\n", host);
                   1055:                HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
                   1056:                           (void *) host, strlen(host), "HTDoConnect");
                   1057:                break;
                   1058:            };
                   1059:            if (!net->addressCount && hosts > 1)
                   1060:                net->addressCount = hosts;
                   1061: #ifdef DECNET
                   1062:            if ((net->sockfd = socket(AF_DECnet, SOCK_STREAM, 0)) < 0)
                   1063: #else
                   1064:            if ((net->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
                   1065: #endif
                   1066:            {
                   1067:                HTErrorSysAdd(net->request, ERR_FATAL, NO, "socket");
                   1068:                break;
                   1069:            }
                   1070:            if (addr)
                   1071:                *addr = ntohl(net->sock_addr.sin_addr.s_addr);
                   1072:            if (PROT_TRACE)
                   1073:                fprintf(stderr, "HTDoConnect. Created socket number %d\n",
                   1074:                        net->sockfd);
                   1075: 
2.28      frystyk  1076:            /* If non-blocking protocol then change socket status
                   1077:            ** I use FCNTL so that I can ask the status before I set it.
                   1078:            ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)
                   1079:            ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()
                   1080:            ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and
                   1081:            ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
                   1082:            */
2.27      frystyk  1083:            if (!HTProtocolBlocking(net->request)) {
2.34    ! roeber   1084: #ifdef O_NONBLOCK
2.27      frystyk  1085:                if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.28      frystyk  1086:                    status |= O_NONBLOCK;                           /* POSIX */
2.27      frystyk  1087:                    status = FCNTL(net->sockfd, F_SETFL, status);
                   1088:                }
2.34    ! roeber   1089: #else
        !          1090:                status = -1;
        !          1091: #endif
2.27      frystyk  1092:                if (status == -1) {
                   1093:                    if (PROT_TRACE)
                   1094:                        fprintf(stderr, "HTDoConnect. Can NOT make socket non-blocking\n");
2.33      frystyk  1095:                } else if (PROT_TRACE)
                   1096:                    fprintf(stderr, "HTDoConnect. Using NON_BLOCKING I/O\n");
2.27      frystyk  1097:            }
                   1098:            
                   1099:            /* If multi-homed host then start timer on connection */
                   1100:            if (net->addressCount >= 1)
                   1101:                net->connecttime = time(NULL);
2.24      frystyk  1102:        }
2.13      frystyk  1103: 
2.27      frystyk  1104:        /* Check for interrupt */
                   1105:        if (HTThreadIntr(net->sockfd)) {
                   1106:            if (NETCLOSE(net->sockfd) < 0)
                   1107:                HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
2.29      frystyk  1108: #ifdef EVENT_LOOP
2.27      frystyk  1109:            HTThreadState(net->sockfd, THD_CLOSE);
2.29      frystyk  1110: #endif /* EVENT_LOOP */
2.27      frystyk  1111:            net->sockfd = -1;
                   1112:            free(p1);
                   1113:            return HT_INTERRUPTED;
                   1114:        }
                   1115: 
                   1116:        /* Do a connect */
                   1117:        status = connect(net->sockfd, (struct sockaddr *) &net->sock_addr,
                   1118:                         sizeof(net->sock_addr));
                   1119:        /*
                   1120:         * According to the Sun man page for connect:
                   1121:         *     EINPROGRESS         The socket is non-blocking and the  con-
                   1122:         *                         nection cannot be completed immediately.
                   1123:         *                         It is possible to select(2) for  comple-
                   1124:         *                         tion  by  selecting the socket for writ-
                   1125:         *                         ing.
                   1126:         * According to the Motorola SVR4 man page for connect:
                   1127:         *     EAGAIN              The socket is non-blocking and the  con-
                   1128:         *                         nection cannot be completed immediately.
                   1129:         *                         It is possible to select for  completion
                   1130:         *                         by  selecting  the  socket  for writing.
                   1131:         *                         However, this is only  possible  if  the
                   1132:         *                         socket  STREAMS  module  is  the topmost
                   1133:         *                         module on  the  protocol  stack  with  a
                   1134:         *                         write  service  procedure.  This will be
                   1135:         *                         the normal case.
                   1136:         */
                   1137: #ifdef EAGAIN
                   1138:        if ((status < 0) && ((errno == EINPROGRESS) || (errno == EAGAIN)))
2.13      frystyk  1139: #else
2.27      frystyk  1140:        if ((status < 0) && (errno == EINPROGRESS))
                   1141: #endif /* EAGAIN */
2.24      frystyk  1142:        {
2.27      frystyk  1143:            if (PROT_TRACE)
                   1144:                fprintf(stderr, "HTDoConnect. WOULD BLOCK `%s'\n", host);
2.29      frystyk  1145: #ifdef EVENT_LOOP
2.27      frystyk  1146:            HTThreadState(net->sockfd, THD_SET_WRITE);
2.29      frystyk  1147: #endif /* EVENT_LOOP */
2.27      frystyk  1148:            free(p1);
                   1149:            return HT_WOULD_BLOCK;
2.24      frystyk  1150:        }
2.27      frystyk  1151:        if (net->addressCount >= 1) {
                   1152:            net->connecttime = time(NULL) - net->connecttime;
2.24      frystyk  1153:            if (status < 0) {
2.27      frystyk  1154:                if (errno == EISCONN) {   /* connect multi after would block */
2.29      frystyk  1155: #ifdef EVENT_LOOP
2.27      frystyk  1156:                    HTThreadState(net->sockfd, THD_CLR_WRITE);
2.29      frystyk  1157: #endif /* EVENT_LOOP */
2.27      frystyk  1158:                    HTTCPAddrWeights(host, net->connecttime);
                   1159:                    free(p1);
                   1160:                    net->addressCount = 0;
                   1161:                    return 0;
                   1162:                }
2.24      frystyk  1163:                HTErrorSysAdd(net->request, ERR_NON_FATAL, NO, "connect");
2.27      frystyk  1164: 
                   1165:                /* I have added EINVAL `invalid argument' as this is what I 
                   1166:                   get back from a non-blocking connect where I should 
                   1167:                   get `connection refused' */
2.24      frystyk  1168:                if (errno==ECONNREFUSED || errno==ETIMEDOUT ||
                   1169:                    errno==ENETUNREACH || errno==EHOSTUNREACH ||
2.27      frystyk  1170:                    errno==EHOSTDOWN || errno==EINVAL)
                   1171:                    net->connecttime += TCP_DELAY;
2.24      frystyk  1172:                else
2.27      frystyk  1173:                    net->connecttime += TCP_PENALTY;
2.24      frystyk  1174:                if (NETCLOSE(net->sockfd) < 0)
2.27      frystyk  1175:                    HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
2.29      frystyk  1176: #ifdef EVENT_LOOP
2.27      frystyk  1177:                HTThreadState(net->sockfd, THD_CLOSE);
2.29      frystyk  1178: #endif /* EVENT_LOOP */
2.27      frystyk  1179:                net->sockfd = -1;
                   1180:                HTTCPAddrWeights(host, net->connecttime);
                   1181:            } else {                               /* Connect on multi-homed */
                   1182:                HTTCPAddrWeights(host, net->connecttime);
                   1183:                free(p1);
                   1184:                net->addressCount = 0;
                   1185:                return 0;
                   1186:            }
                   1187:        } else if (status < 0) {
                   1188:            if (errno == EISCONN) {      /* Connect single after would block */
2.29      frystyk  1189: #ifdef EVENT_LOOP
2.27      frystyk  1190:                HTThreadState(net->sockfd, THD_CLR_WRITE);
2.29      frystyk  1191: #endif /* EVENT_LOOP */
2.27      frystyk  1192:                net->addressCount = 0;
                   1193:                free(p1);
                   1194:                return 0;
2.24      frystyk  1195:            } else {
2.27      frystyk  1196:                HTErrorSysAdd(net->request, ERR_FATAL, NO, "connect");
                   1197:                HTTCPCacheRemoveHost(host);
                   1198:                if (NETCLOSE(net->sockfd) < 0)
                   1199:                    HTErrorSysAdd(net->request, ERR_FATAL, NO, "NETCLOSE");
2.29      frystyk  1200: #ifdef EVENT_LOOP
2.27      frystyk  1201:                HTThreadState(net->sockfd, THD_CLOSE);
2.29      frystyk  1202: #endif /* EVENT_LOOP */
2.24      frystyk  1203:                break;
                   1204:            }
2.27      frystyk  1205:        } else {                                  /* Connect on single homed */
                   1206:            free(p1);
                   1207:            net->addressCount = 0;
                   1208:            return 0;
2.24      frystyk  1209:        }
2.27      frystyk  1210:     } while (--net->addressCount);
2.13      frystyk  1211: 
2.27      frystyk  1212:     if (PROT_TRACE)
                   1213:        fprintf(stderr, "HTDoConnect. Connect failed\n");
2.24      frystyk  1214:     free (p1);
                   1215:     net->addressCount = 0;
                   1216:     net->sockfd = -1;
                   1217:     return -1;
2.13      frystyk  1218: }
                   1219: 
                   1220: 
                   1221: /*                                                             HTDoAccept()
                   1222: **
                   1223: **     This function makes a non-blocking accept on a port and polls every
                   1224: **     second until MAX_ACCEPT_POLL or interrupted by user.
                   1225: **
                   1226: **     BUGS Interrupted is not yet implemented!!!
                   1227: **
2.27      frystyk  1228: **     Returns  HT_WOULD_BLOCK         if waiting
                   1229: **              0              if OK,
                   1230: **              -1             on error
2.13      frystyk  1231: */
2.15      frystyk  1232: PUBLIC int HTDoAccept ARGS1(HTNetInfo *, net)
2.13      frystyk  1233: {
                   1234:     SockA soc_address;                         /* SockA is defined in tcp.h */
                   1235:     int status;
                   1236:     int cnt;
                   1237:     int soc_addrlen = sizeof(soc_address);
2.15      frystyk  1238:     if (net->sockfd < 0) {
2.27      frystyk  1239:        if (PROT_TRACE) fprintf(stderr, "HTDoAccept.. Bad socket number\n");
2.13      frystyk  1240:        return -1;
                   1241:     }
2.27      frystyk  1242: 
2.13      frystyk  1243:     /* First make the socket non-blocking */
2.34    ! roeber   1244: #ifdef HAVE_SOCKET_IOCTL
2.23      duns     1245:     {
                   1246:        int enable = 1;
                   1247:        status = socket_ioctl(net->sockfd, FIONBIO, &enable);
                   1248:     }
2.34    ! roeber   1249: #else /* no socket_ioctl */
2.15      frystyk  1250:     if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.23      duns     1251:        status |= FNDELAY;                                      /* O_NDELAY; */
2.15      frystyk  1252:        status = FCNTL(net->sockfd, F_SETFL, status);
2.13      frystyk  1253:     }
2.34    ! roeber   1254: #endif /* SOCKET_IOCTL */
2.13      frystyk  1255:     if (status == -1) {
2.15      frystyk  1256:        HTErrorSysAdd(net->request, ERR_FATAL, NO, "fcntl");
2.13      frystyk  1257:        return -1;
                   1258:     }
                   1259: 
                   1260:     /* Now poll every sekund */
                   1261:     for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
2.15      frystyk  1262:        if ((status = accept(net->sockfd, (struct sockaddr*) &soc_address,
2.13      frystyk  1263:                             &soc_addrlen)) >= 0) {
2.27      frystyk  1264:            if (PROT_TRACE) fprintf(stderr,
2.13      frystyk  1265:                               "HTDoAccept.. Accepted new socket %d\n", 
                   1266:                               status);
                   1267:            return status;
                   1268:        } else
2.15      frystyk  1269:            HTErrorSysAdd(net->request, ERR_WARNING, YES, "accept");
2.13      frystyk  1270:        sleep(1);
                   1271:     }  
                   1272:     
                   1273:     /* If nothing has happened */    
2.27      frystyk  1274:     if (PROT_TRACE)
2.13      frystyk  1275:        fprintf(stderr, "HTDoAccept.. Timed out, no connection!\n");
2.15      frystyk  1276:     HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0,
                   1277:               "HTDoAccept");
2.13      frystyk  1278:     return -1;
1.1       timbl    1279: }
2.27      frystyk  1280: 
1.1       timbl    1281: 

Webmaster