cURL / Mailing Lists / curl-library / Single Mail

curl-library

[PATCH] Fix TFTP upload problem with piped input

From: Serj Kalichev <serj.kalichev_at_gmail.com>
Date: Mon, 30 May 2016 15:46:46 +0300

We have a problem with TFTP upload. When input stream for curl is stdin and
input stream is not a file but generated by a script then curl can truncate
data transfer to arbitrary size. To reproduce a problem write the simple
script like that:

cat /tmp/s1
sleep 1
cat /tmp/s2

And use this script to generate input stream for curl:

/tmp/test_script | curl -T "-" tftp://192.168.1.2/f1

You will get "cat: write error: Broken pipe" and it transferred the number
of bytes equal to size of /tmp/s1 but /tmp/s2 will not be transferred at all.

The problem the Curl_fillreadbuffer() function can read less bytes than TFTP
block size. But TFTP code considers data size less than block size as an end
of transfer. And the TFTP server does the same.

The solution is to accumulate the full (512 bytes) block before sending
it to TFTP-server. See the patch.

I'm not sure but i think the problem can appear in some another cases than
piped input. The returning with less bytes read than requested is not
error for read.

Signed-off-by: Serj Kalichev <serj.kalichev_at_gmail.com>

---
 lib/tftp.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/lib/tftp.c b/lib/tftp.c
index 3c3eb5e..2bce4a7 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -705,6 +705,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
   int rblock;
   CURLcode result = CURLE_OK;
   struct SingleRequest *k = &data->req;
+  int cb; /* Bytes currently read */
 
   switch(event) {
 
@@ -762,9 +763,20 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
       return CURLE_OK;
     }
 
-    result = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes);
-    if(result)
-      return result;
+    /* TFTP considers data block size < 512 bytes as an end of session. So
+     * in some cases we must wait for additional data to build full (512 bytes)
+     * data block.
+     * */
+    state->sbytes = 0;
+    state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4;
+    do {
+      result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes,
+                                   &cb);
+      if(result)
+        return result;
+      state->sbytes += cb;
+      state->conn->data->req.upload_fromhere += cb;
+    } while(state->sbytes < state->blksize && cb != 0);
 
     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
                     4 + state->sbytes, SEND_4TH_ARG,
-- 
1.9.1
-------------------------------------------------------------------
List admin: https://cool.haxx.se/list/listinfo/curl-library
Etiquette:  https://curl.haxx.se/mail/etiquette.html
Received on 2016-05-30