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:
Denis Vlasenko 2007-05-09 12:50:08 +00:00
parent a035e9f1a9
commit bf678d5423

View File

@ -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);