Skip to Content.
Sympa Menu

freetds - Re: [freetds] What's next?

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: Mitch Freed <mfreed AT nitrosecurity.com>
  • To: freetds AT lists.ibiblio.org
  • Subject: Re: [freetds] What's next?
  • Date: Thu, 18 Aug 2011 09:08:54 -0600

This is my version of the ipv6 patch that was previously posted. I had to tweak it to get it to work with .91. I also furthered the patch and added support for instance databases (e.g. getting dynamic port # via ipv6).

The patch isn't complete, it doesn't build successfully against the apps. I don't build the apps (--disable-apps) and so I didn't need to complete the patch.

The code that parses the port out of the server name (parse_server_name_for_port) isn't dealing with an ipv6 address as the server name. This code probably needs to be updated to handle this (I didn't need to worry about it). Maybe the requirement should be to enclose the ipv6 server name in brackets [...]:port which would allow you to parse off the port when an ipv6 address is used.

I'm not an active contributor and so probably didn't follow all the coding guidelines. But hopefully this will be useful and can be applied to the base in some form.

- Mitch

On 08/18/2011 02:12 AM, Hristo Hristov wrote:
Hi,

Congratulations for the release!

Because I need IPv6 support, I'll probably soon implement it for ODBC.
I'll check the mail archive for the patch.

Hristo
________________________________________
From: freetds-bounces AT lists.ibiblio.org [freetds-bounces AT lists.ibiblio.org]
On Behalf Of Frediano Ziglio [freddy77 AT gmail.com]
Sent: Thursday, August 18, 2011 11:03
To: FreeTDS Development Group
Subject: [freetds] What's next?

Well.. we just released new version, time to start a new roadmap.

- repository

I think it's about an year I don't write to ChangeLog directly and
months I don't use CVS, is time to officially switch to a more
featured VCS. After some discussion Mercurial and GIT was selected.
Now I think we decided to use GIT we are estimating public providers,
SF/GitHub/whatever. Finally we would even rename files!

- return code

mostly libTDS functions return TDS_SUCCESS/TDS_FAIL while other
returns other ranges for success and fail (like convert that return
=0 for success and< 0 for fail). Other functions can return
TDS_NO_MORE_RESULTS/TDS_CANCELLED, others other values, we test for
TDS_SUCCESS, for TDS_FAIL. I'm planning to unify the situation but
there are some problems due to some relationship between dblib/ctlib
values (like assumption TDS_FAIL == CS_FAIL or same constants for
tds_error). Patches are quite ready.

- thread

libTDS is far from fully thread safe. It returns results filling
fields in a structure without any lock. Currently test to change
connection state is unlocked. Locking at upper layer lead cancellation
a problem. I have some patches for odbc thread safety, but not for
cancellation. Also posting data over an encrypted connection while
waiting for read from a different thread (one of possible cancel
situation) lead thread problems on TLS layer. I'm thinking a way to
release a mutex before poll in order to be able to write or another
way to signal main thread (probably using a socketpair, the most
portable and signal safe implementation).

- mars

patches are undergoing but raise thread problems. I think is useful
only for ODBC.

- bcp

port to ODBC. Better testing, even for new types. It would be great to
support streams in order to pipe then, at least with prefix format.

- DBD::ODBC and SQLDescribeParam

It's not a secret that DBD::ODBC require SQLDescribeParam to pass all
tests. It's not a secret that mssql does not support getting
parameters types but lead the problem to library which has to parse
sql syntax in order to inference them.

- tds 7.3 (sql 2008 support)

Undergoing, latest patches for ODBC are quite ready. Currently
ctlib/dblib are limited to tds 7.1 (sql 2000) due to varchar
conversions and some BLOBs feature removed from upper protocols. I
think is time to diverge from proprietary library to support new
protocols.

- ipv6 ?

A patch was posted time ago. I think is time to review it putting in a
good shape.

- cmake ?

windows support are currently a nightmare due to different environment
of this platforms. cmake would be a solution. Curl use it and has
similar portability problems.

- others

??

Frediano
_______________________________________________
FreeTDS mailing list
FreeTDS AT lists.ibiblio.org
http://lists.ibiblio.org/mailman/listinfo/freetds
_______________________________________________
FreeTDS mailing list
FreeTDS AT lists.ibiblio.org
http://lists.ibiblio.org/mailman/listinfo/freetds
.



