IPv6 patch

Peter Deacon <[email protected]>
Newsgroups gmane.comp.db.tds.freetds
Message-ID <alpine.WNT.2.00.1010102321420.6940@SMURF>
This patch adds transport support for IPv6 :)

HAVE_GETADDRINFO is required for v6 or it falls back to current behavior. 
If building on Windows add it to your preprocessor list.

regards,
Peter

_______________________________________________
FreeTDS mailing list
[email protected]
http://lists.ibiblio.org/mailman/listinfo/freetds
freetds_ipv6.diff (application/octet-stream, 15.4 KB)
diff -u -r \freetds_orig/include/tds.h ./include/tds.h
--- \freetds_orig/include/tds.h	Thu Sep 16 00:37:23 2010
+++ ./include/tds.h	Sun Oct 10 21:08:38 2010
@@ -870,6 +870,10 @@
 	DSTR client_charset;
 
 	DSTR ip_addr;	  	/**< ip of server */
+#ifdef HAVE_GETADDRINFO
+	struct addrinfo *addrs;
+#endif
+
 	DSTR instance_name;
 	DSTR database;
 	DSTR dump_file;
@@ -1397,7 +1401,7 @@
 TDSCONNECTION *tds_read_config_info(TDSSOCKET * tds, TDSLOGIN * login, TDSLOCALE * locale);
 void tds_fix_connection(TDSCONNECTION * connection);
 TDS_USMALLINT tds_config_verstr(const char *tdsver, TDSCONNECTION * connection);
-int tds_lookup_host(const char *servername, char *ip);
+int tds_lookup_host(TDSCONNECTION * connection, const char *servername, char *ip);
 int tds_set_interfaces_file_loc(const char *interfloc);
 extern const char STD_DATETIME_FMT[];
 int tds_config_boolean(const char *value);
@@ -1576,7 +1580,7 @@
 
 /* net.c */
 int tds_lastpacket(TDSSOCKET * tds);
-TDSERRNO tds_open_socket(TDSSOCKET * tds, const char *ip_addr, unsigned int port, int timeout, int *p_oserr);
+TDSERRNO tds_open_socket(TDSSOCKET * tds, TDSCONNECTION * connection, int timeout, int *p_oserr);
 int tds_close_socket(TDSSOCKET * tds);
 int tds_read_packet(TDSSOCKET * tds);
 int tds_write_packet(TDSSOCKET * tds, unsigned char final);
diff -u -r \freetds_orig/src/odbc/connectparams.c ./src/odbc/connectparams.c
--- \freetds_orig/src/odbc/connectparams.c	Thu Jul  8 02:39:34 2010
+++ ./src/odbc/connectparams.c	Sun Oct 10 20:31:18 2010
@@ -127,7 +127,7 @@
 		}
 	}
 
-	if (tds_lookup_host(server, ip) == TDS_SUCCEED)
+	if (tds_lookup_host(connection, server, ip) == TDS_SUCCEED)
 		tds_dstr_copy(&connection->server_host_name, server);
 
 	if (!tds_dstr_copy(&connection->ip_addr, ip)) {
@@ -172,6 +172,9 @@
 		}
 	}
 
+	if (myGetPrivateProfileString(DSN, odbc_param_Port, tmp) > 0)
+		tds_parse_conf_section(TDS_STR_PORT, tmp, connection);
+
 	/* search for server (compatible with ms one) */
 	if (freetds_conf_less) {
 		int address_specified = 0;
@@ -179,7 +182,7 @@
 		if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) {
 			address_specified = 1;
 			/* TODO parse like MS */
-			tds_lookup_host(tmp, tmp);
+			tds_lookup_host(connection, tmp, tmp);
 			tds_dstr_copy(&connection->ip_addr, tmp);
 		}
 		if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) {
@@ -190,9 +193,6 @@
 			}
 		}
 	}
-
-	if (myGetPrivateProfileString(DSN, odbc_param_Port, tmp) > 0)
-		tds_parse_conf_section(TDS_STR_PORT, tmp, connection);
 
 	if (myGetPrivateProfileString(DSN, odbc_param_TDS_Version, tmp) > 0)
 		tds_parse_conf_section(TDS_STR_VERSION, tmp, connection);
diff -u -r \freetds_orig/src/tds/config.c ./src/tds/config.c
--- \freetds_orig/src/tds/config.c	Mon Sep 27 14:53:48 2010
+++ ./src/tds/config.c	Sun Oct 10 22:48:26 2010
@@ -586,7 +586,7 @@
 
 		tdsdump_log(TDS_DBG_INFO1, "Found host entry %s.\n", value);
 		tds_dstr_copy(&connection->server_host_name, value);
-		tds_lookup_host(value, tmp);
+		tds_lookup_host(connection, value, tmp);
 		tds_dstr_copy(&connection->ip_addr, tmp);
 		tdsdump_log(TDS_DBG_INFO1, "IP addr is %s.\n", tds_dstr_cstr(&connection->ip_addr));
 	} else if (!strcmp(option, TDS_STR_PORT)) {
@@ -731,7 +731,7 @@
 
 	if ((tdshost = getenv("TDSHOST"))) {
 		tds_dstr_copy(&connection->server_host_name, tdshost);
-		tds_lookup_host(tdshost, tmp);
+		tds_lookup_host(connection,tdshost, tmp);
 		tds_dstr_copy(&connection->ip_addr, tmp);
 		tdsdump_log(TDS_DBG_INFO1, "Setting 'ip_addr' to %s (%s) from $TDSHOST.\n", tmp, tdshost);
 	}
@@ -804,7 +804,7 @@
  */
 /* TODO callers seem to set always connection info... change it */
 int
-tds_lookup_host(const char *servername,	/* (I) name of the server                  */
+tds_lookup_host(TDSCONNECTION * connection, const char *servername,	/* (I) name of the server                  */
 		char *ip	/* (O) dotted-decimal ip address of server */
 	)
 {
@@ -813,30 +813,55 @@
 
 	/* Storage for reentrant getaddrby* calls */
 	struct hostent result;
+#ifdef HAVE_GETADDRINFO
+	struct addrinfo hints, *addrs;
+#endif
 	char buffer[4096];
 	int h_errnop;
 
-	/*
-	 * Call gethostbyname(3) only if servername is not an ip address. 
-	 * This call takes a while and is useless for an ip address.
-	 * mlilback 3/2/02
-	 */
-	ip_addr = inet_addr(servername);
-	if (ip_addr != INADDR_NONE) {
-		tds_strlcpy(ip, servername, 17);
-		return TDS_SUCCEED;
+#ifdef HAVE_GETADDRINFO
+	if (connection != NULL) {
+		memset(&hints,'\0',sizeof(hints));
+		if (getaddrinfo(servername,NULL,&hints,&addrs) == 0) {
+			assert(addrs != NULL);
+
+			if (connection->addrs != NULL)
+				freeaddrinfo(connection->addrs);
+			connection->addrs = addrs;
+
+			if (getnameinfo(addrs->ai_addr,addrs->ai_addrlen,ip,256,NULL,0,NI_NUMERICHOST) == 0)
+				return TDS_SUCCEED;
+			else
+				return TDS_FAIL;
+		}
+	else
+		return TDS_FAIL;
 	}
+	else
+#endif
+		{
+		/*
+		 * Call gethostbyname(3) only if servername is not an ip address. 
+		 * This call takes a while and is useless for an ip address.
+		 * mlilback 3/2/02
+		 */
+		ip_addr = inet_addr(servername);
+		if (ip_addr != INADDR_NONE) {
+			tds_strlcpy(ip, servername, 17);
+			return TDS_SUCCEED;
+		}
 
-	host = tds_gethostbyname_r(servername, &result, buffer, sizeof(buffer), &h_errnop);
+		host = tds_gethostbyname_r(servername, &result, buffer, sizeof(buffer), &h_errnop);
 
-	ip[0] = '\0';
-	if (host) {
-		struct in_addr *ptr = (struct in_addr *) host->h_addr;
+		ip[0] = '\0';
+		if (host) {
+			struct in_addr *ptr = (struct in_addr *) host->h_addr;
 
-		tds_inet_ntoa_r(*ptr, ip, 17);
-		return TDS_SUCCEED;
+			tds_inet_ntoa_r(*ptr, ip, 17);
+			return TDS_SUCCEED;
+		}
+		return TDS_FAIL;
 	}
-	return TDS_FAIL;
 }
 
 /**
@@ -989,12 +1014,12 @@
 	 * Look up the host and service
 	 */
 	if (server_found) {
+		if (tmp_port[0])
+			connection->port = tds_lookup_port(tmp_port);
 		tds_dstr_copy(&connection->server_host_name, tmp_ip);
-		tds_lookup_host(tmp_ip, line);
+		tds_lookup_host(connection, tmp_ip, line);
 		tdsdump_log(TDS_DBG_INFO1, "Resolved IP as '%s'.\n", line);
 		tds_dstr_copy(&connection->ip_addr, line);
-		if (tmp_port[0])
-			connection->port = tds_lookup_port(tmp_port);
 		if (tmp_ver[0])
 			tds_config_verstr(tmp_ver, connection);
 	}
@@ -1096,13 +1121,14 @@
 		/*
 		 * look up the host
 		 */
-		tds_lookup_host(server, ip_addr);
+		tds_lookup_host(connection, server, ip_addr);
+		if (ip_port)
+			connection->port = ip_port;
+
 		if (ip_addr[0]) {
 			tds_dstr_copy(&connection->server_host_name, server);
 			tds_dstr_copy(&connection->ip_addr, ip_addr);
 		}
-		if (ip_port)
-			connection->port = ip_port;
 	}
 
 	return found;
diff -u -r \freetds_orig/src/tds/login.c ./src/tds/login.c
--- \freetds_orig/src/tds/login.c	Sat Oct  2 00:07:17 2010
+++ ./src/tds/login.c	Sun Oct 10 21:08:38 2010
@@ -431,7 +431,7 @@
 
 	memcpy(tds->capabilities, connection->capabilities, TDS_MAX_CAPABILITY);
 
-	if ((erc = tds_open_socket(tds, tds_dstr_cstr(&connection->ip_addr), connection->port, connect_timeout, p_oserr)) != TDSEOK) {
+	if ((erc = tds_open_socket(tds, connection, connect_timeout, p_oserr)) != TDSEOK) {
 		tdserror(tds->tds_ctx, tds, erc, *p_oserr);
 		return erc;
 	}
diff -u -r \freetds_orig/src/tds/mem.c ./src/tds/mem.c
--- \freetds_orig/src/tds/mem.c	Tue Sep 28 01:20:11 2010
+++ ./src/tds/mem.c	Sun Oct 10 20:28:29 2010
@@ -1178,6 +1178,10 @@
 	tds_dstr_free(&connection->language);
 	tds_dstr_free(&connection->server_charset);
 	tds_dstr_free(&connection->ip_addr);
+#ifdef HAVE_GETADDRINFO
+	if (connection->addrs != NULL)
+		freeaddrinfo(connection->addrs);
+#endif
 	tds_dstr_free(&connection->database);
 	tds_dstr_free(&connection->dump_file);
 	tds_dstr_free(&connection->client_charset);
diff -u -r \freetds_orig/src/tds/net.c ./src/tds/net.c
--- \freetds_orig/src/tds/net.c	Wed Oct  6 01:03:00 2010
+++ ./src/tds/net.c	Sun Oct 10 23:20:15 2010
@@ -85,6 +85,10 @@
 #if HAVE_POLL_H
 #include <poll.h>
 #endif /* HAVE_POLL_H */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif /* HAVE_NETDB_H */
 
 #include "tds.h"
 #include "tdsstring.h"
@@ -179,9 +183,17 @@
 #endif
 
 TDSERRNO
-tds_open_socket(TDSSOCKET * tds, const char *ip_addr, unsigned int port, int timeout, int *p_oserr)
+tds_open_socket(TDSSOCKET * tds, TDSCONNECTION * connection, int timeout, int *p_oserr)
 {
 	struct sockaddr_in sin;
+#ifdef HAVE_GETADDRINFO
+	struct addrinfo *addrs;
+	char ipbuf[255];
+#ifdef AF_INET6
+	struct sockaddr_in6 *sin6;
+#endif
+	struct sockaddr_in *sin4;
+#endif
 	ioctl_nonblocking_t ioctl_nonblocking;
 	SOCKLEN_T optlen;
 	
@@ -191,75 +203,145 @@
 
 	*p_oserr = 0;
 
-	memset(&sin, 0, sizeof(sin));
 
-	sin.sin_addr.s_addr = inet_addr(ip_addr);
-	if (sin.sin_addr.s_addr == INADDR_NONE) {
-		tdsdump_log(TDS_DBG_ERROR, "inet_addr() failed, IP = %s\n", ip_addr);
-		return TDSESOCK;
-	}
+#ifdef HAVE_GETADDRINFO
+	if (connection->addrs != NULL) {
+		retval = -1;
+		for (addrs = connection->addrs; addrs != NULL; addrs = addrs->ai_next) {
+			*ipbuf = '\0';
+			if (addrs->ai_family == AF_INET) {
+				sin4 = (struct sockaddr_in *)addrs->ai_addr;
+				sin4->sin_port = htons(connection->port);
+				}
+#ifdef AF_INET6
+			else if (addrs->ai_family == AF_INET6) {
+				sin6 = (struct sockaddr_in6 *)addrs->ai_addr;
+				sin6->sin6_port = htons(connection->port);
+			}
+#endif
+			else {
+				tdsdump_log(TDS_DBG_ERROR, "could not set port - unrecognized protocol family: %d\n", addrs->ai_family);
+				return TDSESOCK;
+			}
+
+			if (TDS_IS_SOCKET_INVALID(tds->s = socket(addrs->ai_family, SOCK_STREAM, 0))) {
+				*p_oserr = sock_errno;
+				tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", sock_strerror(sock_errno));
+				return TDSESOCK;
+			}
+
+#ifdef SO_KEEPALIVE
+			len = 1;
+			setsockopt(tds->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len));
+#endif
 
-	sin.sin_family = AF_INET;
-	sin.sin_port = htons(port);
+			len = 1;
+#if defined(USE_NODELAY) || defined(USE_MSGMORE)
+			setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));
+#elif defined(USE_CORK)
+			if (setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len)) < 0)
+				setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));
+#else
+#error One should be defined
+#endif
 
