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

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.54    ! frystyk    27: #include "HTNetMan.h"
        !            28: #include "HTDNS.h"
2.36      frystyk    29: #include "HTTCP.h"                                      /* Implemented here */
2.29      frystyk    30: 
2.36      frystyk    31: #ifdef VMS 
                     32: #include "HTVMSUtils.h"
                     33: #endif /* VMS */
1.1       timbl      34: 
2.36      frystyk    35: /* VMS stuff */
                     36: #ifdef VMS
                     37: #ifndef MULTINET
                     38: #define FD_SETSIZE 32
                     39: #else /* Multinet */
                     40: #define FD_SETSIZE 256
                     41: #endif /* Multinet */
                     42: #endif /* VMS */
                     43: 
2.13      frystyk    44: /* Macros and other defines */
2.24      frystyk    45: /* x seconds penalty on a multi-homed host if IP-address is down */
                     46: #define TCP_PENALTY            1200
                     47: 
                     48: /* x seconds penalty on a multi-homed host if IP-address is timed out */
                     49: #define TCP_DELAY              600
                     50: 
                     51: /* Max number of non-blocking accepts */
2.13      frystyk    52: #define MAX_ACCEPT_POLL                30
                     53: 
2.36      frystyk    54: #ifndef RESOLV_CONF
                     55: #define RESOLV_CONF "/etc/resolv.conf"
                     56: #endif
                     57: 
2.54    ! frystyk    58: PRIVATE char *hostname = NULL;                     /* The name of this host */
2.13      frystyk    59: 
2.19      frystyk    60: PRIVATE char *mailaddress = NULL;                   /* Current mail address */
2.11      duns       61: 
2.13      frystyk    62: /* ------------------------------------------------------------------------- */
1.1       timbl      63: 
2.36      frystyk    64: /*
                     65: **     Returns the string equivalent to the errno passed in the argument.
2.37      frystyk    66: **     We can't use errno directly as we have both errno and socerrno. The
2.36      frystyk    67: **     result is a static buffer.
1.1       timbl      68: */
2.36      frystyk    69: PUBLIC CONST char * HTErrnoString ARGS1(int, errornumber)
1.1       timbl      70: {
2.41      frystyk    71: 
2.40      frystyk    72: #ifdef HAVE_STRERROR
2.36      frystyk    73:     return strerror(errornumber);
2.34      roeber     74: #else
2.36      frystyk    75: #ifdef VMS
2.12      luotonen   76:     static char buf[60];
2.36      frystyk    77:     sprintf(buf,"Unix errno = %ld dec, VMS error = %lx hex", errornumber,
                     78:            vaxc$errno);
2.12      luotonen   79:     return buf;
2.41      frystyk    80: #else 
2.40      frystyk    81: #ifdef _WINDOWS 
2.41      frystyk    82:        static char buf[60];
                     83:        sprintf(buf, "Unix errno = %ld dec, WinSock erro = %ld", errornumber, WSAGetLastError());
                     84:        return buf;
2.40      frystyk    85: #else
2.36      frystyk    86:     return (errornumber < sys_nerr ? sys_errlist[errornumber]:"Unknown error");
2.40      frystyk    87: #endif  /* WINDOWS */
                     88: #endif /* VMS */
2.51      frystyk    89: #endif /* HAVE_STRERROR */
2.12      luotonen   90: }
                     91: 
2.36      frystyk    92: 
                     93: /*     Debug error message
2.12      luotonen   94: */
2.39      frystyk    95: PUBLIC int HTInetStatus ARGS2(int, errnum, char *, where)
2.12      luotonen   96: {
2.40      frystyk    97: #if ! (defined(VMS) || defined(WINDOWS))
2.12      luotonen   98: 
2.27      frystyk    99:     if (PROT_TRACE)
2.41      frystyk   100:        fprintf(TDEST, "TCP errno... %d after call to %s() failed.\n............ %s\n", errno, where, HTErrnoString(errnum));
1.1       timbl     101: 
2.36      frystyk   102: #else /* VMS */
2.40      frystyk   103: #ifdef VMS 
2.36      frystyk   104:     if (PROT_TRACE) fprintf(TDEST, "         Unix error number          = %ld dec\n", errno);
                    105:     if (PROT_TRACE) fprintf(TDEST, "         VMS error                  = %lx hex\n", vaxc$errno);
2.40      frystyk   106: #endif
                    107: #ifdef WINDOWS 
                    108:     if (PROT_TRACE) fprintf(TDEST, "         Unix error number          = %ld dec\n", errno);
                    109:     if (PROT_TRACE) fprintf(TDEST, "         NT error                  = %lx hex\n", WSAGetLastError());
                    110: #endif 
2.12      luotonen  111: 
2.36      frystyk   112: #ifdef MULTINET
                    113:     if (PROT_TRACE) fprintf(TDEST, "         Multinet error             = %lx hex\n", socket_errno); 
                    114:     if (PROT_TRACE) fprintf(TDEST, "         Error String               = %s\n", vms_errno_string());
                    115: #endif /* MULTINET */
2.12      luotonen  116: 
2.36      frystyk   117: #endif /* VMS */
2.7       duns      118: 
2.36      frystyk   119: #ifdef VMS
2.11      duns      120:     /* errno happen to be zero if vaxc$errno <> 0 */
                    121:     return -vaxc$errno;
2.7       duns      122: #else
1.1       timbl     123:     return -errno;
2.7       duns      124: #endif
1.1       timbl     125: }
                    126: 
                    127: 
                    128: /*     Parse a cardinal value                                 parse_cardinal()
                    129: **     ----------------------
                    130: **
                    131: ** On entry,
                    132: **     *pp         points to first character to be interpreted, terminated by
                    133: **                 non 0:9 character.
                    134: **     *pstatus    points to status already valid
                    135: **     maxvalue    gives the largest allowable value.
                    136: **
                    137: ** On exit,
                    138: **     *pp         points to first unread character
                    139: **     *pstatus    points to status updated iff bad
                    140: */
                    141: 
                    142: PUBLIC unsigned int HTCardinal ARGS3
                    143:        (int *,         pstatus,
                    144:        char **,        pp,
                    145:        unsigned int,   max_value)
                    146: {
2.36      frystyk   147:     unsigned int n=0;
1.1       timbl     148:     if ( (**pp<'0') || (**pp>'9')) {       /* Null string is error */
                    149:        *pstatus = -3;  /* No number where one expeceted */
                    150:        return 0;
                    151:     }
                    152:     while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
                    153: 
                    154:     if (n>max_value) {
                    155:        *pstatus = -4;  /* Cardinal outside range */
                    156:        return 0;
                    157:     }
                    158: 
                    159:     return n;
                    160: }
                    161: 
