f0f8d7
From 71e1317a4b44d9d81ec99c46038ada32c0e51bc9 Mon Sep 17 00:00:00 2001
f0f8d7
From: Daniel Stenberg <daniel@haxx.se>
f0f8d7
Date: Thu, 22 Aug 2013 19:23:08 +0200
f0f8d7
Subject: [PATCH 1/2] tftpd: support "writedelay" within <servercmd>
f0f8d7
f0f8d7
Upstream-commit: 06d1b10cbefaa7c54c73e09df746ae79b7f14e14
f0f8d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f0f8d7
---
f0f8d7
 tests/FILEFORMAT     |  4 +++
f0f8d7
 tests/server/tftpd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++--
f0f8d7
 2 files changed, 84 insertions(+), 3 deletions(-)
f0f8d7
f0f8d7
diff --git a/tests/FILEFORMAT b/tests/FILEFORMAT
f0f8d7
index 702368f..4759668 100644
f0f8d7
--- a/tests/FILEFORMAT
f0f8d7
+++ b/tests/FILEFORMAT
f0f8d7
@@ -137,6 +137,10 @@ rtp: part [num] channel [num] size [num]
f0f8d7
 connection-monitor When used, this will log [DISCONNECT] to the server.input
f0f8d7
                log when the connection is disconnected.
f0f8d7
 
f0f8d7
+
f0f8d7
+For TFTP:
f0f8d7
+writedelay: [secs] delay this amount between reply packets (each packet being
f0f8d7
+                   512 bytes payload)
f0f8d7
 </servercmd>
f0f8d7
 </reply>
f0f8d7
 
f0f8d7
diff --git a/tests/server/tftpd.c b/tests/server/tftpd.c
f0f8d7
index 48950c5..e2ec628 100644
f0f8d7
--- a/tests/server/tftpd.c
f0f8d7
+++ b/tests/server/tftpd.c
f0f8d7
@@ -107,8 +107,10 @@ struct testcase {
f0f8d7
   size_t bufsize; /* size of the data in buffer */
f0f8d7
   char *rptr;     /* read pointer into the buffer */
f0f8d7
   size_t rcount;  /* amount of data left to read of the file */
f0f8d7
-  long num;       /* test case number */
f0f8d7
+  long testno;    /* test case number */
f0f8d7
   int ofile;      /* file descriptor for output file when uploading to us */
f0f8d7
+
f0f8d7
+  int writedelay; /* number of seconds between each packet */
f0f8d7
 };
f0f8d7
 
