[freetds] stuck in endless loop in tds_goodread

Largo largowww at gmail.com
Thu Feb 1 04:50:20 EST 2007


Hi,

I had a problem posted here 2 weeks ago:
http://lists.ibiblio.org/pipermail/freetds/2007q1/021045.html which still
isn't solved. But meanwhile I have some more information as I've been
digging in the code of freetds. It seems freetds is stuck in an endless loop
in the function tds_goodread in the file net.c

Here's the function:
static int
tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen, unsigned char
unfinished)
{
        time_t start, global_start;
        int timeout = 0;
        int got = 0;
        fd_set rfds;
        struct timeval tv;

        tv.tv_usec = 0;

        if (buf == NULL || buflen < 1 || tds == NULL)
                return 0;

        global_start = start = tds->query_start_time ? tds->query_start_time
: time(NULL);

        while (buflen > 0) {
                int len;
                time_t now = time(NULL);

                if (IS_TDSDEAD(tds))
                        return -1;

                FD_ZERO(&rfds);
                FD_SET(tds->s, &rfds);

                timeout = 0;
                if (tds->query_timeout > 0) {
                        timeout = tds->query_timeout - (now - start);
                        if (timeout < 1)
                                timeout = 1;
                }
                tv.tv_sec = timeout;
                if ((len = select(tds->s + 1, &rfds, NULL, NULL, timeout > 0
? &tv : NULL)) > 0) {
                        len = 0;
                        if (FD_ISSET(tds->s, &rfds)) {
#ifndef MSG_NOSIGNAL
                                len = READSOCKET(tds->s, buf + got, buflen);
#else
                                len = recv(tds->s, buf + got, buflen,
MSG_NOSIGNAL);
#endif
                                /* detect connection close */
                                if (len == 0) {
                                        tds_close_socket(tds);
                                        return -1;
                                }
                        }
                }

                if (len < 0) {
                        switch(sock_errno) {
                        case TDSSOCK_EINTR:
                                tdsdump_log(TDS_DBG_NETWORK, "socket read
interrupted\n");
                        case EAGAIN:
                        case TDSSOCK_EINPROGRESS:
                                break;
                        default:
                                return -1;
                        }
                        len = 0;
                }

                buflen -= len;
                got += len;

                now = time(NULL);
                if (tds->query_timeout > 0 && now - start >=
tds->query_timeout) {

                        int timeout_action = TDS_INT_CONTINUE;

                        tdsdump_log(TDS_DBG_NETWORK, "exceeded query
timeout: %d\n", tds->query_timeout);

                        if (tds->query_timeout_func && tds->query_timeout)
                                timeout_action = (*tds->query_timeout_func)
(tds->query_timeout_param, now - global_start)
;

                        switch (timeout_action) {
                        case TDS_INT_EXIT:
                                exit(EXIT_FAILURE);
                                break;
                        case TDS_INT_CANCEL:
                                tds_send_cancel(tds);
                                break;

                        case TDS_INT_CONTINUE:
                                start = now;
                        default:
                                break;
                        }
                }

                if (unfinished && got)
                        return got;
        }
        return got;
}

When my program is running for a while, following is happening: select
returns len=0. This means buflen is never decremented so it stays forever in
the whileloop. If I understand the function correctly, then the timeout
should guard this, but as far as I can see, this can never result in leaving
the while loop. In my case tds->query_timeout_func equals NULL, so
timeout_action is always TDS_INT_CONTINUE.


More information about the FreeTDS mailing list