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 API usage with libevent 2
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_ciWritten by Jeff Pohlmeyer
3213498266Sopenharmony_ci
3313498266Sopenharmony_ciRequires libevent version 2 and a (POSIX?) system that has mkfifo().
3413498266Sopenharmony_ci
3513498266Sopenharmony_ciThis is an adaptation of libcurl's "hipev.c" and libevent's "event-test.c"
3613498266Sopenharmony_cisample programs.
3713498266Sopenharmony_ci
3813498266Sopenharmony_ciWhen running, the program creates the named pipe "hiper.fifo"
3913498266Sopenharmony_ci
4013498266Sopenharmony_ciWhenever there is input into the fifo, the program reads the input as a list
4113498266Sopenharmony_ciof URL's and creates some new easy handles to fetch each URL via the
4213498266Sopenharmony_cicurl_multi "hiper" API.
4313498266Sopenharmony_ci
4413498266Sopenharmony_ci
4513498266Sopenharmony_ciThus, you can try a single URL:
4613498266Sopenharmony_ci  % echo http://www.yahoo.com > hiper.fifo
4713498266Sopenharmony_ci
4813498266Sopenharmony_ciOr a whole bunch of them:
4913498266Sopenharmony_ci  % cat my-url-list > hiper.fifo
5013498266Sopenharmony_ci
5113498266Sopenharmony_ciThe fifo buffer is handled almost instantly, so you can even add more URL's
5213498266Sopenharmony_ciwhile the previous requests are still being downloaded.
5313498266Sopenharmony_ci
5413498266Sopenharmony_ciNote:
5513498266Sopenharmony_ci  For the sake of simplicity, URL length is limited to 1023 char's !
5613498266Sopenharmony_ci
5713498266Sopenharmony_ciThis is purely a demo app, all retrieved data is simply discarded by the write
5813498266Sopenharmony_cicallback.
5913498266Sopenharmony_ci
6013498266Sopenharmony_ci*/
6113498266Sopenharmony_ci
6213498266Sopenharmony_ci#include <stdio.h>
6313498266Sopenharmony_ci#include <string.h>
6413498266Sopenharmony_ci#include <stdlib.h>
6513498266Sopenharmony_ci#include <sys/time.h>
6613498266Sopenharmony_ci#include <time.h>
6713498266Sopenharmony_ci#include <unistd.h>
6813498266Sopenharmony_ci#include <sys/poll.h>
6913498266Sopenharmony_ci#include <curl/curl.h>
7013498266Sopenharmony_ci#include <event2/event.h>
7113498266Sopenharmony_ci#include <event2/event_struct.h>
7213498266Sopenharmony_ci#include <fcntl.h>
7313498266Sopenharmony_ci#include <sys/stat.h>
7413498266Sopenharmony_ci#include <errno.h>
7513498266Sopenharmony_ci#include <sys/cdefs.h>
7613498266Sopenharmony_ci
7713498266Sopenharmony_ci#define MSG_OUT stdout /* Send info to stdout, change to stderr if you want */
7813498266Sopenharmony_ci
7913498266Sopenharmony_ci
8013498266Sopenharmony_ci/* Global information, common to all connections */
8113498266Sopenharmony_citypedef struct _GlobalInfo
8213498266Sopenharmony_ci{
8313498266Sopenharmony_ci  struct event_base *evbase;
8413498266Sopenharmony_ci  struct event fifo_event;
8513498266Sopenharmony_ci  struct event timer_event;
8613498266Sopenharmony_ci  CURLM *multi;
8713498266Sopenharmony_ci  int still_running;
8813498266Sopenharmony_ci  FILE *input;
8913498266Sopenharmony_ci  int stopped;
9013498266Sopenharmony_ci} GlobalInfo;
9113498266Sopenharmony_ci
9213498266Sopenharmony_ci
9313498266Sopenharmony_ci/* Information associated with a specific easy handle */
9413498266Sopenharmony_citypedef struct _ConnInfo
9513498266Sopenharmony_ci{
9613498266Sopenharmony_ci  CURL *easy;
9713498266Sopenharmony_ci  char *url;
9813498266Sopenharmony_ci  GlobalInfo *global;
9913498266Sopenharmony_ci  char error[CURL_ERROR_SIZE];
10013498266Sopenharmony_ci} ConnInfo;
10113498266Sopenharmony_ci
10213498266Sopenharmony_ci
10313498266Sopenharmony_ci/* Information associated with a specific socket */
10413498266Sopenharmony_citypedef struct _SockInfo
10513498266Sopenharmony_ci{
10613498266Sopenharmony_ci  curl_socket_t sockfd;
10713498266Sopenharmony_ci  CURL *easy;
10813498266Sopenharmony_ci  int action;
10913498266Sopenharmony_ci  long timeout;
11013498266Sopenharmony_ci  struct event ev;
11113498266Sopenharmony_ci  GlobalInfo *global;
11213498266Sopenharmony_ci} SockInfo;
11313498266Sopenharmony_ci
11413498266Sopenharmony_ci#define mycase(code) \
11513498266Sopenharmony_ci  case code: s = __STRING(code)
11613498266Sopenharmony_ci
11713498266Sopenharmony_ci/* Die if we get a bad CURLMcode somewhere */
11813498266Sopenharmony_cistatic void mcode_or_die(const char *where, CURLMcode code)
11913498266Sopenharmony_ci{
12013498266Sopenharmony_ci  if(CURLM_OK != code) {
12113498266Sopenharmony_ci    const char *s;
12213498266Sopenharmony_ci    switch(code) {
12313498266Sopenharmony_ci      mycase(CURLM_BAD_HANDLE); break;
12413498266Sopenharmony_ci      mycase(CURLM_BAD_EASY_HANDLE); break;
12513498266Sopenharmony_ci      mycase(CURLM_OUT_OF_MEMORY); break;
12613498266Sopenharmony_ci      mycase(CURLM_INTERNAL_ERROR); break;
12713498266Sopenharmony_ci      mycase(CURLM_UNKNOWN_OPTION); break;
12813498266Sopenharmony_ci      mycase(CURLM_LAST); break;
12913498266Sopenharmony_ci      default: s = "CURLM_unknown"; break;
13013498266Sopenharmony_ci      mycase(CURLM_BAD_SOCKET);
13113498266Sopenharmony_ci      fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s);
13213498266Sopenharmony_ci      /* ignore this error */
13313498266Sopenharmony_ci      return;
13413498266Sopenharmony_ci    }
13513498266Sopenharmony_ci    fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s);
13613498266Sopenharmony_ci    exit(code);
13713498266Sopenharmony_ci  }
13813498266Sopenharmony_ci}
13913498266Sopenharmony_ci
14013498266Sopenharmony_ci
14113498266Sopenharmony_ci/* Update the event timer after curl_multi library calls */
14213498266Sopenharmony_cistatic int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g)
14313498266Sopenharmony_ci{
14413498266Sopenharmony_ci  struct timeval timeout;
14513498266Sopenharmony_ci  (void)multi;
14613498266Sopenharmony_ci
14713498266Sopenharmony_ci  timeout.tv_sec = timeout_ms/1000;
14813498266Sopenharmony_ci  timeout.tv_usec = (timeout_ms%1000)*1000;
14913498266Sopenharmony_ci  fprintf(MSG_OUT, "multi_timer_cb: Setting timeout to %ld ms\n", timeout_ms);
15013498266Sopenharmony_ci
15113498266Sopenharmony_ci  /*
15213498266Sopenharmony_ci   * if timeout_ms is -1, just delete the timer
15313498266Sopenharmony_ci   *
15413498266Sopenharmony_ci   * For all other values of timeout_ms, this should set or *update* the timer
15513498266Sopenharmony_ci   * to the new value
15613498266Sopenharmony_ci   */
15713498266Sopenharmony_ci  if(timeout_ms == -1)
15813498266Sopenharmony_ci    evtimer_del(&g->timer_event);
15913498266Sopenharmony_ci  else /* includes timeout zero */
16013498266Sopenharmony_ci    evtimer_add(&g->timer_event, &timeout);
16113498266Sopenharmony_ci  return 0;
16213498266Sopenharmony_ci}
16313498266Sopenharmony_ci
16413498266Sopenharmony_ci
16513498266Sopenharmony_ci/* Check for completed transfers, and remove their easy handles */
16613498266Sopenharmony_cistatic void check_multi_info(GlobalInfo *g)
16713498266Sopenharmony_ci{
16813498266Sopenharmony_ci  char *eff_url;
16913498266Sopenharmony_ci  CURLMsg *msg;
17013498266Sopenharmony_ci  int msgs_left;
17113498266Sopenharmony_ci  ConnInfo *conn;
17213498266Sopenharmony_ci  CURL *easy;
17313498266Sopenharmony_ci  CURLcode res;
17413498266Sopenharmony_ci
17513498266Sopenharmony_ci  fprintf(MSG_OUT, "REMAINING: %d\n", g->still_running);
17613498266Sopenharmony_ci  while((msg = curl_multi_info_read(g->multi, &msgs_left))) {
17713498266Sopenharmony_ci    if(msg->msg == CURLMSG_DONE) {
17813498266Sopenharmony_ci      easy = msg->easy_handle;
17913498266Sopenharmony_ci      res = msg->data.result;
18013498266Sopenharmony_ci      curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn);
18113498266Sopenharmony_ci      curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url);
18213498266Sopenharmony_ci      fprintf(MSG_OUT, "DONE: %s => (%d) %s\n", eff_url, res, conn->error);
18313498266Sopenharmony_ci      curl_multi_remove_handle(g->multi, easy);
18413498266Sopenharmony_ci      free(conn->url);
18513498266Sopenharmony_ci      curl_easy_cleanup(easy);
18613498266Sopenharmony_ci      free(conn);
18713498266Sopenharmony_ci    }
18813498266Sopenharmony_ci  }
18913498266Sopenharmony_ci  if(g->still_running == 0 && g->stopped)
19013498266Sopenharmony_ci    event_base_loopbreak(g->evbase);
19113498266Sopenharmony_ci}
19213498266Sopenharmony_ci
19313498266Sopenharmony_ci
19413498266Sopenharmony_ci
19513498266Sopenharmony_ci/* Called by libevent when we get action on a multi socket */
19613498266Sopenharmony_cistatic void event_cb(int fd, short kind, void *userp)
19713498266Sopenharmony_ci{
19813498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo*) userp;
19913498266Sopenharmony_ci  CURLMcode rc;
20013498266Sopenharmony_ci
20113498266Sopenharmony_ci  int action =
20213498266Sopenharmony_ci    ((kind & EV_READ) ? CURL_CSELECT_IN : 0) |
20313498266Sopenharmony_ci    ((kind & EV_WRITE) ? CURL_CSELECT_OUT : 0);
20413498266Sopenharmony_ci
20513498266Sopenharmony_ci  rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running);
20613498266Sopenharmony_ci  mcode_or_die("event_cb: curl_multi_socket_action", rc);
20713498266Sopenharmony_ci
20813498266Sopenharmony_ci  check_multi_info(g);
20913498266Sopenharmony_ci  if(g->still_running <= 0) {
21013498266Sopenharmony_ci    fprintf(MSG_OUT, "last transfer done, kill timeout\n");
21113498266Sopenharmony_ci    if(evtimer_pending(&g->timer_event, NULL)) {
21213498266Sopenharmony_ci      evtimer_del(&g->timer_event);
21313498266Sopenharmony_ci    }
21413498266Sopenharmony_ci  }
21513498266Sopenharmony_ci}
21613498266Sopenharmony_ci
21713498266Sopenharmony_ci
21813498266Sopenharmony_ci
21913498266Sopenharmony_ci/* Called by libevent when our timeout expires */
22013498266Sopenharmony_cistatic void timer_cb(int fd, short kind, void *userp)
22113498266Sopenharmony_ci{
22213498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo *)userp;
22313498266Sopenharmony_ci  CURLMcode rc;
22413498266Sopenharmony_ci  (void)fd;
22513498266Sopenharmony_ci  (void)kind;
22613498266Sopenharmony_ci
22713498266Sopenharmony_ci  rc = curl_multi_socket_action(g->multi,
22813498266Sopenharmony_ci                                  CURL_SOCKET_TIMEOUT, 0, &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
23413498266Sopenharmony_ci
23513498266Sopenharmony_ci/* Clean up the SockInfo structure */
23613498266Sopenharmony_cistatic void remsock(SockInfo *f)
23713498266Sopenharmony_ci{
23813498266Sopenharmony_ci  if(f) {
23913498266Sopenharmony_ci    if(event_initialized(&f->ev)) {
24013498266Sopenharmony_ci      event_del(&f->ev);
24113498266Sopenharmony_ci    }
24213498266Sopenharmony_ci    free(f);
24313498266Sopenharmony_ci  }
24413498266Sopenharmony_ci}
24513498266Sopenharmony_ci
24613498266Sopenharmony_ci
24713498266Sopenharmony_ci
24813498266Sopenharmony_ci/* Assign information to a SockInfo structure */
24913498266Sopenharmony_cistatic void setsock(SockInfo *f, curl_socket_t s, CURL *e, int act,
25013498266Sopenharmony_ci                    GlobalInfo *g)
25113498266Sopenharmony_ci{
25213498266Sopenharmony_ci  int kind =
25313498266Sopenharmony_ci     ((act & CURL_POLL_IN) ? EV_READ : 0) |
25413498266Sopenharmony_ci     ((act & CURL_POLL_OUT) ? EV_WRITE : 0) | EV_PERSIST;
25513498266Sopenharmony_ci
25613498266Sopenharmony_ci  f->sockfd = s;
25713498266Sopenharmony_ci  f->action = act;
25813498266Sopenharmony_ci  f->easy = e;
25913498266Sopenharmony_ci  if(event_initialized(&f->ev)) {
26013498266Sopenharmony_ci    event_del(&f->ev);
26113498266Sopenharmony_ci  }
26213498266Sopenharmony_ci  event_assign(&f->ev, g->evbase, f->sockfd, kind, event_cb, g);
26313498266Sopenharmony_ci  event_add(&f->ev, NULL);
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  GlobalInfo *g = (GlobalInfo*) cbp;
28213498266Sopenharmony_ci  SockInfo *fdp = (SockInfo*) sockp;
28313498266Sopenharmony_ci  const char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE" };
28413498266Sopenharmony_ci
28513498266Sopenharmony_ci  fprintf(MSG_OUT,
28613498266Sopenharmony_ci          "socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]);
28713498266Sopenharmony_ci  if(what == CURL_POLL_REMOVE) {
28813498266Sopenharmony_ci    fprintf(MSG_OUT, "\n");
28913498266Sopenharmony_ci    remsock(fdp);
29013498266Sopenharmony_ci  }
29113498266Sopenharmony_ci  else {
29213498266Sopenharmony_ci    if(!fdp) {
29313498266Sopenharmony_ci      fprintf(MSG_OUT, "Adding data: %s\n", whatstr[what]);
29413498266Sopenharmony_ci      addsock(s, e, what, g);
29513498266Sopenharmony_ci    }
29613498266Sopenharmony_ci    else {
29713498266Sopenharmony_ci      fprintf(MSG_OUT,
29813498266Sopenharmony_ci              "Changing action from %s to %s\n",
29913498266Sopenharmony_ci              whatstr[fdp->action], whatstr[what]);
30013498266Sopenharmony_ci      setsock(fdp, s, e, what, g);
30113498266Sopenharmony_ci    }
30213498266Sopenharmony_ci  }
30313498266Sopenharmony_ci  return 0;
30413498266Sopenharmony_ci}
30513498266Sopenharmony_ci
30613498266Sopenharmony_ci
30713498266Sopenharmony_ci
30813498266Sopenharmony_ci/* CURLOPT_WRITEFUNCTION */
30913498266Sopenharmony_cistatic size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
31013498266Sopenharmony_ci{
31113498266Sopenharmony_ci  (void)ptr;
31213498266Sopenharmony_ci  (void)data;
31313498266Sopenharmony_ci  return size * nmemb;
31413498266Sopenharmony_ci}
31513498266Sopenharmony_ci
31613498266Sopenharmony_ci
31713498266Sopenharmony_ci/* CURLOPT_PROGRESSFUNCTION */
31813498266Sopenharmony_cistatic int prog_cb(void *p, double dltotal, double dlnow, double ult,
31913498266Sopenharmony_ci                   double uln)
32013498266Sopenharmony_ci{
32113498266Sopenharmony_ci  ConnInfo *conn = (ConnInfo *)p;
32213498266Sopenharmony_ci  (void)ult;
32313498266Sopenharmony_ci  (void)uln;
32413498266Sopenharmony_ci
32513498266Sopenharmony_ci  fprintf(MSG_OUT, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal);
32613498266Sopenharmony_ci  return 0;
32713498266Sopenharmony_ci}
32813498266Sopenharmony_ci
32913498266Sopenharmony_ci
33013498266Sopenharmony_ci/* Create a new easy handle, and add it to the global curl_multi */
33113498266Sopenharmony_cistatic void new_conn(char *url, GlobalInfo *g)
33213498266Sopenharmony_ci{
33313498266Sopenharmony_ci  ConnInfo *conn;
33413498266Sopenharmony_ci  CURLMcode rc;
33513498266Sopenharmony_ci
33613498266Sopenharmony_ci  conn = calloc(1, sizeof(ConnInfo));
33713498266Sopenharmony_ci  conn->error[0]='\0';
33813498266Sopenharmony_ci
33913498266Sopenharmony_ci  conn->easy = curl_easy_init();
34013498266Sopenharmony_ci  if(!conn->easy) {
34113498266Sopenharmony_ci    fprintf(MSG_OUT, "curl_easy_init() failed, exiting!\n");
34213498266Sopenharmony_ci    exit(2);
34313498266Sopenharmony_ci  }
34413498266Sopenharmony_ci  conn->global = g;
34513498266Sopenharmony_ci  conn->url = strdup(url);
34613498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url);
34713498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb);
34813498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, conn);
34913498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, 1L);
35013498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error);
35113498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn);
35213498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 0L);
35313498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb);
35413498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn);
35513498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L);
35613498266Sopenharmony_ci  fprintf(MSG_OUT,
35713498266Sopenharmony_ci          "Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url);
35813498266Sopenharmony_ci  rc = curl_multi_add_handle(g->multi, conn->easy);
35913498266Sopenharmony_ci  mcode_or_die("new_conn: curl_multi_add_handle", rc);
36013498266Sopenharmony_ci
36113498266Sopenharmony_ci  /* note that the add_handle() will set a time-out to trigger soon so that
36213498266Sopenharmony_ci     the necessary socket_action() call will be called by this app */
36313498266Sopenharmony_ci}
36413498266Sopenharmony_ci
36513498266Sopenharmony_ci/* This gets called whenever data is received from the fifo */
36613498266Sopenharmony_cistatic void fifo_cb(int fd, short event, void *arg)
36713498266Sopenharmony_ci{
36813498266Sopenharmony_ci  char s[1024];
36913498266Sopenharmony_ci  long int rv = 0;
37013498266Sopenharmony_ci  int n = 0;
37113498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo *)arg;
37213498266Sopenharmony_ci  (void)fd;
37313498266Sopenharmony_ci  (void)event;
37413498266Sopenharmony_ci
37513498266Sopenharmony_ci  do {
37613498266Sopenharmony_ci    s[0]='\0';
37713498266Sopenharmony_ci    rv = fscanf(g->input, "%1023s%n", s, &n);
37813498266Sopenharmony_ci    s[n]='\0';
37913498266Sopenharmony_ci    if(n && s[0]) {
38013498266Sopenharmony_ci      if(!strcmp(s, "stop")) {
38113498266Sopenharmony_ci        g->stopped = 1;
38213498266Sopenharmony_ci        if(g->still_running == 0)
38313498266Sopenharmony_ci          event_base_loopbreak(g->evbase);
38413498266Sopenharmony_ci      }
38513498266Sopenharmony_ci      else
38613498266Sopenharmony_ci        new_conn(s, arg);  /* if we read a URL, go get it! */
38713498266Sopenharmony_ci    }
38813498266Sopenharmony_ci    else
38913498266Sopenharmony_ci      break;
39013498266Sopenharmony_ci  } while(rv != EOF);
39113498266Sopenharmony_ci}
39213498266Sopenharmony_ci
39313498266Sopenharmony_ci/* Create a named pipe and tell libevent to monitor it */
39413498266Sopenharmony_cistatic const char *fifo = "hiper.fifo";
39513498266Sopenharmony_cistatic int init_fifo(GlobalInfo *g)
39613498266Sopenharmony_ci{
39713498266Sopenharmony_ci  struct stat st;
39813498266Sopenharmony_ci  curl_socket_t sockfd;
39913498266Sopenharmony_ci
40013498266Sopenharmony_ci  fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo);
40113498266Sopenharmony_ci  if(lstat (fifo, &st) == 0) {
40213498266Sopenharmony_ci    if((st.st_mode & S_IFMT) == S_IFREG) {
40313498266Sopenharmony_ci      errno = EEXIST;
40413498266Sopenharmony_ci      perror("lstat");
40513498266Sopenharmony_ci      exit(1);
40613498266Sopenharmony_ci    }
40713498266Sopenharmony_ci  }
40813498266Sopenharmony_ci  unlink(fifo);
40913498266Sopenharmony_ci  if(mkfifo (fifo, 0600) == -1) {
41013498266Sopenharmony_ci    perror("mkfifo");
41113498266Sopenharmony_ci    exit(1);
41213498266Sopenharmony_ci  }
41313498266Sopenharmony_ci  sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0);
41413498266Sopenharmony_ci  if(sockfd == -1) {
41513498266Sopenharmony_ci    perror("open");
41613498266Sopenharmony_ci    exit(1);
41713498266Sopenharmony_ci  }
41813498266Sopenharmony_ci  g->input = fdopen(sockfd, "r");
41913498266Sopenharmony_ci
42013498266Sopenharmony_ci  fprintf(MSG_OUT, "Now, pipe some URL's into > %s\n", fifo);
42113498266Sopenharmony_ci  event_assign(&g->fifo_event, g->evbase, sockfd, EV_READ|EV_PERSIST,
42213498266Sopenharmony_ci               fifo_cb, g);
42313498266Sopenharmony_ci  event_add(&g->fifo_event, NULL);
42413498266Sopenharmony_ci  return (0);
42513498266Sopenharmony_ci}
42613498266Sopenharmony_ci
42713498266Sopenharmony_cistatic void clean_fifo(GlobalInfo *g)
42813498266Sopenharmony_ci{
42913498266Sopenharmony_ci    event_del(&g->fifo_event);
43013498266Sopenharmony_ci    fclose(g->input);
43113498266Sopenharmony_ci    unlink(fifo);
43213498266Sopenharmony_ci}
43313498266Sopenharmony_ci
43413498266Sopenharmony_ciint main(int argc, char **argv)
43513498266Sopenharmony_ci{
43613498266Sopenharmony_ci  GlobalInfo g;
43713498266Sopenharmony_ci  (void)argc;
43813498266Sopenharmony_ci  (void)argv;
43913498266Sopenharmony_ci
44013498266Sopenharmony_ci  memset(&g, 0, sizeof(GlobalInfo));
44113498266Sopenharmony_ci  g.evbase = event_base_new();
44213498266Sopenharmony_ci  init_fifo(&g);
44313498266Sopenharmony_ci  g.multi = curl_multi_init();
44413498266Sopenharmony_ci  evtimer_assign(&g.timer_event, g.evbase, timer_cb, &g);
44513498266Sopenharmony_ci
44613498266Sopenharmony_ci  /* setup the generic multi interface options we want */
44713498266Sopenharmony_ci  curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
44813498266Sopenharmony_ci  curl_multi_setopt(g.multi, CURLMOPT_SOCKETDATA, &g);
44913498266Sopenharmony_ci  curl_multi_setopt(g.multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
45013498266Sopenharmony_ci  curl_multi_setopt(g.multi, CURLMOPT_TIMERDATA, &g);
45113498266Sopenharmony_ci
45213498266Sopenharmony_ci  /* we do not call any curl_multi_socket*() function yet as we have no handles
45313498266Sopenharmony_ci     added! */
45413498266Sopenharmony_ci
45513498266Sopenharmony_ci  event_base_dispatch(g.evbase);
45613498266Sopenharmony_ci
45713498266Sopenharmony_ci  /* this, of course, will not get called since only way to stop this program
45813498266Sopenharmony_ci     is via ctrl-C, but it is here to show how cleanup /would/ be done. */
45913498266Sopenharmony_ci  clean_fifo(&g);
46013498266Sopenharmony_ci  event_del(&g.timer_event);
46113498266Sopenharmony_ci  event_base_free(g.evbase);
46213498266Sopenharmony_ci  curl_multi_cleanup(g.multi);
46313498266Sopenharmony_ci  return 0;
46413498266Sopenharmony_ci}
465