Skip to Content.
Sympa Menu

freetds - Re: [freetds] tdsdump SIGSEGV with mt apps

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: liam AT inodes.org
  • To: FreeTDS Development Group <freetds AT lists.ibiblio.org>
  • Subject: Re: [freetds] tdsdump SIGSEGV with mt apps
  • Date: Wed, 4 May 2005 19:58:33 +1000

Hi,

Attached is my patch which from my testing, appears to fix the timeout
problems, makes dblib and TDSDUMP thread-safe.

I've had to modify the ODBC test case in order for it to pass. I
believe this is the appropriate behaviour for the test case but I
could be mistaken.

Comments?

Thanks.
diff -rNu -X freetds.exclude freetds-0.64.dev.20050411/include/tds.h
freetds-0.64.dev.20050411-new/include/tds.h
--- freetds-0.64.dev.20050411/include/tds.h 2005-03-25 01:44:09.000000000
+1100
+++ freetds-0.64.dev.20050411-new/include/tds.h 2005-04-19 15:25:39.850012000
+1000
@@ -649,6 +649,7 @@
#define TDS_STR_DEBUGLVL "debug level"
#define TDS_STR_DEBUGFLAGS "debug flags"
#define TDS_STR_TIMEOUT "timeout"
+#define TDS_STR_QUERY_TIMEOUT "query timeout"
#define TDS_STR_CONNTIMEOUT "connect timeout"
#define TDS_STR_HOSTNAME "hostname"
#define TDS_STR_HOST "host"
@@ -1097,6 +1098,7 @@
TDS_STATE state;
volatile unsigned char in_cancel;
int rows_affected;
+ int timeout;
/* timeout stuff from Jeff */
TDS_INT query_timeout;
int (*query_timeout_func) (void *param);
diff -rNu -X freetds.exclude freetds-0.64.dev.20050411/include/tdsthread.h
freetds-0.64.dev.20050411-new/include/tdsthread.h
--- freetds-0.64.dev.20050411/include/tdsthread.h 1970-01-01
10:00:00.000000000 +1000
+++ freetds-0.64.dev.20050411-new/include/tdsthread.h 2005-05-04
19:42:20.810003000 +1000
@@ -0,0 +1,50 @@
+/* FreeTDS - Library of routines accessing Sybase and Microsoft databases
+ *
+ * Copyright (C) 2005 Liam Widdowson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TDSTHREAD_H
+#define TDSTHREAD_H 1
+
+#ifdef _THREAD_SAFE
+
+#include <pthread.h>
+
+#define TDS_MUTEX_T pthread_mutex_t
+#define TDS_MUTEXATTR_T pthread_mutexattr_t
+#define TDS_MUTEX_INIT(a,b) pthread_mutex_init(a,b)
+#define TDS_MUTEX_LOCK(a) pthread_mutex_lock(a)
+#define TDS_MUTEXATTR_INIT(a) pthread_mutexattr_init(a)
+#define TDS_MUTEXATTR_SETTYPE(a,b) pthread_mutexattr_settype(a,b)
+#define TDS_MUTEX_UNLOCK(a) pthread_mutex_unlock(a)
+#define TDS_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE
+#define TDS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#else
+
+#define TDS_MUTEX_T int
+#define TDS_MUTEXATTR_T int
+#define TDS_MUTEX_INIT(a,b)
+#define TDS_MUTEX_LOCK(a)
+#define TDS_MUTEXATTR_INIT(a)
+#define TDS_MUTEXATTR_SETTYPE(a,b)
+#define TDS_MUTEX_UNLOCK(a)
+#define TDS_MUTEX_RECURSIVE
+#define TDS_MUTEX_INITIALIZER
+#endif
+
+#endif
diff -rNu -X freetds.exclude freetds-0.64.dev.20050411/src/dblib/dblib.c
freetds-0.64.dev.20050411-new/src/dblib/dblib.c
--- freetds-0.64.dev.20050411/src/dblib/dblib.c 2005-04-21 11:37:58.570009000
+1000
+++ freetds-0.64.dev.20050411-new/src/dblib/dblib.c 2005-04-22
20:43:31.060048000 +1000
@@ -17,10 +17,13 @@
* Boston, MA 02111-1307, USA.
*/

