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

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

Webmaster