Re: [0.95rc2] Preliminary test results

Frediano Ziglio <[email protected]>
Newsgroups gmane.comp.db.tds.freetds
Message-ID <CAHt6W4d5jzT=iynzw7cSstQU2MXxxqjaE4mxjOPRCsDUehBdYg@mail.gmail.com>
2015-05-12 23:10 GMT+01:00 Frediano Ziglio <[email protected]>:
> 2015-05-12 21:07 GMT+01:00 Sergio NNX <[email protected]>:

....

>
>>
>>>> freeclose test output
>>>>
>>>> [...]
>>>> Error finding last socket opened
>>>> FAIL freeclose.exe (exit status: 1)
>>>>
>>
>>> Can you try the attached version?
>>
>> It didn't work. Same error message as before.
>> I'd like to understand that test. What's a typical result for this function: odbc_find_last_socket(void)?
>> What's a common (or default) value for ip remote addr and remote port? Show me an example.
>>
>> Thanks for your time.
>>
>> Sergio.
>>
>
> This function is quite an hack function. It try to discover the last
> socket connection opened. So it try to scan a lot of possible handles
> (numerically 4096 starting from 4, so 4, 8, 12, 16 ... etc) and call
> some function to check if they are really sockets (getpeername and
> getsockname). I also recently changed to discard pair of socketpair
> (two sockets attached together).
>
> I attached a new version, should handle IPv6 addresses (unfortunately
> sizeof(struct sockaddr) < sizeof(struct sockaddr_in6) on Windows).
>


Sorry, silly mistake in attachment

Frediano

_______________________________________________
FreeTDS mailing list
[email protected]
http://lists.ibiblio.org/mailman/listinfo/freetds
freeclose.c (text/x-csrc, 11.2 KB)
#include "common.h"

#if HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */

#include <freetds/time.h>

#if HAVE_ERRNO_H
#include <errno.h>
#endif /* HAVE_ERRNO_H */

#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */

#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */

#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif /* HAVE_SYS_IOCTL_H */

#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif /* HAVE_SYS_WAIT_H */

#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */

#if (!defined(TDS_NO_THREADSAFE) && HAVE_ALARM && HAVE_FSTAT && defined(S_IFSOCK)) || defined(_WIN32)

#include <ctype.h>

#include <freetds/tds.h>
#include <freetds/thread.h>

/* this crazy test test that we do not send too much prepare ... */

static tds_mutex mtx;

typedef union {
	struct sockaddr sa;
	struct sockaddr_in sin;
	char dummy[256];
} long_sockaddr;

#ifdef _WIN32
static TDS_SYS_SOCKET
odbc_find_last_socket(void)
{
	typedef struct {
		TDS_SYS_SOCKET sock;
		int local_port;
		int remote_port;
	} sock_info;
	sock_info found[8];
	unsigned num_found = 0, n;
	int i;

	for (i = 4; i <= (4096*4); i += 4) {
		long_sockaddr remote_addr, local_addr;
		struct sockaddr_in *in;
		socklen_t remote_addr_len, local_addr_len;
		sock_info *info;

		/* check if is a socket */
		remote_addr_len = sizeof(remote_addr);
		if (tds_getpeername((TDS_SYS_SOCKET) i, &remote_addr.sa, &remote_addr_len))
			continue;
		local_addr_len = sizeof(local_addr);
		if (tds_getsockname((TDS_SYS_SOCKET) i, &local_addr.sa, &local_addr_len))
			continue;

		/* save in the array */
		if (num_found >= 8) {
			memmove(found, found+1, sizeof(found) - sizeof(found[0]));
			num_found = 7;
		}
		info = &found[num_found++];
		info->sock = (TDS_SYS_SOCKET) i;
		info->local_port = -1;
		info->remote_port = -1;

		/* now check if is a socketpair */
		in = &remote_addr.sin;
		if (in->sin_family != AF_INET)
			continue;
		if (in->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
			continue;
		info->remote_port = ntohs(in->sin_port);
		in = &local_addr.sin;
		if (in->sin_family != AF_INET)
			continue;
		if (in->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
			continue;
		info->local_port = ntohs(in->sin_port);
		for (n = 0; n < num_found - 1; ++n) {
			if (found[n].remote_port != info->local_port
			    || found[n].local_port != info->remote_port)
				continue;
			--num_found;
			memmove(found+n, found+n+1, num_found-n-1);
			--num_found;
			break;
		}
	}

	/* return last */
	if (num_found == 0)
		return INVALID_SOCKET;
	return found[num_found-1].sock;
}
#endif

static long_sockaddr remote_addr;
static socklen_t remote_addr_len;

static TDS_SYS_SOCKET fake_sock;

static tds_thread fake_thread;
#ifdef _WIN32
#define alarm(n) do { ; } while(0)
#endif
static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg);

static int
init_fake_server(int ip_port)
{
	struct sockaddr_in sin;
	TDS_SYS_SOCKET s;

	memset(&sin, 0, sizeof(sin));
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = htons((short) ip_port);
	sin.sin_family = AF_INET;

	if (TDS_IS_SOCKET_INVALID(s = socket(AF_INET, SOCK_STREAM, 0))) {
		perror("socket");
		exit(1);
	}
	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
		perror("bind");
		CLOSESOCKET(s);
		return 1;
	}
	listen(s, 5);
	if (tds_thread_create(&fake_thread, fake_thread_proc, int2ptr(s)) != 0) {
		perror("tds_thread_create");
		exit(1);
	}
	return 0;
}

static void
write_all(TDS_SYS_SOCKET s, const void *buf, size_t len)
{
	int res, l;
	fd_set fds_write;

	for (; len > 0;) {
		FD_ZERO(&fds_write);
		FD_SET(s, &fds_write);

		res = select(s + 1, NULL, &fds_write, NULL, NULL);
		if (res <= 0) {
			if (errno == EINTR)
				continue;
			perror("select");
			exit(1);
		}

		l = WRITESOCKET(s, buf, len);
		if (l <= 0) {
			perror("write socket");
			exit(1);
		}
		buf = ((const char *) buf) + l;
		len -= l;
	}
}

static unsigned int inserts = 0;
static char insert_buf[256] = "";

static void
count_insert(const char* buf, size_t len)
{
	static const char search[] = "insert into";
	static unsigned char prev = 'x';
	char *p;
	unsigned char c;
	size_t insert_len;

	/* add to buffer */
	for (p = strchr(insert_buf, 0); len > 0; --len, ++buf) {
		c = (unsigned char) buf[0];
		if (prev == 0 || c != 0)
			*p++ = (c >= ' ' && c < 128) ? tolower(c) : '_';
		prev = c;
	}
	*p = 0;

	/* check it */
	while ((p=strstr(insert_buf, search)) != NULL) {
		tds_mutex_lock(&mtx);
		++inserts;
		tds_mutex_unlock(&mtx);
		/* do not find again */
		p[0] = '_';
	}

	/* avoid buffer too long */
	insert_len = strlen(insert_buf);
	if (insert_len > sizeof(search)) {
		p = insert_buf + insert_len - sizeof(search);
		memmove(insert_buf, p, strlen(p) + 1);
	}
}

static unsigned int round_trips = 0;
static enum { sending, receiving } flow = sending;

static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg)
{
	TDS_SYS_SOCKET s = ptr2int(arg), server_sock;
	socklen_t sock_len;
	int len;
	char buf[128];
	struct sockaddr_in sin;
	fd_set fds_read, fds_write, fds_error;
	TDS_SYS_SOCKET max_fd = 0;

	memset(&sin, 0, sizeof(sin));
	sock_len = sizeof(sin);
	alarm(30);
	if ((fake_sock = tds_accept(s, (struct sockaddr *) &sin, &sock_len)) < 0) {
		perror("accept");
		exit(1);
	}
	CLOSESOCKET(s);

	if (TDS_IS_SOCKET_INVALID(server_sock = socket(AF_INET, SOCK_STREAM, 0))) {
		perror("socket");
		exit(1);
	}

	if (connect(server_sock, &remote_addr.sa, remote_addr_len)) {
		perror("connect");
		exit(1);
	}
	alarm(0);

	if (fake_sock > max_fd) max_fd = fake_sock;
	if (server_sock > max_fd) max_fd = server_sock;

	for (;;) {
		int res;

		FD_ZERO(&fds_read);
		FD_SET(fake_sock, &fds_read);
		FD_SET(server_sock, &fds_read);

		FD_ZERO(&fds_write);

		FD_ZERO(&fds_error);
		FD_SET(fake_sock, &fds_error);
		FD_SET(server_sock, &fds_error);

		alarm(30);
		res = select(max_fd + 1, &fds_read, &fds_write, &fds_error, NULL);
		alarm(0);
		if (res < 0) {
			if (sock_errno == TDSSOCK_EINTR)
				continue;
			perror("select");
			exit(1);
		}

		if (FD_ISSET(fake_sock, &fds_error) || FD_ISSET(server_sock, &fds_error)) {
			fprintf(stderr, "error in select\n");
			exit(1);
		}

		/* just read and forward */
		if (FD_ISSET(fake_sock, &fds_read)) {
			if (flow != sending) {
				tds_mutex_lock(&mtx);
				++round_trips;
				tds_mutex_unlock(&mtx);
			}
			flow = sending;

			len = READSOCKET(fake_sock, buf, sizeof(buf));
			if (len == 0)
				break;
			if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS)
				break;
			count_insert(buf, len);
			write_all(server_sock, buf, len);
		}

		if (FD_ISSET(server_sock, &fds_read)) {
			if (flow != receiving) {
				tds_mutex_lock(&mtx);
				++round_trips;
				tds_mutex_unlock(&mtx);
			}
			flow = receiving;

			len = READSOCKET(server_sock, buf, sizeof(buf));
			if (len == 0)
				break;
			if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS)
				break;
			write_all(fake_sock, buf, len);
		}
	}
	CLOSESOCKET(fake_sock);
	CLOSESOCKET(server_sock);
	return NULL;
}

