Revert "Update to 7.44.0"
[platform/upstream/curl.git] / docs / examples / hiperfifo.c
index e8d7671..84035aa 100644 (file)
@@ -1,18 +1,30 @@
-/*****************************************************************************
+/***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
  *                             / __| | | | |_) | |
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * $Id$
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
- * Example application source code using the multi socket interface to
- * download many files at once.
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
  *
- * Written by Jeff Pohlmeyer
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+/* Example application source code using the multi socket interface to
+   download many files at once.
+
+Written by Jeff Pohlmeyer
 
-Requires libevent and a (POSIX?) system that has mkfifo().
+Requires libevent version 2 and a (POSIX?) system that has mkfifo().
 
 This is an adaptation of libcurl's "hipev.c" and libevent's "event-test.c"
 sample programs.
@@ -49,7 +61,7 @@ callback.
 #include <unistd.h>
 #include <sys/poll.h>
 #include <curl/curl.h>
-#include <event.h>
+#include <event2/event.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <errno.h>
@@ -59,18 +71,20 @@ callback.
 
 
 /* Global information, common to all connections */
-typedef struct _GlobalInfo {
-  struct event fifo_event;
-  struct event timer_event;
+typedef struct _GlobalInfo
+{
+  struct event_base *evbase;
+  struct event *fifo_event;
+  struct event *timer_event;
   CURLM *multi;
-  int prev_running;
   int still_running;
   FILE* input;
 } GlobalInfo;
 
 
 /* Information associated with a specific easy handle */
-typedef struct _ConnInfo {
+typedef struct _ConnInfo
+{
   CURL *easy;
   char *url;
   GlobalInfo *global;
@@ -79,12 +93,13 @@ typedef struct _ConnInfo {
 
 
 /* Information associated with a specific socket */
-typedef struct _SockInfo {
+typedef struct _SockInfo
+{
   curl_socket_t sockfd;
   CURL *easy;
   int action;
   long timeout;
-  struct event ev;
+  struct event *ev;
   int evset;
   GlobalInfo *global;
 } SockInfo;
@@ -95,31 +110,33 @@ typedef struct _SockInfo {
 static int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g)
 {
   struct timeval timeout;
+  (void)multi; /* unused */
 
   timeout.tv_sec = timeout_ms/1000;
   timeout.tv_usec = (timeout_ms%1000)*1000;
   fprintf(MSG_OUT, "multi_timer_cb: Setting timeout to %ld ms\n", timeout_ms);
-  evtimer_add(&g->timer_event, &timeout);
+  evtimer_add(g->timer_event, &timeout);
   return 0;
 }
 
-
-
 /* Die if we get a bad CURLMcode somewhere */
-void mcode_or_die(char *where, CURLMcode code) {
+static void mcode_or_die(const char *where, CURLMcode code)
+{
   if ( CURLM_OK != code ) {
-    char *s;
+    const char *s;
     switch (code) {
-      case     CURLM_CALL_MULTI_PERFORM: s="CURLM_CALL_MULTI_PERFORM"; break;
-      case     CURLM_OK:                 s="CURLM_OK";                 break;
       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_BAD_SOCKET:         s="CURLM_BAD_SOCKET";         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);
@@ -129,44 +146,29 @@ void mcode_or_die(char *where, CURLMcode code) {
 
 
 /* Check for completed transfers, and remove their easy handles */
-static void check_run_count(GlobalInfo *g)
+static void check_multi_info(GlobalInfo *g)
 {
-  if (g->prev_running > g->still_running) {
-    char *eff_url=NULL;
-    CURLMsg *msg;
-    int msgs_left;
-    ConnInfo *conn=NULL;
-    CURL*easy;
-    CURLcode res;
-
-    fprintf(MSG_OUT, "REMAINING: %d\n", g->still_running);
-    /*
-      I am still uncertain whether it is safe to remove an easy handle
-      from inside the curl_multi_info_read loop, so here I will search
-      for completed transfers in the inner "while" loop, and then remove
-      them in the outer "do-while" loop...
-   */
-    do {
-      easy=NULL;
-      while ((msg = curl_multi_info_read(g->multi, &msgs_left))) {
-        if (msg->msg == CURLMSG_DONE) {
-          easy=msg->easy_handle;
-          res=msg->data.result;
-          break;
-        }
-      }
-      if (easy) {
-          curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn);
-          curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url);
-          fprintf(MSG_OUT, "DONE: %s => (%d) %s\n", eff_url, res, conn->error);
-          curl_multi_remove_handle(g->multi, easy);
-          free(conn->url);
-          curl_easy_cleanup(easy);
-          free(conn);
-      }
-    } while ( easy );
+  char *eff_url;
+  CURLMsg *msg;
+  int msgs_left;
+  ConnInfo *conn;
+  CURL *easy;
+  CURLcode res;
+
+  fprintf(MSG_OUT, "REMAINING: %d\n", g->still_running);
+  while ((msg = curl_multi_info_read(g->multi, &msgs_left))) {
+    if (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, "DONE: %s => (%d) %s\n", eff_url, res, conn->error);
+      curl_multi_remove_handle(g->multi, easy);
+      free(conn->url);
+      curl_easy_cleanup(easy);
+      free(conn);
+    }
   }
-  g->prev_running = g->still_running;
 }
 
 
@@ -177,15 +179,18 @@ static void event_cb(int fd, short kind, void *userp)
   GlobalInfo *g = (GlobalInfo*) userp;
   CURLMcode rc;
 
-  do {
-    rc = curl_multi_socket(g->multi, fd, &g->still_running);
-  } while (rc == CURLM_CALL_MULTI_PERFORM);
-  mcode_or_die("event_cb: curl_multi_socket", rc);
-  check_run_count(g);
+  int action =
+    (kind & EV_READ ? CURL_CSELECT_IN : 0) |
+    (kind & EV_WRITE ? CURL_CSELECT_OUT : 0);
+
+  rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running);
+  mcode_or_die("event_cb: curl_multi_socket_action", rc);
+
+  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);
     }
   }
 }
@@ -195,16 +200,15 @@ 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)
 {
-  (void)fd;
-  (void)kind;
   GlobalInfo *g = (GlobalInfo *)userp;
   CURLMcode rc;
+  (void)fd;
+  (void)kind;
 
-  do {
-    rc = curl_multi_socket(g->multi, CURL_SOCKET_TIMEOUT, &g->still_running);
-  } while (rc == CURLM_CALL_MULTI_PERFORM);
-  mcode_or_die("timer_cb: curl_multi_socket", rc);
-  check_run_count(g);
+  rc = curl_multi_socket_action(g->multi,
+                                  CURL_SOCKET_TIMEOUT, 0, &g->still_running);
+  mcode_or_die("timer_cb: curl_multi_socket_action", rc);
+  check_multi_info(g);
 }
 
 
@@ -212,9 +216,11 @@ static void timer_cb(int fd, short kind, void *userp)
 /* Clean up the SockInfo structure */
 static void remsock(SockInfo *f)
 {
-  if (!f) { return; }
-  if (f->evset) { event_del(&f->ev); }
-  free(f);
+  if (f) {
+    if (f->evset)
+      event_free(f->ev);
+    free(f);
+  }
 }
 
 
@@ -228,16 +234,18 @@ static void setsock(SockInfo*f, curl_socket_t s, CURL*e, int act, GlobalInfo*g)
   f->sockfd = s;
   f->action = act;
   f->easy = e;
-  if (f->evset) { event_del(&f->ev); }
-  event_set( &f->ev, f->sockfd, kind, event_cb, g);
-  f->evset=1;
-  event_add(&f->ev, NULL);
+  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);
 }
 
 
 
 /* Initialize a new SockInfo structure */