+
#if HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

+#include "tdsthread.h"
+
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
@@ -110,6 +113,9 @@
int connection_list_size_represented;
char *recftos_filename;
int recftos_filenum;
+ int g_dblib_login_timeout; /* not used unless positive */
+ int g_dblib_query_timeout; /* not used unless positive */
+ TDS_MUTEX_T mutex;
}
DBLIBCONTEXT;

@@ -132,8 +138,6 @@
DBVERSION_80;
#endif

-static int g_dblib_login_timeout = -1; /* not used unless positive */
-static int g_dblib_query_timeout = -1; /* not used unless positive */

static int
dblib_add_connection(DBLIBCONTEXT * ctx, TDSSOCKET * tds)
@@ -500,6 +504,9 @@
RETCODE
dbinit(void)
{
+
+ TDS_MUTEXATTR_T attr;
+
/*
* DBLIBCONTEXT stores a list of current connections so they may be
closed
* with dbexit()
@@ -526,11 +533,20 @@
g_dblib_ctx.tds_ctx->err_handler = _dblib_handle_err_message;


- if (g_dblib_ctx.tds_ctx->locale &&
!g_dblib_ctx.tds_ctx->locale->date_fmt) {
+ if (g_dblib_ctx.tds_ctx->locale &&
+ !g_dblib_ctx.tds_ctx->locale->date_fmt) {
/* set default in case there's no locale file */
- g_dblib_ctx.tds_ctx->locale->date_fmt = strdup("%b %e %Y
%I:%M:%S:%z%p");
+ g_dblib_ctx.tds_ctx->locale->date_fmt =
+ strdup("%b %e %Y %I:%M:%S:%z%p");
}

+ g_dblib_ctx.g_dblib_login_timeout = -1;
+ g_dblib_ctx.g_dblib_query_timeout = -1;
+
+ TDS_MUTEXATTR_INIT(&attr);
+ TDS_MUTEXATTR_SETTYPE(&attr, TDS_MUTEX_RECURSIVE);
+ TDS_MUTEX_INIT(&g_dblib_ctx.mutex, &attr);
+
return SUCCEED;
}

@@ -931,7 +947,10 @@

tds_set_server(login->tds_login, server);

+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
dbproc->tds_socket = tds_alloc_socket(g_dblib_ctx.tds_ctx, 512);
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
+
tds_set_parent(dbproc->tds_socket, (void *) dbproc);
dbproc->tds_socket->option_flag2 &= ~0x02; /* we're not an ODBC
driver */
dbproc->tds_socket->env_chg_func = db_env_chg;
@@ -943,16 +962,6 @@
if (!connection)
return NULL;

- /* override connection timeout if dbsetlogintime() was called */
- if (g_dblib_login_timeout >= 0) {
- connection->connect_timeout = g_dblib_login_timeout;
- }
-
- /* override query timeout if dbsettime() was called */
- if (g_dblib_query_timeout >= 0) {
- connection->timeout = g_dblib_query_timeout;
- }
-
dbproc->dbchkintr = NULL;
dbproc->dbhndlintr = NULL;
dbproc->tds_socket->query_timeout_param = dbproc->tds_socket;
@@ -964,13 +973,34 @@
tds_free_connection(connection);
return NULL;
}
+
+ dbproc->tds_socket->timeout = connection->timeout;
+ dbproc->tds_socket->query_timeout = connection->query_timeout;
+
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
+
+ /* override connection timeout if dbsetlogintime() was called */
+ if (g_dblib_ctx.g_dblib_login_timeout > 0) {
+ connection->connect_timeout =
g_dblib_ctx.g_dblib_login_timeout;
+ }
+
+ /* override query timeout if dbsettime() was called */
+ if (g_dblib_ctx.g_dblib_query_timeout > 0) {
+ connection->query_timeout = g_dblib_ctx.g_dblib_query_timeout;
+ }
+
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
+
tds_free_connection(connection);
+
dbproc->dbbuf = NULL;
dbproc->dbbufsz = 0;

