mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -05:00
Added --limit-rate
This commit is contained in:
parent
d7e9797365
commit
8b4ad40ed6
138
src/main.c
138
src/main.c
@ -69,6 +69,11 @@
|
|||||||
#ifdef HAVE_SYS_UTIME_H
|
#ifdef HAVE_SYS_UTIME_H
|
||||||
#include <sys/utime.h>
|
#include <sys/utime.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_POLL_H
|
||||||
|
#include <sys/poll.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
@ -361,7 +366,8 @@ static void help(void)
|
|||||||
" --interface <interface> Specify the interface to be used\n"
|
" --interface <interface> Specify the interface to be used\n"
|
||||||
" --krb4 <level> Enable krb4 with specified security level (F)\n"
|
" --krb4 <level> Enable krb4 with specified security level (F)\n"
|
||||||
" -K/--config Specify which config file to read\n"
|
" -K/--config Specify which config file to read\n"
|
||||||
" -l/--list-only List only names of an FTP directory (F)");
|
" -l/--list-only List only names of an FTP directory (F)\n"
|
||||||
|
" /--limit-rate <rate> Limit how fast transfers to allow");
|
||||||
puts(" -L/--location Follow Location: hints (H)\n"
|
puts(" -L/--location Follow Location: hints (H)\n"
|
||||||
" -m/--max-time <seconds> Maximum time allowed for the transfer\n"
|
" -m/--max-time <seconds> Maximum time allowed for the transfer\n"
|
||||||
" -M/--manual Display huge help text\n"
|
" -M/--manual Display huge help text\n"
|
||||||
@ -497,6 +503,17 @@ struct Configurable {
|
|||||||
struct curl_slist *telnet_options;
|
struct curl_slist *telnet_options;
|
||||||
|
|
||||||
HttpReq httpreq;
|
HttpReq httpreq;
|
||||||
|
|
||||||
|
/* for bandwidth limiting features: */
|
||||||
|
|
||||||
|
size_t sendpersecond; /* send to peer */
|
||||||
|
size_t recvpersecond; /* receive from peer */
|
||||||
|
|
||||||
|
time_t lastsendtime;
|
||||||
|
size_t lastsendsize;
|
||||||
|
|
||||||
|
time_t lastrecvtime;
|
||||||
|
size_t lastrecvsize;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int parseconfig(const char *filename,
|
static int parseconfig(const char *filename,
|
||||||
@ -979,6 +996,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
|||||||
#endif
|
#endif
|
||||||
{"5g", "trace", TRUE},
|
{"5g", "trace", TRUE},
|
||||||
{"5h", "trace-ascii", TRUE},
|
{"5h", "trace-ascii", TRUE},
|
||||||
|
{"5i", "limit-rate", TRUE},
|
||||||
{"0", "http1.0", FALSE},
|
{"0", "http1.0", FALSE},
|
||||||
{"1", "tlsv1", FALSE},
|
{"1", "tlsv1", FALSE},
|
||||||
{"2", "sslv2", FALSE},
|
{"2", "sslv2", FALSE},
|
||||||
@ -1169,6 +1187,29 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
|||||||
GetStr(&config->trace_dump, nextarg);
|
GetStr(&config->trace_dump, nextarg);
|
||||||
config->trace_ascii = TRUE;
|
config->trace_ascii = TRUE;
|
||||||
break;
|
break;
|
||||||
|
case 'i': /* --limit-rate */
|
||||||
|
{
|
||||||
|
/* We support G, M, K too */
|
||||||
|
char *unit;
|
||||||
|
unsigned long value = strtol(nextarg, &unit, 0);
|
||||||
|
switch(nextarg[strlen(nextarg)-1]) {
|
||||||
|
case 'G':
|
||||||
|
case 'g':
|
||||||
|
value *= 1024*1024*1024;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
case 'm':
|
||||||
|
value *= 1024*1024;
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
case 'k':
|
||||||
|
value *= 1024;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
config->recvpersecond = value;
|
||||||
|
config->sendpersecond = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default: /* the URL! */
|
default: /* the URL! */
|
||||||
{
|
{
|
||||||
struct getout *url;
|
struct getout *url;
|
||||||
@ -1835,6 +1876,12 @@ static int parseconfig(const char *filename,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void go_sleep(long ms)
|
||||||
|
{
|
||||||
|
/* portable subsecond "sleep" */
|
||||||
|
poll((void *)0, 0, ms);
|
||||||
|
}
|
||||||
|
|
||||||
struct OutStruct {
|
struct OutStruct {
|
||||||
char *filename;
|
char *filename;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
@ -1844,21 +1891,87 @@ struct OutStruct {
|
|||||||
int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
|
int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
|
||||||
{
|
{
|
||||||
struct OutStruct *out=(struct OutStruct *)stream;
|
struct OutStruct *out=(struct OutStruct *)stream;
|
||||||
|
struct Configurable *config = out->config;
|
||||||
if(out && !out->stream) {
|
if(out && !out->stream) {
|
||||||
/* open file for writing */
|
/* open file for writing */
|
||||||
out->stream=fopen(out->filename, "wb");
|
out->stream=fopen(out->filename, "wb");
|
||||||
if(!out->stream)
|
if(!out->stream)
|
||||||
return -1; /* failure */
|
return -1; /* failure */
|
||||||
if(out->config->nobuffer) {
|
if(config->nobuffer) {
|
||||||
/* disable output buffering */
|
/* disable output buffering */
|
||||||
#ifdef HAVE_SETVBUF
|
#ifdef HAVE_SETVBUF
|
||||||
setvbuf(out->stream, NULL, _IONBF, 0);
|
setvbuf(out->stream, NULL, _IONBF, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(config->recvpersecond) {
|
||||||
|
/*
|
||||||
|
* We know when we received data the previous time. We know how much data
|
||||||
|
* we get now. Make sure that this is not faster than we are told to run.
|
||||||
|
* If we're faster, sleep a while *before* doing the fwrite() here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
time_t timediff;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
timediff = now - config->lastrecvtime;
|
||||||
|
if( size*nmemb > config->recvpersecond*timediff) {
|
||||||
|
/* figure out how many milliseconds to rest */
|
||||||
|
go_sleep ( (size*nmemb)*1000/config->recvpersecond - timediff*1000 );
|
||||||
|
now = time(NULL);
|
||||||
|
}
|
||||||
|
config->lastrecvtime = now;
|
||||||
|
}
|
||||||
|
|
||||||
return fwrite(buffer, size, nmemb, out->stream);
|
return fwrite(buffer, size, nmemb, out->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InStruct {
|
||||||
|
FILE *stream;
|
||||||
|
struct Configurable *config;
|
||||||
|
};
|
||||||
|
|
||||||
|
int my_fread(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||||
|
{
|
||||||
|
struct InStruct *in=(struct InStruct *)userp;
|
||||||
|
|
||||||
|
struct Configurable *config = in->config;
|
||||||
|
|
||||||
|
if(config->sendpersecond) {
|
||||||
|
/*
|
||||||
|
* We know when we sent data the previous time. We know how much data
|
||||||
|
* we sent. Make sure that this was not faster than we are told to run.
|
||||||
|
* If we're faster, sleep a while *before* doing the fread() here.
|
||||||
|
* Also, make no larger fread() than should be sent this second!
|
||||||
|
*/
|
||||||
|
|
||||||
|
time_t timediff;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
timediff = now - config->lastsendtime;
|
||||||
|
if( config->lastsendsize > config->sendpersecond*timediff) {
|
||||||
|
/* figure out how many milliseconds to rest */
|
||||||
|
go_sleep ( config->lastsendsize*1000/config->sendpersecond -
|
||||||
|
timediff*1000 );
|
||||||
|
now = time(NULL);
|
||||||
|
}
|
||||||
|
config->lastsendtime = now;
|
||||||
|
|
||||||
|
if(size*nmemb > config->sendpersecond) {
|
||||||
|
/* lower the size to actually read */
|
||||||
|
nmemb = config->sendpersecond;
|
||||||
|
size = 1;
|
||||||
|
}
|
||||||
|
config->lastsendsize = size*nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return fread(buffer, size, nmemb, in->stream);
|
||||||
|
}
|
||||||
|
|
||||||
struct ProgressData {
|
struct ProgressData {
|
||||||
int calls;
|
int calls;
|
||||||
double total;
|
double total;
|
||||||
@ -2112,6 +2225,7 @@ operate(struct Configurable *config, int argc, char *argv[])
|
|||||||
|
|
||||||
struct OutStruct outs;
|
struct OutStruct outs;
|
||||||
struct OutStruct heads;
|
struct OutStruct heads;
|
||||||
|
struct InStruct input;
|
||||||
|
|
||||||
char *url = NULL;
|
char *url = NULL;
|
||||||
|
|
||||||
@ -2511,10 +2625,24 @@ operate(struct Configurable *config, int argc, char *argv[])
|
|||||||
curl_easy_setopt(curl, CURLOPT_SSLENGINE, config->engine);
|
curl_easy_setopt(curl, CURLOPT_SSLENGINE, config->engine);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
|
curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_FILE, (FILE *)&outs); /* where to store */
|
/* where to store */
|
||||||
/* what call to write: */
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (FILE *)&outs);
|
||||||
|
/* what call to write */
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
|
||||||
curl_easy_setopt(curl, CURLOPT_INFILE, infd); /* for uploads */
|
|
||||||
|
/* for uploads */
|
||||||
|
input.stream = infd;
|
||||||
|
input.config = config;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_READDATA, &input);
|
||||||
|
/* what call to read */
|
||||||
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_fread);
|
||||||
|
|
||||||
|
if(config->recvpersecond) {
|
||||||
|
/* tell libcurl to use a smaller sized buffer as it allows us to
|
||||||
|
make better sleeps! 7.9.9 stuff! */
|
||||||
|
curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
|
||||||
|
}
|
||||||
|
|
||||||
/* size of uploaded file: */
|
/* size of uploaded file: */
|
||||||
curl_easy_setopt(curl, CURLOPT_INFILESIZE, infilesize);
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, infilesize);
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url); /* what to fetch */
|
curl_easy_setopt(curl, CURLOPT_URL, url); /* what to fetch */
|
||||||
|
Loading…
Reference in New Issue
Block a user