From: Azat Khuzhin Date: Fri, 7 Dec 2018 18:46:27 +0000 (+0300) Subject: http: fix connection retries when there more then one request for connection X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f3f7aa5afff2c0be4a1a299a1a7d0a64558abc23;p=libevent http: fix connection retries when there more then one request for connection We should not attemp to establishe the connection if there is retry timer active, since otherwise there will be a bug. Imagine next situation: con = evhttp_connection_base_new() evhttp_connection_set_retries(con, 2) req = evhttp_request_new() evhttp_make_request(con, req, ...) # failed during connecting, and timer for 2 second scheduler (retry_ev) Then another request scheduled for this evcon: evhttp_make_request(con, req, ...) # got request from server, # and now it tries to read the response from the server # (req.kind == EVHTTP_RESPONSE) # # but at this point retry_ev scheduled, # and it schedules the connect again, # and after the connect will succeeed, it will pick request with # EVHTTP_RESPONSE for sending and this is completelly wrong and will # fail in evhttp_make_header_response() since there is no # "http_server" for this evcon This was a long standing issue, that I came across few years ago firstly, bad only now I had time to dig into it (but right now it was pretty simple, by limiting amount of CPU for the process and using rr for debug to go back and forth). --- diff --git a/http.c b/http.c index b49bc04c..3f2f40f4 100644 --- a/http.c +++ b/http.c @@ -1290,6 +1290,8 @@ evhttp_request_dispatch(struct evhttp_connection* evcon) if (req == NULL) return; + EVUTIL_ASSERT(req->kind == EVHTTP_REQUEST); + /* delete possible close detection events */ evhttp_connection_stop_detectclose(evcon); @@ -2644,6 +2646,10 @@ evhttp_make_request(struct evhttp_connection *evcon, TAILQ_INSERT_TAIL(&evcon->requests, req, next); + /* We do not want to conflict with retry_ev */ + if (evcon->retry_cnt) + return (0); + /* If the connection object is not connected; make it so */ if (!evhttp_connected(evcon)) { int res = evhttp_connection_connect_(evcon); @@ -2654,7 +2660,7 @@ evhttp_make_request(struct evhttp_connection *evcon, if (res != 0) TAILQ_REMOVE(&evcon->requests, req, next); - return res; + return (res); } /*