From 9434194be8cfc896b416ea17d1867725990f8bc9 Mon Sep 17 00:00:00 2001 From: Philip Prindeville Date: Fri, 16 Mar 2018 16:01:01 +0100 Subject: examples/hiperfifo.c: improved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use member struct event’s instead of pointers to alloc’d struct events * simplify the cases for the mcode_or_die() function via macros; * make multi_timer_cb() actually do what the block comment says it should; * accept a “stop” command on the FIFO to shut down the service; * use cleaner notation for unused variables than the (void) hack; * allow following redirections (304’s); --- docs/examples/hiperfifo.c | 140 +++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 64 deletions(-) (limited to 'docs/examples/hiperfifo.c') diff --git a/docs/examples/hiperfifo.c b/docs/examples/hiperfifo.c index 76bc6c1f6..3ca1ed238 100644 --- a/docs/examples/hiperfifo.c +++ b/docs/examples/hiperfifo.c @@ -66,10 +66,17 @@ callback. #include #include #include +#include #include #include #include +#include +#ifdef __GNUC__ +#define _Unused __attribute__((unused)) +#else +#define _Unused +#endif #define MSG_OUT stdout /* Send info to stdout, change to stderr if you want */ @@ -78,11 +85,12 @@ callback. typedef struct _GlobalInfo { struct event_base *evbase; - struct event *fifo_event; - struct event *timer_event; + struct event fifo_event; + struct event timer_event; CURLM *multi; int still_running; FILE *input; + int stopped; } GlobalInfo; @@ -103,16 +111,42 @@ typedef struct _SockInfo CURL *easy; int action; long timeout; - struct event *ev; - int evset; + struct event ev; GlobalInfo *global; } SockInfo; +#define __case(code) \ + case code: s = __STRING(code) + +/* Die if we get a bad CURLMcode somewhere */ +static void mcode_or_die(const char *where, CURLMcode code) +{ + if(CURLM_OK != code) { + const char *s; + switch(code) { + __case(CURLM_BAD_HANDLE); break; + __case(CURLM_BAD_EASY_HANDLE); break; + __case(CURLM_OUT_OF_MEMORY); break; + __case(CURLM_INTERNAL_ERROR); break; + __case(CURLM_UNKNOWN_OPTION); break; + __case(CURLM_LAST); break; + default: s = "CURLM_unknown"; break; + __case(CURLM_BAD_SOCKET); + fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); + /* ignore this error */ + return; + } + fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); + exit(code); + } +} + + /* Update the event timer after curl_multi library calls */ -static int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g) +static int multi_timer_cb(CURLM *multi _Unused, long timeout_ms, GlobalInfo *g) { struct timeval timeout; - (void)multi; /* unused */ + CURLMcode rc; timeout.tv_sec = timeout_ms/1000; timeout.tv_usec = (timeout_ms%1000)*1000; @@ -127,35 +161,17 @@ static int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g) * for all other values of timeout_ms, this should set or *update* * the timer to the new value */ - evtimer_add(g->timer_event, &timeout); + if (timeout_ms == 0) { + rc = curl_multi_socket_action(g->multi, + CURL_SOCKET_TIMEOUT, 0, &g->still_running); + mcode_or_die("multi_timer_cb: curl_multi_socket_action", rc); + } else if (timeout_ms == -1) + evtimer_del(&g->timer_event); + else + evtimer_add(&g->timer_event, &timeout); return 0; } -/* Die if we get a bad CURLMcode somewhere */ -static void mcode_or_die(const char *where, CURLMcode code) -{ - if(CURLM_OK != code) { - const char *s; - switch(code) { - case CURLM_BAD_HANDLE: s = "CURLM_BAD_HANDLE"; break; - case CURLM_BAD_EASY_HANDLE: s = "CURLM_BAD_EASY_HANDLE"; break; - case CURLM_OUT_OF_MEMORY: s = "CURLM_OUT_OF_MEMORY"; break; - case CURLM_INTERNAL_ERROR: s = "CURLM_INTERNAL_ERROR"; break; - case CURLM_UNKNOWN_OPTION: s = "CURLM_UNKNOWN_OPTION"; break; - case CURLM_LAST: s = "CURLM_LAST"; break; - default: s = "CURLM_unknown"; - break; - case CURLM_BAD_SOCKET: s = "CURLM_BAD_SOCKET"; - fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); - /* ignore this error */ - return; - } - fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s); - exit(code); - } -} - - /* Check for completed transfers, and remove their easy handles */ static void check_multi_info(GlobalInfo *g) @@ -181,6 +197,8 @@ static void check_multi_info(GlobalInfo *g) free(conn); } } + if (g->still_running == 0 && g->stopped) + event_base_loopbreak(g->evbase); } @@ -201,8 +219,8 @@ static void event_cb(int fd, short kind, void *userp) check_multi_info(g); if(g->still_running <= 0) { fprintf(MSG_OUT, "last transfer done, kill timeout\n"); - if(evtimer_pending(g->timer_event, NULL)) { - evtimer_del(g->timer_event); + if(evtimer_pending(&g->timer_event, NULL)) { + evtimer_del(&g->timer_event); } } } @@ -210,12 +228,10 @@ static void event_cb(int fd, short kind, void *userp) /* Called by libevent when our timeout expires */ -static void timer_cb(int fd, short kind, void *userp) +static void timer_cb(int fd _Unused, short kind _Unused, void *userp) { GlobalInfo *g = (GlobalInfo *)userp; CURLMcode rc; - (void)fd; - (void)kind; rc = curl_multi_socket_action(g->multi, CURL_SOCKET_TIMEOUT, 0, &g->still_running); @@ -229,8 +245,7 @@ static void timer_cb(int fd, short kind, void *userp) static void remsock(SockInfo *f) { if(f) { - if(f->evset) - event_free(f->ev); + event_del(&f->ev); free(f); } } @@ -247,11 +262,9 @@ static void setsock(SockInfo *f, curl_socket_t s, CURL *e, int act, f->sockfd = s; f->action = act; f->easy = e; - if(f->evset) - event_free(f->ev); - f->ev = event_new(g->evbase, f->sockfd, kind, event_cb, g); - f->evset = 1; - event_add(f->ev, NULL); + event_del(&f->ev); + event_assign(&f->ev, g->evbase, f->sockfd, kind, event_cb, g); + event_add(&f->ev, NULL); } @@ -297,23 +310,20 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) /* CURLOPT_WRITEFUNCTION */ -static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) +static size_t write_cb(void *ptr _Unused, size_t size, size_t nmemb, void *data) { size_t realsize = size * nmemb; - ConnInfo *conn = (ConnInfo*) data; - (void)ptr; - (void)conn; + ConnInfo *conn _Unused = (ConnInfo*) data; + return realsize; } /* CURLOPT_PROGRESSFUNCTION */ -static int prog_cb(void *p, double dltotal, double dlnow, double ult, - double uln) +static int prog_cb(void *p, double dltotal, double dlnow, double ult _Unused, + double uln _Unused) { ConnInfo *conn = (ConnInfo *)p; - (void)ult; - (void)uln; fprintf(MSG_OUT, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal); return 0; @@ -346,6 +356,7 @@ static void new_conn(char *url, GlobalInfo *g) curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb); curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L); fprintf(MSG_OUT, "Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url); rc = curl_multi_add_handle(g->multi, conn->easy); @@ -356,21 +367,24 @@ static void new_conn(char *url, GlobalInfo *g) } /* This gets called whenever data is received from the fifo */ -static void fifo_cb(int fd, short event, void *arg) +static void fifo_cb(int fd _Unused, short event _Unused, void *arg) { char s[1024]; long int rv = 0; int n = 0; GlobalInfo *g = (GlobalInfo *)arg; - (void)fd; /* unused */ - (void)event; /* unused */ do { s[0]='\0'; rv = fscanf(g->input, "%1023s%n", s, &n); s[n]='\0'; if(n && s[0]) { - new_conn(s, arg); /* if we read a URL, go get it! */ + if (!strcmp(s, "stop")) { + g->stopped = 1; + if (g->still_running == 0) + event_base_loopbreak(g->evbase); + } else + new_conn(s, arg); /* if we read a URL, go get it! */ } else break; @@ -405,29 +419,27 @@ static int init_fifo(GlobalInfo *g) g->input = fdopen(sockfd, "r"); fprintf(MSG_OUT, "Now, pipe some URL's into > %s\n", fifo); - g->fifo_event = event_new(g->evbase, sockfd, EV_READ|EV_PERSIST, fifo_cb, g); - event_add(g->fifo_event, NULL); + event_assign(&g->fifo_event, g->evbase, sockfd, EV_READ|EV_PERSIST, fifo_cb, g); + event_add(&g->fifo_event, NULL); return (0); } static void clean_fifo(GlobalInfo *g) { - event_free(g->fifo_event); + event_del(&g->fifo_event); fclose(g->input); unlink(fifo); } -int main(int argc, char **argv) +int main(int argc _Unused, char **argv _Unused) { GlobalInfo g; - (void)argc; - (void)argv; memset(&g, 0, sizeof(GlobalInfo)); g.evbase = event_base_new(); init_fifo(&g); g.multi = curl_multi_init(); - g.timer_event = evtimer_new(g.evbase, timer_cb, &g); + evtimer_assign(&g.timer_event, g.evbase, timer_cb, &g); /* setup the generic multi interface options we want */ curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb); @@ -443,7 +455,7 @@ int main(int argc, char **argv) /* this, of course, won't get called since only way to stop this program is via ctrl-C, but it is here to show how cleanup /would/ be done. */ clean_fifo(&g); - event_free(g.timer_event); + event_del(&g.timer_event); event_base_free(g.evbase); curl_multi_cleanup(g.multi); return 0; -- cgit v1.2.3