curl-library
Re: Re[4]: Working with curl connections as with sockets.
Date: Mon, 05 May 2008 15:07:35 +0400
* Daniel Stenberg <daniel_at_haxx.se> [Sun, 4 May 2008 23:18:29 +0200
(CEST)]:
> I disagree. First, send() is separate from select() so mimicing send()
> does not imply select().
>
> Then, select(), poll(), epoll() and similar functions should all still
> be possible to use and thus it would be pointless for us to offer a
> function with the exact same funtion and purpose.
>
> curl_easy_send() and curl_easy_recv() would be provided because they
> cannot by done otherwise.
Ok, I see the point. Agreed.
> >> So, supporting an EAGAIN-style return code will make our functions
> >> more likely to work as drop-in replacements in existing
applications.
> > In essence this means that we add at least one more CURLE_* error
> > code.
> Yes, I can't think of any better way.
Ok, I will do it - this is easy. :)
> > Besides, Curl_write() should be modified to take into account this
> > error: currently it returns CURLE_SEND_ERROR if the socket is
> > not ready.
> Nope it doesn't. It returns 0 bytes written and CURLE_OK.
Ah, I see now... You are right.
> But yes, of course the underlying code would need to do right.
I have checked the usage of Curl_write(), and have come to conclusion
that if we modify it "to do right", the existing code will break.
Currently, libcurl does not handle EAGAIN at all - it simply retries to
send the data until it all goes out or a failure occurs. By the way,
this means that on slow lines, libcurl can take up lots of CPU time
continuously calling send() in a cycle (am I right? Or did I miss some
waits on the socket?).
Handling EAGAIN from Curl_write() will require modifications of the
"core" libcurl code (e.g., lib/transfer.c around line 1537). Not that I
am afraid of hacking the sources, but isn't it too much for such a
simple feature?
So for the time being I simply check that Curl_write() returns CURLE_OK
with zero bytes sent, and assume that it's the symptom of EAGAIN.
Please find attached the patch (5 existing files modified), 2 man pages
(going to docs/libcurl), and one example of usage (going to
docs/examples).
Your comments are welcome.
-- tetetest tetetest.
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* An example of curl_easy_send() and curl_easy_recv() usage.
*
* $Id$
*/
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Auxiliary function that waits on the socket. */
int wait_on_socket(int sockfd, int for_recv, long timeout_ms)
{
// ok, we know what to check.
// do it.
struct timeval tv;
long seconds, usecs;
fd_set infd, outfd, errfd;
int res;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec= (timeout_ms % 1000) * 1000;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd); /* always check for error */
if(for_recv)
{
FD_SET(sockfd, &infd);
}
else
{
FD_SET(sockfd, &outfd);
}
/* select() returns the number of signalled sockets or -1 */
res = select(sockfd + 1, &infd, &outfd, &errfd, &tv);
return res;
}
int main(void)
{
CURL *curl;
CURLcode res;
/* Minimalistic http request */
char *request = "GET / HTTP/1.0\r\nHost: curl.haxx.se\r\n\r\n";
int sockfd; /* socket */
size_t iolen;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
/* Do not do the transfer - only connect to host */
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
res = curl_easy_perform(curl);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
/* Extract the socket from the curl handle - we'll need it
* for waiting */
res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockfd);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
/* wait for the socket to become ready for sending */
if(!wait_on_socket(sockfd, 0, 60000L))
{
printf("Error: timeout.\n");
return 1;
}
puts("Sending request.");
/* Send the request. Real applications should check the iolen
* to see if all the request has been sent */
res = curl_easy_send(curl, request, strlen(request), &iolen);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
puts("Reading response.");
/* read the response */
for(;;)
{
char buf[1024];
wait_on_socket(sockfd, 1, 60000L);
res = curl_easy_recv(curl, buf, 1024, &iolen);
if(CURLE_OK != res)
break;
printf("Received %u bytes.\n", iolen);
}
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
- application/octet-stream attachment: sendrecv.diff
- application/octet-stream attachment: curl_easy_recv.3
- application/octet-stream attachment: curl_easy_send.3