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 */