2.19      frystyk   162: /* ------------------------------------------------------------------------- */
2.27      frystyk   163: /*                             SIGNAL HANDLING                              */
                    164: /* ------------------------------------------------------------------------- */
                    165: 
                    166: #ifdef WWWLIB_SIG
                    167: /*                                                                 HTSetSignal
                    168: **  This function sets up signal handlers. This might not be necessary to
                    169: **  call if the application has its own handlers.
                    170: */
                    171: #include <signal.h>
                    172: PUBLIC void HTSetSignal NOARGS
                    173: {
                    174:     /* On some systems (SYSV) it is necessary to catch the SIGPIPE signal
                    175:     ** when attemting to connect to a remote host where you normally should
                    176:     ** get `connection refused' back
                    177:     */
                    178:     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
2.36      frystyk   179:        if (PROT_TRACE) fprintf(TDEST, "HTSignal.... Can't catch SIGPIPE\n");
2.27      frystyk   180:     } else {
2.36      frystyk   181:        if (PROT_TRACE) fprintf(TDEST, "HTSignal.... Ignoring SIGPIPE\n");
2.27      frystyk   182:     }
                    183: }
                    184: #endif /* WWWLIB_SIG */
                    185: 
                    186: /* ------------------------------------------------------------------------- */
2.19      frystyk   187: /*                          HOST NAME FUNCTIONS                             */
                    188: /* ------------------------------------------------------------------------- */
                    189: 
                    190: /*     Produce a string for an Internet address
                    191: **     ----------------------------------------
                    192: **
                    193: ** On exit,
                    194: **     returns a pointer to a static string which must be copied if
2.41      frystyk   195: **             it is to be kept.
2.19      frystyk   196: */
                    197: PUBLIC CONST char * HTInetString ARGS1(SockA *, sin)
                    198: {
2.53      frystyk   199: #ifndef DECNET  /* Function only used below for a trace message */
2.41      frystyk   200: #if 0
                    201:     /* This dumps core on some Sun systems :-(. The problem is now, that 
                    202:        the current implememtation only works for IP-addresses and not in
                    203:        other address spaces. */
                    204:     return inet_ntoa(sin->sin_addr);
                    205: #endif
2.19      frystyk   206:     static char string[16];
                    207:     sprintf(string, "%d.%d.%d.%d",
                    208:            (int)*((unsigned char *)(&sin->sin_addr)+0),
                    209:            (int)*((unsigned char *)(&sin->sin_addr)+1),
                    210:            (int)*((unsigned char *)(&sin->sin_addr)+2),
                    211:            (int)*((unsigned char *)(&sin->sin_addr)+3));
                    212:     return string;
2.53      frystyk   213: #else
                    214:     return "";
                    215: #endif /* Decnet */
2.19      frystyk   216: }
                    217: 
1.1       timbl     218: /*     Parse a network node address and port
                    219: **     -------------------------------------
2.54    ! frystyk   220: **     It is assumed that any portnumber and numeric host address
        !           221: **     is given in decimal notation. Separation character is '.'
        !           222: **     Any port number given in host name overrides all other values.
        !           223: **     'host' might be modified.
        !           224: **      Returns:
        !           225: **             >0      Number of homes
        !           226: **              0      Wait for persistent socket
        !           227: **             -1      Error
1.1       timbl     228: */
2.54    ! frystyk   229: PRIVATE int HTParseInet (HTNet * net, char * host)
1.1       timbl     230: {
2.54    ! frystyk   231:     int status = 1;
        !           232:     SockA *sin = &net->sock_addr;
2.27      frystyk   233: 
1.1       timbl     234: #ifdef DECNET
                    235:     /* read Decnet node name. @@ Should know about DECnet addresses, but it's
                    236:        probably worth waiting until the Phase transition from IV to V. */
                    237: 
                    238:     sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host));  /* <=6 in phase 4 */
                    239:     strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1);
                    240: 
2.36      frystyk   241:     if (PROT_TRACE) fprintf(TDEST,  
1.1       timbl     242:        "DECnet: Parsed address as object number %d on host %.6s...\n",
                    243:                      sin->sdn_objnum, host);
