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

1.1       timbl       1: /*                     Generic Communication Code              HTTCP.c
                      2: **                     ==========================
                      3: **
                      4: **     This code is in common between client and server sides.
                      5: **
                      6: **     16 Jan 92  TBL  Fix strtol() undefined on CMU Mach.
                      7: **     25 Jun 92  JFG  Added DECNET option through TCP socket emulation.
2.7       duns        8: **     13 Sep 93  MD   Added correct return of vmserrorno for HTInetStatus.
                      9: **                     Added decoding of vms error message for MULTINET.
2.13      frystyk    10: **     31 May 94  HF   Added cache on host id's; now use inet_ntoa() to
                     11: **                     HTInetString and some other fixes. Added HTDoConnect
                     12: **                     and HTDoAccept
1.1       timbl      13: */
                     14: 
2.19    ! frystyk    15: #include <pwd.h>
2.13      frystyk    16: #include "tcp.h"               /* Defines SHORT_NAMES if necessary */
2.19    ! frystyk    17: 
2.13      frystyk    18: #include "HTUtils.h"
                     19: #include "HTAtom.h"
                     20: #include "HTList.h"
                     21: #include "HTParse.h"
                     22: #include "HTAccess.h"
                     23: #include "HTError.h"
1.1       timbl      24: 
                     25: #ifdef SHORT_NAMES
                     26: #define HTInetStatus           HTInStat
2.12      luotonen   27: #define HTErrnoString          HTErrnoS
1.1       timbl      28: #define HTInetString           HTInStri
                     29: #define HTParseInet            HTPaInet
                     30: #endif
                     31: 
2.8       luotonen   32: 
2.11      duns       33: /* VMS stuff */
                     34: #ifdef VMS
                     35: #ifndef MULTINET
                     36: #define FD_SETSIZE 32
                     37: #else /* Multinet */
                     38: #define FD_SETSIZE 256
                     39: #endif /* Multinet */
                     40: #endif /* VMS */
                     41: 
2.13      frystyk    42: /* Macros and other defines */
                     43: #define MAX_ACCEPT_POLL                30
                     44: #define FCNTL(r, s, t)         fcntl(r, s, t)
                     45: 
2.18      frystyk    46: #ifndef RESOLV_CONF
                     47: #define RESOLV_CONF "/etc/resolv.conf"
                     48: #endif
                     49: 
2.13      frystyk    50: /* Globals */
                     51: PUBLIC unsigned int    HTConCacheSize = 512;    /* Number of cached servers */
                     52: 
                     53: /* Type definitions and global variables etc. local to this module */
                     54: 
                     55: /* This structure is a cache of hosts to whom we have connected over time.
                     56:    The structure contains the necessary parts from hostent. For Internet host
                     57:    hostent->h_addr_list is not an array of char pointers but an array of 
                     58:    pointers of type in_addr. */
                     59: typedef struct _host_info {
                     60:     HTAtom *           hostname;                   /* Official name of host */
                     61:     int                        hits;           /* Total number of hits on this host */
                     62:     int                        addrlength;            /* Length of address in bytes */
                     63:     int                        multihomed;    /* Number of IP addresses on the host */
                     64:     int                        offset;         /* Offset value of active IP address */
                     65:     char **            addrlist;      /* List of addresses from name server */
                     66:     float *            weight;                    /* Weight on each address */
                     67: } host_info;
                     68: 
                     69: PRIVATE char *hostname = NULL;                     /* The name of this host */
2.19    ! frystyk    70: PRIVATE char *mailaddress = NULL;                   /* Current mail address */
2.13      frystyk    71: PRIVATE HTList *hostcache = NULL;  /* List of servers that we have talked to */
                     72: PRIVATE unsigned int HTCacheSize = 0;              /* Current size of cache */
2.11      duns       73: 
2.13      frystyk    74: /* ------------------------------------------------------------------------- */
1.1       timbl      75: 
                     76: /*     Encode INET status (as in sys/errno.h)                    inet_status()
                     77: **     ------------------
                     78: **
                     79: ** On entry,
                     80: **     where           gives a description of what caused the error
                     81: **     global errno    gives the error number in the unix way.
                     82: **
                     83: ** On return,
                     84: **     returns         a negative status in the unix way.
                     85: */
                     86: #ifndef PCNFS
2.7       duns       87: #ifdef VMS
2.10      duns       88: #ifndef __DECC
1.1       timbl      89: extern int uerrno;     /* Deposit of error info (as per errno.h) */
2.7       duns       90: extern volatile noshare int socket_errno; /* socket VMS error info 
                     91:                                              (used for translation of vmserrno) */
1.1       timbl      92: extern volatile noshare int vmserrno;  /* Deposit of VMS error info */
                     93: extern volatile noshare int errno;  /* noshare to avoid PSECT conflict */
2.10      duns       94: #endif /* not DECC */
2.11      duns       95: #endif /* VMS */
                     96: 
1.1       timbl      97: #ifndef errno
                     98: extern int errno;
                     99: #endif /* errno */
                    100: 
                    101: #ifndef VM
2.7       duns      102: #ifndef VMS
1.1       timbl     103: #ifndef NeXT
                    104: #ifndef THINK_C
                    105: extern char *sys_errlist[];            /* see man perror on cernvax */
                    106: extern int sys_nerr;
                    107: #endif  /* think c */
                    108: #endif /* NeXT */
2.7       duns      109: #endif  /* VMS */
1.1       timbl     110: #endif /* VM */
                    111: 
                    112: #endif /* PCNFS */
                    113: 
