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

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

Webmaster