summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixChan.c
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2007-11-13 14:06:04 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2007-11-13 14:06:04 (GMT)
commit04872184780ed99270a3b76d5c204435f432b120 (patch)
tree68a48a34f8572249e9348c6596a25513f5f903ed /unix/tclUnixChan.c
parenta72d42baaff30f0e544d118359c4fdbfd4ae0f21 (diff)
downloadtcl-04872184780ed99270a3b76d5c204435f432b120.zip
tcl-04872184780ed99270a3b76d5c204435f432b120.tar.gz
tcl-04872184780ed99270a3b76d5c204435f432b120.tar.bz2
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]
Diffstat (limited to 'unix/tclUnixChan.c')
-rw-r--r--unix/tclUnixChan.c95
1 files changed, 83 insertions, 12 deletions
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 */
}
/*