if (dbproc->tds_socket) {
/* tds_set_parent( dbproc->tds_socket, dbproc); */
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
dblib_add_connection(&g_dblib_ctx, dbproc->tds_socket);
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
} else {
fprintf(stderr, "DB-Library: Login incorrect.\n");
free(dbproc); /* memory leak fix (mlilback, 11/17/01) */
@@ -979,6 +1009,8 @@

buffer_init(&(dbproc->row_buf));

+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
+
if (g_dblib_ctx.recftos_filename != NULL) {
char *temp_filename = NULL;
const int len = asprintf(&temp_filename, "%s.%d",
@@ -993,6 +1025,9 @@
free(temp_filename);
}
}
+
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
+
return dbproc;
}

@@ -1227,7 +1262,9 @@
dbstring_free(&(dbproc->dboptcmd));

dbfreebuf(dbproc);
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
dblib_del_connection(&g_dblib_ctx, dbproc->tds_socket);
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
free(dbproc);

return;
@@ -1248,8 +1285,10 @@
int i;
const int list_size = g_dblib_ctx.connection_list_size;

-
/* FIX ME -- this breaks if ctlib/dblib used in same process */
+
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
+
for (i = 0; i < list_size; i++) {
tds = g_dblib_ctx.connection_list[i];
if (tds) {
@@ -1267,6 +1306,8 @@
tds_free_context(g_dblib_ctx.tds_ctx);
g_dblib_ctx.tds_ctx = NULL;
}
+
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
}

/**
@@ -1866,7 +1907,9 @@

tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");

+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
len = tds_convert(g_dblib_ctx.tds_ctx, srctype, (const TDS_CHAR *)
src, srclen, desttype, &dres);
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned
%d\n", len);

switch (len) {
@@ -3292,6 +3335,9 @@
TDSSOCKET **old_list = g_dblib_ctx.connection_list;

tdsdump_log(TDS_DBG_FUNC, "UNTESTED dbsetmaxprocs()\n");
+
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
+
/*
* Don't reallocate less memory.
* If maxprocs is less than was initially allocated, just reduce the
represented list size.
@@ -3300,6 +3346,7 @@
*/
if (maxprocs < g_dblib_ctx.connection_list_size) {
g_dblib_ctx.connection_list_size_represented = maxprocs;
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
return SUCCEED;
}

@@ -3307,6 +3354,7 @@

if (g_dblib_ctx.connection_list == NULL) {
g_dblib_ctx.connection_list = old_list;
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
return FAIL;
}

@@ -3317,6 +3365,8 @@
g_dblib_ctx.connection_list_size = maxprocs;
g_dblib_ctx.connection_list_size_represented = maxprocs;

+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
+
return SUCCEED;
}

@@ -3330,7 +3380,11 @@
int
dbgetmaxprocs(void)
{
- return g_dblib_ctx.connection_list_size_represented;
+ int r;
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
+ r = g_dblib_ctx.connection_list_size_represented;
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
+ return r;
}