2.13      frystyk   244: #else /* Internet */
                    245:     {
                    246:        char *strptr = host;
                    247:        while (*strptr) {
2.54    ! frystyk   248:            if (*strptr == ':') {
        !           249:                *strptr = '\0';    /* Don't want port number in numeric host */
2.13      frystyk   250:                break;
                    251:            }
2.54    ! frystyk   252:            if (!isdigit(*strptr) && *strptr != '.')
        !           253:                break;
        !           254:            strptr++;
2.13      frystyk   255:        }
2.54    ! frystyk   256:        if (!*strptr) {
2.51      frystyk   257: #ifdef GUSI
                    258:            sin->sin_addr = inet_addr(host);             /* See netinet/in.h */
                    259: #else
2.13      frystyk   260:            sin->sin_addr.s_addr = inet_addr(host);       /* See arpa/inet.h */
2.51      frystyk   261: #endif
2.54    ! frystyk   262:        } else
        !           263:            status = HTGetHostByName(net, host);
        !           264: 
2.27      frystyk   265:        if (PROT_TRACE) {
2.54    ! frystyk   266:            if (status > 0)
        !           267:                fprintf(TDEST, "ParseInet... as port %d on %s with %d homes\n",
        !           268:                        (int) ntohs(sin->sin_port), HTInetString(sin), status);
1.1       timbl     269:        }
                    270:     }
2.54    ! frystyk   271: #endif /* Internet vs. Decnet */
2.24      frystyk   272:     return status;
1.1       timbl     273: }
                    274: 
                    275: 
2.24      frystyk   276: /*                                                             HTGetDomainName
                    277: **     Returns the current domain name without the local host name.
                    278: **     The response is pointing to a static area that might be changed
2.36      frystyk   279: **     using HTSetHostName().
                    280: **
                    281: **     Returns NULL on error, "" if domain name is not found
2.24      frystyk   282: */
                    283: PUBLIC CONST char *HTGetDomainName NOARGS
                    284: {
                    285:     CONST char *host = HTGetHostName();
                    286:     char *domain;
                    287:     if (host && *host) {
                    288:        if ((domain = strchr(host, '.')) != NULL)
                    289:            return ++domain;
                    290:        else
2.36      frystyk   291:            return "";
2.24      frystyk   292:     } else
                    293:        return NULL;
                    294: }
                    295: 
                    296: 
2.19      frystyk   297: /*                                                             HTSetHostName
                    298: **     Sets the current hostname inclusive domain name.
                    299: **     If this is not set then the default approach is used using
                    300: **     HTGetHostname().
                    301: */
                    302: PUBLIC void HTSetHostName ARGS1(char *, host)
                    303: {
2.24      frystyk   304:     if (host && *host) {
                    305:        char *strptr;
2.19      frystyk   306:        StrAllocCopy(hostname, host);
2.24      frystyk   307:        strptr = hostname;
                    308:        while (*strptr) {
                    309:            *strptr = TOLOWER(*strptr);
                    310:            strptr++;
                    311:        }
                    312:        if (*(hostname+strlen(hostname)-1) == '.')    /* Remove trailing dot */
                    313:            *(hostname+strlen(hostname)-1) = '\0';
                    314:     } else {
2.36      frystyk   315:        if (PROT_TRACE) fprintf(TDEST, "SetHostName. Bad argument ignored\n");
2.19      frystyk   316:     }
                    317: }
                    318: 
                    319: 
                    320: /*                                                             HTGetHostName
2.18      frystyk   321: **     Returns the name of this host. It uses the following algoritm:
                    322: **
                    323: **     1) gethostname()
                    324: **     2) if the hostname doesn't contain any '.' try to read
                    325: **        /etc/resolv.conf. If there is no domain line in this file then
                    326: **     3) Try getdomainname and do as the man pages say for resolv.conf (sun)
2.49      frystyk   327: **        If there is no domain line in this file, then it is derived
                    328: **        from the domain name set by the domainname(1) command, usually
                    329: **        by removing the first component. For example, if the domain-
                    330: **        name is set to ``foo.podunk.edu'' then the default domain name
                    331: **        used will be ``pudunk.edu''.
2.18      frystyk   332: **
                    333: **     This is the same procedure as used by res_init() and sendmail.
2.16      frystyk   334: **
                    335: **     Return: hostname on success else NULL
                    336: */
