tftp: explain "block# 0" codepath; report our decision to bail out to server
if blocksize option doesn't look good (it was a FIXME. +33 bytes code); make code more readable.
This commit is contained in:
parent
a035e9f1a9
commit
bf678d5423
@ -37,15 +37,15 @@
|
|||||||
#define TFTP_OACK 6
|
#define TFTP_OACK 6
|
||||||
|
|
||||||
#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
|
#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
|
||||||
#define USE_GETPUT(a)
|
#define USE_GETPUT(...)
|
||||||
#define CMD_GET(cmd) 1
|
#define CMD_GET(cmd) 1
|
||||||
#define CMD_PUT(cmd) 0
|
#define CMD_PUT(cmd) 0
|
||||||
#elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
|
#elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
|
||||||
#define USE_GETPUT(a)
|
#define USE_GETPUT(...)
|
||||||
#define CMD_GET(cmd) 0
|
#define CMD_GET(cmd) 0
|
||||||
#define CMD_PUT(cmd) 1
|
#define CMD_PUT(cmd) 1
|
||||||
#else
|
#else
|
||||||
#define USE_GETPUT(a) a
|
#define USE_GETPUT(...) __VA_ARGS__
|
||||||
/* masks coming from getpot32 */
|
/* masks coming from getpot32 */
|
||||||
#define CMD_GET(cmd) ((cmd) & 1)
|
#define CMD_GET(cmd) ((cmd) & 1)
|
||||||
#define CMD_PUT(cmd) ((cmd) & 2)
|
#define CMD_PUT(cmd) ((cmd) & 2)
|
||||||
@ -109,10 +109,7 @@ static char *tftp_option_get(char *buf, int len, const char *option)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int tftp(
|
static int tftp( USE_GETPUT(const int cmd,)
|
||||||
#if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
|
|
||||||
const int cmd,
|
|
||||||
#endif
|
|
||||||
len_and_sockaddr *peer_lsa,
|
len_and_sockaddr *peer_lsa,
|
||||||
const char *remotefile, const int localfd,
|
const char *remotefile, const int localfd,
|
||||||
unsigned port, int tftp_bufsize)
|
unsigned port, int tftp_bufsize)
|
||||||
@ -181,6 +178,9 @@ static int tftp(
|
|||||||
/* First packet is built, so skip packet generation */
|
/* First packet is built, so skip packet generation */
|
||||||
goto send_pkt;
|
goto send_pkt;
|
||||||
|
|
||||||
|
/* Using mostly goto's - continue/break will be less clear
|
||||||
|
* in where we actually jump to */
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* Build ACK or DATA */
|
/* Build ACK or DATA */
|
||||||
cp = xbuf + 2;
|
cp = xbuf + 2;
|
||||||
@ -203,67 +203,64 @@ static int tftp(
|
|||||||
send_pkt:
|
send_pkt:
|
||||||
/* Send packet */
|
/* Send packet */
|
||||||
*((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */
|
*((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */
|
||||||
timeout = TFTP_NUM_RETRIES; /* re-initialize */
|
send_len = cp - xbuf;
|
||||||
while (1) {
|
/* NB: send_len value is preserved in code below
|
||||||
send_len = cp - xbuf;
|
* for potential resend */
|
||||||
/* nb: need to preserve send_len value in code below
|
|
||||||
* for potential resend! */
|
|
||||||
send_again:
|
send_again:
|
||||||
#if ENABLE_DEBUG_TFTP
|
#if ENABLE_DEBUG_TFTP
|
||||||
fprintf(stderr, "sending %u bytes\n", send_len);
|
fprintf(stderr, "sending %u bytes\n", send_len);
|
||||||
for (cp = xbuf; cp < &xbuf[send_len]; cp++)
|
for (cp = xbuf; cp < &xbuf[send_len]; cp++)
|
||||||
fprintf(stderr, "%02x ", (unsigned char) *cp);
|
fprintf(stderr, "%02x ", (unsigned char) *cp);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
#endif
|
#endif
|
||||||
xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len);
|
xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len);
|
||||||
/* Was it final ACK? then exit */
|
/* Was it final ACK? then exit */
|
||||||
if (finished && (opcode == TFTP_ACK))
|
if (finished && (opcode == TFTP_ACK))
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
/* Receive packet */
|
timeout = TFTP_NUM_RETRIES; /* re-initialize */
|
||||||
recv_again:
|
recv_again:
|
||||||
tv.tv_sec = TFTP_TIMEOUT;
|
/* Receive packet */
|
||||||
tv.tv_usec = 0;
|
tv.tv_sec = TFTP_TIMEOUT;
|
||||||
FD_ZERO(&rfds);
|
tv.tv_usec = 0;
|
||||||
FD_SET(socketfd, &rfds);
|
FD_ZERO(&rfds);
|
||||||
switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
|
FD_SET(socketfd, &rfds);
|
||||||
unsigned from_port;
|
switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
|
||||||
case 1:
|
unsigned from_port;
|
||||||
from->len = peer_lsa->len;
|
case 1:
|
||||||
memset(&from->sa, 0, peer_lsa->len);
|
from->len = peer_lsa->len;
|
||||||
len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
|
memset(&from->sa, 0, peer_lsa->len);
|
||||||
&from->sa, &from->len);
|
len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
|
||||||
if (len < 0) {
|
&from->sa, &from->len);
|
||||||
bb_perror_msg("recvfrom");
|
if (len < 0) {
|
||||||
goto ret;
|
bb_perror_msg("recvfrom");
|
||||||
}
|
|
||||||
from_port = get_nport(&from->sa);
|
|
||||||
if (port == org_port) {
|
|
||||||
/* Our first query went to port 69
|
|
||||||
* but reply will come from different one.
|
|
||||||
* Remember and use this new port */
|
|
||||||
port = from_port;
|
|
||||||
set_nport(peer_lsa, from_port);
|
|
||||||
}
|
|
||||||
if (port != from_port)
|
|
||||||
goto recv_again;
|
|
||||||
goto recvd_good;
|
|
||||||
case 0:
|
|
||||||
timeout--;
|
|
||||||
if (timeout == 0) {
|
|
||||||
bb_error_msg("last timeout");
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
bb_error_msg("last timeout" + 5);
|
|
||||||
goto send_again; /* resend last sent pkt */
|
|
||||||
default:
|
|
||||||
bb_perror_msg("select");
|
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
} /* while we don't see recv packet with correct port# */
|
from_port = get_nport(&from->sa);
|
||||||
|
if (port == org_port) {
|
||||||
|
/* Our first query went to port 69
|
||||||
|
* but reply will come from different one.
|
||||||
|
* Remember and use this new port */
|
||||||
|
port = from_port;
|
||||||
|
set_nport(peer_lsa, from_port);
|
||||||
|
}
|
||||||
|
if (port != from_port)
|
||||||
|
goto recv_again;
|
||||||
|
goto process_pkt;
|
||||||
|
case 0:
|
||||||
|
timeout--;
|
||||||
|
if (timeout == 0) {
|
||||||
|
bb_error_msg("last timeout");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
bb_error_msg("last timeout" + 5);
|
||||||
|
goto send_again; /* resend last sent pkt */
|
||||||
|
default:
|
||||||
|
bb_perror_msg("select");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
process_pkt:
|
||||||
/* Process recv'ed packet */
|
/* Process recv'ed packet */
|
||||||
recvd_good:
|
|
||||||
opcode = ntohs( ((uint16_t*)rbuf)[0] );
|
opcode = ntohs( ((uint16_t*)rbuf)[0] );
|
||||||
recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
|
recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
|
||||||
|
|
||||||
@ -281,9 +278,9 @@ static int tftp(
|
|||||||
"unknown transfer id",
|
"unknown transfer id",
|
||||||
"file already exists",
|
"file already exists",
|
||||||
"no such user",
|
"no such user",
|
||||||
|
"bad option",
|
||||||
};
|
};
|
||||||
enum { NUM_ERRCODE = sizeof(errcode_str) / sizeof(errcode_str[0]) };
|
enum { NUM_ERRCODE = sizeof(errcode_str) / sizeof(errcode_str[0]) };
|
||||||
|
|
||||||
const char *msg = "";
|
const char *msg = "";
|
||||||
|
|
||||||
if (rbuf[4] != '\0') {
|
if (rbuf[4] != '\0') {
|
||||||
@ -308,8 +305,13 @@ static int tftp(
|
|||||||
if (res) {
|
if (res) {
|
||||||
int blksize = xatoi_u(res);
|
int blksize = xatoi_u(res);
|
||||||
if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
|
if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
|
||||||
|
/* send ERROR 8 to server... */
|
||||||
|
/* htons can be impossible to use in const initializer: */
|
||||||
|
/*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/
|
||||||
|
/* thus we open-code big-endian layout */
|
||||||
|
static const char error_8[4] = { 0,TFTP_ERROR, 0,8 };
|
||||||
|
xsendto(socketfd, error_8, 4, &peer_lsa->sa, peer_lsa->len);
|
||||||
bb_error_msg("server proposes bad blksize %d, exiting", blksize);
|
bb_error_msg("server proposes bad blksize %d, exiting", blksize);
|
||||||
// FIXME: must also send ERROR 8 to server...
|
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
#if ENABLE_DEBUG_TFTP
|
#if ENABLE_DEBUG_TFTP
|
||||||
@ -317,7 +319,8 @@ static int tftp(
|
|||||||
blksize);
|
blksize);
|
||||||
#endif
|
#endif
|
||||||
tftp_bufsize = blksize + 4;
|
tftp_bufsize = blksize + 4;
|
||||||
block_nr = 0; // TODO: explain why???
|
/* Send ACK for OACK ("block" no: 0) */
|
||||||
|
block_nr = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* rfc2347:
|
/* rfc2347:
|
||||||
@ -430,9 +433,8 @@ int tftp_main(int argc, char **argv)
|
|||||||
if (!remotefile || !argv[0])
|
if (!remotefile || !argv[0])
|
||||||
bb_show_usage();
|
bb_show_usage();
|
||||||
|
|
||||||
if (LONE_DASH(localfile)) {
|
fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
|
||||||
fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
|
if (!LONE_DASH(localfile)) {
|
||||||
} else {
|
|
||||||
fd = xopen(localfile, flags);
|
fd = xopen(localfile, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,17 +442,12 @@ int tftp_main(int argc, char **argv)
|
|||||||
peer_lsa = xhost2sockaddr(argv[0], port);
|
peer_lsa = xhost2sockaddr(argv[0], port);
|
||||||
|
|
||||||
#if ENABLE_DEBUG_TFTP
|
#if ENABLE_DEBUG_TFTP
|
||||||
fprintf(stderr, "using server \"%s\", "
|
fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n",
|
||||||
"remotefile \"%s\", localfile \"%s\"\n",
|
|
||||||
xmalloc_sockaddr2dotted(&peer_lsa->sa, peer_lsa->len),
|
xmalloc_sockaddr2dotted(&peer_lsa->sa, peer_lsa->len),
|
||||||
remotefile, localfile);
|
remotefile, localfile);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
result = tftp(
|
result = tftp( USE_GETPUT(cmd,) peer_lsa, remotefile, fd, port, blocksize);
|
||||||
#if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
|
|
||||||
cmd,
|
|
||||||
#endif
|
|
||||||
peer_lsa, remotefile, fd, port, blocksize);
|
|
||||||
|
|
||||||
if (ENABLE_FEATURE_CLEAN_UP)
|
if (ENABLE_FEATURE_CLEAN_UP)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user