int
main(int argc, char **argv)
{
	SQLLEN sql_nts = SQL_NTS;
	const char *query;
	SQLINTEGER id = 0;
	char string[64];
	TDS_SYS_SOCKET last_socket;
	int port;
	const int num_inserts = 20;
	int is_freetds;

#ifdef _WIN32
	WSADATA wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif

	if (tds_mutex_init(&mtx))
		return 1;

	odbc_connect();

	/*
	 * this does not work if server is not connected with socket
	 * (ie ms driver connected locally)
	 */
	last_socket = odbc_find_last_socket();
	if (TDS_IS_SOCKET_INVALID(last_socket)) {
		fprintf(stderr, "Error finding last socket opened\n");
		return 1;
	}

	remote_addr_len = sizeof(remote_addr);
	if (tds_getpeername(last_socket, &remote_addr.sa, &remote_addr_len)) {
		fprintf(stderr, "Unable to get remote address\n");
		return 1;
	}

	is_freetds = odbc_driver_is_freetds();
	odbc_disconnect();

	/* init fake server, behave like a proxy */
	for (port = 12340; port < 12350; ++port)
		if (!init_fake_server(port))
			break;
	if (port == 12350) {
		fprintf(stderr, "Cannot bind to a port\n");
		return 1;
	}
	printf("Fake server bound at port %d\n", port);

	/* override connections */
	if (is_freetds) {
		setenv("TDSHOST", "127.0.0.1", 1);
		sprintf(string, "%d", port);
		setenv("TDSPORT", string, 1);

		odbc_connect();
	} else {
		char tmp[2048];
		SQLSMALLINT len;

		CHKAllocEnv(&odbc_env, "S");
		CHKAllocConnect(&odbc_conn, "S");
		sprintf(tmp, "DRIVER={SQL Server};SERVER=127.0.0.1,%d;UID=%s;PWD=%s;DATABASE=%s;Network=DBMSSOCN;", port, odbc_user, odbc_password, odbc_database);
		printf("connection string: %s\n", tmp);
		CHKDriverConnect(NULL, T(tmp), SQL_NTS, (SQLTCHAR *) tmp, sizeof(tmp)/sizeof(SQLTCHAR), &len, SQL_DRIVER_NOPROMPT, "SI");
		CHKAllocStmt(&odbc_stmt, "S");
	}

	/* real test */
	odbc_command("CREATE TABLE #test(i int, c varchar(40))");

	odbc_reset_statement();

	/* do not take into account connection statistics */
	tds_mutex_lock(&mtx);
	round_trips = 0;
	inserts = 0;
	tds_mutex_unlock(&mtx);

	query = "insert into #test values (?, ?)";

	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(id), 0, &id, 0, &sql_nts, "SI");
	CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(string), 0, string, 0, &sql_nts, "SI");

	CHKPrepare(T(query), SQL_NTS, "SI");
	tds_mutex_lock(&mtx);
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);

	for (id = 0; id < num_inserts; id++) {
		sprintf(string, "This is a test (%d)", (int) id);
		CHKExecute("SI");
		CHKFreeStmt(SQL_CLOSE, "S");
	}

	tds_mutex_lock(&mtx);
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);
	odbc_reset_statement();

	tds_mutex_lock(&mtx);
	if (inserts > 1 || round_trips > (unsigned) (num_inserts * 2 + 6)) {
		fprintf(stderr, "Too much round trips (%u) or insert (%u) !!!\n", round_trips, inserts);
		tds_mutex_unlock(&mtx);
		return 1;
	}
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);

#ifdef ENABLE_DEVELOPING
	/* check for SQL_RESET_PARAMS */
	tds_mutex_lock(&mtx);
	round_trips = 0;
	inserts = 0;
	tds_mutex_unlock(&mtx);

	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(id), 0, &id, 0, &sql_nts, "SI");
	CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(string), 0, string, 0, &sql_nts, "SI");

	CHKPrepare((SQLCHAR *) query, SQL_NTS, "SI");
	tds_mutex_lock(&mtx);
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);

	for (id = 0; id < num_inserts; id++) {
		CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(id), 0, &id, 0, &sql_nts, "SI");
		CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(string), 0, string, 0, &sql_nts, "SI");

		sprintf(string, "This is a test (%d)", (int) id);
		CHKExecute("SI");
		CHKFreeStmt(SQL_RESET_PARAMS, "S");
	}

	tds_mutex_lock(&mtx);
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);
	odbc_reset_statement();

	tds_mutex_lock(&mtx);
	if (inserts > 1 || round_trips > num_inserts * 2 + 6) {
		fprintf(stderr, "Too much round trips (%u) or insert (%u) !!!\n", round_trips, inserts);
		tds_mutex_unlock(&mtx);
		return 1;
	}
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);
#endif

	odbc_disconnect();

	alarm(10);
	tds_thread_join(fake_thread, NULL);

	return 0;
}

#else
int
main(void)
{
        printf("Not possible for this platform.\n");
        return 0;
}
#endif
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.