/**
@@ -3345,7 +3399,9 @@
RETCODE
dbsettime(int seconds)
{
- g_dblib_query_timeout = seconds;
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
+ g_dblib_ctx.g_dblib_query_timeout = seconds;
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
return SUCCEED;
}

@@ -3360,7 +3416,9 @@
RETCODE
dbsetlogintime(int seconds)
{
- g_dblib_login_timeout = seconds;
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
+ g_dblib_ctx.g_dblib_login_timeout = seconds;
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
return SUCCEED;
}

@@ -3721,6 +3779,10 @@
char *cmd;
RETCODE rc;

+ if (dbproc == NULL) {
+ return FAIL;
+ }
+
if ((option < 0) || (option >= DBNUMOPTIONS)) {
_dblib_client_msg(dbproc, SYBEUNOP, EXNONFATAL, "Unknown
option passed to dbsetopt().");
return FAIL;
@@ -5576,11 +5638,13 @@
void
dbrecftos(char *filename)
{
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
g_dblib_ctx.recftos_filename = malloc(strlen(filename) + 1);
if (g_dblib_ctx.recftos_filename != NULL) {
strcpy(g_dblib_ctx.recftos_filename, filename);
g_dblib_ctx.recftos_filenum = 0;
}
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
}

/** \internal
@@ -6157,10 +6221,15 @@
_dblib_client_msg(DBPROCESS * dbproc, int dberr, int severity, const char
*dberrstr)
{
TDSSOCKET *tds = NULL;
+ int r;

if (dbproc)
tds = dbproc->tds_socket;
- return tds_client_msg(g_dblib_ctx.tds_ctx, tds, dberr, severity, -1,
-1, dberrstr);
+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
+ r = tds_client_msg(g_dblib_ctx.tds_ctx, tds, dberr, severity, -1, -1,
dberrstr);
+
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
+ return r;
}

static char *
@@ -6383,7 +6452,10 @@
dres.n.scale = num->scale;
}

+ TDS_MUTEX_LOCK(&g_dblib_ctx.mutex);
len = tds_convert(g_dblib_ctx.tds_ctx, srctype, (const TDS_CHAR *)
src, srclen, desttype, &dres);
+ TDS_MUTEX_UNLOCK(&g_dblib_ctx.mutex);
+
tdsdump_log(TDS_DBG_INFO1, "copy_data_to_host_var() called
tds_convert returned %d\n", len);

switch (len) {
diff -rNu -X freetds.exclude
freetds-0.64.dev.20050411/src/odbc/unittests/common.c
freetds-0.64.dev.20050411-new/src/odbc/unittests/common.c
--- freetds-0.64.dev.20050411/src/odbc/unittests/common.c 2005-04-29
20:50:20.140001000 +1000
+++ freetds-0.64.dev.20050411-new/src/odbc/unittests/common.c 2005-04-29
21:13:52.700002000 +1000
@@ -20,6 +20,8 @@
HSTMT Statement;
int use_odbc_version3 = 0;

+int exit_on_error = 1;
+
char USER[512];
char SERVER[512];
char PASSWORD[512];
@@ -147,8 +149,11 @@
ret = SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, msg,
sizeof(msg), NULL);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
fprintf(stderr, "SQL error %s -- %s\n", sqlstate, msg);
- Disconnect();
- /* exit(1); */
+
+ if (exit_on_error == 1) {
+ Disconnect();
+ exit(1);
+ }
}

void
diff -rNu -X freetds.exclude
freetds-0.64.dev.20050411/src/odbc/unittests/common.h
freetds-0.64.dev.20050411-new/src/odbc/unittests/common.h
--- freetds-0.64.dev.20050411/src/odbc/unittests/common.h 2005-01-15
02:03:12.000000000 +1100
+++ freetds-0.64.dev.20050411-new/src/odbc/unittests/common.h 2005-04-29
21:17:11.510001000 +1000
@@ -37,6 +37,7 @@
extern HDBC Connection;
extern HSTMT Statement;
extern int use_odbc_version3;
+extern int exit_on_error;

extern char USER[512];
extern char SERVER[512];
diff -rNu -X freetds.exclude
freetds-0.64.dev.20050411/src/odbc/unittests/timeout.c
freetds-0.64.dev.20050411-new/src/odbc/unittests/timeout.c
--- freetds-0.64.dev.20050411/src/odbc/unittests/timeout.c 2005-03-30
01:19:36.000000000 +1000
+++ freetds-0.64.dev.20050411-new/src/odbc/unittests/timeout.c 2005-05-04
19:37:30.740001000 +1000
@@ -35,6 +35,7 @@
SQLRETURN ret;
SQLINTEGER i;

+
Connect();

/* here we can't use temporary table cause we use two connection */
@@ -62,6 +63,8 @@
if (ret != SQL_SUCCESS)
ODBC_REPORT_ERROR("Error setting timeout");

+ exit_on_error = 0;
+
i = 1;
ret = SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, &i, 0, NULL);
if (ret != SQL_SUCCESS)
@@ -74,13 +77,10 @@
ODBC_REPORT_ERROR("SQLExecute success ??");
EndTransaction(SQL_ROLLBACK);

+
/* TODO should return error S1T00 Timeout expired */
ret = CommandWithResult(Statement, "update test_timeout set t = 'bad'
where n = 1");
if (ret != SQL_ERROR) {
- Disconnect();
- Environment = env;
- Connection = dbc;
- Statement = stmt;
ODBC_REPORT_ERROR("SQLExecDirect success ??");
}
EndTransaction(SQL_ROLLBACK);
diff -rNu -X freetds.exclude freetds-0.64.dev.20050411/src/tds/config.c
freetds-0.64.dev.20050411-new/src/tds/config.c
--- freetds-0.64.dev.20050411/src/tds/config.c 2005-03-12 22:49:35.000000000
+1100
+++ freetds-0.64.dev.20050411-new/src/tds/config.c 2005-04-19
15:24:33.450003000 +1000
@@ -430,6 +430,9 @@
l = strtol(value, &end, 0);
if (errno == 0 && *end == 0)
connection->debug_flags = l;
+ } else if (!strcmp(option, TDS_STR_QUERY_TIMEOUT)) {
+ if (atoi(value))
+ connection->query_timeout = atoi(value);
} else if (!strcmp(option, TDS_STR_TIMEOUT)) {
if (atoi(value))
connection->timeout = atoi(value);
@@ -535,7 +538,8 @@
connection->connect_timeout = login->connect_timeout;

/* copy other info not present in configuration file */
- connection->query_timeout = login->query_timeout;
+ if (connection->query_timeout == 0)
+ connection->query_timeout = login->query_timeout;
connection->query_timeout_func = login->query_timeout_func;
connection->query_timeout_param = login->query_timeout_param;
memcpy(connection->capabilities, login->capabilities,
TDS_MAX_CAPABILITY);
diff -rNu -X freetds.exclude freetds-0.64.dev.20050411/src/tds/net.c
freetds-0.64.dev.20050411-new/src/tds/net.c
--- freetds-0.64.dev.20050411/src/tds/net.c 2005-05-04 19:31:17.020005000
+1000
+++ freetds-0.64.dev.20050411-new/src/tds/net.c 2005-05-04 19:30:48.250004000
+1000
@@ -240,143 +240,154 @@
return rc;
}

