Attached is an  attempt at a sample program that creates 2 threads each
with an easy handle that is added to the global multi handle. It uses libuv
for socket event handling.

Each thread is supposed to continuously fetch data from an external server
(see http_get() thread function).

However, currently the 2 threads each fetch data from the external server
once and then nothing further happens. In case of CURL_POLL_REMOVE, I
ensure that uv_close is not called, so that further events on the socket
can be detected.

How can I make the external GET a continuous activity on the easy handle?

Thanks
Raj



On Fri, Jul 10, 2015 at 10:38 AM, Daniel Stenberg <[email protected]> wrote:

> On Fri, 10 Jul 2015, Ray Satiro via curl-library wrote:
>
>  Generally there is something in libcurl I'm unclear about (I've asked on
>> the list before but didn't get a reply addressing it) which is it seems
>> that it's acceptable behavior for curl_multi_perform to always be
>> performing and not return for extended periods of time and I thought in
>> that case you can't call multi_add_handle from another thread during that
>> time.
>>
>
> There's no guarantee that this will work. As all internals are lock-free
> and assume exclusive access to lists etc there's a risk for data corruption
> if you do this.
>
> --
>
>  / daniel.haxx.se
>
> -------------------------------------------------------------------
> List admin: http://cool.haxx.se/list/listinfo/curl-library
> Etiquette:  http://curl.haxx.se/mail/etiquette.html
>



-- 

    Rajalakshmi Iyer  *Senior Software Engineer*    raj-blismedia.com
<http://is.gd/L42zBR>[image: Skype icon]       [image: Blis logo]
<http://www.blismedia.com/>    <http://www.blismedia.com/>
<https://www.facebook.com/BlisMedia?fref=ts>
<https://twitter.com/BlisMedia>
<https://www.linkedin.com/company/blismedia>
<https://plus.google.com/u/0/103190831541608378945/about>

-- 
This email and any attachments to it may be confidential and are 
intended solely for the use of the individual to whom it is addressed. Any 
views or opinions expressed are solely those of the author and do not 
necessarily represent those of BlisMedia Ltd, a company registered in 
England and Wales with registered number 06455773. Its registered office is 
3rd Floor, 101 New Cavendish St, London, W1W 6XH, United Kingdom.

If you are not the intended recipient of this email, you must neither take 
any action based upon its contents, nor copy or show it to anyone. Please 
contact the sender if you believe you have received this email in error.
#include <curl/curl.h>
#include <uv.h>
#include <unistd.h>

#include <iostream>
#include <thread>

/*
 * This example tries to employ CURL multi interface with multiple threads working on the easy handles
 * that are part of the multi handle. 
 * It uses libuv for socket event handling.
 */

CURLM* gMultiHandle;
uv_loop_t* gLoop;
uv_timer_t gTimer;
bool gThreadStart = false;

void TermHandler(int signum)
{
   gThreadStart = false;
   uv_stop(gLoop);
}

typedef struct curl_context_s 
{
   uv_poll_t poll_handle;
   curl_socket_t sockfd;
} curl_context_t;
 
/* CURLOPT_WRITEFUNCTION for the easy handle */
static std::size_t OnReceiveReply(void* buffer, std::size_t size, std::size_t count, void* userdata)
{
   std::size_t byteCount = size * count;
   std::cout << " - Inside OnReceiveReply - " << byteCount << std::endl;
   return byteCount;
}

/* CURLMOPT_TIMERFUNCTION for multi handle*/
void on_timeout(uv_timer_t *req, int status)
{
  int running_handles;
  curl_multi_socket_action(gMultiHandle, CURL_SOCKET_TIMEOUT, 0, &running_handles);
}

void start_timeout(CURLM *multi, long timeout_ms, void *userp)
{
   if (timeout_ms <= 0)
   {
      timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in
                       a bit */
   }
   uv_timer_start(&gTimer, on_timeout, timeout_ms, 0);
}

