Re: What's next?
Mitch Freed <[email protected]>
| Newsgroups | gmane.comp.db.tds.freetds |
|---|---|
| Message-ID | <[email protected]> |
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: [email protected] [[email protected]] On Behalf Of Frediano Ziglio [[email protected]] > 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 > [email protected] > http://lists.ibiblio.org/mailman/listinfo/freetds > _______________________________________________ > FreeTDS mailing list > [email protected] > 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 [email protected], and destroy all copies of this message and any attachments without reading or disclosing them. Thank you. _______________________________________________ FreeTDS mailing list [email protected] http://lists.ibiblio.org/mailman/listinfo/freetds
freetds-0.91-ipv6.patch
(text/x-patch, 28.4 KB)
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 */