############ # stdout _GlobalInfo{ ev_loop *loop; ev_io fifo_event; ev_timer timer_event; CURLM *multi; still_running; FILE *input;} GlobalInfo; _ConnInfo{ CURL *easy; *url; GlobalInfo *global; error[CURL_ERROR_SIZE];} ConnInfo; _SockInfo{ curl_socket_t sockfd; CURL *easy; action; timeout; ev_io ev; evset; GlobalInfo *global;} SockInfo; (EV_P_ ev_timer *w, revents); (CURLM *multi, timeout_ms, GlobalInfo *g){ ()multi; printf(, __PRETTY_FUNCTION__, timeout_ms); ev_timer_stop(g->loop, &g->timer_event);(timeout_ms >= 0) { t = timeout_ms / 1000; ev_timer_init(&g->timer_event, timer_cb, t, 0.); ev_timer_start(g->loop, &g->timer_event); } 0;} ( *where, CURLMcode code){(CURLM_OK != code) { *s;(code) {: s =;;: s =;;: s =;;: s =;;: s =;;: s =;;: s =;;: s =; fprintf(MSG_OUT,, where, s);; } fprintf(MSG_OUT,, where, s); exit(code); }} (GlobalInfo *g){ *eff_url; CURLMsg *msg; msgs_left; ConnInfo *conn; CURL *easy; CURLcode res; fprintf(MSG_OUT,, g->still_running);((msg =curl_multi_info_read(g->multi, &msgs_left))) {(msg->msg == CURLMSG_DONE) { easy = msg->easy_handle; res = msg->data.result;curl_easy_getinfo(easy,CURLINFO_PRIVATE, &conn);curl_easy_getinfo(easy,CURLINFO_EFFECTIVE_URL, &eff_url); fprintf(MSG_OUT,, eff_url, res, conn->error);curl_multi_remove_handle(g->multi, easy); free(conn->url);curl_easy_cleanup(easy); free(conn); } }} (EV_P_ ev_io *w, revents){ GlobalInfo *g; CURLMcode rc; action; printf(, __PRETTY_FUNCTION__, ( *)w, revents); g = (GlobalInfo*) w->data; action = ((revents & EV_READ) ? CURL_POLL_IN : 0) | ((revents & EV_WRITE) ? CURL_POLL_OUT : 0); rc =curl_multi_socket_action(g->multi, w->fd, action, &g->still_running); mcode_or_die(, rc); check_multi_info(g);(g->still_running <= 0) { fprintf(MSG_OUT,); ev_timer_stop(g->loop, &g->timer_event); }} (EV_P_ ev_timer *w, revents){ GlobalInfo *g; CURLMcode rc; printf(, __PRETTY_FUNCTION__, ( *)w, revents); g = (GlobalInfo *)w->data; rc =curl_multi_socket_action(g->multi, CURL_SOCKET_TIMEOUT, 0, &g->still_running); mcode_or_die(, rc); check_multi_info(g);} (SockInfo *f, GlobalInfo *g){ printf(, __PRETTY_FUNCTION__);(f) {(f->evset) ev_io_stop(g->loop, &f->ev); free(f); }} (SockInfo *f, curl_socket_t s, CURL *e, act, GlobalInfo *g){ kind = ((act & CURL_POLL_IN) ? EV_READ : 0) | ((act & CURL_POLL_OUT) ? EV_WRITE : 0); printf(, __PRETTY_FUNCTION__); f->sockfd = s; f->action = act; f->easy = e;(f->evset) ev_io_stop(g->loop, &f->ev); ev_io_init(&f->ev, event_cb, f->sockfd, kind); f->ev.data = g; f->evset = 1; ev_io_start(g->loop, &f->ev);} (curl_socket_t s, CURL *easy, action, GlobalInfo *g){ SockInfo *fdp = calloc(1,(SockInfo)); fdp->global = g; setsock(fdp, s, easy, action, g);curl_multi_assign(g->multi, s, fdp);} (CURL *e, curl_socket_t s, what, *cbp, *sockp){ GlobalInfo *g = (GlobalInfo*) cbp; SockInfo *fdp = (SockInfo*) sockp; *whatstr[]={,,,,}; printf(, __PRETTY_FUNCTION__, e, s, what, cbp, sockp); fprintf(MSG_OUT,, s, e, whatstr[what]);(what == CURL_POLL_REMOVE) { fprintf(MSG_OUT,); remsock(fdp, g); } {(!fdp) { fprintf(MSG_OUT,, whatstr[what]); addsock(s, e, what, g); } { fprintf(MSG_OUT,, whatstr[fdp->action], whatstr[what]); setsock(fdp, s, e, what, g); } } 0;} size_t( *ptr, size_t size, size_t nmemb, *data){ size_t realsize = size * nmemb; ConnInfo *conn = (ConnInfo*) data; ()ptr; ()conn; realsize;} ( *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ult, curl_off_t uln){ ConnInfo *conn = (ConnInfo *)p; ()ult; ()uln; fprintf(MSG_OUT, CURL_FORMAT_CURL_OFF_T CURL_FORMAT_CURL_OFF_T, conn->url, dlnow, dltotal); 0;} ( *url, GlobalInfo *g){ ConnInfo *conn; CURLMcode rc; conn = calloc(1,(ConnInfo)); conn->error[0]=; conn->easy =curl_easy_init();(!conn->easy) { fprintf(MSG_OUT,); exit(2); } conn->global = g; conn->url = strdup(url);curl_easy_setopt(conn->easy,CURLOPT_URL, conn->url);curl_easy_setopt(conn->easy,CURLOPT_WRITEFUNCTION, write_cb);curl_easy_setopt(conn->easy,CURLOPT_WRITEDATA, conn);curl_easy_setopt(conn->easy,CURLOPT_VERBOSE, 1L);curl_easy_setopt(conn->easy,CURLOPT_ERRORBUFFER, conn->error);curl_easy_setopt(conn->easy,CURLOPT_PRIVATE, conn);curl_easy_setopt(conn->easy,CURLOPT_NOPROGRESS, 0L);curl_easy_setopt(conn->easy,CURLOPT_XFERINFOFUNCTION, xferinfo_cb);curl_easy_setopt(conn->easy,CURLOPT_PROGRESSDATA, conn);curl_easy_setopt(conn->easy,CURLOPT_LOW_SPEED_TIME, 3L);curl_easy_setopt(conn->easy,CURLOPT_LOW_SPEED_LIMIT, 10L); fprintf(MSG_OUT,, conn->easy, g->multi, url); rc =curl_multi_add_handle(g->multi, conn->easy); mcode_or_die(, rc); } (EV_P_ ev_io *w, revents){ s[1024]; rv = 0; n = 0; GlobalInfo *g = (GlobalInfo *)w->data; ()revents; { s[0]=; rv = fscanf(g->input,, s, &n); s[n]=;(n && s[0]) { new_conn(s, g); }; }(rv != EOF);} (GlobalInfo *g){ stat st; *fifo =; curl_socket_t sockfd; fprintf(MSG_OUT,, fifo);(lstat(fifo, &st) == 0) {((st.st_mode & S_IFMT) == S_IFREG) { errno = EEXIST; perror(); 1; } } unlink(fifo);(mkfifo(fifo, 0600) == -1) { perror(); 1; } sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0);(sockfd == -1) { perror(); 1; } g->input = fdopen(sockfd,); fprintf(MSG_OUT,, fifo); ev_io_init(&g->fifo_event, fifo_cb, sockfd, EV_READ); ev_io_start(g->loop, &g->fifo_event); 0;} ( argc, **argv){ GlobalInfo g; ()argc; ()argv; memset(&g, 0,(GlobalInfo)); g.loop = ev_default_loop(0); (init_fifo(&g)) 1; g.multi =curl_multi_init(); ev_timer_init(&g.timer_event, timer_cb, 0., 0.); g.timer_event.data = &g; g.fifo_event.data = &g;curl_multi_setopt(g.multi,CURLMOPT_SOCKETFUNCTION, sock_cb);curl_multi_setopt(g.multi,CURLMOPT_SOCKETDATA, &g);curl_multi_setopt(g.multi,CURLMOPT_TIMERFUNCTION, multi_timer_cb);curl_multi_setopt(g.multi,CURLMOPT_TIMERDATA, &g); ev_loop(g.loop, 0);curl_multi_cleanup(g.multi); 0;}
A real-world application will of course properly check every return value andexit correctly at the first serious error.