| Summary: | tftp client timeout failure | ||
|---|---|---|---|
| Product: | Base System | Reporter: | yxiao <yxiao> |
| Component: | misc | Assignee: | freebsd-bugs (Nobody) <bugs> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | ||
| Priority: | Normal | ||
| Version: | Unspecified | ||
| Hardware: | Any | ||
| OS: | Any | ||
yxiao@cisco.com wrote: [..] > >Release: $FreeBSD: src/usr.bin/tftp/tftp.c,v 1.5 1999/08/28 01:06:24 peter Exp > >Environment: > Linux dhcp-171-70-93-24.cisco.com 2.2.14-5.0 #1 Tue Mar 7 21:07:39 EST 2000 i 686 unknown Are you running our tftpd under Linux? Or is that just the send-pr environment? > >Description: > Alarm clock can only fired once. Problem: SIGALRM blocked. The patch below has a couple of problems: > >Fix: > change timer function: > --- tftp.c 2000/08/01 20:38:08 1.2 > +++ tftp.c 2001/02/07 16:18:03 > @@ -455,9 +455,15 @@ > timer(sig) > int sig; > { > + sigset_t sigset; > + int error; > > + //signal(SIGALRM, timer); > + error = sigemptyset(&sigset); > + error |= sigdelset(&sigset, SIGALRM); > + error |= sigprocmask(SIG_SETMASK, &sigset, NULL); > timeout += rexmtval; > - if (timeout >= maxtimeout) { > + if (timeout >= maxtimeout || error) { > printf("Transfer timed out.\n"); > global_errno = ETIMEDOUT; > longjmp(toplevel, -1); sigdelset() to delete a signal from an already empty set is a NOP. It might as well be: error = sigemptyset(&sigset); error |= sigprocmask(SIG_SETMASK, &sigset, NULL); There is also a problem.. if sigemptyset() returned an error, sigset would have undefined contents. And yet you call sigprocmask() anyway. I think a more correct fix would be to use sigsetjmp()/siglongjmp() to save/restore the mask.. However, according to the man pages, that shouldn't be necessary: The setjmp()/longjmp() pairs save and restore the signal mask while _setjmp()/_longjmp() pairs save and restore only the register set and the stack. (See sigprocmask(2).) The sigsetjmp()/siglongjmp() function pairs save and restore the signal mask if the argument savemask is non-zero, otherwise only the register set and the stack are saved. Cheers, -Peter -- Peter Wemm - peter@FreeBSD.org; peter@yahoo-inc.com; peter@netplex.com.au "All of this is for nothing if we don't go to the stars" - JMS/B5 State Changed From-To: open->closed This seems to be a non-problem; the timer function works fine on FreeBSD. Below is what happens with an unresponsive host and some extra instrumentation in timer() that outputs 'timer': tftp> get goo timer timer timer timer timer Transfer timed out. tftp> |
Alarm clock can only fired once. Problem: SIGALRM blocked. Fix: change timer function: --- tftp.c 2000/08/01 20:38:08 1.2 +++ tftp.c 2001/02/07 16:18:03 @@ -455,9 +455,15 @@ timer(sig) int sig; { + sigset_t sigset; + int error; + //signal(SIGALRM, timer); + error = sigemptyset(&sigset); + error |= sigdelset(&sigset, SIGALRM); + error |= sigprocmask(SIG_SETMASK, &sigset, NULL); timeout += rexmtval; - if (timeout >= maxtimeout) { + if (timeout >= maxtimeout || error) { printf("Transfer timed out.\n"); global_errno = ETIMEDOUT; longjmp(toplevel, -1);