aboutsummaryrefslogtreecommitdiff
path: root/networking/tftp.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-09 12:50:08 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-09 12:50:08 +0000
commitbf678d54237698a79d41ea3ae49d885f0e83bec4 (patch)
treef7403d48cb8cfeccc2fdd501b0d41cdad8fb7797 /networking/tftp.c
parenta035e9f1a9028ad7fb4e9082cc7e383c3e4615cf (diff)
downloadbusybox-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.c143
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
112static int tftp( 112static 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);