2.12      luotonen  114: 
                    115: /*
                    116:  *     Returns the string equivalent of the current errno.
                    117:  */
                    118: PUBLIC CONST char * HTErrnoString NOARGS
1.1       timbl     119: {
2.11      duns      120: #ifndef VMS
2.7       duns      121: 
1.1       timbl     122: #ifdef VM
2.12      luotonen  123:     return "(Error number not translated)";    /* What Is the VM equiv? */
1.1       timbl     124: #define ER_NO_TRANS_DONE
                    125: #endif
2.12      luotonen  126: 
                    127: #if defined(NeXT) || defined(THINK_C)
                    128:     return strerror(errno);
1.1       timbl     129: #define ER_NO_TRANS_DONE
                    130: #endif
2.12      luotonen  131: 
                    132: #ifndef ER_NO_TRANS_DONE
                    133:     return (errno < sys_nerr ? sys_errlist[errno] : "Unknown error");
1.1       timbl     134: #endif
                    135: 
2.12      luotonen  136: #else /* VMS */
                    137: 
                    138:     static char buf[60];
                    139:     sprintf(buf,"Unix errno = %ld dec, VMS error = %lx hex",errno,vaxc$errno);
                    140:     return buf;
                    141: 
1.1       timbl     142: #endif
2.12      luotonen  143: }
                    144: 
                    145: 
                    146: /*     Report Internet Error
                    147: **     ---------------------
                    148: */
                    149: PUBLIC int HTInetStatus ARGS1(char *, where)
                    150: {
                    151: #ifndef VMS
                    152: 
                    153:     CTRACE(tfp,
                    154:           "TCP errno... %d after call to %s() failed.\n............ %s\n",
                    155:           errno, where, HTErrnoString());
1.1       timbl     156: 
2.11      duns      157: #else /* VMS */
2.12      luotonen  158: 
2.11      duns      159:     CTRACE(tfp, "         Unix error number          = %ld dec\n", errno);
                    160:     CTRACE(tfp, "         VMS error                  = %lx hex\n", vaxc$errno);
2.12      luotonen  161: 
2.11      duns      162: #ifdef MULTINET
                    163:     CTRACE(tfp, "         Multinet error             = %lx hex\n", socket_errno); 
                    164: #endif /* MULTINET */
2.12      luotonen  165: 
2.11      duns      166: #endif /* VMS */
2.7       duns      167: 
                    168: #ifdef VMS
2.11      duns      169:     /* errno happen to be zero if vaxc$errno <> 0 */
                    170:     return -vaxc$errno;
2.7       duns      171: #else
1.1       timbl     172:     return -errno;
2.7       duns      173: #endif
1.1       timbl     174: }
                    175: 
                    176: 
                    177: /*     Parse a cardinal value                                 parse_cardinal()
                    178: **     ----------------------
                    179: **
                    180: ** On entry,
                    181: **     *pp         points to first character to be interpreted, terminated by
                    182: **                 non 0:9 character.
                    183: **     *pstatus    points to status already valid
                    184: **     maxvalue    gives the largest allowable value.
                    185: **
                    186: ** On exit,
                    187: **     *pp         points to first unread character
                    188: **     *pstatus    points to status updated iff bad
                    189: */
                    190: 
                    191: PUBLIC unsigned int HTCardinal ARGS3
                    192:        (int *,         pstatus,
                    193:        char **,        pp,
                    194:        unsigned int,   max_value)
                    195: {
                    196:     int   n;
                    197:     if ( (**pp<'0') || (**pp>'9')) {       /* Null string is error */
                    198:        *pstatus = -3;  /* No number where one expeceted */
                    199:        return 0;
                    200:     }
                    201: 
                    202:     n=0;
                    203:     while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
                    204: 
                    205:     if (n>max_value) {
                    206:        *pstatus = -4;  /* Cardinal outside range */
                    207:        return 0;
                    208:     }
                    209: 
                    210:     return n;
                    211: }
                    212: 
2.19    ! frystyk   213: /* ------------------------------------------------------------------------- */
        !           214: /*                          HOST CACHE MANAGEMENT                           */
        !           215: /* ------------------------------------------------------------------------- */