/* Thread function */
void http_get()
{
   CURL* easyHandle = curl_easy_init();
   curl_easy_setopt(easyHandle, CURLOPT_WRITEFUNCTION, OnReceiveReply);
   curl_multi_add_handle(gMultiHandle, easyHandle);
   std::cout << "Added easy handle to multi handle" << std::endl;
   while (gThreadStart)
   {
      // In the real application, this URL will have different query parameters in each request.
      // Hence this call to set CURLOPT_URL within the loop.
      curl_easy_setopt(easyHandle, CURLOPT_URL, "http://10.91.31.152:8080/index.html";);
      sleep(2);
   }
   curl_multi_remove_handle(gMultiHandle, easyHandle);
   curl_easy_cleanup(easyHandle);
}

curl_context_t* create_curl_context(curl_socket_t sockfd)
{
   curl_context_t* context = (curl_context_t *) malloc(sizeof *context);
   context->sockfd = sockfd;
 
   uv_poll_init_socket(gLoop, &context->poll_handle, sockfd);
   context->poll_handle.data = context;
 
   return context;
}
 
void curl_close_cb(uv_handle_t *handle)
{
   curl_context_t *context = (curl_context_t *) handle->data;
   free(context);
}
 
void destroy_curl_context(curl_context_t *context)
{
   uv_close((uv_handle_t *) &context->poll_handle, curl_close_cb);
}

void curl_perform(uv_poll_t *req, int status, int events)
{
   int flags = 0;
   uv_timer_stop(&gTimer);
 
   if (events & UV_READABLE)
      flags |= CURL_CSELECT_IN;
   if (events & UV_WRITABLE)
      flags |= CURL_CSELECT_OUT;
 
   curl_context_t* context = (curl_context_t *) req;
 
   int running_handles;
   curl_multi_socket_action(gMultiHandle, context->sockfd, flags, &running_handles);

   CURLMsg *message = NULL;
   int pending = 0;
   while (message = curl_multi_info_read(gMultiHandle, &pending))
   {
      if (message->msg == CURLMSG_DONE)
      {
         std::cout << "Finished receiving message" << std::endl; 
      } 
   }
}

int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, void* socketp)
{
   curl_context_t *curl_context = NULL;
   if (action == CURL_POLL_IN || action == CURL_POLL_OUT) 
   {
      if (socketp) 
      {
         curl_context = (curl_context_t *) socketp;
      }
      else 
      {
         curl_context = create_curl_context(s);
      }
      curl_multi_assign(gMultiHandle, s, (void *) curl_context);
   } 

   switch (action) 
   {
      case CURL_POLL_IN:
         std::cout << "handle_socket - CURL_POLL_IN " << std::endl;
         uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform);
         break;
      case CURL_POLL_OUT:
         std::cout << "handle_socket - CURL_POLL_OUT " << std::endl;
         uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform);
         break;
      case CURL_POLL_REMOVE:
         std::cout << "handle_socket - CURL_POLL_REMOVE " << std::endl;
/*         if (socketp) 
         {
            uv_poll_stop(&((curl_context_t*)socketp)->poll_handle);
            destroy_curl_context((curl_context_t*) socketp);
            curl_multi_assign(gMultiHandle, s, NULL);
         }  */
         break;
      default:
         std::cout << "handle_socket - default " << std::endl;
         abort();
   }
   return 0;
}

int main()
{
   signal(SIGTERM, TermHandler);

   gLoop = uv_default_loop();
   uv_timer_init(gLoop, &gTimer);
 
   if (curl_global_init(CURL_GLOBAL_ALL))
   {
      std::cout << "curl_global_init failed";
      return 1;
   };

   gMultiHandle = curl_multi_init();
   curl_multi_setopt(gMultiHandle, CURLMOPT_SOCKETFUNCTION, handle_socket);
   curl_multi_setopt(gMultiHandle, CURLMOPT_TIMERFUNCTION, start_timeout);

   std::thread t1(http_get);
   std::thread t2(http_get);

   gThreadStart = true;

   std::cout << "Starting uv loop" << std::endl;
   uv_run(gLoop, UV_RUN_DEFAULT);

   t1.join();
   t2.join();

   curl_multi_cleanup(gMultiHandle);
   return 0;
}
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to