Skip to content

Instantly share code, notes, and snippets.

@basuke
Last active January 23, 2024 07:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save basuke/59b0b92183846f0424a66f1b3d53cdc6 to your computer and use it in GitHub Desktop.
Save basuke/59b0b92183846f0424a66f1b3d53cdc6 to your computer and use it in GitHub Desktop.
#include <curl/curl.h>
#include <stddef.h>
#include <unistd.h>
static const char* STATE_0 = "started";
static const char* STATE_1 = "paused";
static const char* STATE_2 = "resumed";
static size_t writeFunction(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
{
CURL* handle = static_cast<CURL*>(userData);
long receivedSize = (blockSize * numberOfBlocks);
// pause transfer when this function is called at the first time
const char* state;
curl_easy_getinfo(handle, CURLINFO_PRIVATE, &state);
if (state == STATE_0) {
curl_easy_setopt(handle, CURLOPT_PRIVATE, STATE_1);
printf("> %p: pause\n", handle);
return CURL_WRITEFUNC_PAUSE;
}
printf("> %p: data received (%ld)\n", handle, receivedSize);
return receivedSize;
}
int main()
{
// initialize multi handle with multiplexing = ON
CURLM* multiHandle = curl_multi_init();
curl_multi_setopt(multiHandle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
// initialize 4 easy handles for getting file1~4.dat
const char* urls[4] = {
"https://localhost:8080/file1.dat",
"https://localhost:8080/file2.dat",
"https://localhost:8080/file3.dat",
"https://localhost:8080/file4.dat"
};
CURL* handles[4];
for (int i = 0; i < 4; i++) {
handles[i] = curl_easy_init();
curl_easy_setopt(handles[i], CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(handles[i], CURLOPT_PIPEWAIT, 1L);
curl_easy_setopt(handles[i], CURLOPT_SSL_ENABLE_ALPN, 1L);
curl_easy_setopt(handles[i], CURLOPT_SSL_ENABLE_NPN, 0L);
curl_easy_setopt(handles[i], CURLOPT_HTTPGET, 1L);
curl_easy_setopt(handles[i], CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(handles[i], CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(handles[i], CURLOPT_WRITEFUNCTION, writeFunction);
curl_easy_setopt(handles[i], CURLOPT_WRITEDATA, (void*)handles[i]);
curl_easy_setopt(handles[i], CURLOPT_URL, urls[i]);
curl_easy_setopt(handles[i], CURLOPT_PRIVATE, STATE_0);
curl_multi_add_handle(multiHandle, handles[i]);
}
// transfer is started here, and will be paused when
// receiving header is completed and receiving body is started
int runningHandles = 0;
int seconds = 0;
printf("> --------------: start\n");
do {
curl_multi_perform(multiHandle, &runningHandles);
sleep(1);
for (int i = 0; i < 4; i++) {
curl_easy_setopt(handles[i], CURLOPT_PRIVATE, STATE_1);
printf("> %p: resume\n", handles[i]);
curl_easy_pause(handles[i], CURLPAUSE_CONT);
}
} while (runningHandles > 0);
printf("> --------------: cleanup\n");
for (int i = 0; i < 4; i++)
curl_easy_cleanup(handles[i]);
curl_multi_cleanup(multiHandle);
return 0;
}
#include <curl/curl.h>
#include <stddef.h>
#include <unistd.h>
static const char* STATE_0 = "started";
static const char* STATE_1 = "paused";
static const char* STATE_2 = "resumed";
bool shouldResume { false };
static size_t writeFunction(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
{
CURL* handle = static_cast<CURL*>(userData);
long receivedSize = (blockSize * numberOfBlocks);
// pause transfer when this function is called at the first time
const char* state;
curl_easy_getinfo(handle, CURLINFO_PRIVATE, &state);
if (state == STATE_0) {
curl_easy_setopt(handle, CURLOPT_PRIVATE, STATE_1);
printf("> %p: pause\n", handle);
return CURL_WRITEFUNC_PAUSE;
}
printf("> %p: data received (%ld)\n", handle, receivedSize);
return receivedSize;
}
static int progressCallback(void* clientp, double, double, double, double)
{
if (!shouldResume)
return 0;
// resume transfer from callback
CURL* handle = static_cast<CURL*>(clientp);
const char* state;
curl_easy_getinfo(handle, CURLINFO_PRIVATE, &state);
if (state == STATE_1) {
curl_easy_setopt(handle, CURLOPT_PRIVATE, STATE_2);
printf("> %p: resume\n", handle);
curl_easy_pause(handle, CURLPAUSE_CONT);
}
return 0;
}
int main()
{
// initialize multi handle with multiplexing = ON
CURLM* multiHandle = curl_multi_init();
curl_multi_setopt(multiHandle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
// initialize 4 easy handles for getting file1~4.dat
const char* urls[4] = {
"https://localhost:8080/file1.dat",
"https://localhost:8080/file2.dat",
"https://localhost:8080/file3.dat",
"https://localhost:8080/file4.dat"
};
CURL* handles[4];
for (int i = 0; i < 4; i++) {
handles[i] = curl_easy_init();
curl_easy_setopt(handles[i], CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(handles[i], CURLOPT_PIPEWAIT, 1L);
curl_easy_setopt(handles[i], CURLOPT_SSL_ENABLE_ALPN, 1L);
curl_easy_setopt(handles[i], CURLOPT_SSL_ENABLE_NPN, 0L);
curl_easy_setopt(handles[i], CURLOPT_HTTPGET, 1L);
curl_easy_setopt(handles[i], CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(handles[i], CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(handles[i], CURLOPT_WRITEFUNCTION, writeFunction);
curl_easy_setopt(handles[i], CURLOPT_WRITEDATA, (void*)handles[i]);
curl_easy_setopt(handles[i], CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(handles[i], CURLOPT_PROGRESSFUNCTION, progressCallback);
curl_easy_setopt(handles[i], CURLOPT_PROGRESSDATA, (void*)handles[i]);
curl_easy_setopt(handles[i], CURLOPT_URL, urls[i]);
curl_easy_setopt(handles[i], CURLOPT_PRIVATE, STATE_0);
curl_multi_add_handle(multiHandle, handles[i]);
}
// transfer is started here, and will be paused when
// receiving header is completed and receiving body is started
int runningHandles = 0;
int seconds = 0;
printf("> --------------: start\n");
do {
curl_multi_perform(multiHandle, &runningHandles);
sleep(1);
seconds++;
// turn ON the resume flag 10 seconds after the start of transfer
if (seconds == 10)
shouldResume = true;
} while (runningHandles > 0);
printf("> --------------: cleanup\n");
for (int i = 0; i < 4; i++)
curl_easy_cleanup(handles[i]);
curl_multi_cleanup(multiHandle);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment