From 3cd49200d7d04605090a8dbaba57a127b785ceb5 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 10 Aug 2020 16:16:36 +0000 Subject: windows: replace gethostbyname with getaddrinfo (gethostbyname can hang sporadically, closes [7cf7cce423]); corresponding to MS (https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-gethostbyname): Developers creating Windows Sockets 2 applications are urged to use the getaddrinfo function instead of gethostbyname --- win/tclWinSock.c | 102 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 44 deletions(-) diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 882aa4a..11632c4 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -45,6 +45,8 @@ * SocketCheckProc(). */ +#include +#include #include "tclWinInt.h" #ifdef _MSC_VER @@ -187,8 +189,8 @@ static WNDCLASS windowClass; static SocketInfo * CreateSocket(Tcl_Interp *interp, int port, const char *host, int server, const char *myaddr, int myport, int async); -static int CreateSocketAddress(LPSOCKADDR_IN sockaddrPtr, - const char *host, int port); +static int CreateSocketAddress(struct sockaddr_in *sockaddrPtr, + const char *host, int port, int willBind); static void InitSockets(void); static SocketInfo * NewSocketInfo(SOCKET socket); static void SocketExitHandler(ClientData clientData); @@ -917,8 +919,8 @@ CreateSocket( * asynchronously. */ { u_long flag = 1; /* Indicates nonblocking mode. */ - SOCKADDR_IN sockaddr; /* Socket address */ - SOCKADDR_IN mysockaddr; /* Socket address for client */ + struct sockaddr_in sockaddr; /* Socket address */ + struct sockaddr_in mysockaddr; /* Socket address for client */ SOCKET sock = INVALID_SOCKET; SocketInfo *infoPtr=NULL; /* The returned value. */ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) @@ -934,11 +936,11 @@ CreateSocket( return NULL; } - if (!CreateSocketAddress(&sockaddr, host, port)) { + if (!CreateSocketAddress(&sockaddr, host, port, server)) { goto error; } if ((myaddr != NULL || myport != 0) && - !CreateSocketAddress(&mysockaddr, myaddr, myport)) { + !CreateSocketAddress(&mysockaddr, myaddr, myport, 1)) { goto error; } @@ -1149,55 +1151,67 @@ static int CreateSocketAddress( LPSOCKADDR_IN sockaddrPtr, /* Socket address */ const char *host, /* Host. NULL implies INADDR_ANY */ - int port) /* Port number */ + int port, /* Port number */ + int willBind) /* Is this an address to bind() to or + * to connect() to? */ { - struct hostent *hostent; /* Host database entry */ - struct in_addr addr; /* For 64/32 bit madness */ + struct addrinfo hints, *resPtr = NULL; + char *native; + Tcl_DString ds; + int result; + + if (host == NULL) { + sockaddrPtr->sin_family = AF_INET; + sockaddrPtr->sin_addr.s_addr = INADDR_ANY; + addPort: + sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); + return 1; + } + + (void) memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + if (willBind) { + hints.ai_flags |= AI_PASSIVE; + } /* - * Check that WinSock is initialized; do not call it if not, to prevent - * system crashes. This can happen at exit time if the exit handler for - * WinSock ran before other exit handlers that want to use sockets. + * Note that getaddrinfo() *is* thread-safe. If a platform doesn't get + * that right, it shouldn't use this part of the code. */ - if (!SocketsEnabled()) { - Tcl_SetErrno(EFAULT); - return 0; + native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); + result = getaddrinfo(native, NULL, &hints, &resPtr); + Tcl_DStringFree(&ds); + if (result == 0) { + memcpy(sockaddrPtr, resPtr->ai_addr, sizeof(struct sockaddr_in)); + freeaddrinfo(resPtr); + goto addPort; } - ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN)); - sockaddrPtr->sin_family = AF_INET; - sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); - if (host == NULL) { - addr.s_addr = INADDR_ANY; - } else { - addr.s_addr = inet_addr(host); - if (addr.s_addr == INADDR_NONE) { - hostent = gethostbyname(host); - if (hostent != NULL) { - memcpy(&addr, hostent->h_addr, (size_t) hostent->h_length); - } else { + /* + * errno corresponding result ... + */ + + switch (result) { + case EAI_NONAME: + case EAI_SERVICE: +#if defined(EAI_ADDRFAMILY) && EAI_ADDRFAMILY != EAI_NONAME + case EAI_ADDRFAMILY: +#endif +#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME + case EAI_NODATA: +#endif #ifdef EHOSTUNREACH - Tcl_SetErrno(EHOSTUNREACH); -#else -#ifdef ENXIO - Tcl_SetErrno(ENXIO); + Tcl_SetErrno(EHOSTUNREACH); + return 0; #endif + default: +#ifdef ENXIO + Tcl_SetErrno(ENXIO); #endif - return 0; /* Error. */ - } - } + return 0; } - - /* - * NOTE: On 64 bit machines the assignment below is rumored to not do the - * right thing. Please report errors related to this if you observe - * incorrect behavior on 64 bit machines such as DEC Alphas. Should we - * modify this code to do an explicit memcpy? - */ - - sockaddrPtr->sin_addr.s_addr = addr.s_addr; - return 1; /* Success. */ } /* -- cgit v0.12 From f397a9ac9d2bc4a067fdc01f1e08188db53f5f93 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 10 Aug 2020 16:16:46 +0000 Subject: create server socket with AI_PASSIVE flag (used for bind) --- unix/tclUnixChan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index d3207e2..39bb64f 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -2378,7 +2378,7 @@ CreateSocket( const char *errorMsg = NULL; sock = -1; - if (!CreateSocketAddress(&sockaddr, host, port, 0, &errorMsg)) { + if (!CreateSocketAddress(&sockaddr, host, port, server, &errorMsg)) { goto addressError; } if ((myaddr != NULL || myport != 0) && -- cgit v0.12 From 6c0be70d2b1cc5dbfd1277556ac27ea2e39be4bb Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 10 Aug 2020 16:54:46 +0000 Subject: amend to [8054e19451]: clean up timeout timer event (avoid timing issues on further tests) --- tests/chanio.test | 1 + tests/io.test | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/chanio.test b/tests/chanio.test index 93375a0..66f4a30 100644 --- a/tests/chanio.test +++ b/tests/chanio.test @@ -5734,6 +5734,7 @@ test chan-io-46.1 {Tcl event loop vs multiple interpreters} {testfevent fileeven set timer [after 10 lappend x timeout] testfevent cmd $script vwait x + after cancel $timer testfevent cmd {chan close $f} list [testfevent cmd {set x}] [testfevent cmd {info commands after}] } {{f triggered: foo bar} after} diff --git a/tests/io.test b/tests/io.test index 0db6afb..685394c 100644 --- a/tests/io.test +++ b/tests/io.test @@ -6036,6 +6036,7 @@ test io-46.1 {Tcl event loop vs multiple interpreters} {testfevent fileevent} { set timer [after 10 lappend x timeout] testfevent cmd $script vwait x + after cancel $timer testfevent cmd {close $f} list [testfevent cmd {set x}] [testfevent cmd {info commands after}] } {{f triggered: foo bar} after} -- cgit v0.12 From e29e808f57505a56193de6e0717c7abe95755b03 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Mon, 10 Aug 2020 18:05:10 +0000 Subject: Fix for [29e8848eb976], imported alias in a deletion trace. --- generic/tclBasic.c | 3 ++- generic/tclInt.h | 1 + tests/namespace.test | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index fe64f18..f52ecf5 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3268,6 +3268,7 @@ Tcl_DeleteCommandFromToken( * TclNRExecuteByteCode looks up the command in the command hashtable). */ + cmdPtr->flags |= CMD_IS_DELETED; TclCleanupCommandMacro(cmdPtr); return 0; } @@ -4331,7 +4332,7 @@ EvalObjvCore( * Caller gave it to us. */ - if (!(preCmdPtr->flags & CMD_IS_DELETED)) { + if (!(preCmdPtr->flags & CMD_DEAD)) { /* * So long as it exists, use it. */ diff --git a/generic/tclInt.h b/generic/tclInt.h index 31108c7..1e90b70 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1682,6 +1682,7 @@ typedef struct Command { #define CMD_COMPILES_EXPANDED 0x08 #define CMD_REDEF_IN_PROGRESS 0x10 #define CMD_VIA_RESOLVER 0x20 +#define CMD_DEAD 0x30 /* diff --git a/tests/namespace.test b/tests/namespace.test index dd71697..796b46b 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -3337,6 +3337,49 @@ test namespace-56.5 {Bug 8b9854c3d8} -setup { namespace delete namespace-56.5 } -result 1 + + +test namespace-57.0 { + an imported alias should be usable in the deletion trace for the alias + + see 29e8848eb976 +} -body { + variable res {} + namespace eval ns2 { + namespace export * + proc p1 {oldname newname op} { + return success + } + + interp alias {} [namespace current]::p2 {} [namespace which p1] + } + + + namespace eval ns3 { + namespace import ::ns2::p2 + } + + + set ondelete [list apply [list {oldname newname op} { + variable res + catch { + ns3::p2 $oldname $newname $op + } cres + lappend res $cres + } [namespace current]]] + + + trace add command ::ns2::p2 delete $ondelete + rename ns2::p2 {} + return $res +} -cleanup { + unset res + namespace delete ns2 + namespace delete ns3 +} -result success + + + # cleanup catch {rename cmd1 {}} -- cgit v0.12 From 36d06e1e0b240999e478c750f746a86dbd63caae Mon Sep 17 00:00:00 2001 From: pooryorick Date: Mon, 10 Aug 2020 19:33:18 +0000 Subject: Fix mistake in [7eed2baf73] --- generic/tclBasic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index f52ecf5..50bc84e 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3268,7 +3268,7 @@ Tcl_DeleteCommandFromToken( * TclNRExecuteByteCode looks up the command in the command hashtable). */ - cmdPtr->flags |= CMD_IS_DELETED; + cmdPtr->flags |= CMD_DEAD; TclCleanupCommandMacro(cmdPtr); return 0; } -- cgit v0.12