diff options
Diffstat (limited to 'WWW/Library/Implementation')
-rw-r--r-- | WWW/Library/Implementation/HTFTP.c | 176 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTTCP.c | 274 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTTCP.h | 13 | ||||
-rw-r--r-- | WWW/Library/Implementation/www_tcp.h | 9 |
4 files changed, 458 insertions, 14 deletions
diff --git a/WWW/Library/Implementation/HTFTP.c b/WWW/Library/Implementation/HTFTP.c index 2c01085a..e725080a 100644 --- a/WWW/Library/Implementation/HTFTP.c +++ b/WWW/Library/Implementation/HTFTP.c @@ -1079,8 +1079,15 @@ PRIVATE int close_master_socket NOARGS */ PRIVATE int get_listen_socket NOARGS { +#ifdef INET6 + struct sockaddr_storage soc_address; /* Binary network address */ + struct sockaddr_in* soc_in = (struct sockaddr_in *)&soc_address; + int af; + int slen; +#else struct sockaddr_in soc_address; /* Binary network address */ struct sockaddr_in* soc_in = &soc_address; +#endif /* INET6 */ int new_socket; /* Will be master_socket */ @@ -1092,9 +1099,24 @@ PRIVATE int get_listen_socket NOARGS return master_socket; /* Done already */ #endif /* !REPEAT_LISTEN */ +#ifdef INET6 + /* query address family of control connection */ + slen = sizeof(soc_address); + if (getsockname(control->socket, (struct sockaddr *)&soc_address, + &slen) < 0) { + return HTInetStatus("getsockname failed"); + } + af = ((struct sockaddr *)&soc_address)->sa_family; + memset(&soc_address, 0, sizeof(soc_address)); +#endif /* INET6 */ + /* Create internet socket */ +#ifdef INET6 + new_socket = socket(af, SOCK_STREAM, IPPROTO_TCP); +#else new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +#endif /* INET6 */ if (new_socket < 0) return HTInetStatus(gettext("socket for master socket")); @@ -1103,8 +1125,27 @@ PRIVATE int get_listen_socket NOARGS /* Search for a free port. */ +#ifdef INET6 + memset(&soc_address, 0, sizeof(soc_address)); + ((struct sockaddr *)&soc_address)->sa_family = af; + switch (af) { + case AF_INET: +#ifdef SIN6_LEN + ((struct sockaddr *)&soc_address)->sa_len = sizeof(struct sockaddr_in); +#endif /* SIN6_LEN */ + break; + case AF_INET6: +#ifdef SIN6_LEN + ((struct sockaddr *)&soc_address)->sa_len = sizeof(struct sockaddr_in6); +#endif /* SIN6_LEN */ + break; + default: + HTInetStatus("AF"); + } +#else soc_in->sin_family = AF_INET; /* Family = internet, host order */ soc_in->sin_addr.s_addr = INADDR_ANY; /* Any peer address */ +#endif /* INET6 */ #ifdef POLL_PORTS { unsigned short old_port_number = port_number; @@ -1115,15 +1156,31 @@ PRIVATE int get_listen_socket NOARGS if (port_number == old_port_number) { return HTInetStatus("bind"); } +#ifdef INET6 + soc_in->sin_port = htons(port_number); +#else soc_address.sin_port = htons(port_number); +#endif /* INET6 */ #ifdef SOCKS if (socks_flag) if ((status=Rbind(new_socket, (struct sockaddr*)&soc_address, /* Cast to generic sockaddr */ +#ifdef INET6 +#ifdef SIN6_LEN + ((struct sockaddr *)&soc_address)->sa_len, +#else + SA_LEN((struct sockaddr *)&soc_address), +#endif /* SIN6_LEN */ +#else sizeof(soc_address) +#endif /* INET6 */ #ifndef SHORTENED_RBIND +#ifdef INET6 + socks_bind_remoteAddr +#else ,socks_bind_remoteAddr +#endif /* INET6 */ #endif /* !SHORTENED_RBIND */ )) == 0) { break; @@ -1132,7 +1189,16 @@ PRIVATE int get_listen_socket NOARGS if ((status=bind(new_socket, (struct sockaddr*)&soc_address, /* Cast to generic sockaddr */ +#ifdef INET6 +#ifdef SIN6_LEN + ((struct sockaddr *)&soc_address)->sa_len +#else + SA_LEN((struct sockaddr *)&soc_address) +#endif /* SIN6_LEN */ + )) == 0) { +#else sizeof(soc_address))) == 0) { +#endif /* INET6 */ break; } CTRACE((tfp, "TCP bind attempt to port %d yields %d, errno=%d\n", @@ -1154,10 +1220,17 @@ PRIVATE int get_listen_socket NOARGS (struct sockaddr *)&soc_address, (void *)&address_length); if (status<0) return HTInetStatus("getsockname"); +#ifdef INET6 + CTRACE((tfp, "HTFTP: This host is %s\n", + HTInetString((SockA *)soc_in))); + + soc_in->sin_port = 0; /* Unspecified: please allocate */ +#else CTRACE((tfp, "HTFTP: This host is %s\n", HTInetString(soc_in))); soc_address.sin_port = 0; /* Unspecified: please allocate */ +#endif /* INET6 */ #ifdef SOCKS if (socks_flag) status=Rbind(new_socket, @@ -1165,7 +1238,11 @@ PRIVATE int get_listen_socket NOARGS /* Cast to generic sockaddr */ sizeof(soc_address) #ifndef SHORTENED_RBIND +#ifdef INET6 + socks_bind_remoteAddr +#else ,socks_bind_remoteAddr +#endif /* INET6 */ #endif /* !SHORTENED_RBIND */ ); else @@ -1173,7 +1250,16 @@ PRIVATE int get_listen_socket NOARGS status=bind(new_socket, (struct sockaddr*)&soc_address, /* Cast to generic sockaddr */ +#ifdef INET6 +#ifdef SIN6_LEN + ((struct sockaddr *)&soc_address)->sa_len +#else + SA_LEN((struct sockaddr *)&soc_address) +#endif /* SIN6_LEN */ + ); +#else sizeof(soc_address)); +#endif /* INET6 */ if (status<0) return HTInetStatus("bind"); address_length = sizeof(soc_address); @@ -1191,9 +1277,15 @@ PRIVATE int get_listen_socket NOARGS } #endif /* POLL_PORTS */ +#ifdef INET6 + CTRACE((tfp, "HTFTP: bound to port %d on %s\n", + (int)ntohs(soc_in->sin_port), + HTInetString((SockA *)soc_in))); +#else CTRACE((tfp, "HTFTP: bound to port %d on %s\n", (int)ntohs(soc_in->sin_port), HTInetString(soc_in))); +#endif /* INET6 */ #ifdef REPEAT_LISTEN if (master_socket >= 0) @@ -1205,7 +1297,13 @@ PRIVATE int get_listen_socket NOARGS /* Now we must find out who we are to tell the other guy */ (void)HTHostName(); /* Make address valid - doesn't work*/ +#ifdef INET6 + switch (((struct sockaddr *)&soc_address)->sa_family) { + case AF_INET: + sprintf(port_command, "PORT %d,%d,%d,%d,%d,%d%c%c", +#else sprintf(port_command, "PORT %d,%d,%d,%d,%d,%d%c%c", +#endif /* INET6 */ (int)*((unsigned char *)(&soc_in->sin_addr)+0), (int)*((unsigned char *)(&soc_in->sin_addr)+1), (int)*((unsigned char *)(&soc_in->sin_addr)+2), @@ -1214,6 +1312,30 @@ PRIVATE int get_listen_socket NOARGS (int)*((unsigned char *)(&soc_in->sin_port)+1), CR, LF); +#ifdef INET6 + break; + + case AF_INET6: + { + char hostbuf[MAXHOSTNAMELEN]; + char portbuf[MAXHOSTNAMELEN]; + getnameinfo((struct sockaddr *)&soc_address, +#ifdef SIN6_LEN + ((struct sockaddr *)&soc_address)->sa_len, +#else + SA_LEN((struct sockaddr *)&soc_address), +#endif /* SIN6_LEN */ + hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV); + sprintf(port_command, "EPRT |%d|%s|%s|%c%c", 2, hostbuf, portbuf, + CR, LF); + break; + } + default: + sprintf(port_command, "JUNK%c%c", CR, LF); + break; + } +#endif /* INET6 */ /* Inform TCP that we will accept connections */ @@ -2871,7 +2993,12 @@ PUBLIC int HTFTPLoad ARGS4( if (status < 0) { NETCLOSE (control->socket); control->socket = -1; +#ifdef INET6 + if (master_socket >= 0) + (void)close_master_socket (); +#else close_master_socket (); +#endif /* INET6 */ /* HT_INTERRUPTED would fall through, if we could interrupt somehow in the middle of it, which we currently can't. */ return status; @@ -2903,6 +3030,50 @@ PUBLIC int HTFTPLoad ARGS4( data_soc = status; +#ifdef INET6 + status = send_cmd_1("EPSV"); + if (status < 0) /* retry or Bad return */ + continue; + else if (status != 2) { + status = send_cmd_1("PASV"); + if (status < 0) /* retry or Bad return */ + continue; + else if (status != 2) { + return -status; /* bad reply */ + } + } + + if (strncmp(command, "PASV", 4) == 0) { + for (p = response_text; *p && *p != ','; p++) + ; /* null body */ + + while (--p > response_text && '0' <= *p && *p <= '9') + ; /* null body */ + status = sscanf(p+1, "%d,%d,%d,%d,%d,%d", + &h0, &h1, &h2, &h3, &p0, &p1); + if (status < 4) { + fprintf(tfp, "HTFTP: PASV reply has no inet address!\n"); + return -99; + } + passive_port = (p0<<8) + p1; + } else if (strncmp(command, "EPSV", 4) == 0) { + char ch; + /* + * EPSV |||port| + */ + for (p = response_text; *p && !isspace(*p); p++) + ; /* null body */ + for (p = response_text; *p && isspace(*p); p++) + ; /* null body */ + status = sscanf(p+1, "%c%c%c%d%c", + &h0, &h1, &h2, &p0, &h3); + if (status != 5) { + fprintf(tfp, "HTFTP: EPSV reply has invalid format!\n"); + return -99; + } + passive_port = p0; + } +#else status = send_cmd_1("PASV"); if (status != 2) { if (status < 0) @@ -2922,6 +3093,7 @@ PUBLIC int HTFTPLoad ARGS4( return -99; } passive_port = (p0<<8) + p1; +#endif /* INET6 */ CTRACE((tfp, "HTFTP: Server is listening on port %d\n", passive_port)); @@ -3423,7 +3595,11 @@ PUBLIC int HTFTPLoad ARGS4( listen: if(!ftp_passive) { /* Wait for the connection */ +#ifdef INET6 + struct sockaddr_storage soc_address; +#else struct sockaddr_in soc_address; +#endif /* INET6 */ int soc_addrlen=sizeof(soc_address); #ifdef SOCKS if (socks_flag) diff --git a/WWW/Library/Implementation/HTTCP.c b/WWW/Library/Implementation/HTTCP.c index 70cee43f..859a6734 100644 --- a/WWW/Library/Implementation/HTTCP.c +++ b/WWW/Library/Implementation/HTTCP.c @@ -299,6 +299,17 @@ PUBLIC unsigned int HTCardinal ARGS3( PUBLIC CONST char * HTInetString ARGS1( SockA*, soc_in) { +#ifdef INET6 + static char hostbuf[MAXHOSTNAMELEN]; + getnameinfo((struct sockaddr *)soc_in, +#ifdef SIN6_LEN + ((struct sockaddr *)soc_in)->sa_len, +#else + SA_LEN((struct sockaddr *)soc_in), +#endif /* SIN6_LEN */ + hostbuf, sizeof(hostbuf), NULL, 0, NI_NUMERICHOST); + return hostbuf; +#else static char string[16]; sprintf(string, "%d.%d.%d.%d", (int)*((unsigned char *)(&soc_in->sin_addr)+0), @@ -306,6 +317,7 @@ PUBLIC CONST char * HTInetString ARGS1( (int)*((unsigned char *)(&soc_in->sin_addr)+2), (int)*((unsigned char *)(&soc_in->sin_addr)+3)); return string; +#endif /* INET6 */ } #endif /* !DECNET */ @@ -719,7 +731,12 @@ PUBLIC struct hostent * LYGetHostByName ARGS1( ** control variables. */ pid_t fpid, waitret; - int pfd[2], selret, readret, waitstat = 0; + int pfd[2], selret, readret; +#ifdef HAVE_TYPE_UNIONWAIT + union wait waitstat; +#else + int waitstat = 0; +#endif time_t start_time = time((time_t *)0); fd_set readfds; struct timeval timeout; @@ -999,10 +1016,18 @@ PUBLIC struct hostent * LYGetHostByName ARGS1( ** Make sure child is cleaned up. -BL */ if (!child_exited) +#ifdef HAVE_TYPE_UNIONWAIT + waitret = waitpid(fpid, &waitstat.w_status, WNOHANG); +#else waitret = waitpid(fpid, &waitstat, WNOHANG); +#endif if (!WIFEXITED(waitstat) && !WIFSIGNALED(waitstat)) { kill(fpid, SIGTERM); +#ifdef HAVE_TYPE_UNIONWAIT + waitret = waitpid(fpid, &waitstat.w_status, WNOHANG); +#else waitret = waitpid(fpid, &waitstat, WNOHANG); +#endif } break; } @@ -1011,13 +1036,21 @@ PUBLIC struct hostent * LYGetHostByName ARGS1( ** Clean up if child exited before & no data received. -BL */ if (child_exited) { +#ifdef HAVE_TYPE_UNIONWAIT + waitret = waitpid(fpid, &waitstat.w_status, WNOHANG); +#else waitret = waitpid(fpid, &waitstat, WNOHANG); +#endif break; } /* ** If child exited, loop once more looking for data. -BL */ +#ifdef HAVE_TYPE_UNIONWAIT + if ((waitret = waitpid(fpid, &waitstat.w_status, WNOHANG)) > 0) { +#else if ((waitret = waitpid(fpid, &waitstat, WNOHANG)) > 0) { +#endif /* ** Data will be arriving right now, so make sure we ** don't short-circuit out for too many loops, and @@ -1046,8 +1079,13 @@ PUBLIC struct hostent * LYGetHostByName ARGS1( } if (waitret > 0) { if (WIFEXITED(waitstat)) { +#ifdef HAVE_TYPE_UNIONWAIT CTRACE((tfp, "LYGetHostByName: NSL_FORK child %d exited, status 0x%x.\n", - (int)waitret, waitstat)); + (int)waitret, waitstat.w_status)); +#else + CTRACE((tfp, "LYGetHostByName: NSL_FORK child %d exited, status 0x%x.\n", + (int)waitret, waitstat)); +#endif } else if (WIFSIGNALED(waitstat)) { CTRACE((tfp, "LYGetHostByName: NSL_FORK child %d got signal, status 0x%x!\n", (int)waitret, waitstat)); @@ -1058,8 +1096,13 @@ PUBLIC struct hostent * LYGetHostByName ARGS1( } #endif /* WCOREDUMP */ } else if (WIFSTOPPED(waitstat)) { - CTRACE((tfp, "LYGetHostByName: NSL_FORK child %d is stopped, status 0x%x!\n", - (int)waitret, waitstat)); +#ifdef HAVE_TYPE_UNIONWAIT + CTRACE((tfp, "LYGetHostByName: NSL_FORK child %d is stopped, status 0x%x!\n", + (int)waitret, waitstat.w_status)); +#else + CTRACE((tfp, "LYGetHostByName: NSL_FORK child %d is stopped, status 0x%x!\n", + (int)waitret, waitstat)); +#endif } } if (!got_rehostent) { @@ -1157,10 +1200,19 @@ failed: ** *soc_in is filled in. If no port is specified in str, that ** field is left unchanged in *soc_in. */ +#ifdef INET6 +PUBLIC int HTParseInet ARGS3( + SockA *, soc_in, + CONST char *, str, + int, default_port) +{ + char portstr[NI_MAXSERV]; +#else PUBLIC int HTParseInet ARGS2( SockA *, soc_in, CONST char *, str) { +#endif /* INET6 */ char *port; int dotcount_ip = 0; /* for dotted decimal IP addr */ char *strptr; @@ -1185,6 +1237,19 @@ PUBLIC int HTParseInet ARGS2( /* ** Parse port number if present. */ +#ifdef INET6 + if (!strrchr(host, ']')) + port = strrchr(host, ':'); + else + port = strrchr(strrchr(host, ']'), ':'); + + if (port) { + *port++ = 0; /* Chop off port */ + } + else { + sprintf(portstr,"%d", default_port); + port = portstr; +#else if ((port = strchr(host, ':')) != NULL) { *port++ = 0; /* Chop off port */ strptr = port; @@ -1215,6 +1280,7 @@ PUBLIC int HTParseInet ARGS2( HTAlwaysAlert(NULL, gettext("Address has invalid port")); return -1; } +#endif /* INET6 */ } #ifdef DECNET @@ -1228,6 +1294,13 @@ PUBLIC int HTParseInet ARGS2( soc_in->sdn_objnum, host)); #else /* parse Internet host: */ +#ifdef INET6 + /* [host] case */ + if (host[0] == '[' && host[strlen(host) - 1] == ']') { + host[strlen(host) - 1] = '\0'; + host++; + } +#else if (*host >= '0' && *host <= '9') { /* Test for numeric node address: */ strptr = host; while (*strptr) { @@ -1246,7 +1319,8 @@ PUBLIC int HTParseInet ARGS2( /* ** Parse host number if present. */ - if (dotcount_ip == 3) { /* Numeric node address: */ + if (dotcount_ip == 3) /* Numeric node address: */ + { #if defined(__DJGPP__) && !defined(WATT32) soc_in->sin_addr.s_addr = htonl(aton(host)); @@ -1274,7 +1348,9 @@ PUBLIC int HTParseInet ARGS2( #ifndef _WINDOWS_NSL FREE(host); #endif /* _WINDOWS_NSL */ - } else { /* Alphanumeric node name: */ + } else +#endif /* INET6 */ + { /* Alphanumeric node name: */ #ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */ CTRACE((tfp, "HTParseInet: Calling LYGetHostByName(%s)\n", host)); @@ -1296,10 +1372,25 @@ PUBLIC int HTParseInet ARGS2( memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length); #else /* !(__DJGPP__ && !WATT32) && !_WINDOWS_NSL */ { +#ifdef INET6 + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + error = getaddrinfo(host, port, &hints, &res); + + if (error || !res) { + CTRACE((tfp, "HTParseInet: getaddrinfo(%s): %s\n", host, + gai_strerror(error))); + goto failed; + } +#else struct hostent *phost; phost = LYGetHostByName(host); /* See above */ if (!phost) goto failed; +#endif /* INET6 */ #if defined(VMS) && defined(CMU_TCP) /* ** In LIBCMU, phost->h_length contains not the length of one address @@ -1309,14 +1400,32 @@ PUBLIC int HTParseInet ARGS2( ** longer supported, and CMU users are encouraged to obtain and use ** SOCKETSHR/NETLIB instead. - S. Bjorndahl */ +#ifdef INET6 + if (res->ai_family == AF_INET) { + memcpy((void *)&soc_in->sin_addr, + &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4); + } else { + CTRACE(tfp, "HTParseInet: unsupported address family %d\n", + res->ai_family); + goto failed; + } +#else memcpy((void *)&soc_in->sin_addr, phost->h_addr, 4); +#endif /* INET6 */ +#else +#ifdef INET6 + memcpy((void *)soc_in, res->ai_addr, res->ai_addrlen); #else if (!phost) goto failed; if (phost->h_length != sizeof soc_in->sin_addr) { HTAlwaysAlert(host, gettext("Address length looks invalid")); } memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length); +#endif /* INET6 */ #endif /* VMS && CMU_TCP */ +#ifdef INET6 + freeaddrinfo(res); +#endif /* INET6 */ } #endif /* _WINDOWS_NSL */ #endif /* __DJGPP__ && !WATT32 */ @@ -1326,12 +1435,14 @@ PUBLIC int HTParseInet ARGS2( } /* Alphanumeric node name */ +#ifndef INET6 CTRACE((tfp, "HTParseInet: Parsed address as port %d, IP address %d.%d.%d.%d\n", (int)ntohs(soc_in->sin_port), (int)*((unsigned char *)(&soc_in->sin_addr)+0), (int)*((unsigned char *)(&soc_in->sin_addr)+1), (int)*((unsigned char *)(&soc_in->sin_addr)+2), (int)*((unsigned char *)(&soc_in->sin_addr)+3))); +#endif /* !INET6 */ #endif /* Internet vs. Decnet */ return 0; /* OK */ @@ -1343,13 +1454,57 @@ failed: FREE(host); #endif /* _WINDOWS_NSL */ switch (lynx_nsl_status) { - case HT_NOT_ACCEPTABLE: - case HT_INTERRUPTED: - return lynx_nsl_status; - default: - return -1; + case HT_NOT_ACCEPTABLE: + case HT_INTERRUPTED: + return lynx_nsl_status; + default: + return -1; + } } + +#ifdef INET6 +PRIVATE struct addrinfo * +HTGetAddrInfo ARGS2( + CONST char *, str, + CONST int, defport) +{ + struct addrinfo hints, *res; + int error; + char *p; + char *s; + char *host, *port; + char pbuf[10]; + + s = strdup(str); + + if (s[0] == '[' && (p = strchr(s, ']')) != NULL) { + *p++ = '\0'; + host = s + 1; + } else { + p = s; + host = &s[0]; + } + port = strrchr(p, ':'); + if (port) { + *port++ = '\0'; + } else { + snprintf(pbuf, sizeof(pbuf), "%d", defport); + port = pbuf; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, port, &hints, &res); + if (error || !res) { + CTRACE((tfp, "HTGetAddrInfo: getaddrinfo(%s, %s): %s\n", host, port, + gai_strerror(error))); + return NULL; + } + + return res; } +#endif /* INET6 */ #ifdef LY_FIND_LEAKS /* Free our name for the host on which we are - FM @@ -1377,7 +1532,12 @@ PRIVATE void get_host_details NOARGS char *domain_name; /* The name of this host domain */ #endif /* UCX */ #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */ +#ifdef INET6 + struct addrinfo hints, *res; + int error; +#else struct hostent * phost; /* Pointer to host -- See netdb.h */ +#endif /* INET6 */ #endif /* NEED_HOST_ADDRESS */ int namelength = sizeof(name); @@ -1405,6 +1565,22 @@ PRIVATE void get_host_details NOARGS #ifndef DECNET /* Decnet ain't got no damn name server 8#OO */ #ifdef NEED_HOST_ADDRESS /* no -- needs name server! */ +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(name, NULL, &hints, &res); + if (error || !res || !res->ai_canonname) { + CTRACE((tfp, "TCP: %s: `%s'\n", gai_strerror(error), name)); + if (res) + freeaddrinfo(res); + return; /* Fail! */ + } + StrAllocCopy(hostname, res->ai_canonname); + memcpy(&HTHostAddress, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); +#else phost = gethostbyname(name); /* See netdb.h */ if (!OK_HOST(phost)) { CTRACE((tfp, "TCP: Can't find my own internet node address for `%s'!!\n", @@ -1413,6 +1589,7 @@ PRIVATE void get_host_details NOARGS } StrAllocCopy(hostname, phost->h_name); memcpy(&HTHostAddress, &phost->h_addr, phost->h_length); +#endif /* INET6 */ CTRACE((tfp, " Name server says that I am `%s' = %s\n", hostname, HTInetString(&HTHostAddress))); #endif /* NEED_HOST_ADDRESS */ @@ -1442,13 +1619,18 @@ PUBLIC int HTDoConnect ARGS4( int, default_port, int *, s) { - struct sockaddr_in soc_address; - struct sockaddr_in *soc_in = &soc_address; int status; char *line = NULL; char *p1 = NULL; char *at_sign = NULL; char *host = NULL; +#ifdef INET6 + int error; + struct sockaddr *sa; + struct addrinfo *res, *res0; +#else + struct sockaddr_in soc_address; + struct sockaddr_in *soc_in = &soc_address; /* ** Set up defaults. @@ -1456,6 +1638,7 @@ PUBLIC int HTDoConnect ARGS4( memset(soc_in, 0, sizeof(*soc_in)); soc_in->sin_family = AF_INET; soc_in->sin_port = htons((unsigned short) default_port); +#endif /* INET6 */ /* ** Get node name and optional port number. @@ -1473,6 +1656,17 @@ PUBLIC int HTDoConnect ARGS4( HTSprintf0 (&line, "%s%s", WWW_FIND_MESSAGE, host); _HTProgress (line); +#ifdef INET6 + /* HTParseInet() is useless! */ + _HTProgress(host); + res0 = HTGetAddrInfo(host, default_port); + if (res0 == NULL) { + sprintf (line, "Unable to locate remote host %s.", host); + _HTProgress(line); + FREE(host); + FREE(line); + return HT_NO_DATA; +#else status = HTParseInet(soc_in, host); if (status) { if (status != HT_INTERRUPTED) { @@ -1492,6 +1686,7 @@ PUBLIC int HTDoConnect ARGS4( FREE(host); FREE(line); return status; +#endif /* INET6 */ } HTSprintf0 (&line, gettext("Making %s connection to %s"), protocol, host); @@ -1502,11 +1697,27 @@ PUBLIC int HTDoConnect ARGS4( /* ** Now, let's get a socket set up from the server for the data. */ +#ifdef INET6 + for (res = res0; res; res = res->ai_next) { + *s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (*s == -1) { + char hostbuf[1024], portbuf[1024]; + getnameinfo(res->ai_addr, res->ai_addrlen, + hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), + NI_NUMERICHOST|NI_NUMERICSERV); + HTSprintf0 (&line, "socket failed: family %d addr %s port %s.", + res->ai_family, hostbuf, portbuf); + _HTProgress (line); + FREE(line); + continue; + } +#else *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (*s == -1) { HTAlert(gettext("socket failed.")); return HT_NO_DATA; } +#endif /* INET6 */ #ifndef DOSPATH #if !defined(NO_IOCTL) || defined(USE_FCNTL) @@ -1535,15 +1746,23 @@ PUBLIC int HTDoConnect ARGS4( */ #ifdef SOCKS if (socks_flag) { +#ifdef INET6 + status = Rconnect(*s, res->ai_addr, res->ai_addrlen); +#else status = Rconnect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address)); +#endif /* INET6 */ /* ** For long Rbind. */ socks_bind_remoteAddr = soc_address.sin_addr.s_addr; } else #endif /* SOCKS */ +#ifdef INET6 + status = connect(*s, res->ai_addr, res->ai_addrlen); +#else status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address)); +#endif /* INET6 */ #ifndef __DJGPP__ /* ** According to the Sun man page for connect: @@ -1581,6 +1800,10 @@ PUBLIC int HTDoConnect ARGS4( */ if ((tries++/10) >= connect_timeout) { HTAlert(gettext("Connection failed (too many retries).")); +#ifdef INET6 + FREE(line); + freeaddrinfo(res0); +#endif /* INET6 */ return HT_NO_DATA; } @@ -1642,8 +1865,12 @@ PUBLIC int HTDoConnect ARGS4( status = 0; } else { #endif /* SOCKS */ +#ifdef INET6 + status = connect(*s, res->ai_addr, res->ai_addrlen); +#else status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address)); +#endif /* INET6 */ #ifdef UCX /* ** A UCX feature: Instead of returning EISCONN @@ -1691,8 +1918,12 @@ PUBLIC int HTDoConnect ARGS4( ** For some reason, UCX pre 3 apparently returns ** errno = 18242 instead the EALREADY or EISCONN. */ +#ifdef INET6 + status = connect(*s, res->ai_addr, res->ai_addrlen); +#else status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address)); +#endif /* INET6 */ if ((status < 0) && (SOCKET_ERRNO != EALREADY && SOCKET_ERRNO != EAGAIN) && #ifdef UCX @@ -1722,8 +1953,21 @@ PUBLIC int HTDoConnect ARGS4( HTInetStatus("this socket's first and only connect"); } #endif /* SOCKET_DEBUG_TRACE */ +#ifdef INET6 + if (status < 0) { + NETCLOSE(*s); + *s = -1; + continue; + } + break; + } +#endif /* INET6 */ #endif /* !__DJGPP__ */ +#ifdef INET6 + if (*s < 0) { +#else if (status < 0) { +#endif /* INET6 */ /* ** The connect attempt failed or was interrupted, ** so close up the socket. @@ -1748,6 +1992,10 @@ PUBLIC int HTDoConnect ARGS4( #endif /* !NO_IOCTL || USE_FCNTL */ #endif /* !DOSPATH */ +#ifdef INET6 + FREE(line); + freeaddrinfo(res0); +#endif /* INET6 */ return status; } diff --git a/WWW/Library/Implementation/HTTCP.h b/WWW/Library/Implementation/HTTCP.h index 56a0ee31..345f6077 100644 --- a/WWW/Library/Implementation/HTTCP.h +++ b/WWW/Library/Implementation/HTTCP.h @@ -18,8 +18,11 @@ ** returns a pointer to a static string which must be copied if ** it is to be kept. */ +#ifdef INET6 +extern CONST char * HTInetString PARAMS((SockA* mysin)); +#else extern CONST char * HTInetString PARAMS((struct sockaddr_in* mysin)); - +#endif /* INET6 */ /* Encode INET status (as in sys/errno.h) inet_status() ** ------------------ @@ -100,11 +103,19 @@ extern struct hostent * LYGetHostByName PARAMS((char * str)); ** sin points to the binary internet or decnet address field. ** ** On exit: +** Regular case: ** *sin is filled in. If no port is specified in str, that ** field is left unchanged in *sin. +** INET6 case: +** *sin is filled in. If no port is specified in str, +** default_port is used */ #if defined(__STDC__) || defined(__BORLANDC__) || defined(_MSC_VER) +#ifdef INET6 + extern int HTParseInet(SockA * mysin, CONST char * str, int default_port); +#else extern int HTParseInet(struct sockaddr_in * mysin, CONST char * str); +#endif /* INET6 */ /*!! had to change this to get it to compile. CTB */ #else extern int HTParseInet(); diff --git a/WWW/Library/Implementation/www_tcp.h b/WWW/Library/Implementation/www_tcp.h index adab9ab0..16bca6e2 100644 --- a/WWW/Library/Implementation/www_tcp.h +++ b/WWW/Library/Implementation/www_tcp.h @@ -56,8 +56,17 @@ Default values #define INVSOC (-1) /* Unix invalid socket */ /* NB: newer libwww has something different for Windows */ +/* IPv6 support */ +#if defined(HAVE_GETADDRINFO) && defined(HAVE_GAI_STRERROR) && defined(ENABLE_IPV6) +# define INET6 +#endif /* HAVE_GETADDRINFO && HAVE_GAI_STRERROR && ENABLE_IPV6 */ + #if !defined(__MINGW32__) +#ifdef INET6 +typedef struct sockaddr_storage SockA; /* See netinet/in.h */ +#else typedef struct sockaddr_in SockA; /* See netinet/in.h */ +#endif /* INET6 */ #endif #ifndef VMS |