diff -ru tcl8.4.4.ori/tests/socket.test tcl8.4.4/tests/socket.test --- tcl8.4.4.ori/tests/socket.test Wed Jul 10 13:56:45 2002 +++ tcl8.4.4/tests/socket.test Tue Oct 7 20:44:12 2003 @@ -349,7 +349,9 @@ } close $f set x -} {ready {hello 127.0.0.1}} +} {ready {hello ::ffff:127.0.0.1}} +# The server returns it as IPv6 mapped +#} {ready {hello 127.0.0.1}} test socket-2.4 {tcp connection with server interface specified} {socket stdio} { removeFile script set f [open $path(script) w] @@ -878,7 +880,9 @@ close $s1 set l "" lappend l [lindex $x 0] [expr {[lindex $x 2] == $listen}] [llength $x] -} {127.0.0.1 1 3} +} {::ffff:127.0.0.1 1 3} +# The server returns it as IPv6 mapped +#} {127.0.0.1 1 3} test socket-8.1 {testing -async flag on sockets} {socket} { # NOTE: This test may fail on some Solaris 2.4 systems. If it does, diff -ru tcl8.4.4.ori/tests/unixInit.test tcl8.4.4/tests/unixInit.test --- tcl8.4.4.ori/tests/unixInit.test Wed Dec 4 08:07:40 2002 +++ tcl8.4.4/tests/unixInit.test Tue Oct 7 20:49:44 2003 @@ -87,7 +87,9 @@ # Can't use normal comparison, as hostname varies due to some # installations having a messed up /etc/hosts file. if { - [string equal 127.0.0.1 [lindex $result 0]] && + [string equal ::1 [lindex $result 0]] && + # Obviously the first resolution for "localhost" must be IPv6 + # [string equal 127.0.0.1 [lindex $result 0]] && [string equal $port [lindex $result 2]] } then { subst "OK" diff -ru tcl8.4.4.ori/unix/README tcl8.4.4/unix/README --- tcl8.4.4.ori/unix/README Tue Jul 22 00:29:22 2003 +++ tcl8.4.4/unix/README Tue Oct 7 20:43:50 2003 @@ -47,6 +47,8 @@ type "./configure -help" or refer to the autoconf documentation (not included here). Tcl's "configure" supports the following special switches in addition to the standard ones: + --enable-ipv6 If this switch is set, Tcl will compile + with IPv6 support. --enable-threads If this switch is set, Tcl will compile itself with multithreading support. --disable-load If this switch is specified then Tcl will diff -ru tcl8.4.4.ori/unix/configure.in tcl8.4.4/unix/configure.in --- tcl8.4.4.ori/unix/configure.in Tue Jul 22 00:29:22 2003 +++ tcl8.4.4/unix/configure.in Tue Oct 7 20:43:51 2003 @@ -47,6 +47,12 @@ AC_HAVE_HEADERS(unistd.h limits.h) #------------------------------------------------------------------------ +# IPv6 support +#------------------------------------------------------------------------ + +SC_ENABLE_IPv6 + +#------------------------------------------------------------------------ # Threads support #------------------------------------------------------------------------ diff -ru tcl8.4.4.ori/unix/tcl.m4 tcl8.4.4/unix/tcl.m4 --- tcl8.4.4.ori/unix/tcl.m4 Tue Jul 22 00:29:22 2003 +++ tcl8.4.4/unix/tcl.m4 Tue Oct 7 20:43:51 2003 @@ -378,6 +378,49 @@ ]) #------------------------------------------------------------------------ +# SC_ENABLE_IPv6 -- +# +# Specify if IPv6 support should be enabled +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-ipv6 +# +# +# Defines the following vars: +# TCL_IPv6 +# +#------------------------------------------------------------------------ + +AC_DEFUN(SC_ENABLE_IPv6, [ + AC_MSG_CHECKING(for building with ipv6) + AC_ARG_ENABLE(ipv6, [ --enable-ipv6 build with ipv6], + [tcl_ok=$enableval], [tcl_ok=no]) + + if test "$tcl_ok" = "yes"; then + AC_MSG_RESULT(yes) + TCL_IPv6=1 + AC_DEFINE(TCL_IPv6) + AC_CHECK_LIB(c,getaddrinfo,tcl_ok=yes,tcl_ok=no) + + if test "$tcl_ok" = "no"; then + TCL_IPv6=0 + AC_MSG_ERROR("Don t know how to find ipv6 lib on your system - you must disable ipv6 support or edit the LIBS in the Makefile...") + fi + else + TCL_IPv6=0 + AC_MSG_RESULT([no (default)]) + fi + AC_SUBST(TCL_IPv6) +]) + + + +#------------------------------------------------------------------------ # SC_ENABLE_THREADS -- # # Specify if thread support should be enabled diff -ru tcl8.4.4.ori/unix/tclUnixChan.c tcl8.4.4/unix/tclUnixChan.c --- tcl8.4.4.ori/unix/tclUnixChan.c Fri Feb 21 03:36:27 2003 +++ tcl8.4.4/unix/tclUnixChan.c Tue Oct 7 20:43:51 2003 @@ -13,6 +13,8 @@ * RCS: @(#) $Id: tclUnixChan.c,v 1.42 2003/02/21 02:36:27 hobbs Exp $ */ + + #include "tclInt.h" /* Internal definitions for Tcl. */ #include "tclPort.h" /* Portability features for Tcl. */ #include "tclIO.h" /* To get Channel type declaration. */ @@ -220,6 +222,25 @@ # define SOMAXCONN 100 #endif /* SOMAXCONN < 100 */ +#ifdef TCL_IPv6 +#ifndef SA_LEN +#define SA_LEN(sa) sa_len(sa) + +static size_t sa_len(struct sockaddr_storage *sa) +{ + switch(sa->ss_family) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + default: + return sizeof(struct sockaddr_storage); + } +} +#endif /* SA_LEN */ +#endif + + /* * The following defines how much buffer space the kernel should maintain * for a socket. @@ -234,9 +255,16 @@ static TcpState * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *host, int server, CONST char *myaddr, int myport, int async)); +#ifdef TCL_IPv6 +static int CreateSocketAddress _ANSI_ARGS_( + (struct sockaddr_storage *sockaddrPtr, + CONST char *host, int port)); + +#else static int CreateSocketAddress _ANSI_ARGS_( (struct sockaddr_in *sockaddrPtr, CONST char *host, int port)); +#endif static int FileBlockModeProc _ANSI_ARGS_(( ClientData instanceData, int mode)); static int FileCloseProc _ANSI_ARGS_((ClientData instanceData, @@ -2241,10 +2269,20 @@ * value; initialized by caller. */ { TcpState *statePtr = (TcpState *) instanceData; +#ifdef TCL_IPv6 + struct sockaddr_storage sockname; + struct sockaddr_storage peername; + int n; + char tmphost[INET6_ADDRSTRLEN]; + char tmphost2[INET6_ADDRSTRLEN]; + char tmpport[INET6_ADDRSTRLEN]; + socklen_t size = sizeof(struct sockaddr_storage); +#else struct sockaddr_in sockname; struct sockaddr_in peername; struct hostent *hostEntPtr; socklen_t size = sizeof(struct sockaddr_in); +#endif size_t len = 0; char buf[TCL_INTEGER_SPACE]; @@ -2277,6 +2315,29 @@ Tcl_DStringAppendElement(dsPtr, "-peername"); Tcl_DStringStartSublist(dsPtr); } +#ifdef TCL_IPv6 + memset(tmphost,0,INET6_ADDRSTRLEN); + memset(tmpport,0,INET6_ADDRSTRLEN); + getnameinfo((const struct sockaddr *)&peername,size,tmphost,INET6_ADDRSTRLEN,tmpport,INET6_ADDRSTRLEN,NI_NUMERICHOST|NI_NUMERICSERV); + Tcl_DStringAppendElement(dsPtr, tmphost); + memset(tmphost2,0,INET6_ADDRSTRLEN); + n = getnameinfo((const struct sockaddr *)&peername,size,tmphost2,INET6_ADDRSTRLEN,NULL,0,NI_NAMEREQD); + if (!n) { + Tcl_DString ds; + + Tcl_ExternalToUtfDString(NULL, tmphost2, -1, &ds); + Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); + } else { + Tcl_DStringAppendElement(dsPtr, tmphost); + } + TclFormatInt(buf, atoi(tmpport)); + Tcl_DStringAppendElement(dsPtr, buf); + if (len == 0) { + Tcl_DStringEndSublist(dsPtr); + } else { + return TCL_OK; + } +#else Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); hostEntPtr = gethostbyaddr( /* INTL: Native. */ (char *) &peername.sin_addr, @@ -2296,6 +2357,7 @@ } else { return TCL_OK; } +#endif } else { /* * getpeername failed - but if we were asked for all the options @@ -2323,6 +2385,30 @@ Tcl_DStringAppendElement(dsPtr, "-sockname"); Tcl_DStringStartSublist(dsPtr); } +#ifdef TCL_IPv6 + memset(tmphost,0,INET6_ADDRSTRLEN); + memset(tmpport,0,INET6_ADDRSTRLEN); + getnameinfo((const struct sockaddr *)&sockname,size,tmphost,INET6_ADDRSTRLEN,tmpport,INET6_ADDRSTRLEN,NI_NUMERICHOST|NI_NUMERICSERV); + Tcl_DStringAppendElement(dsPtr, tmphost); + memset(tmphost2,0,INET6_ADDRSTRLEN); + n = getnameinfo((const struct sockaddr *)&sockname,size,tmphost2,INET6_ADDRSTRLEN,NULL,0,NI_NAMEREQD); + if (!n) { + Tcl_DString ds; + + Tcl_ExternalToUtfDString(NULL, tmphost2, -1, &ds); + Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); + } else { + Tcl_DStringAppendElement(dsPtr, tmphost); + } + TclFormatInt(buf, atoi(tmpport)); + Tcl_DStringAppendElement(dsPtr, buf); + if (len == 0) { + Tcl_DStringEndSublist(dsPtr); + } else { + return TCL_OK; + } + +#else Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); hostEntPtr = gethostbyaddr( /* INTL: Native. */ (char *) &sockname.sin_addr, @@ -2342,6 +2428,7 @@ } else { return TCL_OK; } +#endif } else { if (interp) { Tcl_AppendResult(interp, "can't get sockname: ", @@ -2449,7 +2536,6 @@ * *---------------------------------------------------------------------- */ - static TcpState * CreateSocket(interp, port, host, server, myaddr, myport, async) Tcl_Interp *interp; /* For error reporting; can be NULL. */ @@ -2465,8 +2551,13 @@ * do a synchronous connect or bind. */ { int status, sock, asyncConnect, curState, origState; +#ifdef TCL_IPv6 + struct sockaddr_storage sockaddr; /* socket address */ + struct sockaddr_storage mysockaddr; /* Socket address for client */ +#else struct sockaddr_in sockaddr; /* socket address */ struct sockaddr_in mysockaddr; /* Socket address for client */ +#endif TcpState *statePtr; sock = -1; @@ -2479,7 +2570,11 @@ goto addressError; } +#ifdef TCL_IPv6 + sock = socket(sockaddr.ss_family, SOCK_STREAM, 0); +#else sock = socket(AF_INET, SOCK_STREAM, 0); +#endif if (sock < 0) { goto addressError; } @@ -2508,8 +2603,13 @@ status = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &status, sizeof(status)); +#ifdef TCL_IPv6 + status = bind(sock, (struct sockaddr *) &sockaddr, + SA_LEN(&sockaddr)); +#else status = bind(sock, (struct sockaddr *) &sockaddr, sizeof(struct sockaddr)); +#endif if (status != -1) { status = listen(sock, SOMAXCONN); } @@ -2518,8 +2618,13 @@ curState = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &curState, sizeof(curState)); +#ifdef TCL_IPv6 + status = bind(sock, (struct sockaddr *) &mysockaddr, + SA_LEN(&mysockaddr)); +#else status = bind(sock, (struct sockaddr *) &mysockaddr, sizeof(struct sockaddr)); +#endif if (status < 0) { goto bindError; } @@ -2545,8 +2650,13 @@ status = 0; } if (status > -1) { +#ifdef TCL_IPv6 + status = connect(sock, (struct sockaddr *) &sockaddr, + SA_LEN(&sockaddr)); +#else status = connect(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr)); +#endif if (status < 0) { if (errno == EINPROGRESS) { asyncConnect = 1; @@ -2610,6 +2720,9 @@ return NULL; } + + + /* *---------------------------------------------------------------------- * @@ -2619,23 +2732,68 @@ * * Results: * 1 if the host was valid, 0 if the host could not be converted to - * an IP address. + * an IPv4 | IPv6 address. * * Side effects: * Fills in the *sockaddrPtr structure. * *---------------------------------------------------------------------- */ - static int CreateSocketAddress(sockaddrPtr, host, port) +#ifdef TCL_IPv6 + struct sockaddr_storage *sockaddrPtr; /* Socket address */ +#else struct sockaddr_in *sockaddrPtr; /* Socket address */ +#endif CONST char *host; /* Host. NULL implies INADDR_ANY */ int port; /* Port number */ { +#ifdef TCL_IPv6 + struct addrinfo hints,*res; + int n; +#else struct hostent *hostent; /* Host database entry */ struct in_addr addr; /* For 64/32 bit madness */ +#endif +#ifdef TCL_IPv6 + Tcl_DString ds; + CONST char *native; + char service[30]; + (void) memset((VOID *) sockaddrPtr, '\0', sizeof(struct sockaddr_storage)); + (void) memset((VOID *) &hints, 0, sizeof(struct addrinfo)); + hints.ai_family=PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE ; + native = host ? Tcl_UtfToExternalDString(NULL, host, -1, &ds) : NULL ; + memset(service,0,30); + sprintf(service,"%i",port); /* We have been passed the port/service as integer */ + if (!(n=getaddrinfo(native,service,&hints,&res))) + { + memcpy(sockaddrPtr,res->ai_addr,res->ai_addrlen); + freeaddrinfo(res); + if (native != NULL) { + Tcl_DStringFree(&ds); + } + return 1; + } + else + { +#ifdef EHOSTUNREACH + errno = EHOSTUNREACH; +#else /* !EHOSTUNREACH */ +#ifdef ENXIO + errno = ENXIO; +#endif /* ENXIO */ +#endif /* EHOSTUNREACH */ + if (native != NULL) { + Tcl_DStringFree(&ds); + } + return 0; /* error */ + } + +#else (void) memset((VOID *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); sockaddrPtr->sin_family = AF_INET; sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); @@ -2680,6 +2838,7 @@ } } + /* * NOTE: On 64 bit machines the assignment below is rumored to not * do the right thing. Please report errors related to this if you @@ -2688,7 +2847,9 @@ */ sockaddrPtr->sin_addr.s_addr = addr.s_addr; + return 1; /* Success. */ +#endif } /* @@ -2894,13 +3055,23 @@ TcpState *sockState; /* Client data of server socket. */ int newsock; /* The new client socket */ TcpState *newSockState; /* State for new socket. */ +#ifdef TCL_IPv6 + struct sockaddr_storage addr; /* The remote address */ + char tmphost[INET6_ADDRSTRLEN]; + char tmpport[INET6_ADDRSTRLEN]; +#else struct sockaddr_in addr; /* The remote address */ +#endif socklen_t len; /* For accept interface */ char channelName[16 + TCL_INTEGER_SPACE]; sockState = (TcpState *) data; +#ifdef TCL_IPv6 + len = sizeof(struct sockaddr_storage); +#else len = sizeof(struct sockaddr_in); +#endif newsock = accept(sockState->fd, (struct sockaddr *) &addr, &len); if (newsock < 0) { return; @@ -2927,11 +3098,21 @@ Tcl_SetChannelOption(NULL, newSockState->channel, "-translation", "auto crlf"); +#ifdef TCL_IPv6 + if (sockState->acceptProc != NULL) { + memset(tmphost,0,INET6_ADDRSTRLEN); + getnameinfo((const struct sockaddr *)&addr,SA_LEN(&addr),tmphost,INET6_ADDRSTRLEN,tmpport,INET6_ADDRSTRLEN,NI_NUMERICHOST); + (*sockState->acceptProc)(sockState->acceptProcData, + newSockState->channel, tmphost, + atoi(tmpport)); + } +#else if (sockState->acceptProc != NULL) { (*sockState->acceptProc)(sockState->acceptProcData, newSockState->channel, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } +#endif } /* diff -ru tcl8.4.4.ori/unix/tclUnixSock.c tcl8.4.4/unix/tclUnixSock.c --- tcl8.4.4.ori/unix/tclUnixSock.c Wed Feb 27 02:16:43 2002 +++ tcl8.4.4/unix/tclUnixSock.c Tue Oct 7 20:43:51 2003 @@ -67,7 +67,12 @@ { #ifndef NO_UNAME struct utsname u; +#ifdef TCL_IPv6 + struct addrinfo hints,*res; + int n; +#else struct hostent *hp; +#endif #else char buffer[sizeof(hostname)]; #endif @@ -83,8 +88,15 @@ #ifndef NO_UNAME (VOID *) memset((VOID *) &u, (int) 0, sizeof(struct utsname)); if (uname(&u) > -1) { /* INTL: Native. */ +#ifdef TCL_IPv6 + memset(&hints,0,sizeof(struct addrinfo)); + hints.ai_flags=AI_CANONNAME; + n = getaddrinfo(u.nodename,NULL,&hints,&res); + if (n) { +#else hp = gethostbyname(u.nodename); /* INTL: Native. */ if (hp == NULL) { +#endif /* * Sometimes the nodename is fully qualified, but gets truncated * as it exceeds SYS_NMLN. See if we can just get the immediate @@ -95,12 +107,22 @@ char *node = ckalloc((unsigned) (dot - u.nodename + 1)); memcpy(node, u.nodename, (size_t) (dot - u.nodename)); node[dot - u.nodename] = '\0'; +#ifdef TCL_IPv6 + n = getaddrinfo(node,NULL,&hints,&res); +#else hp = gethostbyname(node); +#endif ckfree(node); } } +#ifdef TCL_IPv6 + if (!n) { + native = res->ai_canonname; + freeaddrinfo(res); +#else if (hp != NULL) { native = hp->h_name; +#endif } else { native = u.nodename; }