-static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g) {
+static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g)
+{
   SockInfo *fdp = calloc(sizeof(SockInfo), 1);
 
   fdp->global = g;
@@ -245,30 +253,28 @@ static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g) {
   curl_multi_assign(g->multi, s, fdp);
 }
 
-
-
 /* CURLMOPT_SOCKETFUNCTION */
 static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
 {
   GlobalInfo *g = (GlobalInfo*) cbp;
   SockInfo *fdp = (SockInfo*) sockp;
-  char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE" };
+  const char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE" };
 
   fprintf(MSG_OUT,
           "socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]);
   if (what == CURL_POLL_REMOVE) {
     fprintf(MSG_OUT, "\n");
     remsock(fdp);
-  } else {
+  }
+  else {
     if (!fdp) {
-      fprintf(MSG_OUT, "Adding data: %s%s\n",
-             what&CURL_POLL_IN?"READ":"",
-             what&CURL_POLL_OUT?"WRITE":"" );
+      fprintf(MSG_OUT, "Adding data: %s\n", whatstr[what]);
       addsock(s, e, what, g);
     }
     else {
       fprintf(MSG_OUT,
-        "Changing action from %d to %d\n", fdp->action, what);
+              "Changing action from %s to %s\n",
+              whatstr[fdp->action], whatstr[what]);
       setsock(fdp, s, e, what, g);
     }
   }
@@ -289,16 +295,21 @@ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
 
 
 /* CURLOPT_PROGRESSFUNCTION */
-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,
+                    double uln)
 {
   ConnInfo *conn = (ConnInfo *)p;
+  (void)ult;
+  (void)uln;
+
   fprintf(MSG_OUT, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal);
   return 0;
 }
 
 
 /* Create a new easy handle, and add it to the global curl_multi */