This e-mail message and any attachments contain information that is
confidential and may be privileged. If the reader of this e-mail is not the
intended recipient, you are hereby notified that any dissemination,
distribution or copying of this communication is strictly prohibited. If you
have received this communication in error, please immediately notify us by
replying to this message or by sending an email to
postmaster AT nitrosecurity.com, and destroy all copies of this message and any
attachments without reading or disclosing them. Thank you.
diff -uNrp freetds-0.91_orig/include/tds.h freetds-0.91/include/tds.h
--- freetds-0.91_orig/include/tds.h	2011-08-17 19:54:41.000000000 -0600
+++ freetds-0.91/include/tds.h	2011-08-18 08:46:25.410043299 -0600
@@ -879,6 +879,10 @@ typedef struct tds_connection
 	DSTR client_charset;
 
 	DSTR ip_addr;	  	/**< ip of server */
+#ifdef HAVE_GETADDRINFO
+	struct addrinfo *addrs;
+#endif
+
 	DSTR instance_name;
 	DSTR database;
 	DSTR dump_file;
@@ -1409,7 +1413,7 @@ void tds_parse_conf_section(const char *
 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);
@@ -1592,12 +1596,12 @@ extern int tds_g_append_mode;
 
 /* 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);
 int tds7_get_instance_ports(FILE *output, const char *ip_addr);
-int tds7_get_instance_port(const char *ip_addr, const char *instance);
+int tds7_get_instance_port(TDSCONNECTION *connection);
 int tds_ssl_init(TDSSOCKET *tds);
 void tds_ssl_deinit(TDSSOCKET *tds);
 const char *tds_prwsaerror(int erc);
diff -uNrp freetds-0.91_orig/src/ctlib/ct.c freetds-0.91/src/ctlib/ct.c
--- freetds-0.91_orig/src/ctlib/ct.c	2010-10-05 02:36:36.000000000 -0600
+++ freetds-0.91/src/ctlib/ct.c	2011-08-18 08:46:25.410043299 -0600
@@ -407,6 +407,7 @@ ct_con_props(CS_CONNECTION * con, CS_INT
 			portno = (int)strtol(port, NULL, 10);
 			if (portno < 1 || portno >= 65536)
 				return CS_FAIL;
+
 			con->server_addr = strdup(host);
 			tds_set_port(tds_login, portno);
 			break;
@@ -592,7 +593,7 @@ ct_connect(CS_CONNECTION * con, CS_CHAR
 	tdsdump_log(TDS_DBG_FUNC, "ct_connect(%p, %s, %d)\n", con, servername ? servername : "NULL", snamelen);
 
 	if (con->server_addr) {
-		server = "";
+		server = con->server_addr;
 	} else if (snamelen == 0 || snamelen == CS_UNUSED) {
 		server = NULL;
 	} else if (snamelen == CS_NULLTERM) {
@@ -603,6 +604,7 @@ ct_connect(CS_CONNECTION * con, CS_CHAR
 		strncpy(server, servername, snamelen);
 		server[snamelen] = '\0';
 	}
+
 	tds_set_server(con->tds_login, server);
 	if (needfree)
 		free(server);
diff -uNrp freetds-0.91_orig/src/odbc/connectparams.c freetds-0.91/src/odbc/connectparams.c
--- freetds-0.91_orig/src/odbc/connectparams.c	2010-11-09 08:46:42.000000000 -0700
+++ freetds-0.91/src/odbc/connectparams.c	2011-08-18 08:46:25.410043299 -0600
@@ -127,7 +127,7 @@ parse_server(TDS_ERRS *errs, char *serve
 		}
 	}
 
-	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 @@ odbc_get_dsn_info(TDS_ERRS *errs, const
 		}
 	}
 
+	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 @@ odbc_get_dsn_info(TDS_ERRS *errs, const
 		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) {
@@ -191,9 +194,6 @@ odbc_get_dsn_info(TDS_ERRS *errs, const
 		}
 	}
 
-	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 -uNrp freetds-0.91_orig/src/tds/config.c freetds-0.91/src/tds/config.c
--- freetds-0.91_orig/src/tds/config.c	2011-08-17 19:54:41.000000000 -0600
+++ freetds-0.91/src/tds/config.c	2011-08-18 08:46:25.410043299 -0600
@@ -167,6 +167,9 @@ tds_read_config_info(TDSSOCKET * tds, TD
 	if (!connection)
 		return NULL;
 
+	// init the port so we know if we set it ourselves or not in parse_server_name_for_port
+	connection->port = -1;
+
 	s = getenv("TDSDUMPCONFIG");
 	if (s) {
 		if (*s) {
@@ -187,6 +190,7 @@ tds_read_config_info(TDSSOCKET * tds, TD
 
 	/* Read the config files. */
 	tdsdump_log(TDS_DBG_INFO1, "Attempting to read conf files.\n");