-	tdsdump_log(TDS_DBG_INFO1, "Connecting to %s port %d (TDS version %d.%d)\n", 
-			tds_inet_ntoa_r(sin.sin_addr, ip, sizeof(ip)), ntohs(sin.sin_port), 
-			TDS_MAJOR(tds), TDS_MINOR(tds));
-
-	if (TDS_IS_SOCKET_INVALID(tds->s = socket(AF_INET, SOCK_STREAM, 0))) {
-		*p_oserr = sock_errno;
-		tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", sock_strerror(sock_errno));
-		return TDSESOCK;
+			getnameinfo(addrs->ai_addr,addrs->ai_addrlen,ipbuf,sizeof(ipbuf),NULL,0,NI_NUMERICHOST);
+			tdsdump_log(TDS_DBG_INFO1, "Connecting to %s port %d (TDS version %d.%d)\n", ipbuf,connection->port,
+				TDS_MAJOR(tds), TDS_MINOR(tds));
+
+			tds_dstr_copy(&connection->ip_addr,ipbuf);
+			if ((retval = connect(tds->s,addrs->ai_addr,addrs->ai_addrlen)) == 0) {
+				/* enable non-blocking mode */
+				ioctl_nonblocking = 1;
+				if (IOCTLSOCKET(tds->s, FIONBIO, &ioctl_nonblocking) < 0) {
+					*p_oserr = sock_errno;
+					tds_close_socket(tds);
+					return TDSEUSCT; 	/* close enough: "Unable to set communications timer" */
+				}
+				break;
+			}
+			else {
+				if (addrs->ai_next != NULL)	{
+					CLOSESOCKET(tds->s);
+					tds->s = INVALID_SOCKET;
+				}
+			}
+		}
 	}
