Attached is a patch that implements tftp rate limitation logic.
The change to transfer.c is just a white-space indentation fixup.
This has been lightly tested and could use some review.
[gree...@ben-dt2 curl]$ ./src/curl --limit-rate 8k -o /dev/null
tftp://192.168.100.6/bthelper
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 5304k 0 46080 0 0 7544 0 0:12:00 0:00:06 0:11:54 8147^C
[gree...@ben-dt2 curl]$ ./src/curl --limit-rate 80k -o /dev/null
tftp://192.168.100.6/bthelper
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
5 5304k 5 293k 0 0 80874 0 0:01:07 0:00:03 0:01:04 80871^C
[gree...@ben-dt2 curl]$ ./src/curl --limit-rate 800k -o /dev/null
tftp://192.168.100.6/bthelper
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
44 5304k 44 2347k 0 0 798k 0 0:00:06 0:00:02 0:00:04 798k^C
[gree...@ben-dt2 curl]$ ./src/curl -o /dev/null tftp://192.168.100.6/bthelper
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 5304k 100 5304k 0 0 2482k 0 0:00:02 0:00:02 --:--:-- 2482k
[gree...@ben-dt2 curl]$ ./src/curl --limit-rate 8k -T "config.log"
tftp://192.168.100.6/bthelper
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 10.3M 0 0 0 34304 0 7485 0:12:05 0:00:04 0:12:01 7488^C
[gree...@ben-dt2 curl]$ ./src/curl --limit-rate 80k -T "config.log"
tftp://192.168.100.6/bthelper
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
2 10.3M 0 0 5 273k 0 80964 0:01:07 0:00:03 0:01:04 80966^C
[gree...@ben-dt2 curl]$ ./src/curl --limit-rate 800k -T "config.log"
tftp://192.168.100.6/bthelper
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
26 10.3M 0 0 52 2806k 0 799k 0:00:06 0:00:03 0:00:03 799k^C
[gree...@ben-dt2 curl]$ ./src/curl -T "config.log" tftp://192.168.100.6/bthelper
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
50 10.3M 0 0 100 5304k 0 2458k 0:00:02 0:00:02 --:--:-- 2458k
Thanks,
Ben
--
Ben Greear <[email protected]>
Candela Technologies Inc http://www.candelatech.com
diff --git a/lib/tftp.c b/lib/tftp.c
index f2d4a51..a286077 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -1173,6 +1173,32 @@ static long tftp_state_timeout(struct connectdata *conn,
tftp_event_t *event)
}
}
+long sleep_time(struct SessionHandle *data, long rate_bps, long cur_rate_bps,
int pkt_size) {
+ long min_sleep = 0;
+
+ if (rate_bps == 0) {
+ return 0;
+ }
+
+ if (cur_rate_bps > (rate_bps + (rate_bps >> 10))) {
+ // running too fast
+ rate_bps -= rate_bps >> 6;
+ min_sleep = 1;
+ }
+ else if (cur_rate_bps < (rate_bps - (rate_bps >> 10))) {
+ // running too slow
+ rate_bps += rate_bps >> 6;
+ }
+
+ long rv = ((long)((pkt_size * 8) * 1000) / rate_bps);
+
+ if (rv < min_sleep) {
+ rv = min_sleep;
+ }
+ return rv;
+}
+
+
/**********************************************************
*
* tftp_easy_statemach
@@ -1187,15 +1213,62 @@ static CURLcode tftp_easy_statemach(struct connectdata
*conn)
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
-
+ int fd_read;
+ int timeout_ms;
+ struct SingleRequest *k = &data->req;
+ struct timeval transaction_start = Curl_tvnow();
+
+ k->start = transaction_start;
+ k->now = transaction_start;
+
/* Run the TFTP State Machine */
- for(;
- (state->state != TFTP_STATE_FIN) && (result == CURLE_OK);
- result=tftp_state_machine(state, state->event) ) {
+ for(; (state->state != TFTP_STATE_FIN) && (result == CURLE_OK); ) {
+
+ timeout_ms = state->retry_time * 1000;
+
+ if (data->set.upload) {
+ if (data->set.max_send_speed &&
+ (data->progress.ulspeed > data->set.max_send_speed)) {
+ fd_read = CURL_SOCKET_BAD;
+ timeout_ms = sleep_time(data, data->set.max_send_speed,
data->progress.ulspeed, state->blksize);
+ }
+ else {
+ fd_read = state->sockfd;
+ }
+ }
+ else {
+ if (data->set.max_recv_speed &&
+ (data->progress.dlspeed > data->set.max_recv_speed)) {
+ fd_read = CURL_SOCKET_BAD;
+ timeout_ms = sleep_time(data, data->set.max_recv_speed,
data->progress.dlspeed, state->blksize);
+ }
+ else {
+ fd_read = state->sockfd;
+ }
+ }
+
+ if(data->set.timeout) {
+ timeout_ms = data->set.timeout - Curl_tvdiff(k->now, k->start);
+ if (timeout_ms > state->retry_time * 1000)
+ timeout_ms = state->retry_time * 1000;
+ else if(timeout_ms < 0)
+ timeout_ms = 0;
+ }
+
/* Wait until ready to read or timeout occurs */
- rc=Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD,
- state->retry_time * 1000);
+ rc=Curl_socket_ready(fd_read, CURL_SOCKET_BAD, timeout_ms);
+
+ k->now = Curl_tvnow();
+
+ /* Force a progress callback if it's been too long */
+ if (Curl_tvdiff(k->now, k->start) >= data->set.timeout) {
+ if(Curl_pgrsUpdate(conn)) {
+ tftp_state_machine(state, TFTP_EVENT_ERROR);
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ k->start = k->now;
+ }
if(rc == -1) {
/* bail out */
@@ -1203,27 +1276,40 @@ static CURLcode tftp_easy_statemach(struct connectdata
*conn)
failf(data, "%s", Curl_strerror(conn, error));
state->event = TFTP_EVENT_ERROR;
}
- else if(rc==0) {
- /* A timeout occured */
- state->event = TFTP_EVENT_TIMEOUT;
-
- /* Force a look at transfer timeouts */
- check_time = 0;
-
- }
else {
+
+ if(rc==0) {
+ /* A timeout occured, but our timeout is variable, so maybe just
continue? */
+ if (Curl_tvdiff(k->now, transaction_start) > (state->retry_time *
1000)) {
+ state->event = TFTP_EVENT_TIMEOUT;
+ /* Force a look at transfer timeouts */
+ check_time = 1;
+ }
+ else {
+ continue; /* skip state machine */
+ }
+ }
+ else {
result = tftp_receive_packet(conn);
- }
+ if (result == CURLE_OK)
+ transaction_start = Curl_tvnow();
- /* Check for transfer timeout every 10 blocks, or after timeout */
- if(check_time%10==0) {
- /* ignore the event here as Curl_socket_ready() handles
- * retransmission timeouts inside the easy state mach */
+ if(k->bytecountp)
+ *k->bytecountp = k->bytecount; /* read count */
+ if(k->writebytecountp)
+ *k->writebytecountp = k->writebytecount; /* write count */
+ }
+ }
+
+ if(check_time) {
tftp_state_timeout(conn, NULL);
+ check_time = 0;
}
if(result)
return(result);
+
+ result = tftp_state_machine(state, state->event);
}
/* Tell curl we're done */
diff --git a/lib/transfer.c b/lib/transfer.c
index d3bd4b3..f3cdb2e 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -991,10 +991,10 @@ CURLcode Curl_readwrite(struct connectdata *conn,
else
fd_write = CURL_SOCKET_BAD;
- if(!select_res) { /* Call for select()/poll() only, if read/write/error
+ if(!select_res) { /* Call for select()/poll() only, if read/write/error
status is not known. */
- select_res = Curl_socket_ready(fd_read, fd_write, 0);
- }
+ select_res = Curl_socket_ready(fd_read, fd_write, 0);
+ }
if(select_res == CURL_CSELECT_ERR) {
failf(data, "select/poll returned error");
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html