1.1       timbl     216: 
2.13      frystyk   217: /*                                                     HTTCPCacheRemoveElement
                    218: **
                    219: **     Remove the element specified from the cache
                    220: */
                    221: PRIVATE void HTTCPCacheRemoveElement ARGS1(host_info *, element)
                    222: {
                    223:     if (!hostcache) {
                    224:         if (TRACE)
                    225:             fprintf(stderr, "HostCache... Remove not done, no cache\n");
                    226:         return;
                    227:     }
                    228:     if (TRACE) fprintf(stderr, "HostCache... Remove `%s' from cache\n",
                    229:                       HTAtom_name(element->hostname));
                    230:     HTList_removeObject(hostcache, element);
                    231:     if (element->addrlist)
                    232:        free(element->addrlist);
                    233:     if (element->weight)
                    234:        free(element->weight);
                    235:     free(element);
                    236: }
                    237: 
                    238: 
                    239: /*                                                     HTTCPCacheRemoveHost
                    240: **
                    241: **     Removes the corresponding entrance in the cache
                    242: */
                    243: PRIVATE void HTTCPCacheRemoveHost ARGS1(char *, host)
                    244: {
                    245:     HTAtom *hostatom = HTAtom_for(host);
                    246:     HTList *cur = hostcache;
                    247:     host_info *pres = NULL;
                    248:     if (!hostcache) {
                    249:        fprintf(stderr, "HostCache... Remove host not done, no cache\n");
                    250:        return;
                    251:     }
                    252:     while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
                    253:        if (pres->hostname == hostatom) {
                    254:            break;
                    255:        }
                    256:     }
                    257:     if (pres)
                    258:        HTTCPCacheRemoveElement(pres);
                    259: }
                    260: 
                    261: 
                    262: /*                                                     HTTCPCacheGarbage
                    263: **
                    264: **     Remove the element with the lowest hit rate
                    265: */
                    266: PRIVATE void HTTCPCacheGarbage NOARGS
                    267: {
                    268:     HTList *cur = hostcache;
                    269:     host_info *pres, *worst_match = NULL;
                    270:     unsigned int worst_hits = 30000;             /* Should use UINT_MAX :-( */
                    271:     if (!hostcache) {
                    272:        if (TRACE)
                    273:            fprintf(stderr, "HostCache... Garbage collection not done, no cache\n");
                    274:        return;
                    275:     }
                    276: 
                    277:     /* Seek for worst element */
                    278:     while ((pres = (host_info *) HTList_nextObject(cur))) {
                    279:        if (!worst_match || pres->hits <= worst_hits) {
                    280:            worst_match = pres;
                    281:            worst_hits = pres->hits;
                    282:        }
                    283:     }
                    284:     if (worst_match)
                    285:        HTTCPCacheRemoveElement(worst_match);
                    286: }
                    287: 
                    288: 
                    289: /*                                                     HTTCPCacheAddElement
                    290: **
                    291: **     Add an element to the cache of visited hosts. Note that this function
                    292: **     requires the system implemented structure hostent and not our own
                    293: **     host_info. If multihomed host then multihome indicates the number of
                    294: **     IP addresses found. If not then multihome=0
                    295: **
                    296: **      Returns new element if OK NULL if error
                    297: */
                    298: PRIVATE host_info *HTTCPCacheAddElement ARGS2(HTAtom *, host,
                    299:                                              struct hostent *, element)
                    300: {
                    301:     int homes;                               /* Number of homes on the host */
                    302:     host_info *new;
                    303:     if (!host || !element) {
                    304:        if (TRACE)
                    305:            fprintf(stderr, "HostCache... Bad argument to add to cache\n");
                    306:        return NULL;
                    307:     }
                    308:     if ((new = (host_info *) calloc(1, sizeof(host_info))) == NULL ||
                    309:        (new->addrlist = (char **)
                    310:         calloc(1, sizeof element->h_addr_list)) == NULL)
2.18      frystyk   311:        outofmem(__FILE__, "HTTCPCacheAddElement");
2.13      frystyk   312:     new->hostname = host;
                    313: 
                    314:     if ((homes = (sizeof element->h_addr_list) / element->h_length) > 1) {
                    315:        new->multihomed = homes;
                    316:        if ((new->weight = (float *) calloc(homes, sizeof(float))) == NULL)
                    317:            outofmem(__FILE__, "HTTCPCacheAddElement");
                    318:     }
                    319:     new->addrlength = element->h_length;
                    320:     memcpy((void *) new->addrlist, element->h_addr_list,
                    321:           sizeof element->h_addr_list);
                    322:     if (!hostcache)
                    323:        hostcache = HTList_new();
                    324: 
                    325:     if (TRACE) {
                    326:        if (new->multihomed)
                    327:            fprintf(stderr, "HostCache... Adding multihomed host `%s' having %d homes\n", HTAtom_name(host), new->multihomed);
                    328:        else
                    329:            fprintf(stderr, "HostCache... Adding `%s'\n", HTAtom_name(host));
                    330:     }
                    331:     HTList_addObject(hostcache, (void *) new);
                    332:     HTCacheSize++;                             /* Update number of elements */
                    333:     return new;
                    334: }
                    335: 
                    336: 
                    337: /*                                                                   HTTCPAddrWeights
                    338: **
                    339: **     This function calculates the weights of the different IP addresses
                    340: **     on a multi homed host. Each weight is calculated as
                    341: **
                    342: **             w(n+1) = w(n)*a + (1-a) * deltatime
                    343: **             a = exp(-1/Neff)
                    344: **             Neff is the effective number of samples used
                    345: **             deltatime is time spend on making a connection
                    346: **
                    347: **     A short window (low Neff) gives a high sensibility, but this is
                    348: **     required as we can't expect a lot of data to test on.
                    349: **
                    350: */
                    351: PUBLIC void HTTCPAddrWeights ARGS2(char *, host, time_t, deltatime)
                    352: {
                    353:     HTAtom *hostatom = HTAtom_for(host);
                    354:     HTList *cur = hostcache;
                    355:     host_info *pres = NULL;
                    356:     if (!hostcache) {
                    357:        fprintf(stderr, "HostCache... Weights not calculated, no cache\n");
                    358:        return;
                    359:     }
                    360:     while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
                    361:        if (pres->hostname == hostatom) {
                    362:            break;
                    363:        }
                    364:     }
                    365:     if (pres && pres->multihomed) {
                    366:        int cnt;
2.14      frystyk   367:        CONST float passive = 0.9;        /* Factor for all passive IP_addrs */
2.13      frystyk   368: #if 0
2.14      frystyk   369:        CONST int Neff = 3;
                    370:        CONST float alpha = exp(-1.0/Neff);
2.13      frystyk   371: #else
2.14      frystyk   372:        CONST float alpha = 0.716531310574;
2.13      frystyk   373: #endif
                    374:        for (cnt=0; cnt<pres->multihomed; cnt++) {
                    375:            if (cnt == pres->offset) {
                    376:                *(pres->weight+pres->offset) = *(pres->weight+pres->offset)*alpha + (1.0-alpha)*deltatime;
                    377:            } else {
                    378:                *(pres->weight+cnt) = *(pres->weight+cnt) * passive;
                    379:            }
                    380:        }
                    381:     } else if (TRACE) {
                    382:        fprintf(stderr, "HostCache... Weights not calculated, host not found in cache or is not multihomed: `%s\'\n", host);
                    383:     }
                    384: }
                    385: 