+else
+#endif
+	{
+		memset(&sin, 0, sizeof(sin));
+		sin.sin_addr.s_addr = inet_addr(tds_dstr_cstr(&connection->ip_addr));
+		if (sin.sin_addr.s_addr == INADDR_NONE) {
+			tdsdump_log(TDS_DBG_ERROR, "inet_addr() failed, IP = %s\n", tds_dstr_cstr(&connection->ip_addr));
+			return TDSESOCK;
+		}
+
+		sin.sin_family = AF_INET;
+		sin.sin_port = htons(connection->port);
+
+		tdsdump_log(TDS_DBG_INFO1, "Connecting to %s port %d (TDS version %d.%d)\n", 
+				tds_inet_ntoa_r(sin.sin_addr, ip, sizeof(ip)), ntohs(sin.sin_port), 
+				TDS_MAJOR(tds), TDS_MINOR(tds));
+
+		if (TDS_IS_SOCKET_INVALID(tds->s = socket(AF_INET, SOCK_STREAM, 0))) {
+			*p_oserr = sock_errno;
+			tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", sock_strerror(sock_errno));
+			return TDSESOCK;
+		}
 
 #ifdef SO_KEEPALIVE
-	len = 1;
-	setsockopt(tds->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len));
+		len = 1;
+		setsockopt(tds->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len));
 #endif
 
