tftp: extend tsize support a little
authorMagnus Damm <magnus.damm@gmail.com>
Sun, 8 Nov 2009 17:00:59 +0000 (18:00 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 8 Nov 2009 17:02:53 +0000 (18:02 +0100)
function                                             old     new   delta
tftp_protocol                                       1624    1662     +38
tftpd_main                                           495     513     +18
tftp_main                                            274     276      +2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 58/0)               Total: 58 bytes

Signed-off-by: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/tftp.c

index 9b08c147a8cb660a3cc3ce313832092d0b4a061e..c2d3ccfa8c7f3c377a5c82cf36c2314b8a5ada93 100644 (file)
@@ -110,9 +110,9 @@ static int tftp_blksize_check(const char *blksize_str, int maxsize)
                bb_error_msg("bad blocksize '%s'", blksize_str);
                return -1;
        }
-#if ENABLE_TFTP_DEBUG
+# if ENABLE_TFTP_DEBUG
        bb_error_msg("using blksize %u", blksize);
-#endif
+# endif
        return blksize;
 }
 
@@ -154,19 +154,18 @@ static char *tftp_get_option(const char *option, char *buf, int len)
 #endif
 
 static int tftp_protocol(
-               len_and_sockaddr *our_lsa, /* NULL if tftp, !NULL if tftpd */
+               /* NULL if tftp, !NULL if tftpd: */
+               len_and_sockaddr *our_lsa,
                len_and_sockaddr *peer_lsa,
                const char *local_file
                IF_TFTP(, const char *remote_file)
-               IF_FEATURE_TFTP_BLOCKSIZE(IF_TFTPD(, void *tsize))
-               IF_FEATURE_TFTP_BLOCKSIZE(, int blksize))
-{
 #if !ENABLE_TFTP
 # define remote_file NULL
 #endif
-#if !(ENABLE_FEATURE_TFTP_BLOCKSIZE && ENABLE_TFTPD)
-# define tsize NULL
-#endif
+               /* 1 for tftp; 1/0 for tftpd depending whether client asked about it: */
+               IF_FEATURE_TFTP_BLOCKSIZE(, off_t transfer_size)
+               IF_FEATURE_TFTP_BLOCKSIZE(, int blksize))
+{
 #if !ENABLE_FEATURE_TFTP_BLOCKSIZE
        enum { blksize = TFTP_BLKSIZE_DEFAULT };
 #endif
@@ -270,7 +269,7 @@ static int tftp_protocol(
                }
 /* gcc 4.3.1 would NOT optimize it out as it should! */
 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
-               if (blksize != TFTP_BLKSIZE_DEFAULT || tsize) {
+               if (blksize != TFTP_BLKSIZE_DEFAULT || transfer_size) {
                        /* Create and send OACK packet. */
                        /* For the download case, block_nr is still 1 -
                         * we expect 1st ACK from peer to be for (block_nr-1),
@@ -321,41 +320,50 @@ static int tftp_protocol(
                }
                strcpy(cp, remote_file);
                cp += len;
-               /* add "mode" part of the package */
+               /* add "mode" part of the packet */
                strcpy(cp, "octet");
                cp += sizeof("octet");
 
-#if ENABLE_FEATURE_TFTP_BLOCKSIZE
-               if (blksize == TFTP_BLKSIZE_DEFAULT)
+# if ENABLE_FEATURE_TFTP_BLOCKSIZE
+               if (blksize == TFTP_BLKSIZE_DEFAULT && !transfer_size)
                        goto send_pkt;
 
-               /* Non-standard blocksize: add option to pkt */
-               if ((&xbuf[io_bufsize - 1] - cp) < sizeof("blksize NNNNN")) {
+               /* Need to add option to pkt */
+               if ((&xbuf[io_bufsize - 1] - cp) < sizeof("blksize NNNNN tsize ") + sizeof(transfer_size)*3) {
                        bb_error_msg("remote filename is too long");
                        goto ret;
                }
                expect_OACK = 1;
-#endif
+# endif
 #endif /* ENABLE_TFTP */
 
 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
  add_blksize_opt:
-#if ENABLE_TFTPD
-               if (tsize) {
-                       struct stat st;
-                       /* add "tsize", <nul>, size, <nul> */
-                       strcpy(cp, "tsize");
-                       cp += sizeof("tsize");
-                       fstat(local_fd, &st);
-                       cp += snprintf(cp, 10, "%u", (int) st.st_size) + 1;
-               }
-#endif
                if (blksize != TFTP_BLKSIZE_DEFAULT) {
                        /* add "blksize", <nul>, blksize, <nul> */
                        strcpy(cp, "blksize");
                        cp += sizeof("blksize");
                        cp += snprintf(cp, 6, "%d", blksize) + 1;
                }
+               if (transfer_size) {
+                       /* add "tsize", <nul>, size, <nul> (see RFC2349) */
+                       /* if tftp and downloading, we send "0" (since we opened local_fd with O_TRUNC)
+                        * and this makes server to send "tsize" option with the size */
+                       /* if tftp and uploading, we send file size (maybe dont, to not confuse old servers???) */
+                       /* if tftpd and downloading, we are answering to client's request */
+                       /* if tftpd and uploading: transfer_size == 0, this code is not executed */
+                       struct stat st;
+                       strcpy(cp, "tsize");
+                       cp += sizeof("tsize");
+                       st.st_size = 0;
+                       fstat(local_fd, &st);
+                       cp += sprintf(cp, "%"OFF_FMT"u", (off_t)st.st_size) + 1;
+# if 0 /*ENABLE_FEATURE_TFTP_PROGRESS_BAR*/
+                       /* Save for progress bar. If 0 (tftp downloading),
+                        * we look at server's reply later */
+                       transfer_size = st.st_size;
+# endif
+               }
 #endif
                /* First packet is built, so skip packet generation */
                goto send_pkt;
@@ -497,6 +505,14 @@ static int tftp_protocol(
                                        }
                                        io_bufsize = blksize + 4;
                                }
+# if 0 /*ENABLE_FEATURE_TFTP_PROGRESS_BAR*/
+                               if (transfer_size == 0) { /* if we don't know it yet */
+                                       res = tftp_get_option("tsize", &rbuf[2], len - 2);
+                                       if (res) {
+                                               transfer_size = bb_strtoull(res, NULL, 10);
+                                       }
+                               }
+# endif
                                if (CMD_GET(option_mask32)) {
                                        /* We'll send ACK for OACK,
                                         * such ACK has "block no" of 0 */
@@ -578,7 +594,6 @@ static int tftp_protocol(
                        &peer_lsa->u.sa, peer_lsa->len);
        return EXIT_FAILURE;
 #undef remote_file
-#undef tsize
 }
 
 #if ENABLE_TFTP
@@ -589,10 +604,10 @@ int tftp_main(int argc UNUSED_PARAM, char **argv)
        len_and_sockaddr *peer_lsa;
        const char *local_file = NULL;
        const char *remote_file = NULL;
-#if ENABLE_FEATURE_TFTP_BLOCKSIZE
+# if ENABLE_FEATURE_TFTP_BLOCKSIZE
        const char *blksize_str = TFTP_BLKSIZE_DEFAULT_STR;
        int blksize;
-#endif
+# endif
        int result;
        int port;
        IF_GETPUT(int opt;)
@@ -610,7 +625,7 @@ int tftp_main(int argc UNUSED_PARAM, char **argv)
                        IF_FEATURE_TFTP_BLOCKSIZE(, &blksize_str));
        argv += optind;
 
-#if ENABLE_FEATURE_TFTP_BLOCKSIZE
+# if ENABLE_FEATURE_TFTP_BLOCKSIZE
        /* Check if the blksize is valid:
         * RFC2348 says between 8 and 65464 */
        blksize = tftp_blksize_check(blksize_str, 65564);
@@ -618,7 +633,7 @@ int tftp_main(int argc UNUSED_PARAM, char **argv)
                //bb_error_msg("bad block size");
                return EXIT_FAILURE;
        }
-#endif
+# endif
 
        if (remote_file) {
                if (!local_file) {
@@ -636,16 +651,16 @@ int tftp_main(int argc UNUSED_PARAM, char **argv)
        port = bb_lookup_port(argv[1], "udp", 69);
        peer_lsa = xhost2sockaddr(argv[0], port);
 
-#if ENABLE_TFTP_DEBUG
+# if ENABLE_TFTP_DEBUG
        fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
                        xmalloc_sockaddr2dotted(&peer_lsa->u.sa),
                        remote_file, local_file);
-#endif
+# endif
 
        result = tftp_protocol(
                NULL /*our_lsa*/, peer_lsa,
                local_file, remote_file
-               IF_FEATURE_TFTP_BLOCKSIZE(IF_TFTPD(, NULL /*tsize*/))
+               IF_FEATURE_TFTP_BLOCKSIZE(, 1 /* transfer_size */)
                IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
        );
 
@@ -667,7 +682,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
        const char *error_msg;
        int opt, result, opcode;
        IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;)
-       IF_FEATURE_TFTP_BLOCKSIZE(char *tsize = NULL;)
+       IF_FEATURE_TFTP_BLOCKSIZE(off_t transfer_size = 0;)
 
        INIT_G();
 
@@ -714,7 +729,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
        if (mode >= block_buf + result || strcmp(mode, "octet") != 0) {
                goto err;
        }
-#if ENABLE_FEATURE_TFTP_BLOCKSIZE
+# if ENABLE_FEATURE_TFTP_BLOCKSIZE
        {
                char *res;
                char *opt_str = mode + sizeof("octet");
@@ -730,10 +745,12 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
                                }
                        }
                        /* did client ask us about file size? */
-                       tsize = tftp_get_option("tsize", opt_str, opt_len);
+                       if (tftp_get_option("tsize", opt_str, opt_len)) {
+                               transfer_size = 1;
+                       }
                }
        }
-#endif
+# endif
 
        if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
                if (opt & TFTPD_OPT_r) {
@@ -743,6 +760,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
                        goto err;
                }
                IF_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
+               transfer_size = 0; /* do not send file size, it's meaningless */
        } else {
                IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
        }
@@ -756,7 +774,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
        result = tftp_protocol(
                our_lsa, peer_lsa,
                local_file IF_TFTP(, NULL /*remote_file*/)
-               IF_FEATURE_TFTP_BLOCKSIZE(, tsize)
+               IF_FEATURE_TFTP_BLOCKSIZE(, transfer_size)
                IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
        );