2.19      frystyk   337: PUBLIC CONST char * HTGetHostName NOARGS
1.1       timbl     338: {
2.18      frystyk   339:     BOOL got_it = NO;
                    340:     FILE *fp;
2.16      frystyk   341:     char name[MAXHOSTNAMELEN+1];
2.18      frystyk   342:     if (hostname) {                                      /* If already done */
                    343:        if (*hostname)
                    344:            return hostname;
                    345:        else
                    346:            return NULL;                    /* We couldn't get the last time */
                    347:     }
2.16      frystyk   348:     *(name+MAXHOSTNAMELEN) = '\0';
2.52      frystyk   349: 
                    350: #ifndef NO_GETHOSTNAME
2.16      frystyk   351:     if (gethostname(name, MAXHOSTNAMELEN)) {        /* Maybe without domain */
2.27      frystyk   352:        if (PROT_TRACE)
2.36      frystyk   353:            fprintf(TDEST, "HostName.... Can't get host name\n");
2.16      frystyk   354:        return NULL;
                    355:     }
2.27      frystyk   356:     if (PROT_TRACE)
2.36      frystyk   357:        fprintf(TDEST, "HostName.... Local host name is  `%s\'\n", name);
2.16      frystyk   358:     StrAllocCopy(hostname, name);
2.24      frystyk   359:     {
                    360:        char *strptr = strchr(hostname, '.');
                    361:        if (strptr != NULL)                                /* We have it all */
                    362:            got_it = YES;
                    363:     }
2.16      frystyk   364: 
2.52      frystyk   365: #ifndef NO_RESOLV_CONF
2.18      frystyk   366:     /* Now try the resolver config file */
2.24      frystyk   367:     if (!got_it && (fp = fopen(RESOLV_CONF, "r")) != NULL) {
2.18      frystyk   368:        char buffer[80];
                    369:        *(buffer+79) = '\0';
                    370:        while (fgets(buffer, 79, fp)) {
                    371:            if (!strncasecomp(buffer, "domain", 6)) {   
                    372:                char *domainstr = buffer+6;
                    373:                char *end;
                    374:                while (*domainstr == ' ' || *domainstr == '\t')
                    375:                    domainstr++;
                    376:                end = domainstr;
                    377:                while (*end && !isspace(*end))
                    378:                    end++;
                    379:                *end = '\0';
                    380:                if (*domainstr) {
                    381:                    StrAllocCat(hostname, ".");
                    382:                    StrAllocCat(hostname, domainstr);
                    383:                    got_it = YES;
                    384:                    break;
                    385:                }
                    386:            }
                    387:        }
                    388:        fclose(fp);
2.16      frystyk   389:     }
2.52      frystyk   390: #endif /* NO_RESOLV_CONF */
2.16      frystyk   391: 
2.52      frystyk   392: #ifndef NO_GETDOMAINNAME
2.18      frystyk   393:     /* If everything else has failed then try getdomainname */
                    394:     if (!got_it) {
                    395:        if (getdomainname(name, MAXHOSTNAMELEN)) {
2.27      frystyk   396:            if (PROT_TRACE)
2.36      frystyk   397:                fprintf(TDEST, "HostName.... Can't get domain name\n");
2.24      frystyk   398:            StrAllocCopy(hostname, "");
2.18      frystyk   399:            return NULL;
                    400:        }
                    401: 
                    402:        /* If the host name and the first part of the domain name are different
                    403:           then use the former as it is more exact (I guess) */
                    404:        if (strncmp(name, hostname, (int) strlen(hostname))) {
                    405:            char *domain = strchr(name, '.');
2.50      frystyk   406:            if (!domain)
                    407:                domain = name;
                    408:            StrAllocCat(hostname, domain);
2.18      frystyk   409:        }
2.16      frystyk   410:     }
2.36      frystyk   411: #endif /* NO_GETDOMAINNAME */
2.23      duns      412: 
2.24      frystyk   413:     {
                    414:        char *strptr = hostname;
                    415:        while (*strptr) {           
                    416:            *strptr = TOLOWER(*strptr);
                    417:            strptr++;
                    418:        }
                    419:        if (*(hostname+strlen(hostname)-1) == '.')    /* Remove trailing dot */
                    420:            *(hostname+strlen(hostname)-1) = '\0';
                    421:     }
2.52      frystyk   422: #endif /* NO_GETHOSTNAME */
                    423: 
2.27      frystyk   424:     if (PROT_TRACE)
2.36      frystyk   425:        fprintf(TDEST, "HostName.... Full host name is `%s\'\n", hostname);
2.18      frystyk   426:     return hostname;
2.13      frystyk   427: }
                    428: 
2.19      frystyk   429: 
2.32      frystyk   430: /*
                    431: **     Free the host name. Called from HTLibTerminate
                    432: */
                    433: PUBLIC void HTFreeHostName NOARGS
                    434: {
                    435:     FREE(hostname);
                    436: }
                    437: 
                    438: 
