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

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

Webmaster