f0f8d7
 struct formats {
f0f8d7
@@ -579,7 +581,7 @@ static ssize_t write_behind(struct testcase *test, int convert)
f0f8d7
 
f0f8d7
   if(!test->ofile) {
f0f8d7
     char outfile[256];
f0f8d7
-    snprintf(outfile, sizeof(outfile), "log/upload.%ld", test->num);
f0f8d7
+    snprintf(outfile, sizeof(outfile), "log/upload.%ld", test->testno);
f0f8d7
     test->ofile=open(outfile, O_CREAT|O_RDWR, 0777);
f0f8d7
     if(test->ofile == -1) {
f0f8d7
       logmsg("Couldn't create and/or open file %s for upload!", outfile);
f0f8d7
@@ -1026,6 +1028,73 @@ again:
f0f8d7
   return 0;
f0f8d7
 }
f0f8d7
 
f0f8d7
+/* Based on the testno, parse the correct server commands. */
f0f8d7
+static int parse_servercmd(struct testcase *req)
f0f8d7
+{
f0f8d7
+  FILE *stream;
f0f8d7
+  char *filename;
f0f8d7
+  int error;
f0f8d7
+
f0f8d7
+  filename = test2file(req->testno);
f0f8d7
+
f0f8d7
+  stream=fopen(filename, "rb");
f0f8d7
+  if(!stream) {
f0f8d7
+    error = errno;
f0f8d7
+    logmsg("fopen() failed with error: %d %s", error, strerror(error));
f0f8d7
+    logmsg("  [1] Error opening file: %s", filename);
f0f8d7
+    logmsg("  Couldn't open test file %ld", req->testno);
f0f8d7
+    return 1; /* done */
f0f8d7
+  }
f0f8d7
+  else {
f0f8d7
+    char *orgcmd = NULL;
f0f8d7
+    char *cmd = NULL;
f0f8d7
+    size_t cmdsize = 0;
f0f8d7
+    int num=0;
f0f8d7
+
f0f8d7
+    /* get the custom server control "commands" */
f0f8d7
+    error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream);
f0f8d7
+    fclose(stream);
f0f8d7
+    if(error) {
f0f8d7
+      logmsg("getpart() failed with error: %d", error);
f0f8d7
+      return 1; /* done */
f0f8d7
+    }
f0f8d7
+
f0f8d7
+    cmd = orgcmd;
f0f8d7
+    while(cmd && cmdsize) {
f0f8d7
+      char *check;
f0f8d7
+      if(1 == sscanf(cmd, "writedelay: %d", &num)) {
f0f8d7
+        logmsg("instructed to delay %d secs between packets", num);
f0f8d7
+        req->writedelay = num;
f0f8d7
+      }
f0f8d7
+      else {
f0f8d7
+        logmsg("Unknown <servercmd> instruction found: %s", cmd);
f0f8d7
+      }
f0f8d7
+      /* try to deal with CRLF or just LF */
f0f8d7
+      check = strchr(cmd, '\r');
f0f8d7
+      if(!check)
f0f8d7
+        check = strchr(cmd, '\n');
f0f8d7
+
f0f8d7
+      if(check) {
f0f8d7
+        /* get to the letter following the newline */
f0f8d7
+        while((*check == '\r') || (*check == '\n'))
f0f8d7
+          check++;
f0f8d7
+
f0f8d7
+        if(!*check)
f0f8d7
+          /* if we reached a zero, get out */
f0f8d7
+          break;
f0f8d7
+        cmd = check;
f0f8d7
+      }
f0f8d7
+      else
f0f8d7
+        break;
f0f8d7
+    }
f0f8d7
+    if(orgcmd)
f0f8d7
+      free(orgcmd);
f0f8d7
+  }
f0f8d7
+
f0f8d7
+  return 0; /* OK! */
f0f8d7
+}
f0f8d7
+
f0f8d7
+
f0f8d7
 /*
f0f8d7
  * Validate file access.
f0f8d7
  */
f0f8d7
@@ -1076,7 +1145,9 @@ static int validate_access(struct testcase *test,
f0f8d7
 
f0f8d7
     logmsg("requested test number %ld part %ld", testno, partno);
f0f8d7
 
f0f8d7
-    test->num = testno;
f0f8d7
+    test->testno = testno;
f0f8d7
+
f0f8d7
+    (void)parse_servercmd(test);
f0f8d7
 
f0f8d7
     file = test2file(testno);
f0f8d7
 
f0f8d7
@@ -1147,6 +1218,12 @@ static void sendtftp(struct testcase *test, struct formats *pf)
f0f8d7
 #ifdef HAVE_SIGSETJMP
f0f8d7
     (void) sigsetjmp(timeoutbuf, 1);
f0f8d7
 #endif
f0f8d7
+    if(test->writedelay) {
f0f8d7
+      logmsg("Pausing %d seconds before %d bytes", test->writedelay,
f0f8d7
+             size);
f0f8d7
+      wait_ms(1000*test->writedelay);
f0f8d7
+    }
f0f8d7
+
f0f8d7
     send_data:
f0f8d7
     if (swrite(peer, sdp, size + 4) != size + 4) {
f0f8d7
       logmsg("write");
f0f8d7
-- 
f0f8d7
2.14.4
f0f8d7
f0f8d7
f0f8d7
From fd692a86883109c1ab5b57b9b9ab19ae0ab15a1f Mon Sep 17 00:00:00 2001
f0f8d7
From: Daniel Stenberg <daniel@haxx.se>
f0f8d7
Date: Thu, 22 Aug 2013 22:40:38 +0200
f0f8d7
Subject: [PATCH 2/2] TFTP: make the CURLOPT_LOW_SPEED* options work
f0f8d7
f0f8d7
... this also makes sure that the progess callback gets called more
f0f8d7
often during TFTP transfers.
f0f8d7
f0f8d7
Added test 1238 to verify.
f0f8d7
f0f8d7
Bug: http://curl.haxx.se/bug/view.cgi?id=1269
f0f8d7
Reported-by: Jo3
f0f8d7
f0f8d7
Upstream-commit: 4bea91fc677359f3dcedb05a431258b6cd5d98f3
f0f8d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f0f8d7
---
f0f8d7
 lib/tftp.c             | 10 ++++++++++
f0f8d7
 tests/data/Makefile.am |  2 +-
f0f8d7
 tests/data/test1238    | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
f0f8d7
 3 files changed, 60 insertions(+), 1 deletion(-)
f0f8d7
 create mode 100644 tests/data/test1238
f0f8d7
f0f8d7
diff --git a/lib/tftp.c b/lib/tftp.c
f0f8d7
index ef740b8..79b4f41 100644
f0f8d7
--- a/lib/tftp.c
f0f8d7
+++ b/lib/tftp.c
f0f8d7
@@ -56,6 +56,7 @@
f0f8d7
 #include "multiif.h"
f0f8d7
 #include "url.h"
f0f8d7
 #include "rawstr.h"
f0f8d7
+#include "speedcheck.h"
f0f8d7
 
f0f8d7
 #define _MPRINTF_REPLACE /* use our functions only */
f0f8d7
 #include <curl/mprintf.h>
f0f8d7
@@ -1259,6 +1260,15 @@ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
f0f8d7
   if(*dophase_done) {
f0f8d7
     DEBUGF(infof(conn->data, "DO phase is complete\n"));
f0f8d7
   }
f0f8d7
+  else {
f0f8d7
+    /* The multi code doesn't have this logic for the DOING state so we
f0f8d7
+       provide it for TFTP since it may do the entire transfer in this
f0f8d7
+       state. */
f0f8d7
+    if(Curl_pgrsUpdate(conn))
f0f8d7
+      result = CURLE_ABORTED_BY_CALLBACK;
f0f8d7
+    else
f0f8d7
+      result = Curl_speedcheck(conn->data, Curl_tvnow());
f0f8d7
+  }
f0f8d7
   return result;
f0f8d7
 }
f0f8d7
 
f0f8d7
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
f0f8d7
index 677564b..9d9b9ea 100644
f0f8d7
--- a/tests/data/Makefile.am
f0f8d7
+++ b/tests/data/Makefile.am
f0f8d7
@@ -81,7 +81,7 @@ test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125	\
f0f8d7
 test1126 test1127 test1128 test1129 test1130 test1131 test1132 test1133 \
f0f8d7
 test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
f0f8d7
 test1208 test1209 test1210 test1211 test1213 test1214 test1216 test1218 \
f0f8d7
-test1220 test1221 test1222 test1223 test1233 test1236 \
f0f8d7
+test1220 test1221 test1222 test1223 test1233 test1236 test1238 \
f0f8d7
 test1300 test1301 test1302 test1303 test1304 test1305	\
f0f8d7
 test1306 test1307 test1308 test1309 test1310 test1311 test1312 test1313 \
f0f8d7
 test1314 test1315 test1316 test1317 test1318 test1319 test1320 test1321 \
f0f8d7
diff --git a/tests/data/test1238 b/tests/data/test1238
f0f8d7
new file mode 100644
f0f8d7
index 0000000..1859339
f0f8d7
--- /dev/null
f0f8d7
+++ b/tests/data/test1238
f0f8d7
@@ -0,0 +1,49 @@
f0f8d7
+<testcase>
f0f8d7
+<info>
f0f8d7
+<keywords>
f0f8d7
+TFTP
f0f8d7
+TFTP RRQ
f0f8d7
+</keywords>
f0f8d7
+</info>
f0f8d7
+
f0f8d7
+#
f0f8d7
+# Server-side
f0f8d7
+<reply>
f0f8d7
+<servercmd>
f0f8d7
+writedelay: 2
f0f8d7
+</servercmd>
f0f8d7
+# ~1200 bytes (so that they don't fit in two 512 byte chunks)
f0f8d7
+<data nocheck="yes">
f0f8d7
+012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
f0f8d7
+</data>
f0f8d7
+</reply>
f0f8d7
+
f0f8d7
+#
f0f8d7
+# Client-side
f0f8d7
+<client>
f0f8d7
+<server>
f0f8d7
+tftp
f0f8d7
+</server>
f0f8d7
+ <name>
f0f8d7
+slow TFTP retrieve cancel due to -Y and -y
f0f8d7
+ </name>
f0f8d7
+# if less than 1000 bytes/sec within 2 seconds, abort!
f0f8d7
+ <command>
f0f8d7
+tftp://%HOSTIP:%TFTPPORT//1238 -Y1000 -y2
f0f8d7
+</command>
f0f8d7
+</client>
f0f8d7
+
f0f8d7
+#
f0f8d7
+# Verify pseudo protocol after the test has been "shot"
f0f8d7
+<verify>
f0f8d7
+<protocol>
f0f8d7
+opcode: 1
f0f8d7
+filename: /1238
f0f8d7
+mode: octet
f0f8d7
+</protocol>
f0f8d7
+# 28 = CURLE_OPERATION_TIMEDOUT
f0f8d7
+<errorcode>
f0f8d7
+28
f0f8d7
+</errorcode>
f0f8d7
+</verify>
f0f8d7
+</testcase>
f0f8d7
-- 
f0f8d7
2.14.4
f0f8d7