[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] evhttp client error handling



I've put my sample code up on github, so we have something concrete to talk about:

https://github.com/ppelleti/https-example

However, I think I've figured out why I'm getting the ECONNREFUSED: it's for the obvious reason, that my server is only running on IPv4, and not on IPv6. I was led astray by the comment saying that ECONNREFUSED was expected when connecting to localhost, but I don't think that comment is relevant to my situation. I'm getting a perfectly legitimate ECONNREFUSED, because my server is only running on 127.0.0.1, and isn't running on ::1.

I was also led astray by the fact that curl seems to connect to IPv4 first (or maybe it tries both?), while evhttp tries IPv6 first, and gives up if it doesn't work. So curl was working fine for me, but it was using IPv4 even when I gave it the name "localhost". However, if I give curl the "-6" option, then it doesn't work either. That's when I realized my server wasn't running on ::1.

So, I tried running my server on IPv6 instead of IPv4, by making this change:

--- a/https-server.c
+++ b/https-server.c
@@ -230,7 +230,7 @@ static int serve_some_http (void)
   evhttp_set_gencb (http, send_document_cb, NULL);

   /* Now we tell the evhttp what port to listen on */
-  handle = evhttp_bind_socket_with_handle (http, "0.0.0.0", port);
+  handle = evhttp_bind_socket_with_handle (http, "::0", port);
   if (! handle)
{ fprintf (stderr, "couldn't bind to port %d. Exiting.\n", (int) port);
       return 1;

but then the server fails to run, like this:

ppelletier@chives:~/src/https-example$ ./https-server
Using OpenSSL version "OpenSSL 1.0.1c 10 May 2012"
and libevent version "2.1.2-alpha-dev"
Loading certificate chain from 'server-certificate-chain.pem'
and private key from 'server-private-key.pem'
[warn] getaddrinfo: address family for nodename not supported
couldn't bind to port 8421. Exiting.

So, I'm not sure what's going on there. And anyway, I don't really want to run the server on just IPv6; I want it to answer on both IPv4 and IPv6. But I don't know if there's a way to do that other than running two http servers.

--Patrick


On 01/23/2013 10:18 PM, Azat Khuzhin wrote:
What about your ECONNREFUSED, does you have something like this, if
you run "curl -v --data CORRECT_POST_DATA_HERE HOST" ?
(it seems that you try POST request: client_do_post)
Does you server ("localhost") have the valid HTTP answer?

Why it couldn't get response after first request.
Could you post you code somewhere? If you don't want to show all of
it, you could write 20-40 lines, that can reproduce this problem.

About retries: could you send backtrace when this messages are printed?


Thanks.

On Thu, Jan 24, 2013 at 7:36 AM, Patrick Pelletier
<ppelletier@xxxxxxxxxx> wrote:
On 01/22/2013 02:54 PM, Azat Khuzhin wrote:

Could you try to test my patch

https://github.com/azat/libevent/commit/71e709c7829275a594f767b27468b1b52e8b5bb9.patch

and write if it works for you?


Thanks, I think that's a step in the right direction.

However, I'm still having trouble.  My callback is getting called with
evhttp_request_get_response_code (req) == 0.  (i. e. something went wrong,
but we don't know what.  That gets back to the original topic of this
thread, that evhttp is very vague about what errors happened.)

Here's the backtrace when my callback gets called:

#0  request_finished (req=0x758df0, arg=0x7fffffffe070) at client-http.c:46
#1  0x00007ffff7628b58 in evhttp_connection_cb_cleanup (evcon=0x758280)
     at http.c:1319
#2  0x00007ffff7629050 in evhttp_connection_cb (bufev=0x7579b0, what=33,
     arg=0x758280) at http.c:1462
#3  0x00007ffff75f93d0 in bufferevent_run_deferred_callbacks_locked (
     cb=0x757b50, arg=0x7579b0) at bufferevent.c:161
#4  0x00007ffff7604389 in event_process_active_single_queue (base=0x756790,
     activeq=0x754080, max_to_process=2147483647, endtime=0x0) at
event.c:1476
#5  0x00007ffff760464e in event_process_active (base=0x756790) at
event.c:1538
#6  0x00007ffff7604db2 in event_base_loop (base=0x756790, flags=0)
     at event.c:1761
#7  0x000000000040dd49 in client_do_post (host=0x4e9aa8 "localhost",
     port=8421, passcode=0x4e9ab2 "R23") at client-http.c:246
#8  0x000000000040ddba in main (argc=1, argv=0x7fffffffe288)
     at client-main.c:30

(all the line numbers correspond to your "fix-http-for-ipv6" branch, commit
71e709c7829275a594f767b27468b1b52e8b5bb9)

It appears that what's happening is the "if (errno == ECONNREFUSED) goto
cleanup;" in http.c:1409 is being triggered.  The comment right above it
says:

/* some operating systems return ECONNREFUSED immediately
  * when connecting to a local address.  the cleanup is going
  * to reschedule this function call.
  */

Obviously my operating system (Ubuntu 10.04 LTS) must be one of these
operating systems.  But then I was curious why the cleanup wasn't
rescheduling the function call, the way the comment said it would.

It turns out that at the top of evhttp_connection_cb_cleanup is:

if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max)

and that was the problem.  retry_max defaults to 0, which means that it
actually won't retry the way the comment said it would.  This seems like a
poor default, given that the code is relying on a retry being possible, for
the ECONNREFUSED case.

So, I tried fixing this in my client code by calling:

evhttp_connection_set_retries (conn, 3);

However, now what happens is I get:

[warn] Epoll ADD(1) on fd 7 failed.  Old events were 0; read change was 1
(add); write change was 0 (none): Bad file descriptor
[warn] Epoll ADD(4) on fd 7 failed.  Old events were 0; read change was 0
(none); write change was 1 (add): Bad file descriptor

and my http request still fails.  But that's as far as I've gotten in
debugging it, though.

But thanks for your patch!  I think that will be part of the solution; I'm
just running into other evhttp issues now (the ECONNREFUSED and retry
thing).

--Patrick





***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.