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

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

Webmaster