2.19    ! frystyk   386: /* ------------------------------------------------------------------------- */
        !           387: /*                          HOST NAME FUNCTIONS                             */
        !           388: /* ------------------------------------------------------------------------- */
        !           389: 
        !           390: #ifndef DECNET  /* Function only used below for a trace message */
        !           391: 
        !           392: /*     Produce a string for an Internet address
        !           393: **     ----------------------------------------
        !           394: **
        !           395: ** On exit,
        !           396: **     returns a pointer to a static string which must be copied if
        !           397: **             it is to be kept.
        !           398: */
        !           399: 
        !           400: PUBLIC CONST char * HTInetString ARGS1(SockA *, sin)
        !           401: {
        !           402: #if 0
        !           403:     /* This dumps core on some Sun systems :-(. Yhe problem is now, that 
        !           404:        the current implememtation only works for IP-addresses and not in
        !           405:        other address spaces. */
        !           406:     return inet_ntoa(sin->sin_addr);
        !           407: #endif
        !           408:     static char string[16];
        !           409:     sprintf(string, "%d.%d.%d.%d",
        !           410:            (int)*((unsigned char *)(&sin->sin_addr)+0),
        !           411:            (int)*((unsigned char *)(&sin->sin_addr)+1),
        !           412:            (int)*((unsigned char *)(&sin->sin_addr)+2),
        !           413:            (int)*((unsigned char *)(&sin->sin_addr)+3));
        !           414:     return string;
        !           415: }
        !           416: #endif /* Decnet */
        !           417: 
2.13      frystyk   418: 
                    419: /*                                                          HTGetHostByName
                    420: **
                    421: **     Searched first the local cache then asks the DNS for an address of
                    422: **     the host specified.
                    423: **
                    424: **      Returns 0 if OK else -1
                    425: */
                    426: PUBLIC int HTGetHostByName ARGS3(char *, host, SockA *, sin, BOOL *, multi)
                    427: {
                    428:     HTAtom *hostatom = HTAtom_for(host);
                    429:     host_info *pres = NULL;
                    430:     if (!hostcache)
                    431:        hostcache = HTList_new();                      /* First time through */
                    432:     else {
                    433:        HTList *cur = hostcache;                             /* Search cache */
                    434:        while ((pres = (host_info *) HTList_nextObject(cur)) != NULL) {
                    435:            if (pres->hostname == hostatom) {
                    436:                if (TRACE)
2.18      frystyk   437:                    fprintf(stderr, "HostByName.. Host `%s\' found in cache.\n", host);
2.13      frystyk   438:                break;
                    439:            }
                    440:        }
                    441:     }
                    442:     
                    443:     /* If the host was not found in the cache, then do gethostbyname.
                    444:        If cache found then find the best address if more than one. If we
                    445:        are talking to a multi homed host then take the IP address with the
                    446:        lowest weight */
                    447:     if (pres) {
                    448:        if (pres->multihomed) {
                    449:            int cnt;
                    450:            float best_weight = 1e30;               /* Should be FLT_MAX :-( */
                    451:            for (cnt=0; cnt<pres->multihomed; cnt++) {
                    452:                if (*(pres->weight+cnt) < best_weight) {
                    453:                    best_weight = *(pres->weight+cnt);
                    454:                    pres->offset = cnt;
                    455:                }
                    456:            }
                    457:            *multi = YES;
                    458:        } else
                    459:            *multi = NO;
                    460:        pres->hits++;                               /* Update number of hits */
                    461:     } else {                                           /* Go and ask for it */
                    462:        struct hostent *hostelement;                          /* see netdb.h */
                    463: #ifdef MVS     /* Outstanding problem with crash in MVS gethostbyname */
                    464:        if (TRACE)
                    465:            fprintf(stderr, "HTTCP: gethostbyname(%s)\n", host);
                    466: #endif
                    467:        if ((hostelement = gethostbyname(host)) == NULL) {
2.18      frystyk   468:            if (TRACE) fprintf(stderr, "HostByName.. Can't find internet node name `%s'.\n", host);
2.13      frystyk   469:            return -1;
                    470:        }
                    471:        
                    472:        /* Add element to the cache and maybe do garbage collection */
                    473:        if (HTCacheSize >= HTConCacheSize)
                    474:            HTTCPCacheGarbage();
                    475:        if ((pres = HTTCPCacheAddElement(hostatom, hostelement)) == NULL) {
                    476:            return -1;
                    477:        }
                    478:     }
                    479:     
                    480:     /* Update socket structure using the element with the lowest weight. On
                    481:        single homed hosts it means the first value */
                    482:     memcpy(&sin->sin_addr, *(pres->addrlist+pres->offset), pres->addrlength);
                    483:     return 0;
                    484: }
                    485: 
                    486: 