+
+static int read_t(int fd, unsigned char *data, size_t length, int timeout) {
+
+ fd_set rfds;
+ int r;
+ struct timeval tv = { 60, 0 };
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ if (timeout > 0) {
+ tv.tv_sec = timeout;
+ }
+
+ if ((r=select(fd+1, &rfds, NULL, NULL, &tv)) > 0) {
+ if (FD_ISSET(fd, &rfds)) {
+#ifndef MSG_NOSIGNAL
+ return READSOCKET(fd, data, length);
+#else
+ return recv(fd, data, length, MSG_NOSIGNAL);
+#endif
+ } else {
+ return 0;
+ }
+ } else {
+ return r;
+ }
+ return length;
+}
+
+static int tds_goodread_timeout_handler(TDSSOCKET * tds) {
+
+ int timeout_action;
+
+ timeout_action = TDS_INT_CONTINUE;
+
+ if (tds->query_timeout_func && tds->query_timeout) {
+ timeout_action = (*tds->query_timeout_func)
+ (tds->query_timeout_param);
+ }
+
+ switch (timeout_action)
+ {
+ case TDS_INT_EXIT:
+ exit(EXIT_FAILURE);
+ break;
+ case TDS_INT_CANCEL:
+ tds_send_cancel(tds);
+ break;
+
+ case TDS_INT_CONTINUE:
+ default:
+ break;
+ }
+
+ return timeout_action;
+}
+
/**
* Loops until we have received buflen characters
* return -1 on failure
*/
+
int
tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen, unsigned char
unfinished)
{
+ time_t start = 0, now = 0;
+ int timeout = 0;
+ int query_timeout = 0;
int got = 0;
- int len, retcode;
- int timeout_action;
- fd_set fds;
- time_t start, now;
- struct timeval selecttimeout;
- struct timeval *timeout;
+
+ if (buf == NULL || buflen < 1 || tds == NULL) {
+ return 0;
+ }

assert(tds);

- FD_ZERO(&fds);
- now = time(NULL);
- start = tds->query_start_time ? tds->query_start_time : now;
- while ((buflen > 0) && (!tds->query_timeout || ((now - start) <
tds->query_timeout))) {
- if (IS_TDSDEAD(tds))
- return -1;
+ start = tds->query_start_time ? tds->query_start_time : time(NULL);

- /* set right timeout */
- FD_SET(tds->s, &fds);
- timeout = NULL;
- if (tds->query_timeout_func && tds->query_timeout) {
- long seconds = tds->query_timeout - (now - start);
-
- tdsdump_log(TDS_DBG_INFO1, "time timeout %d now %u
start %u\n", tds->query_timeout, (unsigned int) now, (unsigned int) start);
- if (seconds < 1)
- seconds = 1;
- selecttimeout.tv_sec = seconds;
- selecttimeout.tv_usec = 0;
- timeout = &selecttimeout;
- }
-
- /* retcode == 0 indicates a timeout, OK */
- retcode = select(tds->s + 1, &fds, NULL, NULL, timeout);
-
- if( retcode != 0 ) {
- if( retcode < 0 ) {
- if (sock_errno != TDSSOCK_EINTR) {
- char *msg = strerror(sock_errno);
- tdsdump_log(TDS_DBG_NETWORK,
"tds_goodread select: errno=%d, \"%s\", returning -1\n", sock_errno, (msg)?
msg : "(unknown)");
- return -1;
- }
- goto OK_TIMEOUT;
- }
- /*
- * select succeeded: let's read.
- */
-# ifndef MSG_NOSIGNAL
- len = READSOCKET(tds->s, buf + got, buflen);
-# else
- len = recv(tds->s, buf + got, buflen, MSG_NOSIGNAL);
-# endif
-
- if (len < 0) {
- char *msg = strerror(sock_errno);
- tdsdump_log(TDS_DBG_NETWORK, "tds_goodread:
errno=%d, \"%s\"\n", sock_errno, (msg)? msg : "(unknown)");
-
- switch (sock_errno) {
- case EAGAIN: /* If O_NONBLOCK is
set, read(2) returns -1 and sets errno to [EAGAIN]. */
- case TDSSOCK_EINTR: /* If
interrupted by a signal before it reads any data. */
- case TDSSOCK_EINPROGRESS: /* A lengthy
operation on a non-blocking object is in progress. */
- /* EINPROGRESS is not a documented
errno for read(2), afaict. Remove following assert if it trips. --jkl */
- assert(sock_errno !=
TDSSOCK_EINPROGRESS);
- goto OK_TIMEOUT; /* try again */
- break;
+ if (tds->timeout > 0) timeout = tds->timeout;

- case EBADF:
- /* EBADMSG: not always defined */
- case EDEADLK:
- case EFAULT:
- case EINVAL:
- case EIO:
- case ENOLCK:
- case ENOSPC:
- case ENXIO:
- default:
- printf("returning: -1\n");
- return -1;
- break;
- }
- }
+ if (tds->query_timeout > 0)
+ query_timeout = tds->query_timeout;
+ else
+ query_timeout = 3600;

- /* this means a disconnection from server, exit */
- /* TODO close sockets too ?? */
- if (len == 0) {
- return -1;
- }
+ if (timeout == 0 && tds->query_timeout >0)
+ timeout = tds->query_timeout;
+
+ tdsdump_log(TDS_DBG_NETWORK, "network read timeout: %d\n", timeout);
+
+ while (buflen > 0) {
+
+ int len;
+
+ if (IS_TDSDEAD(tds)) return -1;
+
+ len = read_t(tds->s, buf + got, buflen, timeout);

+ if (len > 0) {
buflen -= len;
got += len;
+ }
+
+ if (query_timeout > 0 &&
+ time(NULL) - start > query_timeout)
+ {
+
+ tdsdump_log(TDS_DBG_NETWORK,
+ "exceeded query timeout: %d\n",
+ query_timeout);

- if (unfinished) {
+ tds_goodread_timeout_handler(tds);
+
+ if (got > 0) {
return got;
+ } else {
+ return -1;
}
- }
+ }

+ if (len < 0) {

- OK_TIMEOUT:
- now = time(NULL);
- timeout_action = TDS_INT_CONTINUE;
- if (tds->query_timeout_func && tds->query_timeout) {
- if ((now - start) >= tds->query_timeout)
- timeout_action = (*tds->query_timeout_func)
(tds->query_timeout_param);
- }
+ if (len < 0 && sock_errno == TDSSOCK_EINTR) {
+ tdsdump_log(TDS_DBG_NETWORK,
+ "socket read interrupted\n");
+ continue;
+ }

- switch (timeout_action) {
- case TDS_INT_EXIT:
- exit(EXIT_FAILURE);
- break;
- case TDS_INT_CANCEL:
- /* TODO should we process cancellation ?? */
- tds_send_cancel(tds);
- break;
- case TDS_INT_CONTINUE:
- /* TODO set timeout or start ?? */
- default:
- break;
+ tdsdump_log(TDS_DBG_NETWORK,
+ "read failed: %d [%s]\n",
+ errno, strerror(errno));
+
+ if (tds_goodread_timeout_handler(tds) ==
+ TDS_INT_CONTINUE)
+ {
+ continue;
+ }
+
+ return -1;
}

- } /* while buflen... */

- /* here buflen <= 0 || (tds->timeout != 0 && (now - start) >=
tds->timeout) */
-
- /* TODO always false ?? */
- if (tds->query_timeout > 0 && now - start < tds->query_timeout &&
buflen > 0) {
- return -1;
+ if (unfinished) {
+ return got;
+ }
}
-
- /* FIXME on timeout this assert got true... */
- assert(buflen == 0);
- return (got);
+ return got;
}

static int
@@ -437,10 +448,13 @@
tds->in_len = 0;
tds->in_pos = 0;
tds->last_packet = 1;
+ /*
if (tds->state != TDS_IDLE && len == 0) {
tds_close_socket(tds);
}
return -1;
+ */
+ return -1;
}
tdsdump_dump_buf(TDS_DBG_NETWORK, "Received header", header,
sizeof(header));

diff -rNu -X freetds.exclude freetds-0.64.dev.20050411/src/tds/util.c
freetds-0.64.dev.20050411-new/src/tds/util.c
--- freetds-0.64.dev.20050411/src/tds/util.c 2005-03-12 22:47:37.000000000
+1100
+++ freetds-0.64.dev.20050411-new/src/tds/util.c 2005-04-21
13:17:44.910003000 +1000
@@ -34,6 +34,8 @@
# endif
#endif

+#include "tdsthread.h"
+
#include <assert.h>
#include <ctype.h>
#include <limits.h>
@@ -72,6 +74,7 @@
static char *g_dump_filename = NULL;
static int write_dump = 0; /* is TDS stream debug log turned on? */
static FILE *g_dumpfile = NULL; /* file pointer for dump log
*/
+TDS_MUTEX_T g_dump_mutex = TDS_MUTEX_INITIALIZER;

#ifdef TDS_ATTRIBUTE_DESTRUCTOR
static void __attribute__((destructor))
@@ -215,7 +218,9 @@
void
tdsdump_off(void)
{
+ TDS_MUTEX_LOCK(&g_dump_mutex);
write_dump = 0;
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
} /* tdsdump_off() */


@@ -225,7 +230,9 @@
void
tdsdump_on(void)
{
+ TDS_MUTEX_LOCK(&g_dump_mutex);
write_dump = 1;
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
} /* tdsdump_on() */


@@ -242,10 +249,18 @@
{
int result; /* really should be a boolean, not an int */

- tdsdump_close();
+ TDS_MUTEX_LOCK(&g_dump_mutex);
+
if (filename == NULL || filename[0] == '\0') {
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
return 1;
}
+
+ if (g_dumpfile != NULL) {
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
+ return 0;
+ }
+
if (tds_g_append_mode) {
g_dump_filename = strdup(filename);
result = 1;
@@ -268,26 +283,33 @@
time(&t);
tm = localtime(&t);

+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
tdsdump_on();
strftime(today, sizeof(today), "%Y-%m-%d %H:%M:%S", tm);
tdsdump_log(TDS_DBG_INFO1, "Starting log file for FreeTDS
%s\n"
"\ton %s with debug flags 0x%x.\n", VERSION,
today, tds_debug_flags);
+ return result;
}
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
return result;
} /* tdsdump_open() */

static FILE*
tdsdump_append(void)
{
- if (!g_dump_filename)
+ FILE *fp = NULL;
+
+ if (!g_dump_filename) {
return NULL;
+ }

if (!strcmp(g_dump_filename, "stdout")) {
return stdout;
} else if (!strcmp(g_dump_filename, "stderr")) {
return stderr;
}
- return fopen(g_dump_filename, "a");
+ fp = fopen(g_dump_filename, "a");
+ return fp;
}


@@ -298,11 +320,13 @@
tdsdump_close(void)
{
tdsdump_off();
+ TDS_MUTEX_LOCK(&g_dump_mutex);
if (g_dumpfile != NULL && g_dumpfile != stdout && g_dumpfile !=
stderr)
fclose(g_dumpfile);
g_dumpfile = NULL;
if (g_dump_filename)
TDS_ZERO_FREE(g_dump_filename);
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
} /* tdsdump_close() */

static void
@@ -362,12 +386,16 @@
if (((tds_debug_flags >> debug_lvl) & 1) == 0 || !write_dump)
return;

+ TDS_MUTEX_LOCK(&g_dump_mutex);
+
dumpfile = g_dumpfile;
if (tds_g_append_mode)
dumpfile = tdsdump_append();

- if (dumpfile == NULL)
+ if (dumpfile == NULL) {
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
return;
+ }

tdsdump_start(dumpfile, file, line);

@@ -414,6 +442,9 @@
if (dumpfile != stdout && dumpfile != stderr)
fclose(dumpfile);
}
+
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
+
} /* tdsdump_dump_buf() */


@@ -433,12 +464,16 @@
if (((tds_debug_flags >> debug_lvl) & 1) == 0 || !write_dump)
return;

+ TDS_MUTEX_LOCK(&g_dump_mutex);
+
dumpfile = g_dumpfile;
if (tds_g_append_mode)
dumpfile = tdsdump_append();
-
- if (dumpfile == NULL)
+
+ if (dumpfile == NULL) {
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
return;
+ }

tdsdump_start(dumpfile, file, line);

@@ -453,5 +488,6 @@
if (dumpfile != stdout && dumpfile != stderr)
fclose(dumpfile);
}
+ TDS_MUTEX_UNLOCK(&g_dump_mutex);
} /* tdsdump_log() */




Archive powered by MHonArc 2.6.24.

Top of Page