From aea752b62dde0f02195b9c2143bdfcdfe65fb6fb Mon Sep 17 00:00:00 2001
From: Azat Khuzhin <azat@libevent.org>
Date: Tue, 23 Mar 2021 09:00:24 +0300
Subject: [PATCH] bufferevent: introduce bufferevent_replacefd() (like setfd()
 but also close fd)

Reference:https://github.com/libevent/libevent/commit/aea752b62dde0f02195b9c2143bdfcdfe65fb6fb
Conflict:NA
---
 bufferevent.c                | 28 ++++++++++++++++++++++++++++
 include/event2/bufferevent.h | 12 ++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/bufferevent.c b/bufferevent.c
index 08c0486..68b35b1 100644
--- a/bufferevent.c
+++ b/bufferevent.c
@@ -876,6 +876,34 @@ bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd)
 	return res;
 }
 
+int
+bufferevent_replacefd(struct bufferevent *bev, evutil_socket_t fd)
+{
+	union bufferevent_ctrl_data d;
+	int err = -1;
+	evutil_socket_t old_fd = EVUTIL_INVALID_SOCKET;
+
+	BEV_LOCK(bev);
+	if (bev->be_ops->ctrl) {
+		err = bev->be_ops->ctrl(bev, BEV_CTRL_GET_FD, &d);
+		if (!err) {
+			old_fd = d.fd;
+			if (old_fd != EVUTIL_INVALID_SOCKET) {
+				err = evutil_closesocket(old_fd);
+			}
+		}
+		if (!err) {
+			d.fd = fd;
+			err = bev->be_ops->ctrl(bev, BEV_CTRL_SET_FD, &d);
+		}
+	}
+	if (err)
+		event_debug(("%s: cannot replace fd for %p from "EV_SOCK_FMT" to "EV_SOCK_FMT, __func__, bev, old_fd, fd));
+	BEV_UNLOCK(bev);
+
+	return err;
+}
+
 evutil_socket_t
 bufferevent_getfd(struct bufferevent *bev)
 {
diff --git a/include/event2/bufferevent.h b/include/event2/bufferevent.h
index 48cd153..e4e5c21 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.
-- 
2.33.0


