cURL / Mailing Lists / curl-library / Single Mail

curl-library

Libcurl Multi-Environment Timing Problems

From: Paul Romero <paulr_at_rcom-software.com>
Date: Thu, 08 Jul 2010 22:40:38 -0700

Dear Group:

I can successfully send a single file via SFTP in the libcurl
multi environment. The basic technique, is to call
curl_multi_perform() and curl_multi_info_read() when Linux
SIGIO occurs. The Linux socket is programmed for
asynchronous IO and generates SIGIO whenever input or
output to the socket is possible. (i.e. The standard
fcntl() technique is used to configure the socket.)

However, a few kludges are necessary to make the
technique work. The one that disturbs me is that
a 20 MS delay must be added prior to calling
curl_multi_perform(). The details are described
below. This technique is important to me because
my target environment does not have libevent.

Best Regards,

Paul R.

1) I am not sure I am using the TCP socket libcurl uses for SFTP
server communications. This kludge is used get a socket after the
file transfer begins. I am fairly sure is not right and would
like to learn of a better technique. Essentially, I need to
learn when a TCP socket is allocated as early as possible.

  if(config != TRUE)
    {
   fd_set fd_write, fd_dummy;
   int k, nfds;

   Xfer_Events++;

   curl_multi_fdset(Xfer_Multi_Handle,
               &fd_dummy, &fd_write, &fd_dummy, &nfds);
   for(k = 0; k < nfds; k++)
     {
    if(FD_ISSET(k, &fd_write))
      {
     printf("Set %d\n", k);
     config = TRUE;
     break;
      }
     }

   if(config)
     {
    Xfer_Events = 1;

    fflush(stdout);
    printf("CONFIG N = %d Fd = %d\n", nfds, k);

    config = TRUE;
    fcntl(k, F_SETFL, (O_NONBLOCK | O_ASYNC));
    fcntl(k, F_SETOWN, getpid());
    (void) signal(SIGIO, xfer_handler);

     }
    }

2) After a socket is obtained, if I call Linux pause() in some other
part of the program and don't put a 20 MS delay before calling
curl_multi_perform(), the pause() often hangs forever regardless
of how many SIGIO occur. This seems strange and is certainly
a performance bottle neck.

The pause() code is as follows:

  //
  // Wait until writing data is possible.
  //
  if( !Xfer_Events )
    {
printf("Wait\n");
   pause();
printf("Go\n");
    }

The call to curl_multi_peform() etc. is as follows:

// fprintf(stderr, "XFER: Sending Data\n");
 usleep((20 * 1000));
   while(curl_multi_perform(Xfer_Multi_Handle, &still_running) ==
                                    CURLM_CALL_MULTI_PERFORM);

// fprintf(stderr, "XFER: Check Transfer Status\n");
 //
 // Read all available messages.
 //
 xfer_handle = NULL;
 while ((msg = curl_multi_info_read(Xfer_Multi_Handle, &msgs_left)))
   {
         if(msg->msg == CURLMSG_DONE)
    {
   //
   // Transfer is complete.
   //
   xfer_handle = msg->easy_handle;
   break;
    }
   }

 if(xfer_handle)
   {
  fprintf(stderr, "XFER DONE: Result = %d\n", msg->data.result);

  *error = msg->data.result;
  if(*error)
   outcome = XFER_FAILURE;
  else
   outcome = XFER_SUCCESS;

           curl_multi_remove_handle(Xfer_Multi_Handle, xfer_handle);
           curl_easy_cleanup(xfer_handle);
   }

Also, note that I use Linux poll() to make sure writing is OK just
before this code segment and it works correctly.

--
Paul Romero
RCOM Communications Software
Phone/Fax: (510)339-2628
E-Mail: paulr_at_rcom-software.com
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2010-07-09