2.19    ! frystyk   487: /*
        !           488: **     Get host name of the machine on the other end of a socket.
        !           489: **
        !           490: **     THIS FUNCTION USED TO BE CALLED HTGetHostName()
        !           491: */
        !           492: PUBLIC char * HTGetHostBySock ARGS1(int, soc)
        !           493: {
        !           494:     struct sockaddr addr;
        !           495:     int len = sizeof(struct sockaddr);
        !           496:     struct in_addr *iaddr;
        !           497:     struct hostent * phost;            /* Pointer to host -- See netdb.h */
        !           498:     char *name = NULL;
        !           499: 
        !           500: #ifdef DECNET  /* Decnet ain't got no damn name server 8#OO */
        !           501:     return NULL;
        !           502: #else
        !           503:     if (getpeername(soc, &addr, &len) < 0)
        !           504:        return NULL;
        !           505: 
        !           506:     iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
        !           507:     phost=gethostbyaddr((char*)iaddr,
        !           508:                        sizeof(struct in_addr),
        !           509:                        AF_INET);
        !           510:     if (!phost) {
        !           511:        if (TRACE) fprintf(stderr,
        !           512:                           "TCP......... Can't find internet node name for peer!!\n");
        !           513:        return NULL;
        !           514:     }
        !           515:     StrAllocCopy(name, phost->h_name);
        !           516:     if (TRACE) fprintf(stderr, "TCP......... Peer name is `%s'\n", name);
        !           517: 
        !           518:     return name;
        !           519: 
        !           520: #endif /* not DECNET */
        !           521: }
        !           522: 
        !           523: 
1.1       timbl     524: /*     Parse a network node address and port
                    525: **     -------------------------------------
                    526: **
                    527: ** On entry,
                    528: **     str     points to a string with a node name or number,
                    529: **             with optional trailing colon and port number.
                    530: **     sin     points to the binary internet or decnet address field.
                    531: **
                    532: ** On exit,
                    533: **     *sin    is filled in. If no port is specified in str, that
                    534: **             field is left unchanged in *sin.
2.13      frystyk   535: **
                    536: ** NOTE:       It is assumed that any portnumber and numeric host address
                    537: **             is given in decimal notation. Separation character is '.'
1.1       timbl     538: */
2.13      frystyk   539: PUBLIC int HTParseInet ARGS3(SockA *,sin, CONST char *,str, BOOL *, multihome)
1.1       timbl     540: {
2.13      frystyk   541:     char *host = NULL;
                    542:     StrAllocCopy(host, str);                 /* Take a copy we can mutilate */
1.1       timbl     543: 
2.13      frystyk   544:     /* Parse port number if present. */    
                    545:     *multihome = NO;
                    546:     {
                    547:        char *port;
                    548:        if ((port=strchr(host, ':'))) {
                    549:            *port++ = 0;                                    /* Chop off port */
                    550:            if (isdigit(*port)) {
1.1       timbl     551: #ifdef DECNET
2.13      frystyk   552:                sin->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10));
                    553: #else /* Internet */
                    554:                sin->sin_port = htons(atol(port));
1.1       timbl     555: #endif
2.13      frystyk   556:            } else {
                    557:                fprintf(stderr, "ParseInet... No port indicated\n");
                    558:            }
1.1       timbl     559:        }
2.13      frystyk   560:     }
1.1       timbl     561: 
2.13      frystyk   562:     /* Parse Internet host */
1.1       timbl     563: #ifdef DECNET
                    564:     /* read Decnet node name. @@ Should know about DECnet addresses, but it's
                    565:        probably worth waiting until the Phase transition from IV to V. */
                    566: 
                    567:     sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host));  /* <=6 in phase 4 */
                    568:     strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
                    569: 
                    570:     if (TRACE) fprintf(stderr,  
                    571:        "DECnet: Parsed address as object number %d on host %.6s...\n",
                    572:                      sin->sdn_objnum, host);
                    573: 
2.13      frystyk   574: #else /* Internet */
1.1       timbl     575: 
2.13      frystyk   576:     /* Parse host number if present */
                    577:     {
                    578:        BOOL numeric = YES;
                    579:        char *strptr = host;
                    580:        while (*strptr) {
                    581:            if (!isdigit(*strptr) && *strptr != '.') {
                    582:                numeric = NO;
                    583:                break;
                    584:            }
                    585:            ++strptr;
                    586:        }
                    587:        if (numeric) {
                    588:            sin->sin_addr.s_addr = inet_addr(host);       /* See arpa/inet.h */
                    589:        } else {
                    590:            if (HTGetHostByName(host, sin, multihome)) {
                    591:                free(host);
                    592:                return -1;
                    593:            }
                    594:        }
                    595:        if (TRACE) {
                    596:            fprintf(stderr, "ParseInet... Parsed address as port %d on %s\n",
                    597:                    (int) ntohs(sin->sin_port),
                    598:                    HTInetString(sin));
1.1       timbl     599:        }
                    600:     }
                    601: #endif  /* Internet vs. Decnet */
2.13      frystyk   602:     free(host);
1.1       timbl     603:     return 0;  /* OK */
                    604: }
                    605: 
                    606: 
2.16      frystyk   607: #ifdef OLD_CODE
1.1       timbl     608: /*     Derive the name of the host on which we are
                    609: **     -------------------------------------------
                    610: **
                    611: */
