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 together with with glib2
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 * Written by Jeff Pohlmeyer
3213498266Sopenharmony_ci
3313498266Sopenharmony_ci Requires glib-2.x and a (POSIX?) system that has mkfifo().
3413498266Sopenharmony_ci
3513498266Sopenharmony_ci This is an adaptation of libcurl's "hipev.c" and libevent's "event-test.c"
3613498266Sopenharmony_ci sample programs, adapted to use glib's g_io_channel in place of libevent.
3713498266Sopenharmony_ci
3813498266Sopenharmony_ci When running, the program creates the named pipe "hiper.fifo"
3913498266Sopenharmony_ci
4013498266Sopenharmony_ci Whenever there is input into the fifo, the program reads the input as a list
4113498266Sopenharmony_ci of URL's and creates some new easy handles to fetch each URL via the
4213498266Sopenharmony_ci curl_multi "hiper" API.
4313498266Sopenharmony_ci
4413498266Sopenharmony_ci
4513498266Sopenharmony_ci Thus, you can try a single URL:
4613498266Sopenharmony_ci % echo http://www.yahoo.com > hiper.fifo
4713498266Sopenharmony_ci
4813498266Sopenharmony_ci Or a whole bunch of them:
4913498266Sopenharmony_ci % cat my-url-list > hiper.fifo
5013498266Sopenharmony_ci
5113498266Sopenharmony_ci The fifo buffer is handled almost instantly, so you can even add more URL's
5213498266Sopenharmony_ci while the previous requests are still being downloaded.
5313498266Sopenharmony_ci
5413498266Sopenharmony_ci This is purely a demo app, all retrieved data is simply discarded by the write
5513498266Sopenharmony_ci callback.
5613498266Sopenharmony_ci
5713498266Sopenharmony_ci*/
5813498266Sopenharmony_ci
5913498266Sopenharmony_ci#include <glib.h>
6013498266Sopenharmony_ci#include <sys/stat.h>
6113498266Sopenharmony_ci#include <unistd.h>
6213498266Sopenharmony_ci#include <fcntl.h>
6313498266Sopenharmony_ci#include <stdlib.h>
6413498266Sopenharmony_ci#include <stdio.h>
6513498266Sopenharmony_ci#include <errno.h>
6613498266Sopenharmony_ci#include <curl/curl.h>
6713498266Sopenharmony_ci
6813498266Sopenharmony_ci#define MSG_OUT g_print   /* Change to "g_error" to write to stderr */
6913498266Sopenharmony_ci#define SHOW_VERBOSE 0    /* Set to non-zero for libcurl messages */
7013498266Sopenharmony_ci#define SHOW_PROGRESS 0   /* Set to non-zero to enable progress callback */
7113498266Sopenharmony_ci
7213498266Sopenharmony_ci/* Global information, common to all connections */
7313498266Sopenharmony_citypedef struct _GlobalInfo {
7413498266Sopenharmony_ci  CURLM *multi;
7513498266Sopenharmony_ci  guint timer_event;
7613498266Sopenharmony_ci  int still_running;
7713498266Sopenharmony_ci} GlobalInfo;
7813498266Sopenharmony_ci
7913498266Sopenharmony_ci/* Information associated with a specific easy handle */
8013498266Sopenharmony_citypedef struct _ConnInfo {
8113498266Sopenharmony_ci  CURL *easy;
8213498266Sopenharmony_ci  char *url;
8313498266Sopenharmony_ci  GlobalInfo *global;
8413498266Sopenharmony_ci  char error[CURL_ERROR_SIZE];
8513498266Sopenharmony_ci} ConnInfo;
8613498266Sopenharmony_ci
8713498266Sopenharmony_ci/* Information associated with a specific socket */
8813498266Sopenharmony_citypedef struct _SockInfo {
8913498266Sopenharmony_ci  curl_socket_t sockfd;
9013498266Sopenharmony_ci  CURL *easy;
9113498266Sopenharmony_ci  int action;
9213498266Sopenharmony_ci  long timeout;
9313498266Sopenharmony_ci  GIOChannel *ch;
9413498266Sopenharmony_ci  guint ev;
9513498266Sopenharmony_ci  GlobalInfo *global;
9613498266Sopenharmony_ci} SockInfo;
9713498266Sopenharmony_ci
9813498266Sopenharmony_ci/* Die if we get a bad CURLMcode somewhere */
9913498266Sopenharmony_cistatic void mcode_or_die(const char *where, CURLMcode code)
10013498266Sopenharmony_ci{
10113498266Sopenharmony_ci  if(CURLM_OK != code) {
10213498266Sopenharmony_ci    const char *s;
10313498266Sopenharmony_ci    switch(code) {
10413498266Sopenharmony_ci    case     CURLM_BAD_HANDLE:         s = "CURLM_BAD_HANDLE";         break;
10513498266Sopenharmony_ci    case     CURLM_BAD_EASY_HANDLE:    s = "CURLM_BAD_EASY_HANDLE";    break;
10613498266Sopenharmony_ci    case     CURLM_OUT_OF_MEMORY:      s = "CURLM_OUT_OF_MEMORY";      break;
10713498266Sopenharmony_ci    case     CURLM_INTERNAL_ERROR:     s = "CURLM_INTERNAL_ERROR";     break;
10813498266Sopenharmony_ci    case     CURLM_BAD_SOCKET:         s = "CURLM_BAD_SOCKET";         break;
10913498266Sopenharmony_ci    case     CURLM_UNKNOWN_OPTION:     s = "CURLM_UNKNOWN_OPTION";     break;
11013498266Sopenharmony_ci    case     CURLM_LAST:               s = "CURLM_LAST";               break;
11113498266Sopenharmony_ci    default: s = "CURLM_unknown";
11213498266Sopenharmony_ci    }
11313498266Sopenharmony_ci    MSG_OUT("ERROR: %s returns %s\n", where, s);
11413498266Sopenharmony_ci    exit(code);
11513498266Sopenharmony_ci  }
11613498266Sopenharmony_ci}
11713498266Sopenharmony_ci
11813498266Sopenharmony_ci/* Check for completed transfers, and remove their easy handles */
11913498266Sopenharmony_cistatic void check_multi_info(GlobalInfo *g)
12013498266Sopenharmony_ci{
12113498266Sopenharmony_ci  char *eff_url;
12213498266Sopenharmony_ci  CURLMsg *msg;
12313498266Sopenharmony_ci  int msgs_left;
12413498266Sopenharmony_ci  ConnInfo *conn;
12513498266Sopenharmony_ci  CURL *easy;
12613498266Sopenharmony_ci  CURLcode res;
12713498266Sopenharmony_ci
12813498266Sopenharmony_ci  MSG_OUT("REMAINING: %d\n", g->still_running);
12913498266Sopenharmony_ci  while((msg = curl_multi_info_read(g->multi, &msgs_left))) {
13013498266Sopenharmony_ci    if(msg->msg == CURLMSG_DONE) {
13113498266Sopenharmony_ci      easy = msg->easy_handle;
13213498266Sopenharmony_ci      res = msg->data.result;
13313498266Sopenharmony_ci      curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn);
13413498266Sopenharmony_ci      curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url);
13513498266Sopenharmony_ci      MSG_OUT("DONE: %s => (%d) %s\n", eff_url, res, conn->error);
13613498266Sopenharmony_ci      curl_multi_remove_handle(g->multi, easy);
13713498266Sopenharmony_ci      free(conn->url);
13813498266Sopenharmony_ci      curl_easy_cleanup(easy);
13913498266Sopenharmony_ci      free(conn);
14013498266Sopenharmony_ci    }
14113498266Sopenharmony_ci  }
14213498266Sopenharmony_ci}
14313498266Sopenharmony_ci
14413498266Sopenharmony_ci/* Called by glib when our timeout expires */
14513498266Sopenharmony_cistatic gboolean timer_cb(gpointer data)
14613498266Sopenharmony_ci{
14713498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo *)data;
14813498266Sopenharmony_ci  CURLMcode rc;
14913498266Sopenharmony_ci
15013498266Sopenharmony_ci  rc = curl_multi_socket_action(g->multi,
15113498266Sopenharmony_ci                                CURL_SOCKET_TIMEOUT, 0, &g->still_running);
15213498266Sopenharmony_ci  mcode_or_die("timer_cb: curl_multi_socket_action", rc);
15313498266Sopenharmony_ci  check_multi_info(g);
15413498266Sopenharmony_ci  return FALSE;
15513498266Sopenharmony_ci}
15613498266Sopenharmony_ci
15713498266Sopenharmony_ci/* Update the event timer after curl_multi library calls */
15813498266Sopenharmony_cistatic int update_timeout_cb(CURLM *multi, long timeout_ms, void *userp)
15913498266Sopenharmony_ci{
16013498266Sopenharmony_ci  struct timeval timeout;
16113498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo *)userp;
16213498266Sopenharmony_ci  timeout.tv_sec = timeout_ms/1000;
16313498266Sopenharmony_ci  timeout.tv_usec = (timeout_ms%1000)*1000;
16413498266Sopenharmony_ci
16513498266Sopenharmony_ci  MSG_OUT("*** update_timeout_cb %ld => %ld:%ld ***\n",
16613498266Sopenharmony_ci          timeout_ms, timeout.tv_sec, timeout.tv_usec);
16713498266Sopenharmony_ci
16813498266Sopenharmony_ci  /*
16913498266Sopenharmony_ci   * if timeout_ms is -1, just delete the timer
17013498266Sopenharmony_ci   *
17113498266Sopenharmony_ci   * For other values of timeout_ms, this should set or *update* the timer to
17213498266Sopenharmony_ci   * the new value
17313498266Sopenharmony_ci   */
17413498266Sopenharmony_ci  if(timeout_ms >= 0)
17513498266Sopenharmony_ci    g->timer_event = g_timeout_add(timeout_ms, timer_cb, g);
17613498266Sopenharmony_ci  return 0;
17713498266Sopenharmony_ci}
17813498266Sopenharmony_ci
17913498266Sopenharmony_ci/* Called by glib when we get action on a multi socket */
18013498266Sopenharmony_cistatic gboolean event_cb(GIOChannel *ch, GIOCondition condition, gpointer data)
18113498266Sopenharmony_ci{
18213498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo*) data;
18313498266Sopenharmony_ci  CURLMcode rc;
18413498266Sopenharmony_ci  int fd = g_io_channel_unix_get_fd(ch);
18513498266Sopenharmony_ci
18613498266Sopenharmony_ci  int action =
18713498266Sopenharmony_ci    ((condition & G_IO_IN) ? CURL_CSELECT_IN : 0) |
18813498266Sopenharmony_ci    ((condition & G_IO_OUT) ? CURL_CSELECT_OUT : 0);
18913498266Sopenharmony_ci
19013498266Sopenharmony_ci  rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running);
19113498266Sopenharmony_ci  mcode_or_die("event_cb: curl_multi_socket_action", rc);
19213498266Sopenharmony_ci
19313498266Sopenharmony_ci  check_multi_info(g);
19413498266Sopenharmony_ci  if(g->still_running) {
19513498266Sopenharmony_ci    return TRUE;
19613498266Sopenharmony_ci  }
19713498266Sopenharmony_ci  else {
19813498266Sopenharmony_ci    MSG_OUT("last transfer done, kill timeout\n");
19913498266Sopenharmony_ci    if(g->timer_event) {
20013498266Sopenharmony_ci      g_source_remove(g->timer_event);
20113498266Sopenharmony_ci    }
20213498266Sopenharmony_ci    return FALSE;
20313498266Sopenharmony_ci  }
20413498266Sopenharmony_ci}
20513498266Sopenharmony_ci
20613498266Sopenharmony_ci/* Clean up the SockInfo structure */
20713498266Sopenharmony_cistatic void remsock(SockInfo *f)
20813498266Sopenharmony_ci{
20913498266Sopenharmony_ci  if(!f) {
21013498266Sopenharmony_ci    return;
21113498266Sopenharmony_ci  }
21213498266Sopenharmony_ci  if(f->ev) {
21313498266Sopenharmony_ci    g_source_remove(f->ev);
21413498266Sopenharmony_ci  }
21513498266Sopenharmony_ci  g_free(f);
21613498266Sopenharmony_ci}
21713498266Sopenharmony_ci
21813498266Sopenharmony_ci/* Assign information to a SockInfo structure */
21913498266Sopenharmony_cistatic void setsock(SockInfo *f, curl_socket_t s, CURL *e, int act,
22013498266Sopenharmony_ci                    GlobalInfo *g)
22113498266Sopenharmony_ci{
22213498266Sopenharmony_ci  GIOCondition kind =
22313498266Sopenharmony_ci    ((act & CURL_POLL_IN) ? G_IO_IN : 0) |
22413498266Sopenharmony_ci    ((act & CURL_POLL_OUT) ? G_IO_OUT : 0);
22513498266Sopenharmony_ci
22613498266Sopenharmony_ci  f->sockfd = s;
22713498266Sopenharmony_ci  f->action = act;
22813498266Sopenharmony_ci  f->easy = e;
22913498266Sopenharmony_ci  if(f->ev) {
23013498266Sopenharmony_ci    g_source_remove(f->ev);
23113498266Sopenharmony_ci  }
23213498266Sopenharmony_ci  f->ev = g_io_add_watch(f->ch, kind, event_cb, g);
23313498266Sopenharmony_ci}
23413498266Sopenharmony_ci
23513498266Sopenharmony_ci/* Initialize a new SockInfo structure */
23613498266Sopenharmony_cistatic void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g)
23713498266Sopenharmony_ci{
23813498266Sopenharmony_ci  SockInfo *fdp = g_malloc0(sizeof(SockInfo));
23913498266Sopenharmony_ci
24013498266Sopenharmony_ci  fdp->global = g;
24113498266Sopenharmony_ci  fdp->ch = g_io_channel_unix_new(s);
24213498266Sopenharmony_ci  setsock(fdp, s, easy, action, g);
24313498266Sopenharmony_ci  curl_multi_assign(g->multi, s, fdp);
24413498266Sopenharmony_ci}
24513498266Sopenharmony_ci
24613498266Sopenharmony_ci/* CURLMOPT_SOCKETFUNCTION */
24713498266Sopenharmony_cistatic int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
24813498266Sopenharmony_ci{
24913498266Sopenharmony_ci  GlobalInfo *g = (GlobalInfo*) cbp;
25013498266Sopenharmony_ci  SockInfo *fdp = (SockInfo*) sockp;
25113498266Sopenharmony_ci  static const char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE" };
25213498266Sopenharmony_ci
25313498266Sopenharmony_ci  MSG_OUT("socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]);
25413498266Sopenharmony_ci  if(what == CURL_POLL_REMOVE) {
25513498266Sopenharmony_ci    MSG_OUT("\n");
25613498266Sopenharmony_ci    remsock(fdp);
25713498266Sopenharmony_ci  }
25813498266Sopenharmony_ci  else {
25913498266Sopenharmony_ci    if(!fdp) {
26013498266Sopenharmony_ci      MSG_OUT("Adding data: %s%s\n",
26113498266Sopenharmony_ci              (what & CURL_POLL_IN) ? "READ" : "",
26213498266Sopenharmony_ci              (what & CURL_POLL_OUT) ? "WRITE" : "");
26313498266Sopenharmony_ci      addsock(s, e, what, g);
26413498266Sopenharmony_ci    }
26513498266Sopenharmony_ci    else {
26613498266Sopenharmony_ci      MSG_OUT(
26713498266Sopenharmony_ci        "Changing action from %d to %d\n", fdp->action, what);
26813498266Sopenharmony_ci      setsock(fdp, s, e, what, g);
26913498266Sopenharmony_ci    }
27013498266Sopenharmony_ci  }
27113498266Sopenharmony_ci  return 0;
27213498266Sopenharmony_ci}
27313498266Sopenharmony_ci
27413498266Sopenharmony_ci/* CURLOPT_WRITEFUNCTION */
27513498266Sopenharmony_cistatic size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
27613498266Sopenharmony_ci{
27713498266Sopenharmony_ci  size_t realsize = size * nmemb;
27813498266Sopenharmony_ci  ConnInfo *conn = (ConnInfo*) data;
27913498266Sopenharmony_ci  (void)ptr;
28013498266Sopenharmony_ci  (void)conn;
28113498266Sopenharmony_ci  return realsize;
28213498266Sopenharmony_ci}
28313498266Sopenharmony_ci
28413498266Sopenharmony_ci/* CURLOPT_PROGRESSFUNCTION */
28513498266Sopenharmony_cistatic int prog_cb(void *p, double dltotal, double dlnow, double ult,
28613498266Sopenharmony_ci                   double uln)
28713498266Sopenharmony_ci{
28813498266Sopenharmony_ci  ConnInfo *conn = (ConnInfo *)p;
28913498266Sopenharmony_ci  MSG_OUT("Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal);
29013498266Sopenharmony_ci  return 0;
29113498266Sopenharmony_ci}
29213498266Sopenharmony_ci
29313498266Sopenharmony_ci/* Create a new easy handle, and add it to the global curl_multi */
29413498266Sopenharmony_cistatic void new_conn(char *url, GlobalInfo *g)
29513498266Sopenharmony_ci{
29613498266Sopenharmony_ci  ConnInfo *conn;
29713498266Sopenharmony_ci  CURLMcode rc;
29813498266Sopenharmony_ci
29913498266Sopenharmony_ci  conn = g_malloc0(sizeof(ConnInfo));
30013498266Sopenharmony_ci  conn->error[0]='\0';
30113498266Sopenharmony_ci  conn->easy = curl_easy_init();
30213498266Sopenharmony_ci  if(!conn->easy) {
30313498266Sopenharmony_ci    MSG_OUT("curl_easy_init() failed, exiting!\n");
30413498266Sopenharmony_ci    exit(2);
30513498266Sopenharmony_ci  }
30613498266Sopenharmony_ci  conn->global = g;
30713498266Sopenharmony_ci  conn->url = g_strdup(url);
30813498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url);
30913498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb);
31013498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, &conn);
31113498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, (long)SHOW_VERBOSE);
31213498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error);
31313498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn);
31413498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, SHOW_PROGRESS?0L:1L);
31513498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb);
31613498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn);
31713498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L);
31813498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_CONNECTTIMEOUT, 30L);
31913498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_LIMIT, 1L);
32013498266Sopenharmony_ci  curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_TIME, 30L);
32113498266Sopenharmony_ci
32213498266Sopenharmony_ci  MSG_OUT("Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url);
32313498266Sopenharmony_ci  rc = curl_multi_add_handle(g->multi, conn->easy);
32413498266Sopenharmony_ci  mcode_or_die("new_conn: curl_multi_add_handle", rc);
32513498266Sopenharmony_ci
32613498266Sopenharmony_ci  /* note that the add_handle() will set a time-out to trigger soon so that
32713498266Sopenharmony_ci     the necessary socket_action() call will be called by this app */
32813498266Sopenharmony_ci}
32913498266Sopenharmony_ci
33013498266Sopenharmony_ci/* This gets called by glib whenever data is received from the fifo */
33113498266Sopenharmony_cistatic gboolean fifo_cb(GIOChannel *ch, GIOCondition condition, gpointer data)
33213498266Sopenharmony_ci{
33313498266Sopenharmony_ci#define BUF_SIZE 1024
33413498266Sopenharmony_ci  gsize len, tp;
33513498266Sopenharmony_ci  gchar *buf, *tmp, *all = NULL;
33613498266Sopenharmony_ci  GIOStatus rv;
33713498266Sopenharmony_ci
33813498266Sopenharmony_ci  do {
33913498266Sopenharmony_ci    GError *err = NULL;
34013498266Sopenharmony_ci    rv = g_io_channel_read_line(ch, &buf, &len, &tp, &err);
34113498266Sopenharmony_ci    if(buf) {
34213498266Sopenharmony_ci      if(tp) {
34313498266Sopenharmony_ci        buf[tp]='\0';
34413498266Sopenharmony_ci      }
34513498266Sopenharmony_ci      new_conn(buf, (GlobalInfo*)data);
34613498266Sopenharmony_ci      g_free(buf);
34713498266Sopenharmony_ci    }
34813498266Sopenharmony_ci    else {
34913498266Sopenharmony_ci      buf = g_malloc(BUF_SIZE + 1);
35013498266Sopenharmony_ci      while(TRUE) {
35113498266Sopenharmony_ci        buf[BUF_SIZE]='\0';
35213498266Sopenharmony_ci        g_io_channel_read_chars(ch, buf, BUF_SIZE, &len, &err);
35313498266Sopenharmony_ci        if(len) {
35413498266Sopenharmony_ci          buf[len]='\0';
35513498266Sopenharmony_ci          if(all) {
35613498266Sopenharmony_ci            tmp = all;
35713498266Sopenharmony_ci            all = g_strdup_printf("%s%s", tmp, buf);
35813498266Sopenharmony_ci            g_free(tmp);
35913498266Sopenharmony_ci          }
36013498266Sopenharmony_ci          else {
36113498266Sopenharmony_ci            all = g_strdup(buf);
36213498266Sopenharmony_ci          }
36313498266Sopenharmony_ci        }
36413498266Sopenharmony_ci        else {
36513498266Sopenharmony_ci          break;
36613498266Sopenharmony_ci        }
36713498266Sopenharmony_ci      }
36813498266Sopenharmony_ci      if(all) {
36913498266Sopenharmony_ci        new_conn(all, (GlobalInfo*)data);
37013498266Sopenharmony_ci        g_free(all);
37113498266Sopenharmony_ci      }
37213498266Sopenharmony_ci      g_free(buf);
37313498266Sopenharmony_ci    }
37413498266Sopenharmony_ci    if(err) {
37513498266Sopenharmony_ci      g_error("fifo_cb: %s", err->message);
37613498266Sopenharmony_ci      g_free(err);
37713498266Sopenharmony_ci      break;
37813498266Sopenharmony_ci    }
37913498266Sopenharmony_ci  } while((len) && (rv == G_IO_STATUS_NORMAL));
38013498266Sopenharmony_ci  return TRUE;
38113498266Sopenharmony_ci}
38213498266Sopenharmony_ci
38313498266Sopenharmony_ciint init_fifo(void)
38413498266Sopenharmony_ci{
38513498266Sopenharmony_ci  struct stat st;
38613498266Sopenharmony_ci  const char *fifo = "hiper.fifo";
38713498266Sopenharmony_ci  int socket;
38813498266Sopenharmony_ci
38913498266Sopenharmony_ci  if(lstat (fifo, &st) == 0) {
39013498266Sopenharmony_ci    if((st.st_mode & S_IFMT) == S_IFREG) {
39113498266Sopenharmony_ci      errno = EEXIST;
39213498266Sopenharmony_ci      perror("lstat");
39313498266Sopenharmony_ci      exit(1);
39413498266Sopenharmony_ci    }
39513498266Sopenharmony_ci  }
39613498266Sopenharmony_ci
39713498266Sopenharmony_ci  unlink(fifo);
39813498266Sopenharmony_ci  if(mkfifo (fifo, 0600) == -1) {
39913498266Sopenharmony_ci    perror("mkfifo");
40013498266Sopenharmony_ci    exit(1);
40113498266Sopenharmony_ci  }
40213498266Sopenharmony_ci
40313498266Sopenharmony_ci  socket = open(fifo, O_RDWR | O_NONBLOCK, 0);
40413498266Sopenharmony_ci
40513498266Sopenharmony_ci  if(socket == -1) {
40613498266Sopenharmony_ci    perror("open");
40713498266Sopenharmony_ci    exit(1);
40813498266Sopenharmony_ci  }
40913498266Sopenharmony_ci  MSG_OUT("Now, pipe some URL's into > %s\n", fifo);
41013498266Sopenharmony_ci
41113498266Sopenharmony_ci  return socket;
41213498266Sopenharmony_ci}
41313498266Sopenharmony_ci
41413498266Sopenharmony_ciint main(int argc, char **argv)
41513498266Sopenharmony_ci{
41613498266Sopenharmony_ci  GlobalInfo *g;
41713498266Sopenharmony_ci  GMainLoop*gmain;
41813498266Sopenharmony_ci  int fd;
41913498266Sopenharmony_ci  GIOChannel* ch;
42013498266Sopenharmony_ci  g = g_malloc0(sizeof(GlobalInfo));
42113498266Sopenharmony_ci
42213498266Sopenharmony_ci  fd = init_fifo();
42313498266Sopenharmony_ci  ch = g_io_channel_unix_new(fd);
42413498266Sopenharmony_ci  g_io_add_watch(ch, G_IO_IN, fifo_cb, g);
42513498266Sopenharmony_ci  gmain = g_main_loop_new(NULL, FALSE);
42613498266Sopenharmony_ci  g->multi = curl_multi_init();
42713498266Sopenharmony_ci  curl_multi_setopt(g->multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
42813498266Sopenharmony_ci  curl_multi_setopt(g->multi, CURLMOPT_SOCKETDATA, g);
42913498266Sopenharmony_ci  curl_multi_setopt(g->multi, CURLMOPT_TIMERFUNCTION, update_timeout_cb);
43013498266Sopenharmony_ci  curl_multi_setopt(g->multi, CURLMOPT_TIMERDATA, g);
43113498266Sopenharmony_ci
43213498266Sopenharmony_ci  /* we do not call any curl_multi_socket*() function yet as we have no handles
43313498266Sopenharmony_ci     added! */
43413498266Sopenharmony_ci
43513498266Sopenharmony_ci  g_main_loop_run(gmain);
43613498266Sopenharmony_ci  curl_multi_cleanup(g->multi);
43713498266Sopenharmony_ci  return 0;
43813498266Sopenharmony_ci}
439