forked from mirrors/tftp-hpa-google
Downgrade client-side errors from LOG_ERR to LOG_WARN
This commit is contained in:
parent
c980666bbe
commit
d2692c9f98
1 changed files with 105 additions and 53 deletions
158
tftpd/tftpd.c
158
tftpd/tftpd.c
|
@ -79,15 +79,17 @@ int allow_severity = -1; /* Don't log at all */
|
||||||
struct request_info wrap_request;
|
struct request_info wrap_request;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TIMEOUT 5 /* Default timeout (seconds) */
|
#define TIMEOUT 1000 /* Default timeout (ms) */
|
||||||
#define TRIES 4 /* Number of attempts to send each packet */
|
#define TRIES 6 /* Number of attempts to send each packet */
|
||||||
#define TIMEOUT_LIMIT (TRIES*(TRIES+1)/2)
|
#define TIMEOUT_LIMIT ((1 << TRIES)-1)
|
||||||
|
|
||||||
char *__progname;
|
char *__progname;
|
||||||
int peer;
|
int peer;
|
||||||
int timeout = TIMEOUT;
|
int timeout = TIMEOUT; /* Current timeout value */
|
||||||
int rexmtval = TIMEOUT;
|
int timeout_quit = 0;
|
||||||
|
int rexmtval = TIMEOUT; /* Basic timeout value */
|
||||||
int maxtimeout = TIMEOUT_LIMIT*TIMEOUT;
|
int maxtimeout = TIMEOUT_LIMIT*TIMEOUT;
|
||||||
|
sigjmp_buf timeoutbuf;
|
||||||
|
|
||||||
#define PKTSIZE MAX_SEGSIZE+4
|
#define PKTSIZE MAX_SEGSIZE+4
|
||||||
char buf[PKTSIZE];
|
char buf[PKTSIZE];
|
||||||
|
@ -121,6 +123,7 @@ int set_blksize(char *, char **);
|
||||||
int set_blksize2(char *, char **);
|
int set_blksize2(char *, char **);
|
||||||
int set_tsize(char *, char **);
|
int set_tsize(char *, char **);
|
||||||
int set_timeout(char *, char **);
|
int set_timeout(char *, char **);
|
||||||
|
int set_utimeout(char *, char **);
|
||||||
|
|
||||||
struct options {
|
struct options {
|
||||||
const char *o_opt;
|
const char *o_opt;
|
||||||
|
@ -130,6 +133,7 @@ struct options {
|
||||||
{ "blksize2", set_blksize2 },
|
{ "blksize2", set_blksize2 },
|
||||||
{ "tsize", set_tsize },
|
{ "tsize", set_tsize },
|
||||||
{ "timeout", set_timeout },
|
{ "timeout", set_timeout },
|
||||||
|
{ "utimeout", set_utimeout },
|
||||||
{ NULL, NULL }
|
{ 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
|
static void
|
||||||
usage(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
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -589,7 +647,6 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
/* Other basic setup */
|
/* Other basic setup */
|
||||||
from.sin_family = AF_INET;
|
from.sin_family = AF_INET;
|
||||||
alarm(0);
|
|
||||||
|
|
||||||
/* Process the request... */
|
/* 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
|
int
|
||||||
set_timeout(char *val, char **ret)
|
set_timeout(char *val, char **ret)
|
||||||
|
@ -824,14 +883,32 @@ set_timeout(char *val, char **ret)
|
||||||
if ( to < 1 || to > 255 || *vend )
|
if ( to < 1 || to > 255 || *vend )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
timeout = to;
|
rexmtval = timeout = to;
|
||||||
rexmtval = to;
|
maxtimeout = rexmtval*TIMEOUT_LIMIT;
|
||||||
maxtimeout = TIMEOUT_LIMIT*to;
|
|
||||||
|
|
||||||
sprintf(*ret = b_ret, "%lu", to);
|
sprintf(*ret = b_ret, "%lu", to);
|
||||||
return(1);
|
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
|
* Parse RFC2347 style options
|
||||||
*/
|
*/
|
||||||
|
@ -1030,20 +1107,6 @@ validate_access(char *filename, int mode, struct formats *pf)
|
||||||
return (0);
|
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.
|
* Send the requested file.
|
||||||
*/
|
*/
|
||||||
|
@ -1058,28 +1121,24 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
ap = (struct tftphdr *)ackbuf;
|
ap = (struct tftphdr *)ackbuf;
|
||||||
|
|
||||||
if (oap) {
|
if (oap) {
|
||||||
timeout = 0;
|
timeout = rexmtval;
|
||||||
(void)sigsetjmp(timeoutbuf,1);
|
(void)sigsetjmp(timeoutbuf,1);
|
||||||
oack:
|
oack:
|
||||||
if (send(peer, oap, oacklen, 0) != oacklen) {
|
if (send(peer, oap, oacklen, 0) != oacklen) {
|
||||||
syslog(LOG_ERR, "tftpd: oack: %m\n");
|
syslog(LOG_WARN, "tftpd: oack: %m\n");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
set_signal(SIGALRM, timer, SA_RESTART);
|
n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, timeout);
|
||||||
alarm(rexmtval);
|
|
||||||
n = recv(peer, ackbuf, sizeof(ackbuf), 0);
|
|
||||||
alarm(0);
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
syslog(LOG_ERR, "tftpd: read: %m\n");
|
syslog(LOG_WARN, "tftpd: read: %m\n");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
ap->th_opcode = ntohs((u_short)ap->th_opcode);
|
ap->th_opcode = ntohs((u_short)ap->th_opcode);
|
||||||
ap->th_block = ntohs((u_short)ap->th_block);
|
ap->th_block = ntohs((u_short)ap->th_block);
|
||||||
|
|
||||||
if (ap->th_opcode == ERROR) {
|
if (ap->th_opcode == ERROR) {
|
||||||
syslog(LOG_ERR, "tftp: client does not accept "
|
syslog(LOG_WARN, "tftp: client does not accept options\n");
|
||||||
"options\n");
|
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
if (ap->th_opcode == ACK) {
|
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_opcode = htons((u_short)DATA);
|
||||||
dp->th_block = htons((u_short)block);
|
dp->th_block = htons((u_short)block);
|
||||||
timeout = 0;
|
timeout = rexmtval;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void) sigsetjmp(timeoutbuf,1);
|
||||||
|
|
||||||
if (send(peer, dp, size + 4, 0) != size + 4) {
|
if (send(peer, dp, size + 4, 0) != size + 4) {
|
||||||
syslog(LOG_ERR, "tftpd: write: %m");
|
syslog(LOG_WARN, "tftpd: write: %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
read_ahead(file, pf->f_convert);
|
read_ahead(file, pf->f_convert);
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
set_signal(SIGALRM, timer, SA_RESTART);
|
n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, timeout);
|
||||||
alarm(rexmtval); /* read the ack */
|
|
||||||
n = recv(peer, ackbuf, sizeof (ackbuf), 0);
|
|
||||||
alarm(0);
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
syslog(LOG_ERR, "tftpd: read(ack): %m");
|
syslog(LOG_WARN, "tftpd: read(ack): %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
ap->th_opcode = ntohs((u_short)ap->th_opcode);
|
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();
|
dp = w_init();
|
||||||
do {
|
do {
|
||||||
timeout = 0;
|
timeout = rexmtval;
|
||||||
|
|
||||||
if (!block && oap) {
|
if (!block && oap) {
|
||||||
ap = (struct tftphdr *)ackbuf;
|
ap = (struct tftphdr *)ackbuf;
|
||||||
|
@ -1181,20 +1237,16 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
}
|
}
|
||||||
block++;
|
block++;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void) sigsetjmp(timeoutbuf,1);
|
||||||
set_signal(SIGALRM, timer, SA_RESTART);
|
|
||||||
send_ack:
|
send_ack:
|
||||||
if (send(peer, ackbuf, acksize, 0) != acksize) {
|
if (send(peer, ackbuf, acksize, 0) != acksize) {
|
||||||
syslog(LOG_ERR, "tftpd: write(ack): %m");
|
syslog(LOG_WARN, "tftpd: write(ack): %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
write_behind(file, pf->f_convert);
|
write_behind(file, pf->f_convert);
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
set_signal(SIGALRM, timer, SA_RESTART);
|
n = recv_time(peer, dp, PKTSIZE, 0, timeout);
|
||||||
alarm(rexmtval);
|
|
||||||
n = recv(peer, dp, PKTSIZE, 0);
|
|
||||||
alarm(0);
|
|
||||||
if (n < 0) { /* really? */
|
if (n < 0) { /* really? */
|
||||||
syslog(LOG_ERR, "tftpd: read: %m");
|
syslog(LOG_WARN, "tftpd: read: %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
dp->th_opcode = ntohs((u_short)dp->th_opcode);
|
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));
|
ap->th_block = htons((u_short)(block));
|
||||||
(void) send(peer, ackbuf, 4, 0);
|
(void) send(peer, ackbuf, 4, 0);
|
||||||
|
|
||||||
set_signal(SIGALRM, justquit, 0); /* just quit on timeout */
|
timeout_quit = 1; /* just quit on timeout */
|
||||||
alarm(rexmtval);
|
n = recv_time(peer, buf, sizeof (buf), 0, timeout); /* normally times out and quits */
|
||||||
n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
|
timeout_quit = 0;
|
||||||
alarm(0);
|
|
||||||
if (n >= 4 && /* if read some data */
|
if (n >= 4 && /* if read some data */
|
||||||
dp->th_opcode == DATA && /* and got a data block */
|
dp->th_opcode == DATA && /* and got a data block */
|
||||||
block == dp->th_block) { /* then my last ack was lost */
|
block == dp->th_block) { /* then my last ack was lost */
|
||||||
|
@ -1289,5 +1341,5 @@ nak(int error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send(peer, buf, length, 0) != length)
|
if (send(peer, buf, length, 0) != length)
|
||||||
syslog(LOG_ERR, "nak: %m");
|
syslog(LOG_WARN, "nak: %m");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue