Created
April 13, 2016 21:03
-
-
Save danieleggert/3c810e8329d59a2449e1cf8d82292646 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.c | |
// pausehandle | |
// | |
// Created by Daniel Eggert on 12/04/16. | |
// | |
// Run an HTTP server like so: | |
// % echo "Hello" > hello.txt | |
// % python -m SimpleHTTPServer | |
// The code expects to be able to get a text file at | |
// http://localhost:8000/hello.txt | |
// You can verify that this works with | |
// % curl http://localhost:8000/hello.txt | |
// | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <assert.h> | |
#include <unistd.h> | |
#include <curl/curl.h> | |
#define checkCode(a) \ | |
do { \ | |
CURLcode const _code = a; \ | |
if (_code != CURLE_OK) { \ | |
printf("%s -- %s (%d)\n", #a, curl_easy_strerror(_code), (int) _code); \ | |
abort(); \ | |
} \ | |
} while (0) | |
#define checkMCode(a) \ | |
do { \ | |
CURLMcode const _code = a; \ | |
if (_code != CURLM_OK) { \ | |
printf("%s -- %s (%d)\n", #a, curl_multi_strerror(_code), (int) _code); \ | |
abort(); \ | |
} \ | |
} while (0) | |
static CURL *createEasyHandle(void); | |
int main(int argc, const char * argv[]) { | |
checkCode(curl_global_init(CURL_GLOBAL_ALL)); | |
CURLM * const multi = curl_multi_init(); | |
CURL * const easy = createEasyHandle(); | |
checkMCode(curl_multi_add_handle(multi, easy)); | |
int repeats = 0; | |
int running = 1; | |
while (running) { | |
// Perform: | |
while (1) { | |
int runningHandles = 0; | |
CURLMcode const result = curl_multi_perform(multi, &runningHandles); | |
if (result == CURLM_CALL_MULTI_PERFORM) { | |
// call again | |
} else if (result != CURLM_OK) { | |
printf("curl_multi_perform() failed: %s (%d)\n", curl_easy_strerror(result), (int) result); | |
abort(); | |
} else { | |
running = (0 < runningHandles); | |
break; | |
} | |
} | |
// Wait: | |
{ | |
int numfds = 0; | |
checkMCode(curl_multi_wait(multi, NULL, 0, 1000, &numfds)); | |
// 'numfds' being zero means either a timeout or no file descriptors to | |
// wait for. Try timeout on first occurrence, then assume no file | |
// descriptors and no file descriptors to wait for means wait for 100 | |
// milliseconds. | |
if (numfds == 0) { | |
repeats++; /* count number of repeated zero numfds */ | |
if(repeats > 1) { | |
// sleep 100 milliseconds | |
(void) usleep(100 * 1000); | |
} | |
} else { | |
repeats = 0; | |
} | |
} | |
} | |
checkMCode(curl_multi_remove_handle(multi, easy)); | |
return 0; | |
} | |
static size_t writeCallback(char *ptr, size_t size, size_t nmemb, void *userdata) { | |
size_t const count = size * nmemb; | |
printf("[write] "); | |
for (size_t i = 0; i < count; ++i) { | |
if ((0x20 <= ptr[i]) && (ptr[i] <= 0x7e)) { | |
printf("%.1s", ptr + i); | |
} else { | |
printf("\\%02x", ptr[i]); | |
} | |
} | |
printf(" (%zu bytes)\n", count); | |
return count; | |
} | |
static size_t headerCallback(char *buffer, size_t size, size_t nitems, void *userdata) { | |
size_t const count = size * nitems; | |
printf("[header] "); | |
for (size_t i = 0; i < count; ++i) { | |
if ((0x20 <= buffer[i]) && (buffer[i] <= 0x7e)) { | |
printf("%.1s", buffer + i); | |
} else { | |
printf("\\%02x", buffer[i]); | |
} | |
} | |
printf(" (%zu bytes)\n", count); | |
// If we've received the final CR LF CR LF, we'll tell libcurl to pause: | |
if ((count == 2) && (buffer[0] == 0xd) && (buffer[1] == 0xa)) { | |
printf("[header] <- returning CURL_WRITEFUNC_PAUSE\n"); | |
return CURL_WRITEFUNC_PAUSE; | |
} else { | |
return count; | |
} | |
} | |
static void dump(const char *text, unsigned char *ptr, size_t size) { | |
unsigned int const width = 0x10; | |
printf("[debug] %s, %10.10ld bytes (0x%8.8lx)\n", text, (long)size, (long)size); | |
for (size_t i=0; i<size; i+= width) { | |
printf(" %4.4lx: ", (long)i); | |
/* show hex to the left */ | |
for (size_t c = 0; c < width; c++) { | |
if (i+c < size) { | |
printf("%02x ", ptr[i+c]); | |
} else { | |
printf(" "); | |
} | |
} | |
/* show data on the right */ | |
for (size_t c = 0; (c < width) && (i+c < size); c++) { | |
char x = (ptr[i+c] >= 0x20 && ptr[i+c] < 0x80) ? ptr[i+c] : '.'; | |
printf("%.1s", &x); | |
} | |
printf("\n"); /* newline */ | |
} | |
} | |
static int debugCallback(CURL *handle, curl_infotype type, char *data, size_t size, void *userp) { | |
(void) handle; /* prevent compiler warning */ | |
const char *text; | |
switch (type) { | |
case CURLINFO_TEXT: | |
printf("== Info: %s", data); | |
default: /* in case a new one is introduced to shock us */ | |
return 0; | |
case CURLINFO_HEADER_OUT: | |
text = "=> Send header"; | |
break; | |
case CURLINFO_DATA_OUT: | |
text = "=> Send data"; | |
break; | |
case CURLINFO_SSL_DATA_OUT: | |
text = "=> Send SSL data"; | |
break; | |
case CURLINFO_HEADER_IN: | |
text = "<= Recv header"; | |
break; | |
case CURLINFO_DATA_IN: | |
text = "<= Recv data"; | |
break; | |
case CURLINFO_SSL_DATA_IN: | |
text = "<= Recv SSL data"; | |
break; | |
} | |
dump(text, (unsigned char *) data, size); | |
return 0; | |
} | |
static CURL *createEasyHandle(void) { | |
CURL *handle = curl_easy_init(); | |
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); | |
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeCallback); | |
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerCallback); | |
curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, debugCallback); | |
curl_easy_setopt(handle, CURLOPT_URL, "http://localhost:8000/hello.txt"); | |
curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, ""); | |
curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L); | |
return handle; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment