diff --git a/0001-http-eliminate-redundant-bev-fd-manipulating-and-cac.patch b/0001-http-eliminate-redundant-bev-fd-manipulating-and-cac.patch index a239904..3fa5bed 100644 --- a/0001-http-eliminate-redundant-bev-fd-manipulating-and-cac.patch +++ b/0001-http-eliminate-redundant-bev-fd-manipulating-and-cac.patch @@ -1,12 +1,45 @@ -diff --git a/bufferevent.c b/bufferevent.c -index 08c0486c..68b35b1b 100644 ---- a/bufferevent.c -+++ b/bufferevent.c -@@ -876,6 +876,34 @@ bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd) - return res; +From 4386f0971e4001227732837c6ec60f8e267f9be3 Mon Sep 17 00:00:00 2001 +From: Azat Khuzhin +Date: Wed, 4 Sep 2019 00:56:20 +0300 +Subject: [PATCH] http: eliminate redundant bev fd manipulating and caching + +At the very beginning we reset the bufferevent fd (if bev has it), which +is not a good idea, since if user passes bufferevent with existing fd he +has some intention. + +So we need to: +- use BEV_OPT_CLOSE_ON_FREE for default bufferevent_socket_new() (to + avoid manual shutdown/closee) +- drop getsockopt(SOL_SOCKET, SO_ERROR), since bufferevent already has + evutil_socket_finished_connecting_() +- drop supperior bufferevent_setfd(bev, -1) in + evhttp_connection_connect_() + +Closes: #795 +Refs: #875 +--- + http.c | 232 ++++++++++++++++++++++-------------------- + include/event2/http.h | 6 +- + 2 files changed, 124 insertions(+), 114 deletions(-) + +diff --git a/http.c b/http.c +index 04f089bc..a6b3f6bb 100644 +--- a/http.c ++++ b/http.c +@@ -634,6 +634,91 @@ evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req) + } } -+int ++/** ++ Replaces the file descriptor on which the bufferevent operates. ++ Not supported for all bufferevent types. ++ ++ Unlike bufferevent_setfd() it will close previous file descriptor (if any). ++ ++ @param bufev the bufferevent object for which to change the file descriptor ++ @param fd the file descriptor to operate on ++*/ ++static int +bufferevent_replacefd(struct bufferevent *bev, evutil_socket_t fd) +{ + union bufferevent_ctrl_data d; @@ -34,62 +67,85 @@ index 08c0486c..68b35b1b 100644 + return err; +} + - evutil_socket_t - bufferevent_getfd(struct bufferevent *bev) - { -diff --git a/http-internal.h b/http-internal.h -index feaf436d..22836032 100644 ---- a/http-internal.h -+++ b/http-internal.h -@@ -53,7 +53,6 @@ struct evhttp_connection { - * server */ - TAILQ_ENTRY(evhttp_connection) next; - -- evutil_socket_t fd; - struct bufferevent *bufev; - - struct event retry_ev; /* for retrying connects */ -@@ -174,7 +173,7 @@ struct evhttp { - /* XXX most of these functions could be static. */ - - /* resets the connection; can be reused for more requests */ --void evhttp_connection_reset_(struct evhttp_connection *); -+void evhttp_connection_reset_(struct evhttp_connection *, int); - - /* connects if necessary */ - int evhttp_connection_connect_(struct evhttp_connection *); -diff --git a/http.c b/http.c -index 04f089bc..9d1d5d15 100644 ---- a/http.c -+++ b/http.c -@@ -777,7 +777,7 @@ evhttp_connection_fail_(struct evhttp_connection *evcon, ++/** Hard-reset our connection state ++ * ++ * This will: ++ * - reset fd ++ * - clears out buffers ++ * - call closecb ++ */ ++static void ++evhttp_connection_reset_hard_(struct evhttp_connection *evcon) ++{ ++ struct evbuffer *tmp; ++ int err; ++ ++ bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL); ++ ++ /* XXXX This is not actually an optimal fix. Instead we ought to have ++ an API for "stop connecting", or use bufferevent_replacefd to turn off ++ connecting. But for Libevent 2.0, this seems like a minimal change ++ least likely to disrupt the rest of the bufferevent and http code. ++ ++ Why is this here? If the fd is set in the bufferevent, and the ++ bufferevent is connecting, then you can't actually stop the ++ bufferevent from trying to connect with bufferevent_disable(). The ++ connect will never trigger, since we close the fd, but the timeout ++ might. That caused an assertion failure in evhttp_connection_fail_. ++ */ ++ bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE); ++ ++ /* inform interested parties about connection close */ ++ if (evhttp_connected(evcon) && evcon->closecb != NULL) ++ (*evcon->closecb)(evcon, evcon->closecb_arg); ++ ++ /** FIXME: manipulating with fd is unwanted */ ++ err = bufferevent_replacefd(evcon->bufev, -1); ++ EVUTIL_ASSERT(!err && "setfd"); ++ ++ /* we need to clean up any buffered data */ ++ tmp = bufferevent_get_output(evcon->bufev); ++ err = evbuffer_drain(tmp, -1); ++ EVUTIL_ASSERT(!err && "drain output"); ++ tmp = bufferevent_get_input(evcon->bufev); ++ err = evbuffer_drain(tmp, -1); ++ EVUTIL_ASSERT(!err && "drain input"); ++ ++ evcon->flags &= ~EVHTTP_CON_READING_ERROR; ++ evcon->state = EVCON_DISCONNECTED; ++} ++ + void + evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, + ev_ssize_t new_max_headers_size) +@@ -777,7 +862,7 @@ evhttp_connection_fail_(struct evhttp_connection *evcon, evhttp_request_free_(evcon, req); /* reset the connection */ - evhttp_connection_reset_(evcon); -+ evhttp_connection_reset_(evcon, 1); ++ evhttp_connection_reset_hard_(evcon); /* We are trying the next request that was queued on us */ if (TAILQ_FIRST(&evcon->requests) != NULL) -@@ -837,7 +837,7 @@ evhttp_connection_done(struct evhttp_connection *evcon) +@@ -837,7 +922,7 @@ evhttp_connection_done(struct evhttp_connection *evcon) /* check if we got asked to close the connection */ if (need_close) - evhttp_connection_reset_(evcon); -+ evhttp_connection_reset_(evcon, 1); ++ evhttp_connection_reset_hard_(evcon); if (TAILQ_FIRST(&evcon->requests) != NULL) { /* -@@ -1171,7 +1171,7 @@ evhttp_read_cb(struct bufferevent *bufev, void *arg) +@@ -1171,7 +1256,7 @@ evhttp_read_cb(struct bufferevent *bufev, void *arg) __func__, EV_SIZE_ARG(total_len))); #endif - evhttp_connection_reset_(evcon); -+ evhttp_connection_reset_(evcon, 1); ++ evhttp_connection_reset_hard_(evcon); } break; case EVCON_DISCONNECTED: -@@ -1221,13 +1221,10 @@ void +@@ -1221,13 +1306,10 @@ void evhttp_connection_free(struct evhttp_connection *evcon) { struct evhttp_request *req; @@ -105,7 +161,7 @@ index 04f089bc..9d1d5d15 100644 /* remove all requests that might be queued on this * connection. for server connections, this should be empty. -@@ -1252,20 +1249,9 @@ evhttp_connection_free(struct evhttp_connection *evcon) +@@ -1252,20 +1334,9 @@ evhttp_connection_free(struct evhttp_connection *evcon) &evcon->read_more_deferred_cb); if (evcon->bufev != NULL) { @@ -126,39 +182,39 @@ index 04f089bc..9d1d5d15 100644 if (evcon->bind_address != NULL) mm_free(evcon->bind_address); -@@ -1324,18 +1310,21 @@ evhttp_request_dispatch(struct evhttp_connection* evcon) +@@ -1324,54 +1395,17 @@ evhttp_request_dispatch(struct evhttp_connection* evcon) evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); } -/* Reset our connection state: disables reading/writing, closes our fd (if -* any), clears out buffers, and puts us in state DISCONNECTED. */ --void --evhttp_connection_reset_(struct evhttp_connection *evcon) -+/** Hard-reset our connection state ++/** Reset our connection state + * + * This will: -+ * - reset fd -+ * - clears out buffers -+ * - call closecb ++ * - disables reading/writing ++ * - puts us in DISCONNECTED state + */ -+static void -+evhttp_connection_reset_hard_(struct evhttp_connection *evcon) + void + evhttp_connection_reset_(struct evhttp_connection *evcon) { - struct evbuffer *tmp; - int err; - -- bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL); +- struct evbuffer *tmp; +- int err; - - /* XXXX This is not actually an optimal fix. Instead we ought to have + bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL); +- +- /* XXXX This is not actually an optimal fix. Instead we ought to have - an API for "stop connecting", or use bufferevent_setfd to turn off -+ an API for "stop connecting", or use bufferevent_replacefd to turn off - connecting. But for Libevent 2.0, this seems like a minimal change - least likely to disrupt the rest of the bufferevent and http code. - -@@ -1347,19 +1336,12 @@ evhttp_connection_reset_(struct evhttp_connection *evcon) - */ - bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE); - +- connecting. But for Libevent 2.0, this seems like a minimal change +- least likely to disrupt the rest of the bufferevent and http code. +- +- Why is this here? If the fd is set in the bufferevent, and the +- bufferevent is connecting, then you can't actually stop the +- bufferevent from trying to connect with bufferevent_disable(). The +- connect will never trigger, since we close the fd, but the timeout +- might. That caused an assertion failure in evhttp_connection_fail_. +- */ +- bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE); +- - if (evcon->fd == -1) - evcon->fd = bufferevent_getfd(evcon->bufev); - @@ -166,59 +222,38 @@ index 04f089bc..9d1d5d15 100644 - /* inform interested parties about connection close */ - if (evhttp_connected(evcon) && evcon->closecb != NULL) - (*evcon->closecb)(evcon, evcon->closecb_arg); -+ /* inform interested parties about connection close */ -+ if (evhttp_connected(evcon) && evcon->closecb != NULL) -+ (*evcon->closecb)(evcon, evcon->closecb_arg); - +- - shutdown(evcon->fd, EVUTIL_SHUT_WR); - evutil_closesocket(evcon->fd); - evcon->fd = -1; - } - err = bufferevent_setfd(evcon->bufev, -1); -+ /** FIXME: manipulating with fd is unwanted */ -+ err = bufferevent_replacefd(evcon->bufev, -1); - EVUTIL_ASSERT(!err && "setfd"); - - /* we need to clean up any buffered data */ -@@ -1369,9 +1351,26 @@ evhttp_connection_reset_(struct evhttp_connection *evcon) - tmp = bufferevent_get_input(evcon->bufev); - err = evbuffer_drain(tmp, -1); - EVUTIL_ASSERT(!err && "drain input"); -+} - -- evcon->flags &= ~EVHTTP_CON_READING_ERROR; -+/** Reset our connection state -+ * -+ * This will: -+ * - disables reading/writing -+ * - puts us in DISCONNECTED state -+ * -+ * @param hard - hard reset will (@see evhttp_connection_reset_hard_()) -+ */ -+void -+evhttp_connection_reset_(struct evhttp_connection *evcon, int hard) -+{ -+ bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL); - -+ if (hard) { -+ evhttp_connection_reset_hard_(evcon); -+ } -+ -+ evcon->flags &= ~EVHTTP_CON_READING_ERROR; +- EVUTIL_ASSERT(!err && "setfd"); +- +- /* we need to clean up any buffered data */ +- tmp = bufferevent_get_output(evcon->bufev); +- err = evbuffer_drain(tmp, -1); +- EVUTIL_ASSERT(!err && "drain output"); +- tmp = bufferevent_get_input(evcon->bufev); +- err = evbuffer_drain(tmp, -1); +- EVUTIL_ASSERT(!err && "drain input"); +- + evcon->flags &= ~EVHTTP_CON_READING_ERROR; +- evcon->state = EVCON_DISCONNECTED; } -@@ -1403,7 +1402,8 @@ evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) +@@ -1403,7 +1437,8 @@ evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) { struct evcon_requestq requests; - evhttp_connection_reset_(evcon); -+ evhttp_connection_reset_(evcon, 1); ++ evhttp_connection_reset_hard_(evcon); + if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { struct timeval tv_retry = evcon->initial_retry_timeout; int i; -@@ -1481,16 +1481,13 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) +@@ -1481,16 +1516,13 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) struct evhttp_connection *evcon = arg; struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); @@ -236,16 +271,16 @@ index 04f089bc..9d1d5d15 100644 evhttp_connection_cb_cleanup(evcon); return; } -@@ -1526,7 +1523,7 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) +@@ -1526,7 +1558,7 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) * disconnected. */ EVUTIL_ASSERT(evcon->state == EVCON_IDLE); - evhttp_connection_reset_(evcon); -+ evhttp_connection_reset_(evcon, 1); ++ evhttp_connection_reset_hard_(evcon); /* * If we have no more requests that need completion -@@ -1572,11 +1569,6 @@ static void +@@ -1572,11 +1604,6 @@ static void evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) { struct evhttp_connection *evcon = arg; @@ -257,7 +292,7 @@ index 04f089bc..9d1d5d15 100644 if (!(what & BEV_EVENT_CONNECTED)) { /* some operating systems return ECONNREFUSED immediately -@@ -1591,34 +1583,10 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) +@@ -1591,34 +1618,10 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) return; } @@ -293,7 +328,7 @@ index 04f089bc..9d1d5d15 100644 /* Reset the retry count as we were successful in connecting */ evcon->retry_cnt = 0; -@@ -2280,7 +2248,7 @@ evhttp_read_firstline(struct evhttp_connection *evcon, +@@ -2280,7 +2283,7 @@ evhttp_read_firstline(struct evhttp_connection *evcon, if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { /* Error while reading, terminate */ event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", @@ -302,7 +337,7 @@ index 04f089bc..9d1d5d15 100644 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); return; } else if (res == MORE_DATA_EXPECTED) { -@@ -2297,7 +2265,7 @@ evhttp_read_header(struct evhttp_connection *evcon, +@@ -2297,7 +2300,7 @@ evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req) { enum message_read_status res; @@ -311,7 +346,7 @@ index 04f089bc..9d1d5d15 100644 res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev)); if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { -@@ -2388,7 +2356,6 @@ evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_bas +@@ -2388,7 +2391,6 @@ evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_bas goto error; } @@ -319,7 +354,7 @@ index 04f089bc..9d1d5d15 100644 evcon->port = port; evcon->max_headers_size = EV_SIZE_MAX; -@@ -2403,7 +2370,7 @@ evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_bas +@@ -2403,7 +2405,7 @@ evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_bas } if (bev == NULL) { @@ -328,11 +363,10 @@ index 04f089bc..9d1d5d15 100644 event_warn("%s: bufferevent_socket_new failed", __func__); goto error; } -@@ -2571,24 +2538,30 @@ evhttp_connection_connect_(struct evhttp_connection *evcon) +@@ -2571,24 +2573,30 @@ evhttp_connection_connect_(struct evhttp_connection *evcon) if (evcon->state == EVCON_CONNECTING) return (0); -- evhttp_connection_reset_(evcon); + /* Do not do hard reset, since this will reset the fd, but someone may + * change some options for it (i.e. setsockopt(), #875) + * @@ -342,7 +376,7 @@ index 04f089bc..9d1d5d15 100644 + * - evhttp_connection_set_local_port() + * - evhttp_connection_set_retries() + * */ -+ evhttp_connection_reset_(evcon, 0); + evhttp_connection_reset_(evcon); EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING)); evcon->flags |= EVHTTP_CON_OUTGOING; @@ -367,7 +401,7 @@ index 04f089bc..9d1d5d15 100644 return (-1); } -@@ -2625,7 +2598,7 @@ evhttp_connection_connect_(struct evhttp_connection *evcon) +@@ -2625,7 +2633,7 @@ evhttp_connection_connect_(struct evhttp_connection *evcon) if (ret < 0) { evcon->state = old_state; @@ -376,7 +410,7 @@ index 04f089bc..9d1d5d15 100644 __func__, evcon->address); /* some operating systems return ECONNREFUSED immediately * when connecting to a local address. the cleanup is going -@@ -4265,9 +4238,7 @@ evhttp_get_request_connection( +@@ -4265,9 +4273,7 @@ evhttp_get_request_connection( evcon->flags |= EVHTTP_CON_INCOMING; evcon->state = EVCON_READING_FIRSTLINE; @@ -387,29 +421,6 @@ index 04f089bc..9d1d5d15 100644 goto err; if (bufferevent_enable(evcon->bufev, EV_READ)) goto err; -diff --git a/include/event2/bufferevent.h b/include/event2/bufferevent.h -index 48cd1535..e4e5c21b 100644 ---- a/include/event2/bufferevent.h -+++ b/include/event2/bufferevent.h -@@ -355,6 +355,18 @@ void bufferevent_getcb(struct bufferevent *bufev, - EVENT2_EXPORT_SYMBOL - int bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd); - -+/** -+ Replaces the file descriptor on which the bufferevent operates. -+ Not supported for all bufferevent types. -+ -+ Unlike bufferevent_setfd() it will close previous file descriptor (if any). -+ -+ @param bufev the bufferevent object for which to change the file descriptor -+ @param fd the file descriptor to operate on -+*/ -+EVENT2_EXPORT_SYMBOL -+int bufferevent_replacefd(struct bufferevent *bufev, evutil_socket_t fd); -+ - /** - Returns the file descriptor associated with a bufferevent, or -1 if - no file descriptor is associated with the bufferevent. diff --git a/include/event2/http.h b/include/event2/http.h index 2a41303e..90f4cf9a 100644 --- a/include/event2/http.h @@ -427,3 +438,6 @@ index 2a41303e..90f4cf9a 100644 EVENT2_EXPORT_SYMBOL void evhttp_connection_set_local_address(struct evhttp_connection *evcon, const char *address); +-- +2.46.0 + diff --git a/libevent.spec b/libevent.spec index f5d2e69..4e8efe4 100644 --- a/libevent.spec +++ b/libevent.spec @@ -2,7 +2,7 @@ Name: libevent Version: 2.1.12 -Release: 7%{?dist} +Release: 8%{?dist} Summary: Abstract asynchronous event notification library # arc4random.c, which is used in build, is ISC. The rest is BSD. @@ -31,6 +31,7 @@ Patch03: 0001-build-add-doxygen-to-all.patch # issue is fixed. # https://github.com/transmission/transmission/issues/1437 Patch04: 0001-Revert-Fix-checking-return-value-of-the-evdns_base_r.patch +# 3 cherry-picked upstream commits adjusted to not break ABI # https://github.com/libevent/libevent/commit/afa66ea # https://github.com/libevent/libevent/commit/aea752b # https://github.com/libevent/libevent/commit/2385638 @@ -153,6 +154,10 @@ mkdir -p $RPM_BUILD_ROOT/%{develdocdir}/sample %doc %{develdocdir}/ %changelog +* Tue Aug 20 2024 Pavol Žáčik - 2.1.12-8 +- Rework the patch from 2.1.12-7 to prevent ABI changes. +- Related: RHEL-26128 + * Tue Aug 13 2024 Pavol Žáčik - 2.1.12-7 - Patch duplicate file descriptor manipulation - Resolves: RHEL-26128