2.8       luotonen  612: PRIVATE void get_host_details NOARGS
1.1       timbl     613: 
                    614: #ifndef MAXHOSTNAMELEN
                    615: #define MAXHOSTNAMELEN 64              /* Arbitrary limit */
                    616: #endif
                    617: 
                    618: {
                    619:     char name[MAXHOSTNAMELEN+1];       /* The name of this host */
                    620:     struct hostent * phost;            /* Pointer to host -- See netdb.h */
                    621:     int namelength = sizeof(name);
                    622:     
                    623:     if (hostname) return;              /* Already done */
                    624:     gethostname(name, namelength);     /* Without domain */
2.18      frystyk   625:     if (TRACE) fprintf(stderr, "TCP......... Local host name is %s\n", name);
1.1       timbl     626:     StrAllocCopy(hostname, name);
                    627: 
                    628: #ifndef DECNET  /* Decnet ain't got no damn name server 8#OO */
                    629:     phost=gethostbyname(name);         /* See netdb.h */
                    630:     if (!phost) {
                    631:        if (TRACE) fprintf(stderr, 
2.9       luotonen  632:                "TCP......... Can't find my own internet node address for `%s'!!\n",
1.1       timbl     633:                name);
                    634:        return;  /* Fail! */
                    635:     }
                    636:     StrAllocCopy(hostname, phost->h_name);
2.18      frystyk   637:     if (TRACE)
                    638:        fprintf(stderr, "TCP......... Full local host name is %s\n", hostname);
2.8       luotonen  639: 
                    640: #ifdef NEED_HOST_ADDRESS               /* no -- needs name server! */
1.1       timbl     641:     memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
                    642:     if (TRACE) fprintf(stderr, "     Name server says that I am `%s' = %s\n",
                    643:            hostname, HTInetString(&HTHostAddress));
2.8       luotonen  644: #endif /* NEED_HOST_ADDRESS */
1.1       timbl     645: 
                    646: #endif /* not Decnet */
                    647: }
2.16      frystyk   648: #endif /* OLD_CODE */
1.1       timbl     649: 
2.19    ! frystyk   650: 
        !           651: /*                                                             HTSetHostName
        !           652: **     Sets the current hostname inclusive domain name.
        !           653: **     If this is not set then the default approach is used using
        !           654: **     HTGetHostname().
        !           655: */
        !           656: PUBLIC void HTSetHostName ARGS1(char *, host)
        !           657: {
        !           658:     if (host && *host)
        !           659:        StrAllocCopy(hostname, host);
        !           660:     else {
        !           661:        if (TRACE) fprintf(stderr, "SetHostName. Bad argument ignored\n");
        !           662:     }
        !           663: }
        !           664: 
        !           665: 
        !           666: /*                                                             HTGetHostName
2.18      frystyk   667: **     Returns the name of this host. It uses the following algoritm:
                    668: **
                    669: **     1) gethostname()
                    670: **     2) if the hostname doesn't contain any '.' try to read
                    671: **        /etc/resolv.conf. If there is no domain line in this file then
                    672: **     3) Try getdomainname and do as the man pages say for resolv.conf (sun)
                    673: **             If there is no domain line in this file, then it is derived
                    674: **             from the domain name set by the domainname(1) command, usually
                    675: **             by removing the first component. For example, if the domain-
                    676: **             name is set to ``foo.podunk.edu'' then the default domain name
                    677: **             used will be ``pudunk.edu''.
                    678: **
                    679: **     This is the same procedure as used by res_init() and sendmail.
2.16      frystyk   680: **
                    681: **     Return: hostname on success else NULL
                    682: */
2.19    ! frystyk   683: PUBLIC CONST char * HTGetHostName NOARGS
1.1       timbl     684: {
2.18      frystyk   685:     BOOL got_it = NO;
                    686:     FILE *fp;
2.16      frystyk   687:     char name[MAXHOSTNAMELEN+1];
2.18      frystyk   688:     if (hostname) {                                      /* If already done */
                    689:        if (*hostname)
                    690:            return hostname;
                    691:        else
                    692:            return NULL;                    /* We couldn't get the last time */
                    693:     }
2.16      frystyk   694:     *(name+MAXHOSTNAMELEN) = '\0';
                    695:     if (gethostname(name, MAXHOSTNAMELEN)) {        /* Maybe without domain */
                    696:        if (TRACE)
                    697:            fprintf(stderr, "HostName.... Can't get host name\n");
                    698:        return NULL;
                    699:     }
2.18      frystyk   700:     if (TRACE)
                    701:        fprintf(stderr, "HostName.... Local host name is %s\n", name);
2.16      frystyk   702:     StrAllocCopy(hostname, name);
                    703: 
2.18      frystyk   704:     /* Now try the resolver config file */
                    705:     if ((fp = fopen(RESOLV_CONF, "r")) != NULL) {
                    706:        char buffer[80];
                    707:        *(buffer+79) = '\0';
                    708:        while (fgets(buffer, 79, fp)) {
                    709:            if (!strncasecomp(buffer, "domain", 6)) {   
                    710:                char *domainstr = buffer+6;
                    711:                char *end;
                    712:                while (*domainstr == ' ' || *domainstr == '\t')
                    713:                    domainstr++;
                    714:                end = domainstr;
                    715:                while (*end && !isspace(*end))
                    716:                    end++;
                    717:                *end = '\0';
                    718:                if (*domainstr) {
                    719:                    StrAllocCat(hostname, ".");
                    720:                    StrAllocCat(hostname, domainstr);
                    721:                    got_it = YES;
                    722:                    break;
                    723:                }
                    724:            }
                    725:        }
                    726:        fclose(fp);
2.16      frystyk   727:     }
                    728: 
2.18      frystyk   729:     /* If everything else has failed then try getdomainname */
                    730:     if (!got_it) {
                    731:        if (getdomainname(name, MAXHOSTNAMELEN)) {
                    732:            if (TRACE)
                    733:                fprintf(stderr, "HostName.... Can't get domain name\n");
                    734:            *hostname = '\0';
                    735:            return NULL;
                    736:        }
                    737: 
                    738:        /* If the host name and the first part of the domain name are different
                    739:           then use the former as it is more exact (I guess) */
                    740:        if (strncmp(name, hostname, (int) strlen(hostname))) {
                    741:            char *domain = strchr(name, '.');
                    742:            if (!domain)
                    743:                domain = name;
                    744:            StrAllocCat(hostname, domain);
                    745:        }
2.16      frystyk   746:     }
2.18      frystyk   747:     if (TRACE)
                    748:        fprintf(stderr, "HostName.... Full local host name is %s\n", hostname);
                    749:     return hostname;
                    750: 
                    751: #ifndef DECNET  /* Decnet ain't got no damn name server 8#OO */
                    752: #ifdef OLD_CODE
                    753:                              /* Now we try to get information on the domain */
2.16      frystyk   754:     {
                    755:        struct hostent *hostelement;
                    756:        if ((hostelement = gethostbyname(hostname)) == NULL) {
                    757:            if (TRACE)
                    758:                fprintf(stderr, "HostName.... Can't find host name on DNS\n");
                    759:            FREE(hostname);
                    760:            return NULL;
                    761:        }
2.17      frystyk   762:        StrAllocCopy(hostname, (char *) hostelement->h_name);
2.16      frystyk   763:     }
2.18      frystyk   764: #endif /* OLD_CODE */
2.16      frystyk   765: #endif /* not Decnet */
2.13      frystyk   766: }
                    767: 