2.19      frystyk   439: /*                                                            HTSetMailAddress
                    440: **     Sets the current mail address plus host name and domain name.
                    441: **     If this is not set then the default approach is used using
2.27      frystyk   442: **     HTGetMailAddress(). If the argument is NULL or "" then HTGetMailAddress
                    443: **     returns NULL on a succeding request.
2.19      frystyk   444: */
                    445: PUBLIC void HTSetMailAddress ARGS1(char *, address)
                    446: {
2.27      frystyk   447:     if (!address || !*address)
                    448:        StrAllocCopy(mailaddress, "");
                    449:     else
2.19      frystyk   450:        StrAllocCopy(mailaddress, address);
2.27      frystyk   451:     if (TRACE)
2.36      frystyk   452:        fprintf(TDEST, "SetMailAdr.. Set mail address to `%s\'\n",
2.27      frystyk   453:                mailaddress);
2.19      frystyk   454: }
                    455: 
                    456: 
                    457: /*                                                            HTGetMailAddress
                    458: **
                    459: **     Get the mail address of the current user on the current host. The
                    460: **     domain name used is the one initialized in HTSetHostName or
                    461: **     HTGetHostName. The login name is determined using (ordered):
                    462: **
                    463: **             getlogin
                    464: **             getpwuid(getuid())
                    465: **
                    466: **     The weakness about the last attempt is if the user has multiple
                    467: **     login names each with the same user ID. If this fails as well then:
                    468: **
                    469: **             LOGNAME environment variable
                    470: **             USER environment variable
                    471: **
                    472: **     Returns NULL if error else pointer to static string
                    473: */
                    474: PUBLIC CONST char * HTGetMailAddress NOARGS
                    475: {
2.47      frystyk   476: #ifdef HT_REENTRANT
                    477:     char name[LOGNAME_MAX+1];                             /* For getlogin_r */
                    478: #endif
2.19      frystyk   479:     char *login;
                    480:     CONST char *domain;
                    481:     struct passwd *pw_info;
2.21      frystyk   482:     if (mailaddress) {
                    483:        if (*mailaddress)
                    484:            return mailaddress;
                    485:        else
                    486:            return NULL;       /* No luck the last time so we wont try again */
                    487:     }
2.23      duns      488: 
2.36      frystyk   489: #ifdef VMS
2.23      duns      490:     if ((login = (char *) cuserid(NULL)) == NULL) {
2.36      frystyk   491:         if (PROT_TRACE) fprintf(TDEST, "MailAddress. cuserid returns NULL\n");
                    492:     }
                    493: #else
2.40      frystyk   494: #ifdef WIN32 
2.41      frystyk   495:     login = getenv("USERNAME") ;
2.40      frystyk   496: #else 
2.41      frystyk   497: #ifdef _WINDOWS
2.36      frystyk   498:     login = "PCUSER";                            /* @@@ COULD BE BETTER @@@ */
2.51      frystyk   499: #else
                    500: #ifdef GUSI
                    501:     if ((login = getenv("LOGNAME")) == NULL) 
                    502:        login = "MACUSER";
2.36      frystyk   503: #else /* Unix like... */
2.47      frystyk   504: #ifdef HT_REENTRANT
                    505:     if ((login = (char *) getlogin_r(name, LOGNAME_MAX)) == NULL) {
                    506: #else
2.34      roeber    507:     if ((login = (char *) getlogin()) == NULL) {
2.47      frystyk   508: #endif
2.36      frystyk   509:        if (PROT_TRACE)
                    510:            fprintf(TDEST, "MailAddress. getlogin returns NULL\n");
                    511:        if ((pw_info = getpwuid(getuid())) == NULL) {
                    512:            if (PROT_TRACE)
                    513:                fprintf(TDEST, "MailAddress. getpwid returns NULL\n");
                    514:            if ((login = getenv("LOGNAME")) == NULL) {
                    515:                if (PROT_TRACE)
                    516:                    fprintf(TDEST, "MailAddress. LOGNAME not found\n");
                    517:                if ((login = getenv("USER")) == NULL) {
                    518:                    if (PROT_TRACE)
                    519:                        fprintf(TDEST,"MailAddress. USER not found\n");
                    520:                    return NULL;                /* I GIVE UP */
                    521:                }
                    522:            }
                    523:        } else
                    524:            login = pw_info->pw_name;
                    525:     }
2.51      frystyk   526: #endif /* GUSI */
                    527: #endif /* _WINDOWS */
                    528: #endif /* WIN32 */
                    529: #endif /* VMS */
2.34      roeber    530: 
2.19      frystyk   531:     if (login) {
                    532:        StrAllocCopy(mailaddress, login);
                    533:        StrAllocCat(mailaddress, "@");
                    534:        if ((domain = HTGetHostName()) != NULL)
                    535:            StrAllocCat(mailaddress, domain);
2.21      frystyk   536:        else {
                    537:            *mailaddress = '\0';
                    538:            return NULL;                        /* Domain name not available */
                    539:        }
2.19      frystyk   540:        return mailaddress;
                    541:     }
                    542:     return NULL;
                    543: }
2.32      frystyk   544: 
                    545: 
                    546: /*
                    547: **     Free the mail address. Called from HTLibTerminate
                    548: */
                    549: PUBLIC void HTFreeMailAddress NOARGS
                    550: {
                    551:     FREE(mailaddress);
                    552: }
                    553: 
2.19      frystyk   554: 
                    555: /* ------------------------------------------------------------------------- */
                    556: /*                   CONNECTION ESTABLISHMENT MANAGEMENT                    */
                    557: /* ------------------------------------------------------------------------- */
2.13      frystyk   558: 
                    559: /*                                                             HTDoConnect()
                    560: **
                    561: **     Note: Any port indication in URL, e.g., as `host:port' overwrites
2.54    ! frystyk   562: **     the default port value.
2.13      frystyk   563: **
2.40      frystyk   564: **     returns         HT_ERROR        Error has occured or interrupted
                    565: **                     HT_OK           if connected
                    566: **                     HT_WOULD_BLOCK  if operation would have blocked
2.13      frystyk   567: */
2.54    ! frystyk   568: PUBLIC int HTDoConnect (HTNet * net, char * url, u_short default_port)
2.13      frystyk   569: {
                    570:     int status;
                    571:     char *p1 = HTParse(url, "", PARSE_HOST);
                    572:     char *at_sign;
                    573:     char *host;
                    574: 
2.54    ! frystyk   575:     /* if there's an @ then use the stuff after it as a hostname */
        !           576:     if ((at_sign = strchr(p1, '@')) != NULL)
2.13      frystyk   577:        host = at_sign+1;
                    578:     else
                    579:        host = p1;
2.24      frystyk   580:     if (!*host) {
                    581:        HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_HOST,
                    582:                   NULL, 0, "HTDoConnect");
                    583:        free(p1);
2.40      frystyk   584:        return HT_ERROR;
2.27      frystyk   585:     }
2.13      frystyk   586: 
2.54    ! frystyk   587:     /* Look for a port number, else use default port */
        !           588:     if (net->sockfd == INVSOC) {
        !           589:        char *port = strchr(host, ':');
        !           590:        SockA *sin = &net->sock_addr;
        !           591:        memset((void *) sin, '\0', sizeof(SockA));
        !           592:        if (port++ && isdigit(*port)) {
        !           593: #ifdef DECNET
        !           594:            sin->sdn_family = AF_DECnet;      /* Family = DECnet, host order */
        !           595:            sin->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10));
        !           596: #else /* Internet */
        !           597:            sin->sin_family = AF_INET;
        !           598:            sin->sin_port = htons(atol(port));
        !           599: #endif
        !           600:        } else {
2.13      frystyk   601: #ifdef DECNET
2.54    ! frystyk   602:            sin->sdn_family = AF_DECnet;      /* Family = DECnet, host order */
        !           603:            net->sock_addr.sdn_objnum = DNP_OBJ; /* Default: http object num */
2.13      frystyk   604: #else  /* Internet */
2.54    ! frystyk   605:            sin->sin_family = AF_INET;
        !           606:            sin->sin_port = htons(default_port);
2.13      frystyk   607: #endif
2.54    ! frystyk   608:        }
2.27      frystyk   609:     }
2.54    ! frystyk   610: 
2.24      frystyk   611:     /* If we are trying to connect to a multi-homed host then loop here until
                    612:        success or we have tried all IP-addresses */
                    613:     do {
2.54    ! frystyk   614:        BOOL reuse = NO;
2.36      frystyk   615:        if (net->sockfd==INVSOC) {
2.54    ! frystyk   616:            int homes;
2.44      frystyk   617:            if (PROT_TRACE)
                    618:                fprintf(TDEST, "HTDoConnect. Looking up `%s\'\n", host);
2.54    ! frystyk   619:            if ((homes = HTParseInet(net, host)) < 0) {
2.27      frystyk   620:                if (PROT_TRACE)
2.36      frystyk   621:                    fprintf(TDEST, "HTDoConnect. Can't locate remote host `%s\'\n", host);
2.27      frystyk   622:                HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
                    623:                           (void *) host, strlen(host), "HTDoConnect");
                    624:                break;
2.54    ! frystyk   625:            } else if (!homes)
        !           626:                return HT_PERSISTENT;
        !           627: 
        !           628:            if (net->sockfd != INVSOC) {
        !           629:                reuse = YES;
        !           630:                if (PROT_TRACE)
        !           631:                    fprintf(TDEST, "HTDoConnect. REUSING SOCKET %d\n", net->sockfd);
        !           632:                goto connect;
2.41      frystyk   633:            }
2.54    ! frystyk   634:            if (!net->retry && homes > 1)
        !           635:                net->retry = homes;
2.27      frystyk   636: #ifdef DECNET
2.36      frystyk   637:            if ((net->sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC)
2.27      frystyk   638: #else
2.36      frystyk   639:            if ((net->sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVSOC)
2.27      frystyk   640: #endif
                    641:            {
2.36      frystyk   642:                HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, "socket");
2.27      frystyk   643:                break;
                    644:            }
                    645:            if (PROT_TRACE)
2.36      frystyk   646:                fprintf(TDEST, "HTDoConnect. Created socket number %d\n",
2.27      frystyk   647:                        net->sockfd);
                    648: 
2.28      frystyk   649:            /* If non-blocking protocol then change socket status
2.50      frystyk   650:            ** I use FCNTL so that I can ask the status before I set it.
                    651:            ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)
                    652:            ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()
                    653:            ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and
                    654:            ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
                    655:            */
2.53      frystyk   656:            if (!net->preemtive) {
2.41      frystyk   657: #ifdef _WINDOWS 
                    658:                {               /* begin windows scope  */
                    659:                    HTRequest * rq = net->request;
                    660:                    long levents = FD_READ | FD_WRITE | FD_ACCEPT | 
                    661:                        FD_CONNECT | FD_CLOSE ;
                    662:                    int rv = 0 ;
                    663:                                    
                    664: #ifndef _WIN32                 
                    665:                    if (net->request->hwnd == 0) {
                    666:                                        
                    667:                    }
                    668: #endif 
                    669:                    /* N.B WSAAsyncSelect() turns on non-blocking I/O */
                    670: 
                    671:                    if (net->request->hwnd != 0) {
                    672:                        rv = WSAAsyncSelect( net->sockfd, rq->hwnd, 
                    673:                                            rq->winMsg, levents);
                    674:                        if (rv == SOCKET_ERROR) {
                    675:                            status = -1 ;
                    676:                            if (PROT_TRACE) 
                    677:                                fprintf(TDEST, 
                    678:                                        "HTDoConnect: WSAAsyncSelect() fails: %d\n", 
                    679:                                        WSAGetLastError());
                    680:                        } /* error returns */
                    681:                    } else {
                    682:                        int enable = 1 ;
                    683:                        status = IOCTL(net->sockfd, FIONBIO, &enable);
                    684:                    }
                    685:                } /* end scope */
                    686: #else 
                    687: #if defined(VMS)
2.36      frystyk   688:                {
                    689:                    int enable = 1;
                    690:                    status = IOCTL(net->sockfd, FIONBIO, &enable);
                    691:                }
                    692: #else
2.27      frystyk   693:                if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.41      frystyk   694:                    status |= O_NONBLOCK; /* POSIX */
2.27      frystyk   695:                    status = FCNTL(net->sockfd, F_SETFL, status);
                    696:                }
2.41      frystyk   697: #endif /* VMS */
                    698: #endif /* WINDOW */
2.43      frystyk   699:                if (PROT_TRACE) {
                    700:                    if (status == -1)
                    701:                        fprintf(TDEST, "HTDoConnect. Can't make socket non-blocking\n");
                    702:                    else
                    703:                        fprintf(TDEST, "HTDoConnect. Using NON_BLOCKING I/O\n");
                    704:                }
2.27      frystyk   705:            }
                    706:            
                    707:            /* If multi-homed host then start timer on connection */
2.54    ! frystyk   708:            if (net->retry)
2.27      frystyk   709:                net->connecttime = time(NULL);
2.50      frystyk   710: 
                    711:            /* Update progress state */
                    712:            HTProgress(net->request, HT_PROG_CONNECT, NULL);
2.54    ! frystyk   713:        }
        !           714: 
