diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-09 12:50:08 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-09 12:50:08 +0000 |
| commit | bf678d54237698a79d41ea3ae49d885f0e83bec4 (patch) | |
| tree | f7403d48cb8cfeccc2fdd501b0d41cdad8fb7797 | |
| parent | a035e9f1a9028ad7fb4e9082cc7e383c3e4615cf (diff) | |
| download | busybox-w32-bf678d54237698a79d41ea3ae49d885f0e83bec4.tar.gz busybox-w32-bf678d54237698a79d41ea3ae49d885f0e83bec4.tar.bz2 busybox-w32-bf678d54237698a79d41ea3ae49d885f0e83bec4.zip | |
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.
| -rw-r--r-- | networking/tftp.c | 143 |
1 files changed, 70 insertions, 73 deletions
diff --git a/networking/tftp.c b/networking/tftp.c index 1f1dfff71..3fb76ecbb 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
| @@ -37,15 +37,15 @@ | |||
| 37 | #define TFTP_OACK 6 | 37 | #define TFTP_OACK 6 |
| 38 | 38 | ||
| 39 | #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT | 39 | #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT |
| 40 | #define USE_GETPUT(a) | 40 | #define USE_GETPUT(...) |
| 41 | #define CMD_GET(cmd) 1 | 41 | #define CMD_GET(cmd) 1 |
| 42 | #define CMD_PUT(cmd) 0 | 42 | #define CMD_PUT(cmd) 0 |
| 43 | #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT | 43 | #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT |
| 44 | #define USE_GETPUT(a) | 44 | #define USE_GETPUT(...) |
| 45 | #define CMD_GET(cmd) 0 | 45 | #define CMD_GET(cmd) 0 |
| 46 | #define CMD_PUT(cmd) 1 | 46 | #define CMD_PUT(cmd) 1 |
| 47 | #else | 47 | #else |
| 48 | #define USE_GETPUT(a) a | 48 | #define USE_GETPUT(...) __VA_ARGS__ |
| 49 | /* masks coming from getpot32 */ | 49 | /* masks coming from getpot32 */ |
| 50 | #define CMD_GET(cmd) ((cmd) & 1) | 50 | #define CMD_GET(cmd) ((cmd) & 1) |
| 51 | #define CMD_PUT(cmd) ((cmd) & 2) | 51 | #define CMD_PUT(cmd) ((cmd) & 2) |
| @@ -109,10 +109,7 @@ static char *tftp_option_get(char *buf, int len, const char *option) | |||
| 109 | 109 | ||
| 110 | #endif | 110 | #endif |
| 111 | 111 | ||
| 112 | static int tftp( | 112 | static int tftp( USE_GETPUT(const int cmd,) |
| 113 | #if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT | ||
| 114 | const int cmd, | ||
| 115 | #endif | ||
| 116 | len_and_sockaddr *peer_lsa, | 113 | len_and_sockaddr *peer_lsa, |
| 117 | const char *remotefile, const int localfd, | 114 | const char *remotefile, const int localfd, |
| 118 | unsigned port, int tftp_bufsize) | 115 | unsigned port, int tftp_bufsize) |
| @@ -181,6 +178,9 @@ static int tftp( | |||
| 181 | /* First packet is built, so skip packet generation */ | 178 | /* First packet is built, so skip packet generation */ |
| 182 | goto send_pkt; | 179 | goto send_pkt; |
| 183 | 180 | ||
| 181 | /* Using mostly goto's - continue/break will be less clear | ||
| 182 | * in where we actually jump to */ | ||
| 183 | |||
| 184 | while (1) { | 184 | while (1) { |
| 185 | /* Build ACK or DATA */ | 185 | /* Build ACK or DATA */ |
| 186 | cp = xbuf + 2; | 186 | cp = xbuf + 2; |
| @@ -203,67 +203,64 @@ static int tftp( | |||
| 203 | send_pkt: | 203 | send_pkt: |
| 204 | /* Send packet */ | 204 | /* Send packet */ |
| 205 | *((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */ | 205 | *((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */ |
| 206 | timeout = TFTP_NUM_RETRIES; /* re-initialize */ | 206 | send_len = cp - xbuf; |
| 207 | while (1) { | 207 | /* NB: send_len value is preserved in code below |
| 208 | send_len = cp - xbuf; | 208 | * for potential resend */ |
| 209 | /* nb: need to preserve send_len value in code below | ||
| 210 | * for potential resend! */ | ||
| 211 | send_again: | 209 | send_again: |
| 212 | #if ENABLE_DEBUG_TFTP | 210 | #if ENABLE_DEBUG_TFTP |
| 213 | fprintf(stderr, "sending %u bytes\n", send_len); | 211 | fprintf(stderr, "sending %u bytes\n", send_len); |
| 214 | for (cp = xbuf; cp < &xbuf[send_len]; cp++) | 212 | for (cp = xbuf; cp < &xbuf[send_len]; cp++) |
| 215 | fprintf(stderr, "%02x ", (unsigned char) *cp); | 213 | fprintf(stderr, "%02x ", (unsigned char) *cp); |
| 216 | fprintf(stderr, "\n"); | 214 | fprintf(stderr, "\n"); |
| 217 | #endif | 215 | #endif |
| 218 | xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len); | 216 | xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len); |
| 219 | /* Was it final ACK? then exit */ | 217 | /* Was it final ACK? then exit */ |
| 220 | if (finished && (opcode == TFTP_ACK)) | 218 | if (finished && (opcode == TFTP_ACK)) |
| 221 | goto ret; | 219 | goto ret; |
| 222 | 220 | ||
| 223 | /* Receive packet */ | 221 | timeout = TFTP_NUM_RETRIES; /* re-initialize */ |
| 224 | recv_again: | 222 | recv_again: |
| 225 | tv.tv_sec = TFTP_TIMEOUT; | 223 | /* Receive packet */ |
| 226 | tv.tv_usec = 0; | 224 | tv.tv_sec = TFTP_TIMEOUT; |
| 227 | FD_ZERO(&rfds); | 225 | tv.tv_usec = 0; |
| 228 | FD_SET(socketfd, &rfds); | 226 | FD_ZERO(&rfds); |
| 229 | switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { | 227 | FD_SET(socketfd, &rfds); |
| 230 | unsigned from_port; | 228 | switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { |
| 231 | case 1: | 229 | unsigned from_port; |
| 232 | from->len = peer_lsa->len; | 230 | case 1: |
| 233 | memset(&from->sa, 0, peer_lsa->len); | 231 | from->len = peer_lsa->len; |
| 234 | len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, | 232 | memset(&from->sa, 0, peer_lsa->len); |
| 235 | &from->sa, &from->len); | 233 | len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, |
| 236 | if (len < 0) { | 234 | &from->sa, &from->len); |
| 237 | bb_perror_msg("recvfrom"); | 235 | if (len < 0) { |
| 238 | goto ret; | 236 | bb_perror_msg("recvfrom"); |
| 239 | } | ||
| 240 | from_port = get_nport(&from->sa); | ||
| 241 | if (port == org_port) { | ||
| 242 | /* Our first query went to port 69 | ||
| 243 | * but reply will come from different one. | ||
| 244 | * Remember and use this new port */ | ||
| 245 | port = from_port; | ||
| 246 | set_nport(peer_lsa, from_port); | ||
| 247 | } | ||
| 248 | if (port != from_port) | ||
| 249 | goto recv_again; | ||
| 250 | goto recvd_good; | ||
| 251 | case 0: | ||
| 252 | timeout--; | ||
| 253 | if (timeout == 0) { | ||
| 254 | bb_error_msg("last timeout"); | ||
| 255 | goto ret; | ||
| 256 | } | ||
| 257 | bb_error_msg("last timeout" + 5); | ||
| 258 | goto send_again; /* resend last sent pkt */ | ||
| 259 | default: | ||
| 260 | bb_perror_msg("select"); | ||
| 261 | goto ret; | 237 | goto ret; |
| 262 | } | 238 | } |
| 263 | } /* while we don't see recv packet with correct port# */ | 239 | from_port = get_nport(&from->sa); |
| 264 | 240 | if (port == org_port) { | |
| 241 | /* Our first query went to port 69 | ||
| 242 | * but reply will come from different one. | ||
| 243 | * Remember and use this new port */ | ||
| 244 | port = from_port; | ||
| 245 | set_nport(peer_lsa, from_port); | ||
| 246 | } | ||
| 247 | if (port != from_port) | ||
| 248 | goto recv_again; | ||
| 249 | goto process_pkt; | ||
| 250 | case 0: | ||
| 251 | timeout--; | ||
| 252 | if (timeout == 0) { | ||
| 253 | bb_error_msg("last timeout"); | ||
| 254 | goto ret; | ||
| 255 | } | ||
| 256 | bb_error_msg("last timeout" + 5); | ||
| 257 | goto send_again; /* resend last sent pkt */ | ||
| 258 | default: | ||
| 259 | bb_perror_msg("select"); | ||
| 260 | goto ret; | ||
| 261 | } | ||
| 262 | process_pkt: | ||
| 265 | /* Process recv'ed packet */ | 263 | /* Process recv'ed packet */ |
| 266 | recvd_good: | ||
| 267 | opcode = ntohs( ((uint16_t*)rbuf)[0] ); | 264 | opcode = ntohs( ((uint16_t*)rbuf)[0] ); |
| 268 | recv_blk = ntohs( ((uint16_t*)rbuf)[1] ); | 265 | recv_blk = ntohs( ((uint16_t*)rbuf)[1] ); |
| 269 | 266 | ||
| @@ -281,9 +278,9 @@ static int tftp( | |||
| 281 | "unknown transfer id", | 278 | "unknown transfer id", |
| 282 | "file already exists", | 279 | "file already exists", |
| 283 | "no such user", | 280 | "no such user", |
| 281 | "bad option", | ||
| 284 | }; | 282 | }; |
| 285 | enum { NUM_ERRCODE = sizeof(errcode_str) / sizeof(errcode_str[0]) }; | 283 | enum { NUM_ERRCODE = sizeof(errcode_str) / sizeof(errcode_str[0]) }; |
| 286 | |||
| 287 | const char *msg = ""; | 284 | const char *msg = ""; |
| 288 | 285 | ||
| 289 | if (rbuf[4] != '\0') { | 286 | if (rbuf[4] != '\0') { |
| @@ -308,8 +305,13 @@ static int tftp( | |||
| 308 | if (res) { | 305 | if (res) { |
| 309 | int blksize = xatoi_u(res); | 306 | int blksize = xatoi_u(res); |
| 310 | if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) { | 307 | if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) { |
| 308 | /* send ERROR 8 to server... */ | ||
| 309 | /* htons can be impossible to use in const initializer: */ | ||
| 310 | /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/ | ||
| 311 | /* thus we open-code big-endian layout */ | ||
| 312 | static const char error_8[4] = { 0,TFTP_ERROR, 0,8 }; | ||
| 313 | xsendto(socketfd, error_8, 4, &peer_lsa->sa, peer_lsa->len); | ||
| 311 | bb_error_msg("server proposes bad blksize %d, exiting", blksize); | 314 | bb_error_msg("server proposes bad blksize %d, exiting", blksize); |
| 312 | // FIXME: must also send ERROR 8 to server... | ||
| 313 | goto ret; | 315 | goto ret; |
| 314 | } | 316 | } |
| 315 | #if ENABLE_DEBUG_TFTP | 317 | #if ENABLE_DEBUG_TFTP |
| @@ -317,7 +319,8 @@ static int tftp( | |||
| 317 | blksize); | 319 | blksize); |
| 318 | #endif | 320 | #endif |
| 319 | tftp_bufsize = blksize + 4; | 321 | tftp_bufsize = blksize + 4; |
| 320 | block_nr = 0; // TODO: explain why??? | 322 | /* Send ACK for OACK ("block" no: 0) */ |
| 323 | block_nr = 0; | ||
| 321 | continue; | 324 | continue; |
| 322 | } | 325 | } |
| 323 | /* rfc2347: | 326 | /* rfc2347: |
| @@ -430,9 +433,8 @@ int tftp_main(int argc, char **argv) | |||
| 430 | if (!remotefile || !argv[0]) | 433 | if (!remotefile || !argv[0]) |
| 431 | bb_show_usage(); | 434 | bb_show_usage(); |
| 432 | 435 | ||
| 433 | if (LONE_DASH(localfile)) { | 436 | fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; |
| 434 | fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; | 437 | if (!LONE_DASH(localfile)) { |
| 435 | } else { | ||
| 436 | fd = xopen(localfile, flags); | 438 | fd = xopen(localfile, flags); |
| 437 | } | 439 | } |
| 438 | 440 | ||
| @@ -440,17 +442,12 @@ int tftp_main(int argc, char **argv) | |||
| 440 | peer_lsa = xhost2sockaddr(argv[0], port); | 442 | peer_lsa = xhost2sockaddr(argv[0], port); |
| 441 | 443 | ||
| 442 | #if ENABLE_DEBUG_TFTP | 444 | #if ENABLE_DEBUG_TFTP |
| 443 | fprintf(stderr, "using server \"%s\", " | 445 | fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n", |
| 444 | "remotefile \"%s\", localfile \"%s\"\n", | ||
| 445 | xmalloc_sockaddr2dotted(&peer_lsa->sa, peer_lsa->len), | 446 | xmalloc_sockaddr2dotted(&peer_lsa->sa, peer_lsa->len), |
| 446 | remotefile, localfile); | 447 | remotefile, localfile); |
| 447 | #endif | 448 | #endif |
| 448 | 449 | ||
| 449 | result = tftp( | 450 | result = tftp( USE_GETPUT(cmd,) peer_lsa, remotefile, fd, port, blocksize); |
| 450 | #if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT | ||
| 451 | cmd, | ||
| 452 | #endif | ||
| 453 | peer_lsa, remotefile, fd, port, blocksize); | ||
| 454 | 451 | ||
| 455 | if (ENABLE_FEATURE_CLEAN_UP) | 452 | if (ENABLE_FEATURE_CLEAN_UP) |
| 456 | close(fd); | 453 | close(fd); |