2.19    ! frystyk   768: 
        !           769: /*                                                            HTSetMailAddress
        !           770: **     Sets the current mail address plus host name and domain name.
        !           771: **     If this is not set then the default approach is used using
        !           772: **     HTGetMailAddress().
        !           773: */
        !           774: PUBLIC void HTSetMailAddress ARGS1(char *, address)
        !           775: {
        !           776:     if (address && *address)
        !           777:        StrAllocCopy(mailaddress, address);
        !           778:     else {
        !           779:        if (TRACE) fprintf(stderr, "SetMailAddress. Bad argument ignored\n");
        !           780:     }
        !           781: }
        !           782: 
        !           783: 
        !           784: /*                                                            HTGetMailAddress
        !           785: **
        !           786: **     Get the mail address of the current user on the current host. The
        !           787: **     domain name used is the one initialized in HTSetHostName or
        !           788: **     HTGetHostName. The login name is determined using (ordered):
        !           789: **
        !           790: **             getlogin
        !           791: **             getpwuid(getuid())
        !           792: **
        !           793: **     The weakness about the last attempt is if the user has multiple
        !           794: **     login names each with the same user ID. If this fails as well then:
        !           795: **
        !           796: **             LOGNAME environment variable
        !           797: **             USER environment variable
        !           798: **
        !           799: **     Returns NULL if error else pointer to static string
        !           800: */
        !           801: PUBLIC CONST char * HTGetMailAddress NOARGS
        !           802: {
        !           803:     char *login;
        !           804:     CONST char *domain;
        !           805:     struct passwd *pw_info;
        !           806:     if (mailaddress)
        !           807:        return mailaddress;
        !           808:     if ((login = (char *) getlogin()) == NULL) {
        !           809:        if (TRACE) fprintf(stderr, "MailAddress. getlogin returns NULL\n");
        !           810:        if ((pw_info = getpwuid(getuid())) == NULL) {
        !           811:            if (TRACE) fprintf(stderr, "MailAddress. getpwid returns NULL\n");
        !           812:            if ((login = getenv("LOGNAME")) == NULL) {
        !           813:                if (TRACE) fprintf(stderr, "MailAddress. LOGNAME not found\n");
        !           814:                if ((login = getenv("USER")) == NULL) {
        !           815:                    if (TRACE) fprintf(stderr,"MailAddress. USER not found\n");
        !           816:                    return NULL;                /* I GIVE UP */
        !           817:                }
        !           818:            }
        !           819:        } else
        !           820:            login = pw_info->pw_name;
        !           821:     }
        !           822:     if (login) {
        !           823:        StrAllocCopy(mailaddress, login);
        !           824:        StrAllocCat(mailaddress, "@");
        !           825:        if ((domain = HTGetHostName()) != NULL)
        !           826:            StrAllocCat(mailaddress, domain);
        !           827:        return mailaddress;
        !           828:     }
        !           829:     return NULL;
        !           830: }
        !           831: 
        !           832: /* ------------------------------------------------------------------------- */
        !           833: /*                   CONNECTION ESTABLISHMENT MANAGEMENT                    */
        !           834: /* ------------------------------------------------------------------------- */
2.13      frystyk   835: 
                    836: /*                                                             HTDoConnect()
                    837: **
                    838: **     Note: Any port indication in URL, e.g., as `host:port' overwrites
                    839: **     the default_port value.
                    840: **
                    841: **     Returns 0 if OK, -1 on error
                    842: */
2.15      frystyk   843: PUBLIC int HTDoConnect ARGS4(HTNetInfo *, net, char *, url,
                    844:                             u_short, default_port, u_long *, addr)
