Merge branch 'http-fix-fd-leak'

* http-fix-fd-leak:
  http: fix fd leak on fd reset (by using bufferevent_replacefd())
  bufferevent: introduce bufferevent_replacefd() (like setfd() but also close fd)

Fixes: #1143
This commit is contained in:
Azat Khuzhin 2021-03-23 09:10:00 +03:00
commit 3b9b655da9
3 changed files with 44 additions and 4 deletions

View File

@ -881,6 +881,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)
{

8
http.c
View File

@ -1420,7 +1420,7 @@ evhttp_connection_reset_hard_(struct evhttp_connection *evcon)
int err;
/* 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.
@ -1437,7 +1437,7 @@ evhttp_connection_reset_hard_(struct evhttp_connection *evcon)
(*evcon->closecb)(evcon, evcon->closecb_arg);
/** FIXME: manipulating with fd is unwanted */
err = bufferevent_setfd(evcon->bufev, -1);
err = bufferevent_replacefd(evcon->bufev, -1);
EVUTIL_ASSERT(!err && "setfd");
/* we need to clean up any buffered data */
@ -2766,7 +2766,7 @@ evhttp_connection_connect_(struct evhttp_connection *evcon)
return (-1);
}
if (bufferevent_setfd(evcon->bufev, fd))
if (bufferevent_replacefd(evcon->bufev, fd))
return (-1);
}
@ -4495,7 +4495,7 @@ evhttp_get_request_connection(
evcon->flags |= EVHTTP_CON_INCOMING;
evcon->state = EVCON_READING_FIRSTLINE;
if (bufferevent_setfd(evcon->bufev, fd))
if (bufferevent_replacefd(evcon->bufev, fd))
goto err;
if (bufferevent_enable(evcon->bufev, EV_READ))
goto err;

View File

@ -377,6 +377,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.