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

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

Webmaster