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 /networking/tftp.c | |
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.
Diffstat (limited to 'networking/tftp.c')
-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); |