From d2692c9f98a4060b33232c648d5ce9cfffc18e44 Mon Sep 17 00:00:00 2001 From: hpa Date: Tue, 3 Sep 2002 19:02:02 +0000 Subject: [PATCH] Downgrade client-side errors from LOG_ERR to LOG_WARN --- tftpd/tftpd.c | 158 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 53 deletions(-) diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c index 05337a5..9f4235a 100644 --- a/tftpd/tftpd.c +++ b/tftpd/tftpd.c @@ -79,15 +79,17 @@ int allow_severity = -1; /* Don't log at all */ struct request_info wrap_request; #endif -#define TIMEOUT 5 /* Default timeout (seconds) */ -#define TRIES 4 /* Number of attempts to send each packet */ -#define TIMEOUT_LIMIT (TRIES*(TRIES+1)/2) +#define TIMEOUT 1000 /* Default timeout (ms) */ +#define TRIES 6 /* Number of attempts to send each packet */ +#define TIMEOUT_LIMIT ((1 << TRIES)-1) char *__progname; int peer; -int timeout = TIMEOUT; -int rexmtval = TIMEOUT; +int timeout = TIMEOUT; /* Current timeout value */ +int timeout_quit = 0; +int rexmtval = TIMEOUT; /* Basic timeout value */ int maxtimeout = TIMEOUT_LIMIT*TIMEOUT; +sigjmp_buf timeoutbuf; #define PKTSIZE MAX_SEGSIZE+4 char buf[PKTSIZE]; @@ -121,6 +123,7 @@ int set_blksize(char *, char **); int set_blksize2(char *, char **); int set_tsize(char *, char **); int set_timeout(char *, char **); +int set_utimeout(char *, char **); struct options { const char *o_opt; @@ -130,6 +133,7 @@ struct options { { "blksize2", set_blksize2 }, { "tsize", set_tsize }, { "timeout", set_timeout }, + { "utimeout", set_utimeout }, { NULL, NULL } }; @@ -142,6 +146,17 @@ static void handle_sighup(int sig) } +/* Handle timeout signal or timeout event */ +void +timer(int sig) +{ + (void)sig; /* Suppress unused warning */ + timeout <<= 1; + if (timeout >= maxtimeout || timeout_quit) + exit(0); + siglongjmp(timeoutbuf, 1); +} + static void usage(void) { @@ -189,6 +204,49 @@ set_socket_nonblock(int fd, int flag) } } +/* + * Receive packet with synchronous timeout + */ +static int recv_time(int s, void *rbuf, int len, unsigned int flags, + unsigned long timeout_ms) +{ + fd_set fdset; + struct timeval tmv; + int rv, err; + + for ( ; ; ) { + FD_ZERO(&fdset); + FD_SET(s, &fdset); + + tmv.tv_sec = timeout_ms/1000; + tmv.tv_usec = (timeout_ms%1000)*1000; + + do { + rv = select(s+1, &fdset, NULL, NULL, &tmv); + } while ( rv == -1 && errno == EINTR ); + + if ( rv == 0 ) { + timer(0); /* Should not return */ + return -1; + } + + set_socket_nonblock(s, 1); + rv = recv(s, rbuf, len, flags); + err = errno; + set_socket_nonblock(s, 0); + if ( rv < 0 ) { + if ( E_WOULD_BLOCK(err) || err == EINTR ) { + continue; /* Once again, with feeling... */ + } else { + errno = err; + return rv; + } + } else { + return rv; + } + } +} + int main(int argc, char **argv) { @@ -589,7 +647,6 @@ main(int argc, char **argv) /* Other basic setup */ from.sin_family = AF_INET; - alarm(0); /* Process the request... */ @@ -810,7 +867,9 @@ set_tsize(char *val, char **ret) } /* - * Set the timeout (c.f. RFC2349) + * Set the timeout (c.f. RFC2349). This is supposed + * to be the (default) retransmission timeout, but being an + * integer in seconds it seems a bit limited. */ int set_timeout(char *val, char **ret) @@ -824,14 +883,32 @@ set_timeout(char *val, char **ret) if ( to < 1 || to > 255 || *vend ) return 0; - timeout = to; - rexmtval = to; - maxtimeout = TIMEOUT_LIMIT*to; + rexmtval = timeout = to; + maxtimeout = rexmtval*TIMEOUT_LIMIT; sprintf(*ret = b_ret, "%lu", to); return(1); } +/* Similar, but in microseconds. We allow down to 10 ms. */ +int +set_utimeout(char *val, char **ret) +{ + static char b_ret[4]; + unsigned long to; + char *vend; + + to = strtoul(val, &vend, 10); + + if ( to < 10000UL || to > 255000000UL || *vend ) + return 0; + + rexmtval = timeout = to/1000UL; + maxtimeout = rexmtval*TIMEOUT_LIMIT; + + sprintf(*ret = b_ret, "%lu", to); + return(1); +} /* * Parse RFC2347 style options */ @@ -1030,20 +1107,6 @@ validate_access(char *filename, int mode, struct formats *pf) return (0); } -int timeout; -sigjmp_buf timeoutbuf; - -/* Handle timeout signal */ -void -timer(int sig) -{ - (void)sig; /* Suppress unused warning */ - timeout += rexmtval; - if (timeout >= maxtimeout) - exit(0); - siglongjmp(timeoutbuf, 1); -} - /* * Send the requested file. */ @@ -1058,28 +1121,24 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen) ap = (struct tftphdr *)ackbuf; if (oap) { - timeout = 0; + timeout = rexmtval; (void)sigsetjmp(timeoutbuf,1); oack: if (send(peer, oap, oacklen, 0) != oacklen) { - syslog(LOG_ERR, "tftpd: oack: %m\n"); + syslog(LOG_WARN, "tftpd: oack: %m\n"); goto abort; } for ( ; ; ) { - set_signal(SIGALRM, timer, SA_RESTART); - alarm(rexmtval); - n = recv(peer, ackbuf, sizeof(ackbuf), 0); - alarm(0); + n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, timeout); if (n < 0) { - syslog(LOG_ERR, "tftpd: read: %m\n"); + syslog(LOG_WARN, "tftpd: read: %m\n"); goto abort; } ap->th_opcode = ntohs((u_short)ap->th_opcode); ap->th_block = ntohs((u_short)ap->th_block); if (ap->th_opcode == ERROR) { - syslog(LOG_ERR, "tftp: client does not accept " - "options\n"); + syslog(LOG_WARN, "tftp: client does not accept options\n"); goto abort; } if (ap->th_opcode == ACK) { @@ -1101,21 +1160,18 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen) } dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); - timeout = 0; + timeout = rexmtval; (void) sigsetjmp(timeoutbuf,1); if (send(peer, dp, size + 4, 0) != size + 4) { - syslog(LOG_ERR, "tftpd: write: %m"); + syslog(LOG_WARN, "tftpd: write: %m"); goto abort; } read_ahead(file, pf->f_convert); for ( ; ; ) { - set_signal(SIGALRM, timer, SA_RESTART); - alarm(rexmtval); /* read the ack */ - n = recv(peer, ackbuf, sizeof (ackbuf), 0); - alarm(0); + n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, timeout); if (n < 0) { - syslog(LOG_ERR, "tftpd: read(ack): %m"); + syslog(LOG_WARN, "tftpd: read(ack): %m"); goto abort; } ap->th_opcode = ntohs((u_short)ap->th_opcode); @@ -1168,7 +1224,7 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) dp = w_init(); do { - timeout = 0; + timeout = rexmtval; if (!block && oap) { ap = (struct tftphdr *)ackbuf; @@ -1181,20 +1237,16 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) } block++; (void) sigsetjmp(timeoutbuf,1); - set_signal(SIGALRM, timer, SA_RESTART); send_ack: if (send(peer, ackbuf, acksize, 0) != acksize) { - syslog(LOG_ERR, "tftpd: write(ack): %m"); + syslog(LOG_WARN, "tftpd: write(ack): %m"); goto abort; } write_behind(file, pf->f_convert); for ( ; ; ) { - set_signal(SIGALRM, timer, SA_RESTART); - alarm(rexmtval); - n = recv(peer, dp, PKTSIZE, 0); - alarm(0); + n = recv_time(peer, dp, PKTSIZE, 0, timeout); if (n < 0) { /* really? */ - syslog(LOG_ERR, "tftpd: read: %m"); + syslog(LOG_WARN, "tftpd: read: %m"); goto abort; } dp->th_opcode = ntohs((u_short)dp->th_opcode); @@ -1226,10 +1278,10 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) ap->th_block = htons((u_short)(block)); (void) send(peer, ackbuf, 4, 0); - set_signal(SIGALRM, justquit, 0); /* just quit on timeout */ - alarm(rexmtval); - n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ - alarm(0); + timeout_quit = 1; /* just quit on timeout */ + n = recv_time(peer, buf, sizeof (buf), 0, timeout); /* normally times out and quits */ + timeout_quit = 0; + if (n >= 4 && /* if read some data */ dp->th_opcode == DATA && /* and got a data block */ block == dp->th_block) { /* then my last ack was lost */ @@ -1289,5 +1341,5 @@ nak(int error) } if (send(peer, buf, length, 0) != length) - syslog(LOG_ERR, "nak: %m"); + syslog(LOG_WARN, "nak: %m"); }