Skip to Content.
Sympa Menu

freetds - Re: [freetds] Timeout for reading from the server doesn't work.

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: "ZIGLIO, Frediano, VF-IT" <Frediano.Ziglio AT vodafone.com>
  • To: "FreeTDS Development Group" <freetds AT lists.ibiblio.org>
  • Subject: Re: [freetds] Timeout for reading from the server doesn't work.
  • Date: Thu, 24 Nov 2005 09:21:00 +0100

>
> Dear list,
>
> I use this great library (libtds) to communicate with MSSQL
> server on an
> embedded system. It's rather important that this system never stops
> sending data for a longer period of time. But as far as I
> could observe
> this occurs every time the server becomes unreachable. In both the
> stable release and the CVS version a timeout can be set for this case,
> but in the stable version this triggers an assertion and in the CVS

Mmm... assertion == DoS here... not that fine...

> version as far as I understand the code it leads to an infinite loop.
> For the latter case there is a rather simple fix which makes the
> goodread function abort instead of waiting forever. I only insert data
> into the database but this has worked reliably now for the
> last 4 days.
>
> best regards
> Omar Siam
>

Well, this code has been revise a lot of time... I still don't
understand why with correct timeouts you should have an infinite loop...
probably dblib say continue or sending cancel connection close are not
detected...

Let's look at the code a bit deeper.

291 global_start = start = tds->query_start_time ?
tds->query_start_time : time(NULL);
292
293 while (buflen > 0) {
294
295 int len;
296 time_t now = time(NULL);
297
298 if (IS_TDSDEAD(tds))
299 return -1;
300
301 FD_ZERO(&rfds);
302 FD_SET(tds->s, &rfds);
303
304 timeout = 0;
305 if (tds->query_timeout > 0) {
306 timeout = tds->query_timeout - (now -
start);
307 if (timeout < 1)
308 timeout = 1;
309 }
310 tv.tv_sec = timeout;
311
312 if ((len = select(tds->s + 1, &rfds, NULL, NULL,
timeout > 0 ? &tv : NULL)) > 0) {
313 len = 0;
314 if (FD_ISSET(tds->s, &rfds)) {
315 #ifndef MSG_NOSIGNAL
316 len = READSOCKET(tds->s, buf + got,
buflen);
317 #else
318 len = recv(tds->s, buf + got,
buflen, MSG_NOSIGNAL);
319 #endif
320 }
321 }
322
323 if (len < 0) {

Here you suggest len <= 0 however len == 0 means mainly a timeout in
select. It seems that if connection is closed select in this case just
timeouts. I would try to change line 312 in

if ((len = select(tds->s + 1, &rfds, NULL, &rfds, timeout > 0 ? &tv :
NULL)) > 0) {

This should detect socket error and next read should set correctly len
and sock_errno. Can you try this ??
If this works as I expect some other selects in net.c should be changed
too...

324 switch(sock_errno) {
325 case TDSSOCK_EINTR:
326 tdsdump_log(TDS_DBG_NETWORK, "socket
read interrupted\n");
327 case EAGAIN:
328 case TDSSOCK_EINPROGRESS:
329 break;
330 default:
331 return -1;
332 }
333 len = 0;
334 }
335
336 buflen -= len;
337 got += len;
338
339 now = time(NULL);
340 if (tds->query_timeout > 0 && now - start >=
tds->query_timeout) {
341
342 int timeout_action = TDS_INT_CONTINUE;
343
344 tdsdump_log(TDS_DBG_NETWORK, "exceeded query
timeout: %d\n", tds->query_timeout);
345
346 if (tds->query_timeout_func &&
tds->query_timeout)
347 timeout_action =
(*tds->query_timeout_func) (tds->query_timeout_param, now -
global_start);
348
349 switch (timeout_action) {
350 case TDS_INT_EXIT:
351 exit(EXIT_FAILURE);
352 break;
353 case TDS_INT_CANCEL:
354 tds_send_cancel(tds);
355 break;
356
357 case TDS_INT_CONTINUE:
358 start = now;
359 default:
360 break;
361 }
362 }
363
364 if (unfinished && got)
365 return got;
366 }
367 return got;
368 }

freddy77




Archive powered by MHonArc 2.6.24.

Top of Page