From 04872184780ed99270a3b76d5c204435f432b120 Mon Sep 17 00:00:00 2001 From: dkf Date: Tue, 13 Nov 2007 14:06:04 +0000 Subject: Rewrote to use the thread-safe version of gethostbyname() by forward-porting the code used in 8.4, and added rudimentary support for getaddrinfo() (not enabled by default, as no autoconf-ery written). Part of fix for [Bug 1618235] --- ChangeLog | 8 +++++ unix/tclUnixChan.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4431805..0786d4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-11-13 Donal K. Fellows + + * unix/tclUnixChan.c (CreateSocketAddress): Rewrote to use the + thread-safe version of gethostbyname() by forward-porting the code + used in 8.4, and added rudimentary support for getaddrinfo() (not + enabled by default, as no autoconf-ery written). Part of fix for [Bug + 1618235] + 2007-11-12 Jeff Hobbs * generic/tclGet.c (Tcl_Get, Tcl_GetInt): revert use of TclGet* diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index aeb8539..dc104f0 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixChan.c,v 1.83 2007/11/05 19:37:07 andreas_kupries Exp $ + * RCS: @(#) $Id: tclUnixChan.c,v 1.84 2007/11/13 14:06:05 dkf Exp $ */ #include "tclInt.h" /* Internal definitions for Tcl. */ @@ -237,7 +237,8 @@ static TcpState * CreateSocket(Tcl_Interp *interp, int port, const char *host, int server, const char *myaddr, int myport, int async); static int CreateSocketAddress(struct sockaddr_in *sockaddrPtr, - const char *host, int port); + const char *host, int port, int willBind, + const char **errorMsgPtr); static int FileBlockModeProc(ClientData instanceData, int mode); static int FileCloseProc(ClientData instanceData, Tcl_Interp *interp); @@ -2469,14 +2470,15 @@ CreateSocket( struct sockaddr_in sockaddr; /* socket address */ struct sockaddr_in mysockaddr; /* Socket address for client */ TcpState *statePtr; + const char *errorMsg = NULL; sock = -1; origState = 0; - if (!CreateSocketAddress(&sockaddr, host, port)) { + if (!CreateSocketAddress(&sockaddr, host, port, 0, &errorMsg)) { goto addressError; } if ((myaddr != NULL || myport != 0) && - !CreateSocketAddress(&mysockaddr, myaddr, myport)) { + !CreateSocketAddress(&mysockaddr, myaddr, myport, 1, &errorMsg)) { goto addressError; } @@ -2608,6 +2610,9 @@ CreateSocket( if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), NULL); + if (errorMsg != NULL) { + Tcl_AppendResult(interp, " (", errorMsg, ")", NULL); + } } return NULL; } @@ -2633,9 +2638,63 @@ static int CreateSocketAddress( struct sockaddr_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? */ + const char **errorMsgPtr) /* Place to store the error message + * detail, if available. */ { - struct hostent *hostent; /* Host database entry */ +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *resPtr = NULL; + 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; + } + + /* + * Note that getaddrinfo() *is* thread-safe. If a platform doesn't get + * that right, it shouldn't use this part of the code. + */ + + result = getaddrinfo(host, NULL, &hints, &resPtr); + if (result == 0) { + memcpy(sockaddrPtr, resPtr->ai_addr, sizeof(struct sockaddr_in)); + freeaddrinfo(resPtr); + goto addPort; + } + + /* + * Ought to use gai_strerror() here... + */ + + switch (result) { + case EAI_NONAME: + case EAI_SERVICE: + case EAI_ADDRFAMILY: + case EAI_NODATA: + *errorMsgPtr = gai_strerror(result); + errno = EHOSTUNREACH; + return 0; + case EAI_SYSTEM: + return 0; + default: + *errorMsgPtr = gai_strerror(result); + errno = ENXIO; + return 0; + } +#else /* !HAVE_GETADDRINFO */ struct in_addr addr; /* For 64/32 bit madness */ (void) memset(sockaddrPtr, '\0', sizeof(struct sockaddr_in)); @@ -2644,10 +2703,15 @@ CreateSocketAddress( if (host == NULL) { addr.s_addr = INADDR_ANY; } else { + struct hostent *hostent; /* Host database entry */ Tcl_DString ds; const char *native; - native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); + if (host == NULL) { + native = NULL; + } else { + native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); + } addr.s_addr = inet_addr(native); /* INTL: Native. */ /* @@ -2656,8 +2720,11 @@ CreateSocketAddress( */ if (addr.s_addr == 0xFFFFFFFF) { - hostent = gethostbyname(native); /* INTL: Native. */ - if (hostent == NULL) { + hostent = TclpGetHostByName(native); /* INTL: Native. */ + if (hostent != NULL) { + memcpy(&addr, hostent->h_addr_list[0], + (size_t) hostent->h_length); + } else { #ifdef EHOSTUNREACH errno = EHOSTUNREACH; #else /* !EHOSTUNREACH */ @@ -2665,11 +2732,14 @@ CreateSocketAddress( errno = ENXIO; #endif /* ENXIO */ #endif /* EHOSTUNREACH */ - Tcl_DStringFree(&ds); + if (native != NULL) { + Tcl_DStringFree(&ds); + } return 0; /* Error. */ } - memcpy(&addr, (void *) hostent->h_addr_list[0], - (size_t) hostent->h_length); + } + if (native != NULL) { + Tcl_DStringFree(&ds); } Tcl_DStringFree(&ds); } @@ -2683,6 +2753,7 @@ CreateSocketAddress( sockaddrPtr->sin_addr.s_addr = addr.s_addr; return 1; /* Success. */ +#endif /* HAVE_GETADDRINFO */ } /* -- cgit v0.12