Guest User

Untitled

a guest
Jun 18th, 2015
655
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.31 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <sys/time.h>
  5. #include <time.h>
  6. #include <unistd.h>
  7. #include <sys/poll.h>
  8. #include <curl/curl.h>
  9. #include <event2/event.h>
  10. #include <fcntl.h>
  11. #include <sys/stat.h>
  12. #include <errno.h>
  13.  
  14.  
  15. #define MSG_OUT stdout /* Send info to stdout, change to stderr if you want */
  16.  
  17.  
  18. /* Global information, common to all connections */
  19. typedef struct _GlobalInfo
  20. {
  21.   struct event_base *evbase;
  22.   struct event *fifo_event;
  23.   struct event *timer_event;
  24.   CURLM *multi;
  25.   int still_running;
  26.   FILE* input;
  27. } GlobalInfo;
  28.  
  29.  
  30. /* Information associated with a specific easy handle */
  31. typedef struct _ConnInfo
  32. {
  33.   CURL *easy;
  34.   char *url;
  35.   GlobalInfo *global;
  36.   char error[CURL_ERROR_SIZE];
  37. } ConnInfo;
  38.  
  39.  
  40. /* Information associated with a specific socket */
  41. typedef struct _SockInfo
  42. {
  43.   curl_socket_t sockfd;
  44.   CURL *easy;
  45.   int action;
  46.   long timeout;
  47.   struct event *ev;
  48.   int evset;
  49.   GlobalInfo *global;
  50. } SockInfo;
  51.  
  52.  
  53.  
  54. /* Update the event timer after curl_multi library calls */
  55. static int multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g)
  56. {
  57.   struct timeval timeout;
  58.   (void)multi; /* unused */
  59.  
  60.   timeout.tv_sec = timeout_ms/1000;
  61.   timeout.tv_usec = (timeout_ms%1000)*1000;
  62.   fprintf(MSG_OUT, "multi_timer_cb: Setting timeout to %ld ms\n", timeout_ms);
  63.   evtimer_add(g->timer_event, &timeout);
  64.   return 0;
  65. }
  66.  
  67. /* Die if we get a bad CURLMcode somewhere */
  68. static void mcode_or_die(const char *where, CURLMcode code)
  69. {
  70.   if ( CURLM_OK != code ) {
  71.     const char *s;
  72.     switch (code) {
  73.       case     CURLM_BAD_HANDLE:         s="CURLM_BAD_HANDLE";         break;
  74.       case     CURLM_BAD_EASY_HANDLE:    s="CURLM_BAD_EASY_HANDLE";    break;
  75.       case     CURLM_OUT_OF_MEMORY:      s="CURLM_OUT_OF_MEMORY";      break;
  76.       case     CURLM_INTERNAL_ERROR:     s="CURLM_INTERNAL_ERROR";     break;
  77.       case     CURLM_UNKNOWN_OPTION:     s="CURLM_UNKNOWN_OPTION";     break;
  78.       case     CURLM_LAST:               s="CURLM_LAST";               break;
  79.       default: s="CURLM_unknown";
  80.         break;
  81.     case     CURLM_BAD_SOCKET:         s="CURLM_BAD_SOCKET";
  82.       fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s);
  83.       /* ignore this error */
  84.       return;
  85.     }
  86.     fprintf(MSG_OUT, "ERROR: %s returns %s\n", where, s);
  87.     exit(code);
  88.   }
  89. }
  90.  
  91.  
  92.  
  93. /* Check for completed transfers, and remove their easy handles */
  94. static void check_multi_info(GlobalInfo *g)
  95. {
  96.   char *eff_url;
  97.   CURLMsg *msg;
  98.   int msgs_left;
  99.   ConnInfo *conn;
  100.   CURL *easy;
  101.   CURLcode res;
  102.  
  103.   fprintf(MSG_OUT, "REMAINING: %d\n", g->still_running);
  104.   while ((msg = curl_multi_info_read(g->multi, &msgs_left))) {
  105.     if (msg->msg == CURLMSG_DONE) {
  106.       easy = msg->easy_handle;
  107.       res = msg->data.result;
  108.       curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn);
  109.       curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url);
  110.       fprintf(MSG_OUT, "DONE: %s => (%d) %s\n", eff_url, res, conn->error);
  111.       curl_multi_remove_handle(g->multi, easy);
  112.       free(conn->url);
  113.       curl_easy_cleanup(easy);
  114.       free(conn);
  115.     }
  116.   }
  117. }
  118.  
  119.  
  120.  
  121. /* Called by libevent when we get action on a multi socket */
  122. static void event_cb(int fd, short kind, void *userp)
  123. {
  124.   GlobalInfo *g = (GlobalInfo*) userp;
  125.   CURLMcode rc;
  126.  
  127.   int action =
  128.     (kind & EV_READ ? CURL_CSELECT_IN : 0) |
  129.     (kind & EV_WRITE ? CURL_CSELECT_OUT : 0);
  130.  
  131.   rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running);
  132.   mcode_or_die("event_cb: curl_multi_socket_action", rc);
  133.  
  134.   check_multi_info(g);
  135.   if ( g->still_running <= 0 ) {
  136.     fprintf(MSG_OUT, "last transfer done, kill timeout\n");
  137.     if (evtimer_pending(g->timer_event, NULL)) {
  138.       evtimer_del(g->timer_event);
  139.     }
  140.   }
  141. }
  142.  
  143.  
  144.  
  145. /* Called by libevent when our timeout expires */
  146. static void timer_cb(int fd, short kind, void *userp)
  147. {
  148.   GlobalInfo *g = (GlobalInfo *)userp;
  149.   CURLMcode rc;
  150.   (void)fd;
  151.   (void)kind;
  152.  
  153.   rc = curl_multi_socket_action(g->multi,
  154.                                   CURL_SOCKET_TIMEOUT, 0, &g->still_running);
  155.   mcode_or_die("timer_cb: curl_multi_socket_action", rc);
  156.   check_multi_info(g);
  157. }
  158.  
  159.  
  160.  
  161. /* Clean up the SockInfo structure */
  162. static void remsock(SockInfo *f)
  163. {
  164.   if (f) {
  165.     if (f->evset)
  166.       event_free(f->ev);
  167.     free(f);
  168.   }
  169. }
  170.  
  171.  
  172.  
  173. /* Assign information to a SockInfo structure */
  174. static void setsock(SockInfo*f, curl_socket_t s, CURL*e, int act, GlobalInfo*g)
  175. {
  176.   int kind =
  177.      (act&CURL_POLL_IN?EV_READ:0)|(act&CURL_POLL_OUT?EV_WRITE:0)|EV_PERSIST;
  178.  
  179.   f->sockfd = s;
  180.   f->action = act;
  181.   f->easy = e;
  182.   if (f->evset)
  183.     event_free(f->ev);
  184.   f->ev = event_new(g->evbase, f->sockfd, kind, event_cb, g);
  185.   f->evset = 1;
  186.   event_add(f->ev, NULL);
  187. }
  188.  
  189.  
  190.  
  191. /* Initialize a new SockInfo structure */
  192. static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g)
  193. {
  194.   SockInfo *fdp = calloc(sizeof(SockInfo), 1);
  195.  
  196.   fdp->global = g;
  197.   setsock(fdp, s, easy, action, g);
  198.   curl_multi_assign(g->multi, s, fdp);
  199. }
  200.  
  201. /* CURLMOPT_SOCKETFUNCTION */
  202. static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
  203. {
  204.   GlobalInfo *g = (GlobalInfo*) cbp;
  205.   SockInfo *fdp = (SockInfo*) sockp;
  206.   const char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE" };
  207.  
  208.   fprintf(MSG_OUT,
  209.           "socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]);
  210.   if (what == CURL_POLL_REMOVE) {
  211.     fprintf(MSG_OUT, "\n");
  212.     remsock(fdp);
  213.   }
  214.   else {
  215.     if (!fdp) {
  216.       fprintf(MSG_OUT, "Adding data: %s\n", whatstr[what]);
  217.       addsock(s, e, what, g);
  218.     }
  219.     else {
  220.       fprintf(MSG_OUT,
  221.               "Changing action from %s to %s\n",
  222.               whatstr[fdp->action], whatstr[what]);
  223.       setsock(fdp, s, e, what, g);
  224.     }
  225.   }
  226.   return 0;
  227. }
  228.  
  229.  
  230.  
  231. /* CURLOPT_WRITEFUNCTION */
  232. static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
  233. {
  234.   size_t realsize = size * nmemb;
  235.   ConnInfo *conn = (ConnInfo*) data;
  236.   (void)ptr;
  237.   (void)conn;
  238.   return realsize;
  239. }
  240.  
  241.  
  242. /* CURLOPT_PROGRESSFUNCTION */
  243. static int prog_cb (void *p, double dltotal, double dlnow, double ult,
  244.                     double uln)
  245. {
  246.   ConnInfo *conn = (ConnInfo *)p;
  247.   (void)ult;
  248.   (void)uln;
  249.  
  250.   fprintf(MSG_OUT, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal);
  251.   return 0;
  252. }
  253.  
  254.  
  255. /* Create a new easy handle, and add it to the global curl_multi */
  256. static void new_conn(char *url, GlobalInfo *g )
  257. {
  258.   ConnInfo *conn;
  259.   CURLMcode rc;
  260.  
  261.   conn = calloc(1, sizeof(ConnInfo));
  262.   memset(conn, 0, sizeof(ConnInfo));
  263.   conn->error[0]='\0';
  264.  
  265.   conn->easy = curl_easy_init();
  266.   if (!conn->easy) {
  267.     fprintf(MSG_OUT, "curl_easy_init() failed, exiting!\n");
  268.     exit(2);
  269.   }
  270.   conn->global = g;
  271.   conn->url = strdup(url);
  272.   curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url);
  273.   curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb);
  274.   curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, &conn);
  275.   curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, 1L);
  276.   curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error);
  277.   curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn);
  278.   curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 0L);
  279.   curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb);
  280.   curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn);
  281.   curl_easy_setopt(conn->easy, CURLOPT_PIPEWAIT, 1L);
  282.  
  283.   fprintf(MSG_OUT,
  284.           "Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url);
  285.   rc = curl_multi_add_handle(g->multi, conn->easy);
  286.   mcode_or_die("new_conn: curl_multi_add_handle", rc);
  287.  
  288.   /* note that the add_handle() will set a time-out to trigger very soon so
  289.      that the necessary socket_action() call will be called by this app */
  290. }
  291.  
  292. int main(int argc, char **argv)
  293. {
  294.   GlobalInfo g;
  295.   (void)argc;
  296.   (void)argv;
  297.  
  298.   memset(&g, 0, sizeof(GlobalInfo));
  299.   g.evbase = event_base_new();
  300.   g.multi = curl_multi_init();  
  301.   g.timer_event = evtimer_new(g.evbase, timer_cb, &g);
  302.  
  303.   /* setup the generic multi interface options we want */
  304.   curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
  305.   curl_multi_setopt(g.multi, CURLMOPT_SOCKETDATA, &g);
  306.   curl_multi_setopt(g.multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
  307.   curl_multi_setopt(g.multi, CURLMOPT_TIMERDATA, &g);
  308.   curl_multi_setopt(g.multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, 1L);
  309.   curl_multi_setopt(g.multi, CURLMOPT_PIPELINING, 1L);
  310.  
  311.   new_conn("http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/QualityLevels(2962000)/Fragments(video=0)", &g);
  312.   new_conn("http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/QualityLevels(2962000)/Fragments(video=20020000)", &g);
  313.   new_conn("http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/QualityLevels(2962000)/Fragments(video=40040000)", &g);
  314.   new_conn("http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/QualityLevels(2962000)/Fragments(video=60060000)", &g);
  315.  
  316.   /* we don't call any curl_multi_socket*() function yet as we have no handles
  317.      added! */
  318.  
  319.   event_base_dispatch(g.evbase);
  320.  
  321.   /* this, of course, won't get called since only way to stop this program is
  322.      via ctrl-C, but it is here to show how cleanup /would/ be done. */
  323.   event_free(g.timer_event);
  324.   event_base_free(g.evbase);
  325.   curl_multi_cleanup(g.multi);
  326.   return 0;
  327. }
Advertisement
Add Comment
Please, Sign In to add comment