-void new_conn(char *url, GlobalInfo *g ) {
+static void new_conn(char *url, GlobalInfo *g )
+{
   ConnInfo *conn;
   CURLMcode rc;
 
@@ -316,31 +327,30 @@ void new_conn(char *url, GlobalInfo *g ) {
   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, 0);
+  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, 0);
+  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);
   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);
+  rc = curl_multi_add_handle(g->multi, conn->easy);
   mcode_or_die("new_conn: curl_multi_add_handle", rc);
-  do {
-    rc = curl_multi_socket_all(g->multi, &g->still_running);
-  } while (CURLM_CALL_MULTI_PERFORM == rc);
-  mcode_or_die("new_conn: curl_multi_socket_all", rc);
-  check_run_count(g);
-}
-
 
+  /* note that the add_handle() will set a time-out to trigger very soon so
+     that the necessary socket_action() call will be called by this app */
+}
 
 /* This gets called whenever data is received from the fifo */
-void fifo_cb(int fd, short event, void *arg) {
+static void fifo_cb(int fd, short event, 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';
@@ -352,13 +362,12 @@ void fifo_cb(int fd, short event, void *arg) {
   } while ( rv != EOF);
 }
 
-
-
 /* Create a named pipe and tell libevent to monitor it */
-int init_fifo (GlobalInfo *g) {
+static const char *fifo = "hiper.fifo";
+static int init_fifo (GlobalInfo *g)
+{
   struct stat st;
-  char *fifo = "hiper.fifo";
-  int socket;
+  curl_socket_t sockfd;
 
   fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo);
   if (lstat (fifo, &st) == 0) {
@@ -373,39 +382,54 @@ int init_fifo (GlobalInfo *g) {
     perror("mkfifo");
     exit (1);
   }
-  socket = open(fifo, O_RDWR | O_NONBLOCK, 0);
-  if (socket == -1) {
-     perror("open");
-     exit (1);
+  sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0);
+  if (sockfd == -1) {
+    perror("open");
+    exit (1);
   }
-  g->input = fdopen(socket, "r");
+  g->input = fdopen(sockfd, "r");
 
   fprintf(MSG_OUT, "Now, pipe some URL's into > %s\n", fifo);
-  event_set(&g->fifo_event, socket, EV_READ | EV_PERSIST, fifo_cb, g);
-  event_add(&g->fifo_event, NULL);
+  g->fifo_event = event_new(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);
+    fclose(g->input);
+    unlink(fifo);
+}
 
 int main(int argc, char **argv)
 {
   GlobalInfo g;
-  CURLMcode rc;
+  (void)argc;
+  (void)argv;
 
   memset(&g, 0, sizeof(GlobalInfo));
-  event_init();
+  g.evbase = event_base_new();
   init_fifo(&g);
   g.multi = curl_multi_init();
-  evtimer_set(&g.timer_event, timer_cb, &g);
+  g.timer_event = evtimer_new(g.evbase, timer_cb, &g);
+
+  /* setup the generic multi interface options we want */
   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);
-  do {
-    rc = curl_multi_socket_all(g.multi, &g.still_running);
-  } while (CURLM_CALL_MULTI_PERFORM == rc);
-  event_dispatch();
+
+  /* we don't call any curl_multi_socket*() function yet as we have no handles
+     added! */
+
+  event_base_dispatch(g.evbase);
+
+  /* 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_base_free(g.evbase);
   curl_multi_cleanup(g.multi);
   return 0;
 }