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

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

Webmaster