-	len = 1;
+		len = 1;
 #if defined(USE_NODELAY) || defined(USE_MSGMORE)
-	setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));
-#elif defined(USE_CORK)
-	if (setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len)) < 0)
 		setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));
+#elif defined(USE_CORK)
+		if (setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len)) < 0)
+			setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));
 #else
 #error One should be defined
 #endif
 
 #ifdef  DOS32X			/* the other connection doesn't work  on WATTCP32 */
-	if (connect(tds->s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-		char *message;
+		if (connect(tds->s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+			char *message;
 
-		*p_oserr = sock_errno;
-		if (asprintf(&message, "tds_open_socket(): %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)) >= 0) {
-			perror(message);
-			free(message);
+			*p_oserr = sock_errno;
+			if (asprintf(&message, "tds_open_socket(): %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)) >= 0) {
+				perror(message);
+				free(message);
+			}
+			tds_close_socket(tds);
+			return TDSECONN;
+		}
 		}
-		tds_close_socket(tds);
-		return TDSECONN;
-	}
 #else
+		/* enable non-blocking mode */
+		ioctl_nonblocking = 1;
+		if (IOCTLSOCKET(tds->s, FIONBIO, &ioctl_nonblocking) < 0) {
+			*p_oserr = sock_errno;
+			tds_close_socket(tds);
+			return TDSEUSCT; 	/* close enough: "Unable to set communications timer" */
+		}
+
+		retval = connect(tds->s, (struct sockaddr *) &sin, sizeof(sin));
+	} /* !HAVE_GETADDRINFO */
+
 	if (!timeout) {
 		/* A timeout of zero means wait forever; 90,000 seconds will feel like forever. */
 		timeout = 90000;
 	}
 
-	/* enable non-blocking mode */
-	ioctl_nonblocking = 1;
-	if (IOCTLSOCKET(tds->s, FIONBIO, &ioctl_nonblocking) < 0) {
-		*p_oserr = sock_errno;
-		tds_close_socket(tds);
-		return TDSEUSCT; 	/* close enough: "Unable to set communications timer" */
-	}
-
-	retval = connect(tds->s, (struct sockaddr *) &sin, sizeof(sin));
 	if (retval == 0) {
 		tdsdump_log(TDS_DBG_INFO2, "connection established\n");
 	} else {
 		int err = *p_oserr = sock_errno;
 		tdsdump_log(TDS_DBG_ERROR, "tds_open_socket: connect(2) returned \"%s\"\n", sock_strerror(err));
-#if DEBUGGING_CONNECTING_PROBLEM
+#if defined(DEBUGGING_CONNECTING_PROBLEM) && !defined(HAVE_GETADDRINFO)
 		if (err != ECONNREFUSED && err != ENETUNREACH && err != TDSSOCK_EINPROGRESS) {
 			tdsdump_dump_buf(TDS_DBG_ERROR, "Contents of sockaddr_in", &sin, sizeof(sin));
 			tdsdump_log(TDS_DBG_ERROR, 	" sockaddr_in:\t"
Only in ./win32/msvc6: FreeTDS.vcproj
Only in ./win32/msvc6: libTDS.vcproj
Only in ./win32/msvc6: odbc_Debug
Only in ./win32/msvc6: tds_Debug
diff -u -r \freetds_orig/win32/tds_sysdep_public.h ./win32/tds_sysdep_public.h
--- \freetds_orig/win32/tds_sysdep_public.h	Mon Mar 16 13:46:20 2009
+++ ./win32/tds_sysdep_public.h	Sun Oct 10 21:01:01 2010
@@ -30,6 +30,8 @@
 
 #include <windows.h>
 #include <winsock2.h>
+#include <ws2tcpip.h>
+
 #define tds_sysdep_int16_type short	/* 16-bit int */
 #define tds_sysdep_int32_type int	/* 32-bit int */
 #define tds_sysdep_int64_type __int64	/* 64-bit int */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.