+
 	found = tds_read_conf_file(connection, tds_dstr_cstr(&login->server_name));
 	if (!found) {
 		if (parse_server_name_for_port(connection, login)) {
@@ -196,7 +200,7 @@ tds_read_config_info(TDSSOCKET * tds, TD
 			/* do it again to really override what found in freetds.conf */
 			if (found) {
 				parse_server_name_for_port(connection, login);
-			} else if (tds_lookup_host(tds_dstr_cstr(&connection->server_name), ip_addr) == TDS_SUCCEED) {
+			} else if (tds_lookup_host(connection, tds_dstr_cstr(&connection->server_name), ip_addr) == TDS_SUCCEED) {
 				tds_dstr_dup(&connection->server_host_name, &connection->server_name);
 				tds_dstr_copy(&connection->ip_addr, ip_addr);
 				found = 1;
@@ -219,6 +223,9 @@ tds_read_config_info(TDSSOCKET * tds, TD
 
 	/* And finally apply anything from the login structure */
 	tds_config_login(connection, login);
+
+	// if it didn't get modified through all that, set it to 0
+	if(connection->port == -1) connection->port = 0;
 	
 	if (opened) {
 		tdsdump_log(TDS_DBG_INFO1, "Final connection parameters:\n");
@@ -594,7 +601,7 @@ tds_parse_conf_section(const char *optio
 
 		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)) {
@@ -684,7 +691,8 @@ tds_config_login(TDSCONNECTION * connect
 	if (login->block_size) {
 		connection->block_size = login->block_size;
 	}
-	if (login->port)
+	// make sure it hasn't been touched yet
+	if (connection->port == -1 && login->port)
 		connection->port = login->port;
 	if (login->connect_timeout)
 		connection->connect_timeout = login->connect_timeout;
@@ -748,7 +756,7 @@ tds_config_env_tdshost(TDSCONNECTION * c
 
 	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);
 	}
@@ -821,7 +829,7 @@ tds_set_interfaces_file_loc(const char *
  */
 /* 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 */
 	)
 {
@@ -830,18 +838,44 @@ tds_lookup_host(const char *servername,
 
 	/* 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) {
+		*ip = '\0';
+		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);
@@ -1006,12 +1040,12 @@ search_interface_file(TDSCONNECTION * co
 	 * 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);
 	}
@@ -1113,13 +1147,14 @@ tds_read_interfaces(const char *server,
 		/*
 		 * 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;
@@ -1133,14 +1168,27 @@ tds_read_interfaces(const char *server,
 static int
 parse_server_name_for_port(TDSCONNECTION * connection, TDSLOGIN * login)
 {
-	const char *pSep;
+	const char *pSep = NULL;
 	const char *server;
+	char *pServer;
+	int i = 0;
 
-	/* seek the ':' in login server_name */
 	server = tds_dstr_cstr(&login->server_name);
-	pSep = strrchr(server, ':');
 
-	if (pSep && pSep != server) {	/* yes, i found it! */
+	// seek the ':' in login server_name
+	// determine if the server is specified as an ipv6 address or not, if so we won't grab a port
+	pServer = server;
+	while(*pServer)
+	{
+		if(*pServer == ':')
+		{
+			pSep = pServer;
+			++i;
+		}
+		++pServer;
+	}
+
+	if (pSep && i < 2 && pSep != server) {	/* yes, i found it! */
 		/* modify connection-> && login->server_name & ->port */
 		login->port = connection->port = atoi(pSep + 1);
 		tds_dstr_copy(&connection->instance_name, "");
@@ -1154,7 +1202,7 @@ parse_server_name_for_port(TDSCONNECTION
 		connection->port = 0;
 	}
 
-	if (!tds_dstr_copyn(&connection->server_name, server, pSep - server))
+	if(!tds_dstr_copyn(&connection->server_name, server, pSep - server))
 		return 0;
 
 	return 1;
diff -uNrp freetds-0.91_orig/src/tds/login.c freetds-0.91/src/tds/login.c
--- freetds-0.91_orig/src/tds/login.c	2011-04-11 15:33:54.000000000 -0600
+++ freetds-0.91/src/tds/login.c	2011-08-18 08:46:25.410043299 -0600
@@ -383,7 +383,6 @@ tds_connect(TDSSOCKET * tds, TDSCONNECTI
 		return erc;
 	}
 	
-
 	/*
 	 * If a dump file has been specified, start logging
 	 */
@@ -430,7 +429,7 @@ tds_connect(TDSSOCKET * tds, TDSCONNECTI
 	}
 
 	if (!IS_TDS50(tds) && !tds_dstr_isempty(&connection->instance_name) && !connection->port)
-		connection->port = tds7_get_instance_port(tds_dstr_cstr(&connection->ip_addr), tds_dstr_cstr(&connection->instance_name));
+		connection->port = tds7_get_instance_port(connection);
 
 	if (connection->port < 1) {
 		tdsdump_log(TDS_DBG_ERROR, "invalid port number\n");
@@ -439,7 +438,7 @@ tds_connect(TDSSOCKET * tds, TDSCONNECTI
 
 	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 -uNrp freetds-0.91_orig/src/tds/mem.c freetds-0.91/src/tds/mem.c
--- freetds-0.91_orig/src/tds/mem.c	2011-08-17 19:54:42.000000000 -0600
+++ freetds-0.91/src/tds/mem.c	2011-08-18 08:46:25.410043299 -0600
@@ -1179,6 +1179,10 @@ tds_free_connection(TDSCONNECTION * conn
 	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 -uNrp freetds-0.91_orig/src/tds/net.c freetds-0.91/src/tds/net.c
--- freetds-0.91_orig/src/tds/net.c	2011-08-17 19:54:42.000000000 -0600
+++ freetds-0.91/src/tds/net.c	2011-08-18 08:46:25.420043746 -0600
@@ -86,6 +86,10 @@
 #include <poll.h>
 #endif /* HAVE_POLL_H */
 
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif /* HAVE_NETDB_H */
+
 #include "tds.h"
 #include "tdsstring.h"
 #include "replacements.h"
@@ -179,9 +183,17 @@ typedef u_long ioctl_nonblocking_t;
 #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,84 +203,152 @@ tds_open_socket(TDSSOCKET * tds, const c
 
 	*p_oserr = 0;
 
-	memset(&sin, 0, sizeof(sin));
+#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;
+			}
 
-	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;
-	}
+			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;
+			}
 
-	sin.sin_family = AF_INET;
-	sin.sin_port = htons(port);
+#ifdef SO_KEEPALIVE
+			len = 1;
+			setsockopt(tds->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len));
+#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));
+			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
 
-	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
 
 #if defined(__APPLE__) && defined(SO_NOSIGPIPE)
-	len = 1;
-	if (setsockopt(tds->s, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &len, sizeof(len))) {
-		*p_oserr = sock_errno;
-		tds_close_socket(tds);
-		return TDSESOCK;
-	}
+		len = 1;
+		if (setsockopt(tds->s, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &len, sizeof(len))) {
+			*p_oserr = sock_errno;
+			tds_close_socket(tds);
+			return TDSESOCK;
+		}
 #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"
@@ -919,10 +999,10 @@ tds7_get_instance_ports(FILE *output, co
  * @return port number or 0 if error
  */
 int
-tds7_get_instance_port(const char *ip_addr, const char *instance)
+//tds7_get_instance_port(const char *ip_addr, const char *instance)
+tds7_get_instance_port(TDSCONNECTION *connection)
 {
 	int num_try;
-	struct sockaddr_in sin;
 	ioctl_nonblocking_t ioctl_nonblocking;
 	struct pollfd fd;
 	int retval;
@@ -930,130 +1010,170 @@ tds7_get_instance_port(const char *ip_ad
 	char msg[1024];
 	size_t msg_len;
 	int port = 0;
+	int conn_port = htons(1434);
+	const char *instance = tds_dstr_cstr(&connection->instance_name);
+	const char *ip_addr = tds_dstr_cstr(&connection->ip_addr);
 
 	tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port(%s, %s)\n", ip_addr, instance);
 
-	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 0;
-	}
-
-	sin.sin_family = AF_INET;
-	sin.sin_port = htons(1434);
-
-	/* create an UDP socket */
-	if (TDS_IS_SOCKET_INVALID(s = socket(AF_INET, SOCK_DGRAM, 0))) {
-		tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", sock_strerror(sock_errno));
+	if (connection->addrs == NULL) {
+		tdsdump_log(TDS_DBG_ERROR, "no connection address available\n");
 		return 0;
 	}
+	
+	struct sockaddr_in *sin;
+	struct addrinfo *addr;
+	size_t sin_size;
+
+	for(addr = connection->addrs; addr != NULL; addr = addr->ai_next)
+	{
+		if(addr->ai_family == AF_INET)
+		{
+			sin = (struct sockaddr_in *)addr->ai_addr;
+			sin->sin_port = conn_port;
+			sin_size = sizeof(struct sockaddr_in);
+		}
+#ifdef AF_INET6
+		else if(addr->ai_family == AF_INET6)
+		{
+			sin = (struct sockaddr_in *)addr->ai_addr;
+			((struct sockaddr_in6 *)sin)->sin6_port = conn_port;
+			sin_size = sizeof(struct sockaddr_in6);
+		}
+#endif
+		else
+		{
+			tdsdump_log(TDS_DBG_ERROR, "could not set port - unrecognized protocol family: %d\n", addr->ai_family);
+			continue;
+		}
 
-	/*
-	 * on cluster environment is possible that reply packet came from
-	 * different IP so do not filter by ip with connect
-	 */
-
-	ioctl_nonblocking = 1;
-	if (IOCTLSOCKET(s, FIONBIO, &ioctl_nonblocking) < 0) {
-		CLOSESOCKET(s);
-		return 0;
-	}
-
-	/* 
-	 * Request the instance's port from the server.  
-	 * There is no easy way to detect if port is closed so we always try to
-	 * get a reply from server 16 times. 
-	 */
-	for (num_try = 0; num_try < 16; ++num_try) {
-		/* send the request */
-		msg[0] = 4;
-		tds_strlcpy(msg + 1, instance, sizeof(msg) - 1);
-		sendto(s, msg, (int)strlen(msg) + 1, 0, (struct sockaddr *) &sin, sizeof(sin));
-
-		fd.fd = s;
-		fd.events = POLLIN;
-		fd.revents = 0;
-
-		retval = poll(&fd, 1, 1000);
-		
-		/* on interrupt ignore */
-		if (retval < 0 && sock_errno == TDSSOCK_EINTR)
+		if(TDS_IS_SOCKET_INVALID(s = socket(addr->ai_family, SOCK_DGRAM, 0)))
+		{
+			tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", sock_strerror(sock_errno));
 			continue;
-		
-		if (retval == 0) { /* timed out */
-#if 1
-			tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port: timed out on try %d of 16\n", num_try);
+		}
+	
+		/*
+		 * on cluster environment is possible that reply packet came from
+		 * different IP so do not filter by ip with connect
+		 */
+		ioctl_nonblocking = 1;
+		if(IOCTLSOCKET(s, FIONBIO, &ioctl_nonblocking) < 0)
+		{
+			CLOSESOCKET(s);
 			continue;
-#else
-			int rc;
-			tdsdump_log(TDS_DBG_INFO1, "timed out\n");
-
-			switch(rc = tdserror(NULL, NULL, TDSETIME, 0)) {
-			case TDS_INT_CONTINUE:
-				continue;	/* try again */
-
-			default:
-				tdsdump_log(TDS_DBG_ERROR, "error: client error handler returned %d\n", rc);
-			case TDS_INT_CANCEL: 
-				CLOSESOCKET(s);
-				return 0;
-			}
-#endif
 		}
-		if (retval < 0)
-			break;
 
-		/* TODO pass also connection and set instance/servername ?? */
+		/* 
+		 * Request the instance's port from the server.  
+		 * There is no easy way to detect if port is closed so we always try to
+		 * get a reply from server 16 times. 
+		 */
+		for(num_try = 0; num_try < 16; ++num_try)
+		{
+			/* send the request */
+			msg[0] = 4;
+			tds_strlcpy(msg + 1, instance, sizeof(msg) - 1);
+			sendto(s, msg, (int)strlen(msg) + 1, 0, (struct sockaddr *)sin, sin_size);
+
+			fd.fd = s;
+			fd.events = POLLIN;
+			fd.revents = 0;
 
-		/* got data, read and parse */
-		if ((msg_len = recv(s, msg, sizeof(msg) - 1, 0)) > 3 && msg[0] == 5) {
-			char *p;
-			long l = 0;
-			int instance_ok = 0, port_ok = 0;
+			retval = poll(&fd, 1, 1000);
+			
+			/* on interrupt ignore */
+			if(retval < 0 && sock_errno == TDSSOCK_EINTR)
+				continue;
 
-			/* assure null terminated */
-			msg[msg_len] = 0;
-			tdsdump_dump_buf(TDS_DBG_INFO1, "instance info", msg, msg_len);
+			if(retval == 0) /* timed out */
+			{
+	#if 1
+				tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port: timed out on try %d of 16\n", num_try);
+				continue;
+	#else
+				int rc;
+				tdsdump_log(TDS_DBG_INFO1, "timed out\n");
+
+				switch(rc = tdserror(NULL, NULL, TDSETIME, 0))
+				{
+					case TDS_INT_CONTINUE:
+						continue;	/* try again */
+
+					default:
+						tdsdump_log(TDS_DBG_ERROR, "error: client error handler returned %d\n", rc);
+					case TDS_INT_CANCEL: 
+						CLOSESOCKET(s);
+						break;
+				}
+	#endif
+			}
+			if (retval < 0)
+				break;
 
-			/*
-			 * Parse message and check instance name and port.
-			 * We don't check servername cause it can be very different from the client's. 
-			 */
-			for (p = msg + 3;;) {
-				char *name, *value;
+			/* TODO pass also connection and set instance/servername ?? */
 
-				name = p;
-				p = strchr(p, ';');
-				if (!p)
-					break;
-				*p++ = 0;
+			/* got data, read and parse */
+			if((msg_len = recv(s, msg, sizeof(msg) - 1, 0)) > 3 && msg[0] == 5)
+			{
+				char *p;
+				long l = 0;
+				int instance_ok = 0, port_ok = 0;
+
+				/* assure null terminated */
+				msg[msg_len] = 0;
+				tdsdump_dump_buf(TDS_DBG_INFO1, "instance info", msg, msg_len);
+
+				/*
+				 * Parse message and check instance name and port.
+				 * We don't check servername cause it can be very different from the client's. 
+				 */
+				for(p = msg + 3;;)
+				{
+					char *name, *value;
 
-				value = name;
-				if (*name) {
-					value = p;
+					name = p;
 					p = strchr(p, ';');
-					if (!p)
+					if(!p)
 						break;
 					*p++ = 0;
-				}
 
-				if (strcasecmp(name, "InstanceName") == 0) {
-					if (strcasecmp(value, instance) != 0)
-						break;
-					instance_ok = 1;
-				} else if (strcasecmp(name, "tcp") == 0) {
-					l = strtol(value, &p, 10);
-					if (l > 0 && l <= 0xffff && *p == 0)
-						port_ok = 1;
+					value = name;
+					if(*name)
+					{
+						value = p;
+						p = strchr(p, ';');
+						if (!p)
+							break;
+						*p++ = 0;
+					}
+
+					if(strcasecmp(name, "InstanceName") == 0)
+					{
+						if(strcasecmp(value, instance) != 0)
+							break;
+						instance_ok = 1;
+					}
+					else if(strcasecmp(name, "tcp") == 0)
+					{
+						l = strtol(value, &p, 10);
+						if(l > 0 && l <= 0xffff && *p == 0)
+							port_ok = 1;
+					}
+				}
+				if(port_ok && instance_ok)
+				{
+					port = l;
+					break;
 				}
-			}
-			if (port_ok && instance_ok) {
-				port = l;
-				break;
 			}
 		}
+
+		CLOSESOCKET(s);
+		if(port)
+			break;
 	}
-	CLOSESOCKET(s);
+
 	tdsdump_log(TDS_DBG_ERROR, "instance port is %d\n", port);
 	return port;
 }
diff -uNrp freetds-0.91_orig/win32/tds_sysdep_public.h freetds-0.91/win32/tds_sysdep_public.h
--- freetds-0.91_orig/win32/tds_sysdep_public.h	2011-08-17 19:54:42.000000000 -0600
+++ freetds-0.91/win32/tds_sysdep_public.h	2011-08-18 08:46:42.660822309 -0600
@@ -30,6 +30,7 @@ extern "C"
 
 #include <winsock2.h>
 #include <windows.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 */



Archive powered by MHonArc 2.6.24.

Top of Page