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

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

Webmaster