On 03/05/2010 01:36 PM, Daniel Stenberg wrote:
On Wed, 3 Mar 2010, Ben Greear wrote:
Attached is a patch that implements tftp rate limitation logic.
Thanks, it does need a little extra love:
tftp.c:1184:7: warning: C++ style comments are not allowed in ISO C90
tftp.c:1193: warning: ISO C90 forbids mixed declarations and code
tftp.c:1176: warning: unused parameter ‘data’
tftp.c:1233: warning: conversion to ‘long int’ from ‘curl_off_t’ may
alter its value
tftp.c:1243: warning: conversion to ‘long int’ from ‘curl_off_t’ may
alter its value
And some additional comments:
o It uses >80 column lines with non-curl indent levels
o sleep_time() should be made static
o sleep_time() is only used within tftp_easy_statemach() which thus
tells us
that it won't work for the multi interface which uses the
tftp_multi_statemach() function instead. Hm, thinking about it. Perhaps
the existing multi interface speed limiting is already working for TFTP
as well. Do you know?
Here's an updated patch. I'm not seeing any of those compile warnings
on my systems (tried F11 64-bit, FC8 32-bit). Are you compiling with something
other than 'make' to get warnings to show up..or do I have to hack a makefile?
Please let me know if you see more areas for improvement.
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..0020255 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -1173,6 +1173,33 @@ static long tftp_state_timeout(struct connectdata *conn,
tftp_event_t *event)
}
}
+static curl_off_t sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, int
pkt_size) {
+ curl_off_t min_sleep = 0;
+ curl_off_t rv = 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;
+ }
+
+ rv = ((curl_off_t)((pkt_size * 8) * 1000) / rate_bps);
+
+ if (rv < min_sleep) {
+ rv = min_sleep;
+ }
+ return rv;
+}
+
+
/**********************************************************
*
* tftp_easy_statemach
@@ -1187,15 +1214,64 @@ 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;
+ curl_off_t 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->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->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 +1279,42 @@ 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? */
+ long rtms = state->retry_time * 1000;
+ if (Curl_tvdiff(k->now, transaction_start) > rtms) {
+ 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