2.13      frystyk   845: {
                    846:     BOOL multihomed = NO;
                    847:     time_t deltatime;
                    848:     int status;
                    849:     SockA sock_addr;                           /* SockA is defined in tcp.h */
                    850:     char *p1 = HTParse(url, "", PARSE_HOST);
                    851:     char *at_sign;
                    852:     char *host;
                    853: 
                    854:     /* if theres an @ then use the stuff after it as a hostname */
                    855:     if((at_sign = strchr(p1,'@')) != NULL)
                    856:        host = at_sign+1;
                    857:     else
                    858:        host = p1;
                    859:     if (TRACE) fprintf(stderr, "HTDoConnect. Looking up `%s\'\n", host);
                    860: 
                    861:    /* Set up defaults */
                    862:     memset((void *) &sock_addr, '\0', sizeof(sock_addr));
                    863: #ifdef DECNET
                    864:     sock_addr.sdn_family = AF_DECnet;        /* Family = DECnet, host order */
                    865:     sock_addr.sdn_objnum = DNP_OBJ;          /* Default: http object number */
                    866: #else  /* Internet */
                    867:     sock_addr.sin_family = AF_INET;
                    868:     sock_addr.sin_port = htons(default_port);
                    869: #endif
                    870: 
                    871:     /* Get node name */
                    872:     if (HTParseInet(&sock_addr, host, &multihomed)) {
                    873:        if (TRACE) fprintf(stderr, "HTDoConnect. Can't locate remote host `%s\'\n", host);
2.15      frystyk   874:        HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
2.13      frystyk   875:                   (void *) host, strlen(host), "HTDoConnect");
                    876:        free (p1);
2.15      frystyk   877:        net->sockfd = -1;
2.13      frystyk   878:        return -1;
                    879:     }
                    880: 
                    881: #ifdef DECNET
2.15      frystyk   882:     if ((net->sockfd = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
2.13      frystyk   883: #else
2.15      frystyk   884:     if ((net->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
2.13      frystyk   885: #endif
2.15      frystyk   886:        HTErrorSysAdd(net->request, ERR_FATAL, NO, "socket");
2.13      frystyk   887:        free (p1);
                    888:        return -1;
                    889:     }
                    890:     if (addr)
                    891:        *addr = ntohl(sock_addr.sin_addr.s_addr);
                    892: 
                    893:     if (TRACE)
2.15      frystyk   894:        fprintf(stderr, "HTDoConnect. Created socket number %d\n",
                    895:                net->sockfd);
2.13      frystyk   896: 
                    897:     if (multihomed)                            /* Start timer on connection */
                    898:        deltatime = time(NULL);
2.15      frystyk   899:     if ((status = connect(net->sockfd, (struct sockaddr *) &sock_addr,
2.13      frystyk   900:                          sizeof(sock_addr))) < 0) {
2.15      frystyk   901:        HTErrorSysAdd(net->request, ERR_FATAL, NO, "connect");
2.13      frystyk   902:        HTTCPCacheRemoveHost(host);                /* Remove host from cache */
2.15      frystyk   903:        if (NETCLOSE(net->sockfd) < 0)
                    904:            HTErrorSysAdd(net->request, ERR_FATAL, NO, "close");
2.13      frystyk   905:        free(p1);
2.15      frystyk   906:        net->sockfd = -1;
2.13      frystyk   907:        return -1;
                    908:     }
                    909: 
                    910:     /* Measure time to make a connection and recalculate weights */
                    911:     if (multihomed) {
                    912:        deltatime = time(NULL) - deltatime;
                    913:        HTTCPAddrWeights(host, deltatime);
                    914:     }
                    915:     free(p1);
                    916:     return status;
                    917: }
                    918: 
                    919: 
                    920: /*                                                             HTDoAccept()
                    921: **
                    922: **     This function makes a non-blocking accept on a port and polls every
                    923: **     second until MAX_ACCEPT_POLL or interrupted by user.
                    924: **
                    925: **     BUGS Interrupted is not yet implemented!!!
                    926: **
                    927: **     Returns 0 if OK, -1 on error
                    928: */
2.15      frystyk   929: PUBLIC int HTDoAccept ARGS1(HTNetInfo *, net)
2.13      frystyk   930: {
                    931:     SockA soc_address;                         /* SockA is defined in tcp.h */
                    932:     int status;
                    933:     int cnt;
                    934:     int soc_addrlen = sizeof(soc_address);
2.15      frystyk   935:     if (net->sockfd < 0) {
2.13      frystyk   936:        if (TRACE) fprintf(stderr, "HTDoAccept.. Bad socket number\n");
                    937:        return -1;
                    938:     }
                    939:        
                    940:     /* First make the socket non-blocking */
2.15      frystyk   941:     if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.13      frystyk   942:        status |= FNDELAY;
2.15      frystyk   943:        status = FCNTL(net->sockfd, F_SETFL, status);
2.13      frystyk   944:     }
                    945:     if (status == -1) {
2.15      frystyk   946:        HTErrorSysAdd(net->request, ERR_FATAL, NO, "fcntl");
2.13      frystyk   947:        return -1;
                    948:     }
                    949: 
                    950:     /* Now poll every sekund */
                    951:     for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
2.15      frystyk   952:        if ((status = accept(net->sockfd, (struct sockaddr*) &soc_address,
2.13      frystyk   953:                             &soc_addrlen)) >= 0) {
                    954:            if (TRACE) fprintf(stderr,
                    955:                               "HTDoAccept.. Accepted new socket %d\n", 
                    956:                               status);
                    957:            return status;
                    958:        } else
2.15      frystyk   959:            HTErrorSysAdd(net->request, ERR_WARNING, YES, "accept");
2.13      frystyk   960:        sleep(1);
                    961:     }  
                    962:     
                    963:     /* If nothing has happened */    
                    964:     if (TRACE)
                    965:        fprintf(stderr, "HTDoAccept.. Timed out, no connection!\n");
2.15      frystyk   966:     HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0,
                    967:               "HTDoAccept");
2.13      frystyk   968:     return -1;
1.1       timbl     969: }
                    970: 

Webmaster