113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci/* <DESC>
2513498266Sopenharmony_ci * multi socket interface together with libev
2613498266Sopenharmony_ci * </DESC>
2713498266Sopenharmony_ci */
2813498266Sopenharmony_ci/* Example application source code using the multi socket interface to
2913498266Sopenharmony_ci * download many files at once.
3013498266Sopenharmony_ci *
3113498266Sopenharmony_ci * This example features the same basic functionality as hiperfifo.c does,
3213498266Sopenharmony_ci * but this uses libev instead of libevent.
3313498266Sopenharmony_ci *
3413498266Sopenharmony_ci * Written by Jeff Pohlmeyer, converted to use libev by Markus Koetter
3513498266Sopenharmony_ci
3613498266Sopenharmony_ciRequires libev and a (POSIX?) system that has mkfifo().
3713498266Sopenharmony_ci
3813498266Sopenharmony_ciThis is an adaptation of libcurl's "hipev.c" and libevent's "event-test.c"
3913498266Sopenharmony_cisample programs.
4013498266Sopenharmony_ci
4113498266Sopenharmony_ciWhen running, the program creates the named pipe "hiper.fifo"
4213498266Sopenharmony_ci
4313498266Sopenharmony_ciWhenever there is input into the fifo, the program reads the input as a list
4413498266Sopenharmony_ciof URL's and creates some new easy handles to fetch each URL via the
4513498266Sopenharmony_cicurl_multi "hiper" API.
4613498266Sopenharmony_ci
4713498266Sopenharmony_ci
4813498266Sopenharmony_ciThus, you can try a single URL:
4913498266Sopenharmony_ci  % echo http://www.yahoo.com > hiper.fifo
5013498266Sopenharmony_ci
5113498266Sopenharmony_ciOr a whole bunch of them:
5213498266Sopenharmony_ci  % cat my-url-list > hiper.fifo
5313498266Sopenharmony_ci
5413498266Sopenharmony_ciThe fifo buffer is handled almost instantly, so you can even add more URL's
5513498266Sopenharmony_ciwhile the previous requests are still being downloaded.
5613498266Sopenharmony_ci
5713498266Sopenharmony_ciNote:
5813498266Sopenharmony_ci  For the sake of simplicity, URL length is limited to 1023 char's !
5913498266Sopenharmony_ci
6013498266Sopenharmony_ciThis is purely a demo app, all retrieved data is simply discarded by the write
6113498266Sopenharmony_cicallback.
6213498266Sopenharmony_ci
6313498266Sopenharmony_ci*/
6413498266Sopenharmony_ci
6513498266Sopenharmony_ci#include <stdio.h>
6613498266Sopenharmony_ci#include <string.h>
6713498266Sopenharmony_ci#include <stdlib.h>
6813498266Sopenharmony_ci#include <sys/time.h>
6913498266Sopenharmony_ci#include <time.h>
7013498266Sopenharmony_ci#include <unistd.h>
7113498266Sopenharmony_ci#include <sys/poll.h>
7213498266Sopenharmony_ci#include <curl/curl.h>
7313498266Sopenharmony_ci#include <ev.h>
7413498266Sopenharmony_ci#include <fcntl.h>
7513498266Sopenharmony_ci#include <sys/stat.h>
7613498266Sopenharmony_ci#include <errno.h>
7713498266Sopenharmony_ci
7813498266Sopenharmony_ci#define DPRINT(x...) printf(x)
7913498266Sopenharmony_ci
8013498266Sopenharmony_ci#define MSG_OUT stdout /* Send info to stdout, change to stderr if you want */
8113498266Sopenharmony_ci
8213498266Sopenharmony_ci
8313498266Sopenharmony_ci/* Global information, common to all connections */
8413498266Sopenharmony_citypedef struct _GlobalInfo
8513498266Sopenharmony_ci{
8613498266Sopenharmony_ci  struct ev_loop *loop;
8713498266Sopenharmony_ci  struct ev_io fifo_event;
8813498266Sopenharmony_ci  struct ev_timer timer_event;
8913498266Sopenharmony_ci  CURLM *multi;
9013498266Sopenharmony_ci  int still_running;
9113498266Sopenharmony_ci  FILE *input;
9213498266Sopenharmony_ci} GlobalInfo;
9313498266Sopenharmony_ci
9413498266Sopenharmony_ci
9513498266Sopenharmony_ci/* Information associated with a specific easy handle */
9613498266Sopenharmony_citypedef struct _ConnInfo
9713498266Sopenharmony_ci{
9813498266Sopenharmony_ci  CURL *easy;
9913498266Sopenharmony_ci  char *url;
10013498266Sopenharmony_ci  GlobalInfo *global;
10113498266Sopenharmony_ci  char error[CURL_ERROR_SIZE];
10213498266Sopenharmony_ci} ConnInfo;
10313498266Sopenharmony_ci
10413498266Sopenharmony_ci
10513498266Sopenharmony_ci/* Information associated with a specific socket */
10613498266Sopenharmony_citypedef struct _SockInfo
10713498266Sopenharmony_ci{
10813498266Sopenharmony_ci  curl_socket_t sockfd;
10913498266Sopenharmony_ci  CURL *easy;
11013498266Sopenharmony_ci  int action;
11113498266Sopenharmony_ci  long timeout;
11213498266Sopenharmony_ci  struct ev_io ev;
11313498266Sopenharmony_ci  int evset;
11413498266Sopenharmony_ci  GlobalInfo *global;
11513498266Sopenharmony_ci} SockInfo;
11613498266Sopenharmony_ci
11713498266Sopenharmony_cistatic void timer_cb(EV_P_ struct ev_timer *w, int revents);
11813498266Sopenharmony_ci
11913498266Sopenharmony_ci/* Update the event timer after curl_multi library calls */
12013498266Sopenharmony_cistatic int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g)
12113498266Sopenharmony_ci{
12213498266Sopenharmony_ci  DPRINT("%s %li\n", __PRETTY_FUNCTION__,  timeout_ms);
12313498266Sopenharmony_ci  ev_timer_stop(g->loop, &g->timer_event);
12413498266Sopenharmony_ci  if(timeout_ms >= 0) {
12513498266Sopenharmony_ci    /* -1 means delete, other values are timeout times in milliseconds */
12613498266Sopenharmony_ci    double  t = timeout_ms / 1000;
12713498266Sopenharmony_ci    ev_timer_init(&g->timer_event, timer_cb, t, 0.);
12813498266Sopenharmony_ci    ev_timer_start(g->loop, &g->timer_event);
12913498266Sopenharmony_ci  }
13013498266Sopenharmony_ci  return 0;
13113498266Sopenharmony_ci}
13213498266Sopenharmony_ci
13313498266Sopenharmony_ci/* Die if we get a bad CURLMcode somewhere */
13413498266Sopenharmony_cistatic void mcode_or_die(const char *where, CURLMcode code)
13513498266Sopenharmony_ci{
13613498266Sopenharmony_ci  if(CURLM_OK != code) {
13713498266Sopenharmony_ci    const char *s;
13813498266Sopenharmony_ci    switch(code) {
13913498266Sopenharmony_ci    case CURLM_BAD_HANDLE:
14013498266Sopenharmony_ci      s = "CURLM_BAD_HANDLE";
14113498266Sopenharmony_ci      break;
14213498266Sopenharmony_ci    case CURLM_BAD_EASY_HANDLE:
14313498266Sopenharmony_ci      s = "CURLM_BAD_EASY_HANDLE";
14413498266Sopenharmony_ci      break;
14513498266Sopenharmony_ci    case CURLM_OUT_OF_MEMORY:
14613498266Sopenharmony_ci      s = "CURLM_OUT_OF_MEMORY";
14713498266Sopenharmony_ci      break;
14813498266Sopenharmony_ci    case CURLM_INTERNAL_ERROR:
14913498266Sopenharmony_ci      s = "CURLM_INTERNAL_ERROR";
15013498266Sopenharmony_ci      break;
15113498266Sopenharmony_ci    case CURLM_UNKNOWN_OPTION:
15213498266Sopenharmony_ci      s = "CURLM_UNKNOWN_OPTION";
15313498266Sopenharmony_ci      break;
15413498266Sopenharmony_ci    case CURLM_LAST:
15513498266Sopenharmony_ci      s = "CURLM_LAST";
15613498266Sopenharmony_ci      break;
15713498266Sopenharmony_ci    default:
15813498266Sopenharmony_ci      s = "CURLM_unknown";
15913498266Sopenharmony_ci      break;
16013498266Sopenharmony_ci    case CURLM_BAD_SOCKET:
16113498266Sopenharmony_ci      s = "CURLM_BAD_SOCKET";
16213498266Sopenharmony_ci      fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s);
16313498266Sopenharmony_ci      /* ignore this error */
16413498266Sopenharmony_ci      return;
16513498266Sopenharmony_ci    }
16613498266Sopenharmony_ci    fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s);
16713498266Sopenharmony_ci    exit(code);
16813498266Sopenharmony_ci  }
16913498266Sopenharmony_ci}
17013498266Sopenharmony_ci
17113498266Sopenharmony_ci
17213498266Sopenharmony_ci
17313498266Sopenharmony_ci/* Check for completed transfers, and remove their easy handles */
17413498266Sopenharmony_cistatic void check_multi_info(GlobalInfo *g)
17513498266Sopenharmony_ci{
17613498266Sopenharmony_ci  char *eff_url;
17713498266Sopenharmony_ci  CURLMsg *msg;
17813498266Sopenharmony_ci  int msgs_left;
17913498266Sopenharmony_ci  ConnInfo *conn;
18013498266Sopenharmony_ci  CURL *easy;
18113498266Sopenharmony_ci  CURLcode res;
18213498266Sopenharmony_ci
18313498266Sopenharmony_ci  fprintf(MSG_OUT, "REMAINING: %d\n", g->still_running);
18413498266Sopenharmony_ci  while((msg = curl_multi_info_read(g->multi, &msgs_left))) {
18513498266Sopenharmony_ci    if(msg->msg == CURLMSG_DONE) {
18613498266Sopenharmony_ci      easy = msg->easy_handle;
18713498266Sopenharmony_ci      res = msg->data.result;
18813498266Sopenharmony_ci      curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn);
18913498266Sopenharmony_ci      curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url);
19013498266Sopenharmony_ci      fprintf(MSG_OUT, "DONE: %s => (%d) %s\n", eff_url, res, conn->error);
19113498266Sopenharmony_ci      curl_multi_remove_handle(g->multi, easy);
19213498266Sopenharmony_ci      free(conn->url);
19313498266Sopenharmony_ci      curl_easy_cleanup(easy);
19413498266Sopenharmony_ci      free(conn);
19513498266Sopenharmony_ci    }
19613498266Sopenharmony_ci  }
19713498266Sopenharmony_ci}
19813498266Sopenharmony_ci
19913498266Sopenharmony_ci
20013498266Sopenharmony_ci
20113498266Sopenharmony_ci/* Called by libevent when we get action on a multi socket */
20213498266Sopenharmony_cistatic void event_cb(EV_P_ struct ev_io *w, int revents)
20313498266Sopenharmony_ci{
20413498266Sopenharmony_ci  DPRINT("%s  w %p revents %i\n", __PRETTY_FUNCTION__, w, revents);
20513498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo*) w->data;
20613498266Sopenharmony_ci  CURLMcode rc;
20713498266Sopenharmony_ci
20813498266Sopenharmony_ci  int action = ((revents & EV_READ) ? CURL_POLL_IN : 0) |
20913498266Sopenharmony_ci    ((revents & EV_WRITE) ? CURL_POLL_OUT : 0);
21013498266Sopenharmony_ci  rc = curl_multi_socket_action(g->multi, w->fd, action, &g->still_running);
21113498266Sopenharmony_ci  mcode_or_die("event_cb: curl_multi_socket_action", rc);
21213498266Sopenharmony_ci  check_multi_info(g);
21313498266Sopenharmony_ci  if(g->still_running <= 0) {
21413498266Sopenharmony_ci    fprintf(MSG_OUT, "last transfer done, kill timeout\n");
21513498266Sopenharmony_ci    ev_timer_stop(g->loop, &g->timer_event);
21613498266Sopenharmony_ci  }
21713498266Sopenharmony_ci}
21813498266Sopenharmony_ci
21913498266Sopenharmony_ci/* Called by libevent when our timeout expires */
22013498266Sopenharmony_cistatic void timer_cb(EV_P_ struct ev_timer *w, int revents)
22113498266Sopenharmony_ci{
22213498266Sopenharmony_ci  DPRINT("%s  w %p revents %i\n", __PRETTY_FUNCTION__, w, revents);
22313498266Sopenharmony_ci
22413498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo *)w->data;
22513498266Sopenharmony_ci  CURLMcode rc;
22613498266Sopenharmony_ci
22713498266Sopenharmony_ci  rc = curl_multi_socket_action(g->multi, CURL_SOCKET_TIMEOUT, 0,
22813498266Sopenharmony_ci                                &g->still_running);
22913498266Sopenharmony_ci  mcode_or_die("timer_cb: curl_multi_socket_action", rc);
23013498266Sopenharmony_ci  check_multi_info(g);
23113498266Sopenharmony_ci}
23213498266Sopenharmony_ci
23313498266Sopenharmony_ci/* Clean up the SockInfo structure */
23413498266Sopenharmony_cistatic void remsock(SockInfo *f, GlobalInfo *g)
23513498266Sopenharmony_ci{
23613498266Sopenharmony_ci  printf("%s  \n", __PRETTY_FUNCTION__);
23713498266Sopenharmony_ci  if(f) {
23813498266Sopenharmony_ci    if(f->evset)
23913498266Sopenharmony_ci      ev_io_stop(g->loop, &f->ev);
24013498266Sopenharmony_ci    free(f);
24113498266Sopenharmony_ci  }
24213498266Sopenharmony_ci}
24313498266Sopenharmony_ci
24413498266Sopenharmony_ci
24513498266Sopenharmony_ci
24613498266Sopenharmony_ci/* Assign information to a SockInfo structure */
24713498266Sopenharmony_cistatic void setsock(SockInfo *f, curl_socket_t s, CURL *e, int act,
24813498266Sopenharmony_ci                    GlobalInfo *g)
24913498266Sopenharmony_ci{
25013498266Sopenharmony_ci  printf("%s  \n", __PRETTY_FUNCTION__);
25113498266Sopenharmony_ci
25213498266Sopenharmony_ci  int kind = ((act & CURL_POLL_IN) ? EV_READ : 0) |
25313498266Sopenharmony_ci             ((act & CURL_POLL_OUT) ? EV_WRITE : 0);
25413498266Sopenharmony_ci
25513498266Sopenharmony_ci  f->sockfd = s;
25613498266Sopenharmony_ci  f->action = act;
25713498266Sopenharmony_ci  f->easy = e;
25813498266Sopenharmony_ci  if(f->evset)
25913498266Sopenharmony_ci    ev_io_stop(g->loop, &f->ev);
26013498266Sopenharmony_ci  ev_io_init(&f->ev, event_cb, f->sockfd, kind);
26113498266Sopenharmony_ci  f->ev.data = g;
26213498266Sopenharmony_ci  f->evset = 1;
26313498266Sopenharmony_ci  ev_io_start(g->loop, &f->ev);
26413498266Sopenharmony_ci}
26513498266Sopenharmony_ci
26613498266Sopenharmony_ci
26713498266Sopenharmony_ci
26813498266Sopenharmony_ci/* Initialize a new SockInfo structure */
26913498266Sopenharmony_cistatic void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g)
27013498266Sopenharmony_ci{
27113498266Sopenharmony_ci  SockInfo *fdp = calloc(1, sizeof(SockInfo));
27213498266Sopenharmony_ci
27313498266Sopenharmony_ci  fdp->global = g;
27413498266Sopenharmony_ci  setsock(fdp, s, easy, action, g);
27513498266Sopenharmony_ci  curl_multi_assign(g->multi, s, fdp);
27613498266Sopenharmony_ci}
27713498266Sopenharmony_ci
27813498266Sopenharmony_ci/* CURLMOPT_SOCKETFUNCTION */
27913498266Sopenharmony_cistatic int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
28013498266Sopenharmony_ci{
28113498266Sopenharmony_ci  DPRINT("%s e %p s %i what %i cbp %p sockp %p\n",
28213498266Sopenharmony_ci         __PRETTY_FUNCTION__, e, s, what, cbp, sockp);
28313498266Sopenharmony_ci
28413498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo*) cbp;
28513498266Sopenharmony_ci  SockInfo *fdp = (SockInfo*) sockp;
28613498266Sopenharmony_ci  const char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE"};
28713498266Sopenharmony_ci
28813498266Sopenharmony_ci  fprintf(MSG_OUT,
28913498266Sopenharmony_ci          "socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]);
29013498266Sopenharmony_ci  if(what == CURL_POLL_REMOVE) {
29113498266Sopenharmony_ci    fprintf(MSG_OUT, "\n");
29213498266Sopenharmony_ci    remsock(fdp, g);
29313498266Sopenharmony_ci  }
29413498266Sopenharmony_ci  else {
29513498266Sopenharmony_ci    if(!fdp) {
29613498266Sopenharmony_ci      fprintf(MSG_OUT, "Adding data: %s\n", whatstr[what]);
29713498266Sopenharmony_ci      addsock(s, e, what, g);
29813498266Sopenharmony_ci    }
29913498266Sopenharmony_ci    else {
30013498266Sopenharmony_ci      fprintf(MSG_OUT,
30113498266Sopenharmony_ci              "Changing action from %s to %s\n",
30213498266Sopenharmony_ci              whatstr[fdp->action], whatstr[what]);
30313498266Sopenharmony_ci      setsock(fdp, s, e, what, g);
30413498266Sopenharmony_ci    }
30513498266Sopenharmony_ci  }
30613498266Sopenharmony_ci  return 0;
30713498266Sopenharmony_ci}
30813498266Sopenharmony_ci
30913498266Sopenharmony_ci
31013498266Sopenharmony_ci/* CURLOPT_WRITEFUNCTION */
31113498266Sopenharmony_cistatic size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
31213498266Sopenharmony_ci{
31313498266Sopenharmony_ci  size_t realsize = size * nmemb;
31413498266Sopenharmony_ci  ConnInfo *conn = (ConnInfo*) data;
31513498266Sopenharmony_ci  (void)ptr;
31613498266Sopenharmony_ci  (void)conn;
31713498266Sopenharmony_ci  return realsize;
31813498266Sopenharmony_ci}
31913498266Sopenharmony_ci
32013498266Sopenharmony_ci
32113498266Sopenharmony_ci/* CURLOPT_PROGRESSFUNCTION */
32213498266Sopenharmony_cistatic int prog_cb(void *p, double dltotal, double dlnow, double ult,
32313498266Sopenharmony_ci                   double uln)
32413498266Sopenharmony_ci{
32513498266Sopenharmony_ci  ConnInfo *conn = (ConnInfo *)p;
32613498266Sopenharmony_ci  (void)ult;
32713498266Sopenharmony_ci  (void)uln;
32813498266Sopenharmony_ci
32913498266Sopenharmony_ci  fprintf(MSG_OUT, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal);
33013498266Sopenharmony_ci  return 0;
33113498266Sopenharmony_ci}
33213498266Sopenharmony_ci
33313498266Sopenharmony_ci
33413498266Sopenharmony_ci/* Create a new easy handle, and add it to the global curl_multi */
33513498266Sopenharmony_cistatic void new_conn(char *url, GlobalInfo *g)
33613498266Sopenharmony_ci{
33713498266Sopenharmony_ci  ConnInfo *conn;
33813498266Sopenharmony_ci  CURLMcode rc;
33913498266Sopenharmony_ci
34013498266Sopenharmony_ci  conn = calloc(1, sizeof(ConnInfo));
34113498266Sopenharmony_ci  conn->error[0]='\0';
34213498266Sopenharmony_ci
34313498266Sopenharmony_ci  conn->easy = curl_easy_init();
34413498266Sopenharmony_ci  if(!conn->easy) {
34513498266Sopenharmony_ci    fprintf(MSG_OUT, "curl_easy_init() failed, exiting!\n");
34613498266Sopenharmony_ci    exit(2);
34713498266Sopenharmony_ci  }
34813498266Sopenharmony_ci  conn->global = g;
34913498266Sopenharmony_ci  conn->url = strdup(url);
35013498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url);
35113498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb);
35213498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, conn);
35313498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, 1L);
35413498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error);
35513498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn);
35613498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 0L);
35713498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb);
35813498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn);
35913498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_TIME, 3L);
36013498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_LIMIT, 10L);
36113498266Sopenharmony_ci
36213498266Sopenharmony_ci  fprintf(MSG_OUT,
36313498266Sopenharmony_ci          "Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url);
36413498266Sopenharmony_ci  rc = curl_multi_add_handle(g->multi, conn->easy);
36513498266Sopenharmony_ci  mcode_or_die("new_conn: curl_multi_add_handle", rc);
36613498266Sopenharmony_ci
36713498266Sopenharmony_ci  /* note that the add_handle() will set a time-out to trigger soon so that
36813498266Sopenharmony_ci     the necessary socket_action() call will be called by this app */
36913498266Sopenharmony_ci}
37013498266Sopenharmony_ci
37113498266Sopenharmony_ci/* This gets called whenever data is received from the fifo */
37213498266Sopenharmony_cistatic void fifo_cb(EV_P_ struct ev_io *w, int revents)
37313498266Sopenharmony_ci{
37413498266Sopenharmony_ci  char s[1024];
37513498266Sopenharmony_ci  long int rv = 0;
37613498266Sopenharmony_ci  int n = 0;
37713498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo *)w->data;
37813498266Sopenharmony_ci
37913498266Sopenharmony_ci  do {
38013498266Sopenharmony_ci    s[0]='\0';
38113498266Sopenharmony_ci    rv = fscanf(g->input, "%1023s%n", s, &n);
38213498266Sopenharmony_ci    s[n]='\0';
38313498266Sopenharmony_ci    if(n && s[0]) {
38413498266Sopenharmony_ci      new_conn(s, g);  /* if we read a URL, go get it! */
38513498266Sopenharmony_ci    }
38613498266Sopenharmony_ci    else
38713498266Sopenharmony_ci      break;
38813498266Sopenharmony_ci  } while(rv != EOF);
38913498266Sopenharmony_ci}
39013498266Sopenharmony_ci
39113498266Sopenharmony_ci/* Create a named pipe and tell libevent to monitor it */
39213498266Sopenharmony_cistatic int init_fifo(GlobalInfo *g)
39313498266Sopenharmony_ci{
39413498266Sopenharmony_ci  struct stat st;
39513498266Sopenharmony_ci  static const char *fifo = "hiper.fifo";
39613498266Sopenharmony_ci  curl_socket_t sockfd;
39713498266Sopenharmony_ci
39813498266Sopenharmony_ci  fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo);
39913498266Sopenharmony_ci  if(lstat (fifo, &st) == 0) {
40013498266Sopenharmony_ci    if((st.st_mode & S_IFMT) == S_IFREG) {
40113498266Sopenharmony_ci      errno = EEXIST;
40213498266Sopenharmony_ci      perror("lstat");
40313498266Sopenharmony_ci      exit(1);
40413498266Sopenharmony_ci    }
40513498266Sopenharmony_ci  }
40613498266Sopenharmony_ci  unlink(fifo);
40713498266Sopenharmony_ci  if(mkfifo (fifo, 0600) == -1) {
40813498266Sopenharmony_ci    perror("mkfifo");
40913498266Sopenharmony_ci    exit(1);
41013498266Sopenharmony_ci  }
41113498266Sopenharmony_ci  sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0);
41213498266Sopenharmony_ci  if(sockfd == -1) {
41313498266Sopenharmony_ci    perror("open");
41413498266Sopenharmony_ci    exit(1);
41513498266Sopenharmony_ci  }
41613498266Sopenharmony_ci  g->input = fdopen(sockfd, "r");
41713498266Sopenharmony_ci
41813498266Sopenharmony_ci  fprintf(MSG_OUT, "Now, pipe some URL's into > %s\n", fifo);
41913498266Sopenharmony_ci  ev_io_init(&g->fifo_event, fifo_cb, sockfd, EV_READ);
42013498266Sopenharmony_ci  ev_io_start(g->loop, &g->fifo_event);
42113498266Sopenharmony_ci  return (0);
42213498266Sopenharmony_ci}
42313498266Sopenharmony_ci
42413498266Sopenharmony_ciint main(int argc, char **argv)
42513498266Sopenharmony_ci{
42613498266Sopenharmony_ci  GlobalInfo g;
42713498266Sopenharmony_ci  (void)argc;
42813498266Sopenharmony_ci  (void)argv;
42913498266Sopenharmony_ci
43013498266Sopenharmony_ci  memset(&g, 0, sizeof(GlobalInfo));
43113498266Sopenharmony_ci  g.loop = ev_default_loop(0);
43213498266Sopenharmony_ci
43313498266Sopenharmony_ci  init_fifo(&g);
43413498266Sopenharmony_ci  g.multi = curl_multi_init();
43513498266Sopenharmony_ci
43613498266Sopenharmony_ci  ev_timer_init(&g.timer_event, timer_cb, 0., 0.);
43713498266Sopenharmony_ci  g.timer_event.data = &g;
43813498266Sopenharmony_ci  g.fifo_event.data = &g;
43913498266Sopenharmony_ci  curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
44013498266Sopenharmony_ci  curl_multi_setopt(g.multi, CURLMOPT_SOCKETDATA, &g);
44113498266Sopenharmony_ci  curl_multi_setopt(g.multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
44213498266Sopenharmony_ci  curl_multi_setopt(g.multi, CURLMOPT_TIMERDATA, &g);
44313498266Sopenharmony_ci
44413498266Sopenharmony_ci  /* we do not call any curl_multi_socket*() function yet as we have no handles
44513498266Sopenharmony_ci     added! */
44613498266Sopenharmony_ci
44713498266Sopenharmony_ci  ev_loop(g.loop, 0);
44813498266Sopenharmony_ci  curl_multi_cleanup(g.multi);
44913498266Sopenharmony_ci  return 0;
45013498266Sopenharmony_ci}
451