2.27      frystyk   715:        /* Do a connect */
2.54    ! frystyk   716:       connect:
2.27      frystyk   717:        status = connect(net->sockfd, (struct sockaddr *) &net->sock_addr,
                    718:                         sizeof(net->sock_addr));
                    719:        /*
                    720:         * According to the Sun man page for connect:
                    721:         *     EINPROGRESS         The socket is non-blocking and the  con-
                    722:         *                         nection cannot be completed immediately.
                    723:         *                         It is possible to select(2) for  comple-
                    724:         *                         tion  by  selecting the socket for writ-
                    725:         *                         ing.
                    726:         * According to the Motorola SVR4 man page for connect:
                    727:         *     EAGAIN              The socket is non-blocking and the  con-
                    728:         *                         nection cannot be completed immediately.
                    729:         *                         It is possible to select for  completion
                    730:         *                         by  selecting  the  socket  for writing.
                    731:         *                         However, this is only  possible  if  the
                    732:         *                         socket  STREAMS  module  is  the topmost
                    733:         *                         module on  the  protocol  stack  with  a
                    734:         *                         write  service  procedure.  This will be
                    735:         *                         the normal case.
                    736:         */
2.41      frystyk   737:        
2.27      frystyk   738: #ifdef EAGAIN
2.36      frystyk   739:        if ((status < 0) && ((socerrno==EINPROGRESS) || (socerrno==EAGAIN)))
2.41      frystyk   740: #else 
2.40      frystyk   741: #ifdef WSAEWOULDBLOCK     /* WinSock API */
                    742:        if ((status == SOCKET_ERROR) && (socerrno == WSAEWOULDBLOCK))
                    743: #else
2.41      frystyk   744:        if ((status < 0) && (socerrno == EINPROGRESS))
                    745: #endif /* WSAEWOULDBLOCK */
2.27      frystyk   746: #endif /* EAGAIN */
2.24      frystyk   747:        {
2.27      frystyk   748:            if (PROT_TRACE)
2.36      frystyk   749:                fprintf(TDEST, "HTDoConnect. WOULD BLOCK `%s'\n", host);
2.53      frystyk   750:            HTEvent_Register(net->sockfd, net->request, (SockOps) FD_CONNECT,
                    751:                             net->cbf, net->priority);
2.27      frystyk   752:            free(p1);
                    753:            return HT_WOULD_BLOCK;
2.24      frystyk   754:        }
2.41      frystyk   755:        
                    756:        /* We have 4 situations: single OK, Pb and multi OK, pb */
2.54    ! frystyk   757:        if (net->retry) {
2.48      frystyk   758:            net->connecttime = time(NULL) - net->connecttime;
2.41      frystyk   759:            if (status < 0) {                                    /* multi PB */
                    760:                if (socerrno == EISCONN) { /* connect multi after would block*/
2.53      frystyk   761:                    HTEvent_UnRegister(net->sockfd, (SockOps) FD_CONNECT);
2.54    ! frystyk   762:                    HTDNS_updateWeigths(net->dns, net->home, net->connecttime);
        !           763:                    net->retry = 0;
2.27      frystyk   764:                    free(p1);
2.40      frystyk   765:                    return HT_OK;
2.27      frystyk   766:                }
2.54    ! frystyk   767:                if (reuse)
        !           768:                    HTDNS_setSocket(net->dns, INVSOC);
        !           769:                else  {
        !           770:                    HTErrorSysAdd(net->request, ERR_NON_FATAL, socerrno, NO,
        !           771:                                  "connect");
        !           772:                    
        !           773:                    /* Added EINVAL `invalid argument' as this is what I 
        !           774:                       get back from a non-blocking connect where I should 
        !           775:                       get `connection refused' on BSD. SVR4 gives SIG_PIPE */
        !           776:                    if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT ||
        !           777:                        socerrno==ENETUNREACH || socerrno==EHOSTUNREACH ||
2.36      frystyk   778: #ifdef __srv4__
2.54    ! frystyk   779:                        socerrno==EHOSTDOWN || socerrno==EINVAL)
2.36      frystyk   780: #else
2.54    ! frystyk   781:                        socerrno==EHOSTDOWN)
2.35      roeber    782: #endif
2.54    ! frystyk   783:                        net->connecttime += TCP_DELAY;
        !           784:                    else
        !           785:                        net->connecttime += TCP_PENALTY;
        !           786:                }
        !           787:                if (NETCLOSE(net->sockfd) < 0)
        !           788:                    HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, 
        !           789:                                  "NETCLOSE");
2.53      frystyk   790:                HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
2.41      frystyk   791:                net->sockfd = INVSOC;
2.54    ! frystyk   792:                HTDNS_updateWeigths(net->dns, net->home, net->connecttime);
2.41      frystyk   793:            } else {                                             /* multi OK */
2.54    ! frystyk   794:                HTDNS_updateWeigths(net->dns, net->home, net->connecttime);
        !           795:                net->retry = 0;
2.27      frystyk   796:                free(p1);
2.40      frystyk   797:                return HT_OK;
2.27      frystyk   798:            }
2.41      frystyk   799:         } else if (status < 0) {                               /* single PB */
                    800:            if (socerrno==EISCONN) {     /* Connect single after would block */
2.53      frystyk   801:                HTEvent_UnRegister(net->sockfd, (SockOps) FD_CONNECT);
2.54    ! frystyk   802:                net->retry = 0;
2.27      frystyk   803:                free(p1);
2.40      frystyk   804:                return HT_OK;
2.24      frystyk   805:            } else {
2.36      frystyk   806:                HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO,
2.41      frystyk   807:                          "connect");
2.54    ! frystyk   808:                HTDNS_delete(host);
2.27      frystyk   809:                if (NETCLOSE(net->sockfd) < 0)
2.36      frystyk   810:                    HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO,
                    811:                                  "NETCLOSE");
2.53      frystyk   812:                HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
2.24      frystyk   813:                break;
                    814:            }
2.41      frystyk   815:        } else {                                                /* single OK */
2.27      frystyk   816:            free(p1);
2.54    ! frystyk   817:            net->retry = 0;
2.40      frystyk   818:            return HT_OK;
2.24      frystyk   819:        }
2.54    ! frystyk   820:     } while (--net->retry);                             /* End of mega loop */
2.13      frystyk   821: 
2.27      frystyk   822:     if (PROT_TRACE)
2.41      frystyk   823:         fprintf(TDEST, "HTDoConnect. Connect failed\n");
2.24      frystyk   824:     free (p1);
2.54    ! frystyk   825:     net->retry = 0;
2.36      frystyk   826:     net->sockfd = INVSOC;
2.40      frystyk   827:     return HT_ERROR;
2.13      frystyk   828: }
                    829: 
                    830: 
                    831: /*                                                             HTDoAccept()
                    832: **
                    833: **     This function makes a non-blocking accept on a port and polls every
                    834: **     second until MAX_ACCEPT_POLL or interrupted by user.
                    835: **
                    836: **     BUGS Interrupted is not yet implemented!!!
                    837: **
2.27      frystyk   838: **     Returns  HT_WOULD_BLOCK         if waiting
                    839: **              0              if OK,
                    840: **              -1             on error
2.13      frystyk   841: */
2.53      frystyk   842: PUBLIC int HTDoAccept ARGS1(HTNet *, net)
2.13      frystyk   843: {
                    844:     SockA soc_address;                         /* SockA is defined in tcp.h */
                    845:     int status;
                    846:     int cnt;
                    847:     int soc_addrlen = sizeof(soc_address);
2.36      frystyk   848:     if (net->sockfd==INVSOC) {
                    849:        if (PROT_TRACE) fprintf(TDEST, "HTDoAccept.. Bad socket number\n");
2.13      frystyk   850:        return -1;
                    851:     }
2.27      frystyk   852: 
2.13      frystyk   853:     /* First make the socket non-blocking */
2.36      frystyk   854: #if defined(_WINDOWS) || defined(VMS)
2.23      duns      855:     {
2.36      frystyk   856:        int enable = 1;         /* Need the variable! */
                    857:        status = IOCTL(net->sockfd, FIONBIO, enable);
2.23      duns      858:     }
2.36      frystyk   859: #else
2.15      frystyk   860:     if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
2.36      frystyk   861:        status |= O_NONBLOCK;   /* POSIX */
2.15      frystyk   862:        status = FCNTL(net->sockfd, F_SETFL, status);
2.13      frystyk   863:     }
2.36      frystyk   864: #endif
2.13      frystyk   865:     if (status == -1) {
2.36      frystyk   866:        HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, "IOCTL");
2.13      frystyk   867:        return -1;
                    868:     }
                    869: 
                    870:     /* Now poll every sekund */
                    871:     for(cnt=0; cnt<MAX_ACCEPT_POLL; cnt++) {
2.15      frystyk   872:        if ((status = accept(net->sockfd, (struct sockaddr*) &soc_address,
2.36      frystyk   873:                             &soc_addrlen)) != INVSOC) {
                    874:            if (PROT_TRACE) fprintf(TDEST,
2.13      frystyk   875:                               "HTDoAccept.. Accepted new socket %d\n", 
                    876:                               status);
                    877:            return status;
                    878:        } else
2.36      frystyk   879:            HTErrorSysAdd(net->request, ERR_WARN, socerrno, YES, "accept");
2.38      frystyk   880:        SLEEP(1);
                    881:     }
2.13      frystyk   882:     
                    883:     /* If nothing has happened */    
2.27      frystyk   884:     if (PROT_TRACE)
2.36      frystyk   885:        fprintf(TDEST, "HTDoAccept.. Timed out, no connection!\n");
2.15      frystyk   886:     HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0,
                    887:               "HTDoAccept");
2.13      frystyk   888:     return -1;
1.1       timbl     889: }
2.27      frystyk   890: 
1.1       timbl     891: 

Webmaster