2009-02-02 19:22:13 +00:00
|
|
|
/*
|
2012-02-10 17:29:53 -05:00
|
|
|
* Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
|
2009-04-19 20:54:12 +00:00
|
|
|
* Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
|
2009-02-02 19:22:13 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2010-07-07 16:45:03 -04:00
|
|
|
#include "event2/event-config.h"
|
2011-01-02 08:43:45 -07:00
|
|
|
#include "evconfig-private.h"
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifdef EVENT__HAVE_SYS_TIME_H
|
2009-02-02 19:22:13 +00:00
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifdef EVENT__HAVE_STDARG_H
|
2009-02-02 19:22:13 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#endif
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifdef EVENT__HAVE_UNISTD_H
|
2009-02-02 19:22:13 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2011-05-25 19:50:56 -04:00
|
|
|
#ifdef _WIN32
|
2009-02-02 19:22:13 +00:00
|
|
|
#include <winsock2.h>
|
2009-11-04 03:54:05 +00:00
|
|
|
#include <ws2tcpip.h>
|
2009-02-02 19:22:13 +00:00
|
|
|
#endif
|
|
|
|
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifdef EVENT__HAVE_SYS_SOCKET_H
|
2009-05-05 02:59:26 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifdef EVENT__HAVE_NETINET_IN_H
|
2009-11-03 20:40:48 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#endif
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifdef EVENT__HAVE_NETINET_IN6_H
|
2009-11-03 20:40:48 +00:00
|
|
|
#include <netinet/in6.h>
|
|
|
|
#endif
|
2009-05-05 02:59:26 +00:00
|
|
|
|
2009-02-02 19:22:13 +00:00
|
|
|
#include "event2/util.h"
|
|
|
|
#include "event2/bufferevent.h"
|
|
|
|
#include "event2/buffer.h"
|
|
|
|
#include "event2/bufferevent_struct.h"
|
|
|
|
#include "event2/bufferevent_compat.h"
|
|
|
|
#include "event2/event.h"
|
|
|
|
#include "log-internal.h"
|
|
|
|
#include "mm-internal.h"
|
|
|
|
#include "bufferevent-internal.h"
|
|
|
|
#include "util-internal.h"
|
2011-05-25 19:50:56 -04:00
|
|
|
#ifdef _WIN32
|
2009-10-23 22:00:29 +00:00
|
|
|
#include "iocp-internal.h"
|
|
|
|
#endif
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
/* prototypes */
|
|
|
|
static int be_socket_enable(struct bufferevent *, short);
|
|
|
|
static int be_socket_disable(struct bufferevent *, short);
|
|
|
|
static void be_socket_destruct(struct bufferevent *);
|
|
|
|
static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
|
2009-05-13 20:37:21 +00:00
|
|
|
static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
|
|
|
|
|
|
|
|
static void be_socket_setfd(struct bufferevent *, evutil_socket_t);
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2009-04-10 15:01:31 +00:00
|
|
|
const struct bufferevent_ops bufferevent_ops_socket = {
|
2009-02-02 19:22:13 +00:00
|
|
|
"socket",
|
2010-03-13 01:06:57 -05:00
|
|
|
evutil_offsetof(struct bufferevent_private, bev),
|
2009-02-02 19:22:13 +00:00
|
|
|
be_socket_enable,
|
|
|
|
be_socket_disable,
|
2013-04-09 18:16:13 -04:00
|
|
|
NULL, /* unlink */
|
2009-02-02 19:22:13 +00:00
|
|
|
be_socket_destruct,
|
2015-11-05 17:45:09 +03:00
|
|
|
bufferevent_generic_adj_existing_timeouts_,
|
2009-08-14 20:06:48 +00:00
|
|
|
be_socket_flush,
|
2009-05-13 20:37:21 +00:00
|
|
|
be_socket_ctrl,
|
2009-02-02 19:22:13 +00:00
|
|
|
};
|
|
|
|
|
2014-11-15 21:46:11 +03:00
|
|
|
const struct sockaddr*
|
|
|
|
bufferevent_socket_get_conn_address_(struct bufferevent *bev)
|
|
|
|
{
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bev_p = BEV_UPCAST(bev);
|
2014-11-16 00:29:19 +03:00
|
|
|
return (struct sockaddr *)&bev_p->conn_address;
|
2014-11-15 21:46:11 +03:00
|
|
|
}
|
2018-02-11 16:28:58 -08:00
|
|
|
|
|
|
|
void
|
2019-01-29 21:12:33 +03:00
|
|
|
bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev,
|
|
|
|
evutil_socket_t fd)
|
2014-11-15 21:46:11 +03:00
|
|
|
{
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bev_p = BEV_UPCAST(bev);
|
2018-02-11 16:28:58 -08:00
|
|
|
|
2014-11-16 00:29:19 +03:00
|
|
|
socklen_t len = sizeof(bev_p->conn_address);
|
2014-11-15 21:46:11 +03:00
|
|
|
|
2014-11-16 00:29:19 +03:00
|
|
|
struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address;
|
2014-11-16 00:30:11 +03:00
|
|
|
if (addr->sa_family != AF_UNSPEC)
|
|
|
|
getpeername(fd, addr, &len);
|
2014-11-15 21:46:11 +03:00
|
|
|
}
|
2018-02-11 16:28:58 -08:00
|
|
|
|
|
|
|
void
|
|
|
|
bufferevent_socket_set_conn_address_(struct bufferevent *bev,
|
2014-11-15 21:46:11 +03:00
|
|
|
struct sockaddr *addr, size_t addrlen)
|
|
|
|
{
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bev_p = BEV_UPCAST(bev);
|
2015-08-18 20:41:16 +03:00
|
|
|
EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address));
|
|
|
|
memcpy(&bev_p->conn_address, addr, addrlen);
|
2014-11-15 21:46:11 +03:00
|
|
|
}
|
|
|
|
|
2009-02-02 19:22:13 +00:00
|
|
|
static void
|
|
|
|
bufferevent_socket_outbuf_cb(struct evbuffer *buf,
|
2009-04-03 14:27:03 +00:00
|
|
|
const struct evbuffer_cb_info *cbinfo,
|
|
|
|
void *arg)
|
2009-02-02 19:22:13 +00:00
|
|
|
{
|
|
|
|
struct bufferevent *bufev = arg;
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2009-04-03 14:27:03 +00:00
|
|
|
if (cbinfo->n_added &&
|
2009-02-02 19:22:13 +00:00
|
|
|
(bufev->enabled & EV_WRITE) &&
|
2010-02-20 18:44:35 -05:00
|
|
|
!event_pending(&bufev->ev_write, EV_WRITE, NULL) &&
|
|
|
|
!bufev_p->write_suspended) {
|
2009-02-02 19:22:13 +00:00
|
|
|
/* Somebody added data to the buffer, and we would like to
|
|
|
|
* write, and we were not writing. So, start writing. */
|
2015-11-05 17:51:46 +03:00
|
|
|
if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) {
|
2011-11-21 09:41:55 +13:00
|
|
|
/* Should we log this? */
|
2011-08-27 05:48:11 -04:00
|
|
|
}
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
|
|
|
|
{
|
|
|
|
struct bufferevent *bufev = arg;
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
struct evbuffer *input;
|
|
|
|
int res = 0;
|
2009-05-13 20:36:56 +00:00
|
|
|
short what = BEV_EVENT_READING;
|
2010-10-27 22:57:53 -04:00
|
|
|
ev_ssize_t howmuch = -1, readmax=-1;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_incref_and_lock_(bufev);
|
2009-07-10 19:34:00 +00:00
|
|
|
|
2009-02-02 19:22:13 +00:00
|
|
|
if (event == EV_TIMEOUT) {
|
2012-09-07 15:53:02 -04:00
|
|
|
/* Note that we only check for event==EV_TIMEOUT. If
|
|
|
|
* event==EV_TIMEOUT|EV_READ, we can safely ignore the
|
|
|
|
* timeout, since a read has occurred */
|
2009-05-13 20:36:56 +00:00
|
|
|
what |= BEV_EVENT_TIMEOUT;
|
2009-02-02 19:22:13 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
input = bufev->input;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have a high watermark configured then we don't want to
|
|
|
|
* read more data than would make us reach the watermark.
|
|
|
|
*/
|
|
|
|
if (bufev->wm_read.high != 0) {
|
2009-04-17 06:56:09 +00:00
|
|
|
howmuch = bufev->wm_read.high - evbuffer_get_length(input);
|
2009-02-02 19:22:13 +00:00
|
|
|
/* we somehow lowered the watermark, stop reading */
|
|
|
|
if (howmuch <= 0) {
|
|
|
|
bufferevent_wm_suspend_read(bufev);
|
2009-07-10 19:34:00 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-29 15:07:32 -05:00
|
|
|
readmax = bufferevent_get_read_max_(bufev_p);
|
2009-11-27 13:16:54 -05:00
|
|
|
if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited"
|
2010-11-01 13:43:43 -04:00
|
|
|
* uglifies this code. XXXX */
|
2009-11-27 13:16:54 -05:00
|
|
|
howmuch = readmax;
|
|
|
|
if (bufev_p->read_suspended)
|
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2009-04-08 03:05:42 +00:00
|
|
|
evbuffer_unfreeze(input, 0);
|
2010-11-01 13:43:43 -04:00
|
|
|
res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */
|
2009-04-08 03:05:42 +00:00
|
|
|
evbuffer_freeze(input, 0);
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
if (res == -1) {
|
|
|
|
int err = evutil_socket_geterror(fd);
|
|
|
|
if (EVUTIL_ERR_RW_RETRIABLE(err))
|
|
|
|
goto reschedule;
|
2016-08-10 16:04:33 +03:00
|
|
|
if (EVUTIL_ERR_CONNECT_REFUSED(err)) {
|
|
|
|
bufev_p->connection_refused = 1;
|
|
|
|
goto done;
|
|
|
|
}
|
2009-02-02 19:22:13 +00:00
|
|
|
/* error case */
|
2009-05-13 20:36:56 +00:00
|
|
|
what |= BEV_EVENT_ERROR;
|
2009-02-02 19:22:13 +00:00
|
|
|
} else if (res == 0) {
|
|
|
|
/* eof case */
|
2009-05-13 20:36:56 +00:00
|
|
|
what |= BEV_EVENT_EOF;
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (res <= 0)
|
|
|
|
goto error;
|
|
|
|
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_decrement_read_buckets_(bufev_p, res);
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
/* Invoke the user callback - must always be called last */
|
2013-12-03 22:49:57 +00:00
|
|
|
bufferevent_trigger_nolock_(bufev, EV_READ, 0);
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2009-07-10 19:34:00 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
reschedule:
|
2009-07-10 19:34:00 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
error:
|
2010-02-20 18:44:35 -05:00
|
|
|
bufferevent_disable(bufev, EV_READ);
|
2013-12-03 23:01:54 +00:00
|
|
|
bufferevent_run_eventcb_(bufev, what, 0);
|
2009-07-10 19:34:00 +00:00
|
|
|
|
|
|
|
done:
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_decref_and_unlock_(bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
|
|
|
|
{
|
|
|
|
struct bufferevent *bufev = arg;
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
int res = 0;
|
2009-05-13 20:36:56 +00:00
|
|
|
short what = BEV_EVENT_WRITING;
|
2009-08-19 20:55:25 +00:00
|
|
|
int connected = 0;
|
2010-11-01 13:43:43 -04:00
|
|
|
ev_ssize_t atmost = -1;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_incref_and_lock_(bufev);
|
2009-07-10 19:34:00 +00:00
|
|
|
|
2009-02-02 19:22:13 +00:00
|
|
|
if (event == EV_TIMEOUT) {
|
2012-09-07 15:53:02 -04:00
|
|
|
/* Note that we only check for event==EV_TIMEOUT. If
|
|
|
|
* event==EV_TIMEOUT|EV_WRITE, we can safely ignore the
|
|
|
|
* timeout, since a read has occurred */
|
2009-05-13 20:36:56 +00:00
|
|
|
what |= BEV_EVENT_TIMEOUT;
|
2009-02-02 19:22:13 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2009-05-05 02:59:26 +00:00
|
|
|
if (bufev_p->connecting) {
|
2012-02-29 15:07:33 -05:00
|
|
|
int c = evutil_socket_finished_connecting_(fd);
|
2010-02-27 18:59:06 -08:00
|
|
|
/* we need to fake the error if the connection was refused
|
|
|
|
* immediately - usually connection to localhost on BSD */
|
|
|
|
if (bufev_p->connection_refused) {
|
2017-01-16 02:31:54 +03:00
|
|
|
bufev_p->connection_refused = 0;
|
|
|
|
c = -1;
|
2010-02-27 18:59:06 -08:00
|
|
|
}
|
2009-10-14 00:46:47 +00:00
|
|
|
|
|
|
|
if (c == 0)
|
|
|
|
goto done;
|
|
|
|
|
2009-05-05 02:59:26 +00:00
|
|
|
bufev_p->connecting = 0;
|
2009-10-14 00:46:47 +00:00
|
|
|
if (c < 0) {
|
2009-05-05 02:59:26 +00:00
|
|
|
event_del(&bufev->ev_write);
|
2009-10-14 00:46:47 +00:00
|
|
|
event_del(&bufev->ev_read);
|
2013-12-03 23:01:54 +00:00
|
|
|
bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0);
|
2009-07-10 19:34:00 +00:00
|
|
|
goto done;
|
2009-10-14 00:46:47 +00:00
|
|
|
} else {
|
|
|
|
connected = 1;
|
2018-02-11 16:28:58 -08:00
|
|
|
bufferevent_socket_set_conn_address_fd_(bufev, fd);
|
2011-05-25 19:50:56 -04:00
|
|
|
#ifdef _WIN32
|
2010-02-18 17:08:50 -05:00
|
|
|
if (BEV_IS_ASYNC(bufev)) {
|
2009-11-17 20:31:09 +00:00
|
|
|
event_del(&bufev->ev_write);
|
2012-02-29 15:07:33 -05:00
|
|
|
bufferevent_async_set_connected_(bufev);
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_run_eventcb_(bufev,
|
2013-12-03 23:01:54 +00:00
|
|
|
BEV_EVENT_CONNECTED, 0);
|
2009-11-17 20:31:09 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
#endif
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_run_eventcb_(bufev,
|
2013-12-03 23:01:54 +00:00
|
|
|
BEV_EVENT_CONNECTED, 0);
|
2009-12-23 07:48:43 -05:00
|
|
|
if (!(bufev->enabled & EV_WRITE) ||
|
|
|
|
bufev_p->write_suspended) {
|
2009-10-14 00:46:47 +00:00
|
|
|
event_del(&bufev->ev_write);
|
|
|
|
goto done;
|
|
|
|
}
|
2009-05-05 02:59:26 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2012-02-29 15:07:32 -05:00
|
|
|
atmost = bufferevent_get_write_max_(bufev_p);
|
2009-11-27 13:16:54 -05:00
|
|
|
|
|
|
|
if (bufev_p->write_suspended)
|
|
|
|
goto done;
|
|
|
|
|
2009-04-17 06:56:09 +00:00
|
|
|
if (evbuffer_get_length(bufev->output)) {
|
2009-08-14 20:06:48 +00:00
|
|
|
evbuffer_unfreeze(bufev->output, 1);
|
2009-11-27 13:16:54 -05:00
|
|
|
res = evbuffer_write_atmost(bufev->output, fd, atmost);
|
2009-08-14 20:06:48 +00:00
|
|
|
evbuffer_freeze(bufev->output, 1);
|
|
|
|
if (res == -1) {
|
2009-02-02 19:22:13 +00:00
|
|
|
int err = evutil_socket_geterror(fd);
|
|
|
|
if (EVUTIL_ERR_RW_RETRIABLE(err))
|
|
|
|
goto reschedule;
|
2009-08-14 20:06:48 +00:00
|
|
|
what |= BEV_EVENT_ERROR;
|
|
|
|
} else if (res == 0) {
|
|
|
|
/* eof case
|
|
|
|
XXXX Actually, a 0 on write doesn't indicate
|
|
|
|
an EOF. An ECONNRESET might be more typical.
|
|
|
|
*/
|
|
|
|
what |= BEV_EVENT_EOF;
|
|
|
|
}
|
|
|
|
if (res <= 0)
|
|
|
|
goto error;
|
2009-11-27 13:16:54 -05:00
|
|
|
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_decrement_write_buckets_(bufev_p, res);
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
2010-02-20 18:44:35 -05:00
|
|
|
if (evbuffer_get_length(bufev->output) == 0) {
|
2009-02-02 19:22:13 +00:00
|
|
|
event_del(&bufev->ev_write);
|
2010-02-20 18:44:35 -05:00
|
|
|
}
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Invoke the user callback if our buffer is drained or below the
|
|
|
|
* low watermark.
|
|
|
|
*/
|
2013-12-03 22:49:57 +00:00
|
|
|
if (res || !connected) {
|
|
|
|
bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
|
2010-02-18 14:50:44 -05:00
|
|
|
}
|
2009-02-02 19:22:13 +00:00
|
|
|
|
2009-07-10 19:34:00 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
reschedule:
|
2010-02-20 18:44:35 -05:00
|
|
|
if (evbuffer_get_length(bufev->output) == 0) {
|
2009-02-02 19:22:13 +00:00
|
|
|
event_del(&bufev->ev_write);
|
2010-02-20 18:44:35 -05:00
|
|
|
}
|
2009-07-10 19:34:00 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
error:
|
2010-02-20 18:44:35 -05:00
|
|
|
bufferevent_disable(bufev, EV_WRITE);
|
2013-12-03 23:01:54 +00:00
|
|
|
bufferevent_run_eventcb_(bufev, what, 0);
|
2009-07-10 19:34:00 +00:00
|
|
|
|
|
|
|
done:
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_decref_and_unlock_(bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct bufferevent *
|
|
|
|
bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
|
2009-10-21 18:48:22 +00:00
|
|
|
int options)
|
2009-02-02 19:22:13 +00:00
|
|
|
{
|
2009-04-13 03:08:11 +00:00
|
|
|
struct bufferevent_private *bufev_p;
|
2009-02-02 19:22:13 +00:00
|
|
|
struct bufferevent *bufev;
|
|
|
|
|
2011-05-25 19:50:56 -04:00
|
|
|
#ifdef _WIN32
|
2012-02-29 15:07:33 -05:00
|
|
|
if (base && event_base_get_iocp_(base))
|
|
|
|
return bufferevent_async_new_(base, fd, options);
|
2009-10-23 22:00:29 +00:00
|
|
|
#endif
|
|
|
|
|
2009-04-13 03:08:11 +00:00
|
|
|
if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL)
|
2009-02-02 19:22:13 +00:00
|
|
|
return NULL;
|
|
|
|
|
2012-02-29 15:07:33 -05:00
|
|
|
if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket,
|
2009-02-02 19:22:13 +00:00
|
|
|
options) < 0) {
|
2009-04-13 03:08:11 +00:00
|
|
|
mm_free(bufev_p);
|
2009-02-02 19:22:13 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-04-13 03:08:11 +00:00
|
|
|
bufev = &bufev_p->bev;
|
Prefer mmap to sendfile unless a DRAINS_TO_FD flag is set. Allows add_file to work with SSL.
The sendfile() implementation for evbuffer_add_file is potentially more
efficient, but it has a problem: you can only use it to send bytes over
a socket using sendfile(). If you are writing bytes via SSL_send() or
via a filter, or if you need to be able to inspect your buffer, it
doesn't work.
As an easy fix, this patch disables the sendfile-based implementation of
evbuffer_add_file on an evbuffer unless the user sets a new
EVBUFFER_FLAG_DRAINS_TO_FD flag on that evbuffer, indicating that the
evbuffer will not be inspected, but only written out via
evbuffer_write(), evbuffer_write_atmost(), or drained with stuff like
evbuffer_drain() or evbuffer_add_buffer(). This flag is off by
default, except for evbuffers used for output on bufferevent_socket.
In the future, it could be interesting to make a best-effort file
segment implementation that tries to send via sendfile, but mmaps on
demand. That's too much complexity for a stable release series, though.
2011-09-29 09:30:04 -04:00
|
|
|
evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD);
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
event_assign(&bufev->ev_read, bufev->ev_base, fd,
|
2013-04-09 18:16:13 -04:00
|
|
|
EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
event_assign(&bufev->ev_write, bufev->ev_base, fd,
|
2013-04-09 18:16:13 -04:00
|
|
|
EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev);
|
|
|
|
|
2009-04-08 03:05:42 +00:00
|
|
|
evbuffer_freeze(bufev->input, 0);
|
|
|
|
evbuffer_freeze(bufev->output, 1);
|
|
|
|
|
2009-02-02 19:22:13 +00:00
|
|
|
return bufev;
|
|
|
|
}
|
|
|
|
|
2009-05-05 02:59:26 +00:00
|
|
|
int
|
|
|
|
bufferevent_socket_connect(struct bufferevent *bev,
|
2014-12-02 15:05:59 +03:00
|
|
|
const struct sockaddr *sa, int socklen)
|
2009-05-05 02:59:26 +00:00
|
|
|
{
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bufev_p = BEV_UPCAST(bev);
|
2009-05-05 02:59:26 +00:00
|
|
|
|
|
|
|
evutil_socket_t fd;
|
2009-08-09 20:17:29 +00:00
|
|
|
int r = 0;
|
2009-07-28 04:03:57 +00:00
|
|
|
int result=-1;
|
2009-07-30 20:41:31 +00:00
|
|
|
int ownfd = 0;
|
2009-07-17 17:46:17 +00:00
|
|
|
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_incref_and_lock_(bev);
|
2009-05-05 02:59:26 +00:00
|
|
|
|
2009-07-28 04:03:57 +00:00
|
|
|
fd = bufferevent_getfd(bev);
|
2009-07-30 20:41:31 +00:00
|
|
|
if (fd < 0) {
|
2009-08-09 20:17:29 +00:00
|
|
|
if (!sa)
|
|
|
|
goto done;
|
2012-02-29 15:07:33 -05:00
|
|
|
fd = evutil_socket_(sa->sa_family,
|
2012-02-10 16:33:25 -05:00
|
|
|
SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0);
|
2009-07-30 20:41:31 +00:00
|
|
|
if (fd < 0)
|
2018-02-23 19:15:12 +08:00
|
|
|
goto freesock;
|
2009-07-30 20:41:31 +00:00
|
|
|
ownfd = 1;
|
|
|
|
}
|
2009-08-09 20:17:29 +00:00
|
|
|
if (sa) {
|
2011-05-25 19:50:56 -04:00
|
|
|
#ifdef _WIN32
|
2012-02-29 15:07:33 -05:00
|
|
|
if (bufferevent_async_can_connect_(bev)) {
|
2009-11-04 05:19:26 +00:00
|
|
|
bufferevent_setfd(bev, fd);
|
2012-02-29 15:07:33 -05:00
|
|
|
r = bufferevent_async_connect_(bev, fd, sa, socklen);
|
2009-11-04 05:19:26 +00:00
|
|
|
if (r < 0)
|
|
|
|
goto freesock;
|
|
|
|
bufev_p->connecting = 1;
|
|
|
|
result = 0;
|
2009-08-09 20:17:29 +00:00
|
|
|
goto done;
|
2009-11-04 05:19:26 +00:00
|
|
|
} else
|
|
|
|
#endif
|
2012-02-29 15:07:33 -05:00
|
|
|
r = evutil_socket_connect_(&fd, sa, socklen);
|
2009-11-04 05:19:26 +00:00
|
|
|
if (r < 0)
|
|
|
|
goto freesock;
|
2009-05-05 02:59:26 +00:00
|
|
|
}
|
2011-05-25 19:50:56 -04:00
|
|
|
#ifdef _WIN32
|
2009-11-04 05:19:26 +00:00
|
|
|
/* ConnectEx() isn't always around, even when IOCP is enabled.
|
|
|
|
* Here, we borrow the socket object's write handler to fall back
|
|
|
|
* on a non-blocking connect() when ConnectEx() is unavailable. */
|
|
|
|
if (BEV_IS_ASYNC(bev)) {
|
|
|
|
event_assign(&bev->ev_write, bev->ev_base, fd,
|
2013-04-09 18:16:13 -04:00
|
|
|
EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bev);
|
2009-11-04 05:19:26 +00:00
|
|
|
}
|
|
|
|
#endif
|
2009-07-28 04:03:57 +00:00
|
|
|
bufferevent_setfd(bev, fd);
|
|
|
|
if (r == 0) {
|
2009-11-04 05:19:26 +00:00
|
|
|
if (! be_socket_enable(bev, EV_WRITE)) {
|
2009-07-28 04:03:57 +00:00
|
|
|
bufev_p->connecting = 1;
|
|
|
|
result = 0;
|
|
|
|
goto done;
|
2009-05-05 02:59:26 +00:00
|
|
|
}
|
2010-02-27 22:27:13 -05:00
|
|
|
} else if (r == 1) {
|
2010-02-18 14:50:44 -05:00
|
|
|
/* The connect succeeded already. How very BSD of it. */
|
2009-07-30 20:41:31 +00:00
|
|
|
result = 0;
|
2010-02-18 14:50:44 -05:00
|
|
|
bufev_p->connecting = 1;
|
2017-01-16 02:31:54 +03:00
|
|
|
bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
|
2010-02-27 18:59:06 -08:00
|
|
|
} else {
|
|
|
|
/* The connect failed already. How very BSD of it. */
|
2010-02-27 22:27:13 -05:00
|
|
|
result = 0;
|
2017-01-16 02:31:54 +03:00
|
|
|
bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS);
|
|
|
|
bufferevent_disable(bev, EV_WRITE|EV_READ);
|
2009-05-05 02:59:26 +00:00
|
|
|
}
|
|
|
|
|
2009-11-04 05:19:26 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
freesock:
|
|
|
|
if (ownfd)
|
2010-04-14 15:42:57 -04:00
|
|
|
evutil_closesocket(fd);
|
2009-07-17 17:46:17 +00:00
|
|
|
done:
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_decref_and_unlock_(bev);
|
2009-07-17 17:46:17 +00:00
|
|
|
return result;
|
2009-05-05 02:59:26 +00:00
|
|
|
}
|
|
|
|
|
2009-11-16 22:25:46 +00:00
|
|
|
static void
|
|
|
|
bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
|
|
|
|
void *arg)
|
2009-11-03 20:40:48 +00:00
|
|
|
{
|
2009-11-16 22:25:46 +00:00
|
|
|
struct bufferevent *bev = arg;
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bev_p = BEV_UPCAST(bev);
|
2009-11-16 22:25:46 +00:00
|
|
|
int r;
|
|
|
|
BEV_LOCK(bev);
|
|
|
|
|
2012-02-29 15:07:33 -05:00
|
|
|
bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP);
|
|
|
|
bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP);
|
2010-02-20 12:55:59 -05:00
|
|
|
|
be_sock: cancel in-progress dns requests
Before this patch we didn't have such functionality and this can cause some
issues when we are cancelling HTTP request while after this we will get a
response/timeout from the NS and in this case error_cb will be called and can
damage newly started HTTP request.
We could also have problems with connect, but we don't have them since we
closes the fd in HTTP layer.
This is not so good that this is done in be_sock, but it is internal, so we can
change without pain. Plus I don't like that callback-via-evutil, but since we
have event_extra we need do like that.
And after this patch the following tests doesn't report leaks:
$ valgrind --leak-check=full --show-reachable=yes --track-fds=yes --error-exitcode=1 regress --no-fork http/cancel..
...
==10469== FILE DESCRIPTORS: 2309 open at exit.
...
==10469== HEAP SUMMARY:
==10469== in use at exit: 0 bytes in 0 blocks
==10469== total heap usage: 33,846 allocs, 33,846 frees, 4,617,651 bytes allocated
==10469==
==10469== All heap blocks were freed -- no leaks are possible
v2: do under lock
v3: reset dns request
v4: ignore EVUTIL_EAI_CANCEL in regular callback
2016-03-21 17:09:17 +03:00
|
|
|
bev_p->dns_request = NULL;
|
|
|
|
|
|
|
|
if (result == EVUTIL_EAI_CANCEL) {
|
|
|
|
bev_p->dns_error = result;
|
|
|
|
bufferevent_decref_and_unlock_(bev);
|
|
|
|
return;
|
|
|
|
}
|
2009-11-16 22:25:46 +00:00
|
|
|
if (result != 0) {
|
2010-04-24 00:06:38 -07:00
|
|
|
bev_p->dns_error = result;
|
2013-12-03 23:01:54 +00:00
|
|
|
bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_decref_and_unlock_(bev);
|
2009-11-16 22:25:46 +00:00
|
|
|
if (ai)
|
|
|
|
evutil_freeaddrinfo(ai);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX use the other addrinfos? */
|
2018-02-11 16:28:58 -08:00
|
|
|
bufferevent_socket_set_conn_address_(bev, ai->ai_addr, (int)ai->ai_addrlen);
|
2010-10-27 22:57:53 -04:00
|
|
|
r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
|
2018-02-23 19:15:12 +08:00
|
|
|
if (r < 0)
|
|
|
|
bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
|
2012-02-29 15:07:32 -05:00
|
|
|
bufferevent_decref_and_unlock_(bev);
|
2009-11-16 22:25:46 +00:00
|
|
|
evutil_freeaddrinfo(ai);
|
2009-11-03 20:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bufferevent_socket_connect_hostname(struct bufferevent *bev,
|
|
|
|
struct evdns_base *evdns_base, int family, const char *hostname, int port)
|
|
|
|
{
|
2009-11-16 22:25:46 +00:00
|
|
|
struct evutil_addrinfo hint;
|
|
|
|
memset(&hint, 0, sizeof(hint));
|
|
|
|
hint.ai_family = family;
|
|
|
|
hint.ai_protocol = IPPROTO_TCP;
|
|
|
|
hint.ai_socktype = SOCK_STREAM;
|
2009-11-03 20:40:48 +00:00
|
|
|
|
2014-12-08 17:32:07 +00:00
|
|
|
return bufferevent_socket_connect_hostname_hints(bev, evdns_base, &hint, hostname, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bufferevent_socket_connect_hostname_hints(struct bufferevent *bev,
|
|
|
|
struct evdns_base *evdns_base, const struct evutil_addrinfo *hints_in,
|
|
|
|
const char *hostname, int port)
|
|
|
|
{
|
|
|
|
char portbuf[10];
|
|
|
|
struct bufferevent_private *bev_p =
|
|
|
|
EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
|
|
|
|
|
|
|
|
if (hints_in->ai_family != AF_INET && hints_in->ai_family != AF_INET6 &&
|
|
|
|
hints_in->ai_family != AF_UNSPEC)
|
|
|
|
return -1;
|
|
|
|
if (port < 1 || port > 65535)
|
|
|
|
return -1;
|
2015-11-23 13:52:31 +03:00
|
|
|
|
|
|
|
BEV_LOCK(bev);
|
|
|
|
bev_p->dns_error = 0;
|
|
|
|
|
2014-12-08 17:32:07 +00:00
|
|
|
evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
|
|
|
|
|
2012-02-29 15:07:33 -05:00
|
|
|
bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP);
|
|
|
|
bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP);
|
2010-02-20 12:55:59 -05:00
|
|
|
|
2012-02-29 15:07:33 -05:00
|
|
|
bufferevent_incref_(bev);
|
be_sock: cancel in-progress dns requests
Before this patch we didn't have such functionality and this can cause some
issues when we are cancelling HTTP request while after this we will get a
response/timeout from the NS and in this case error_cb will be called and can
damage newly started HTTP request.
We could also have problems with connect, but we don't have them since we
closes the fd in HTTP layer.
This is not so good that this is done in be_sock, but it is internal, so we can
change without pain. Plus I don't like that callback-via-evutil, but since we
have event_extra we need do like that.
And after this patch the following tests doesn't report leaks:
$ valgrind --leak-check=full --show-reachable=yes --track-fds=yes --error-exitcode=1 regress --no-fork http/cancel..
...
==10469== FILE DESCRIPTORS: 2309 open at exit.
...
==10469== HEAP SUMMARY:
==10469== in use at exit: 0 bytes in 0 blocks
==10469== total heap usage: 33,846 allocs, 33,846 frees, 4,617,651 bytes allocated
==10469==
==10469== All heap blocks were freed -- no leaks are possible
v2: do under lock
v3: reset dns request
v4: ignore EVUTIL_EAI_CANCEL in regular callback
2016-03-21 17:09:17 +03:00
|
|
|
bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname,
|
2014-12-08 17:32:07 +00:00
|
|
|
portbuf, hints_in, bufferevent_connect_getaddrinfo_cb, bev);
|
|
|
|
|
2015-11-23 13:52:31 +03:00
|
|
|
BEV_UNLOCK(bev);
|
2009-11-03 20:40:48 +00:00
|
|
|
|
2016-03-21 16:55:59 +03:00
|
|
|
return 0;
|
2009-11-03 20:40:48 +00:00
|
|
|
}
|
|
|
|
|
2010-04-24 00:06:38 -07:00
|
|
|
int
|
|
|
|
bufferevent_socket_get_dns_error(struct bufferevent *bev)
|
|
|
|
{
|
|
|
|
int rv;
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bev_p = BEV_UPCAST(bev);
|
2010-04-24 00:06:38 -07:00
|
|
|
|
|
|
|
BEV_LOCK(bev);
|
|
|
|
rv = bev_p->dns_error;
|
2013-02-05 15:07:32 -05:00
|
|
|
BEV_UNLOCK(bev);
|
2010-04-24 00:06:38 -07:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2009-02-02 19:22:13 +00:00
|
|
|
/*
|
|
|
|
* Create a new buffered event object.
|
|
|
|
*
|
|
|
|
* The read callback is invoked whenever we read new data.
|
|
|
|
* The write callback is invoked whenever the output buffer is drained.
|
|
|
|
* The error callback is invoked on a write/read error or on EOF.
|
|
|
|
*
|
|
|
|
* Both read and write callbacks maybe NULL. The error callback is not
|
|
|
|
* allowed to be NULL and have to be provided always.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct bufferevent *
|
2009-05-13 20:36:56 +00:00
|
|
|
bufferevent_new(evutil_socket_t fd,
|
|
|
|
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
|
2009-05-25 23:11:20 +00:00
|
|
|
bufferevent_event_cb eventcb, void *cbarg)
|
2009-02-02 19:22:13 +00:00
|
|
|
{
|
|
|
|
struct bufferevent *bufev;
|
|
|
|
|
|
|
|
if (!(bufev = bufferevent_socket_new(NULL, fd, 0)))
|
|
|
|
return NULL;
|
|
|
|
|
2009-05-25 23:11:20 +00:00
|
|
|
bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg);
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
return bufev;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
be_socket_enable(struct bufferevent *bufev, short event)
|
|
|
|
{
|
2015-11-05 17:56:07 +03:00
|
|
|
if (event & EV_READ &&
|
|
|
|
bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1)
|
2009-02-02 19:22:13 +00:00
|
|
|
return -1;
|
2015-11-05 17:56:07 +03:00
|
|
|
if (event & EV_WRITE &&
|
|
|
|
bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1)
|
2009-02-02 19:22:13 +00:00
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
be_socket_disable(struct bufferevent *bufev, short event)
|
|
|
|
{
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
if (event & EV_READ) {
|
|
|
|
if (event_del(&bufev->ev_read) == -1)
|
|
|
|
return -1;
|
|
|
|
}
|
2009-05-05 02:59:26 +00:00
|
|
|
/* Don't actually disable the write if we are trying to connect. */
|
|
|
|
if ((event & EV_WRITE) && ! bufev_p->connecting) {
|
2009-02-02 19:22:13 +00:00
|
|
|
if (event_del(&bufev->ev_write) == -1)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
be_socket_destruct(struct bufferevent *bufev)
|
|
|
|
{
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
evutil_socket_t fd;
|
2017-04-13 14:58:13 -04:00
|
|
|
EVUTIL_ASSERT(BEV_IS_SOCKET(bufev));
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
fd = event_get_fd(&bufev->ev_read);
|
|
|
|
|
2010-03-12 18:36:18 -05:00
|
|
|
if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0)
|
2009-02-02 19:22:13 +00:00
|
|
|
EVUTIL_CLOSESOCKET(fd);
|
be_sock: cancel in-progress dns requests
Before this patch we didn't have such functionality and this can cause some
issues when we are cancelling HTTP request while after this we will get a
response/timeout from the NS and in this case error_cb will be called and can
damage newly started HTTP request.
We could also have problems with connect, but we don't have them since we
closes the fd in HTTP layer.
This is not so good that this is done in be_sock, but it is internal, so we can
change without pain. Plus I don't like that callback-via-evutil, but since we
have event_extra we need do like that.
And after this patch the following tests doesn't report leaks:
$ valgrind --leak-check=full --show-reachable=yes --track-fds=yes --error-exitcode=1 regress --no-fork http/cancel..
...
==10469== FILE DESCRIPTORS: 2309 open at exit.
...
==10469== HEAP SUMMARY:
==10469== in use at exit: 0 bytes in 0 blocks
==10469== total heap usage: 33,846 allocs, 33,846 frees, 4,617,651 bytes allocated
==10469==
==10469== All heap blocks were freed -- no leaks are possible
v2: do under lock
v3: reset dns request
v4: ignore EVUTIL_EAI_CANCEL in regular callback
2016-03-21 17:09:17 +03:00
|
|
|
|
|
|
|
evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
be_socket_flush(struct bufferevent *bev, short iotype,
|
|
|
|
enum bufferevent_flush_mode mode)
|
|
|
|
{
|
2009-08-14 20:06:48 +00:00
|
|
|
return 0;
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-13 20:37:21 +00:00
|
|
|
static void
|
|
|
|
be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd)
|
2009-02-02 19:22:13 +00:00
|
|
|
{
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
|
be_sock: cancel in-progress dns requests
Before this patch we didn't have such functionality and this can cause some
issues when we are cancelling HTTP request while after this we will get a
response/timeout from the NS and in this case error_cb will be called and can
damage newly started HTTP request.
We could also have problems with connect, but we don't have them since we
closes the fd in HTTP layer.
This is not so good that this is done in be_sock, but it is internal, so we can
change without pain. Plus I don't like that callback-via-evutil, but since we
have event_extra we need do like that.
And after this patch the following tests doesn't report leaks:
$ valgrind --leak-check=full --show-reachable=yes --track-fds=yes --error-exitcode=1 regress --no-fork http/cancel..
...
==10469== FILE DESCRIPTORS: 2309 open at exit.
...
==10469== HEAP SUMMARY:
==10469== in use at exit: 0 bytes in 0 blocks
==10469== total heap usage: 33,846 allocs, 33,846 frees, 4,617,651 bytes allocated
==10469==
==10469== All heap blocks were freed -- no leaks are possible
v2: do under lock
v3: reset dns request
v4: ignore EVUTIL_EAI_CANCEL in regular callback
2016-03-21 17:09:17 +03:00
|
|
|
|
2009-04-13 03:17:19 +00:00
|
|
|
BEV_LOCK(bufev);
|
2017-04-13 14:58:13 -04:00
|
|
|
EVUTIL_ASSERT(BEV_IS_SOCKET(bufev));
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
event_del(&bufev->ev_read);
|
|
|
|
event_del(&bufev->ev_write);
|
|
|
|
|
2016-03-11 13:55:41 +03:00
|
|
|
evbuffer_unfreeze(bufev->input, 0);
|
|
|
|
evbuffer_unfreeze(bufev->output, 1);
|
|
|
|
|
2009-02-02 19:22:13 +00:00
|
|
|
event_assign(&bufev->ev_read, bufev->ev_base, fd,
|
2013-04-09 18:16:13 -04:00
|
|
|
EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
event_assign(&bufev->ev_write, bufev->ev_base, fd,
|
2013-04-09 18:16:13 -04:00
|
|
|
EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
|
2009-12-24 17:47:14 -05:00
|
|
|
|
|
|
|
if (fd >= 0)
|
|
|
|
bufferevent_enable(bufev, bufev->enabled);
|
|
|
|
|
be_sock: cancel in-progress dns requests
Before this patch we didn't have such functionality and this can cause some
issues when we are cancelling HTTP request while after this we will get a
response/timeout from the NS and in this case error_cb will be called and can
damage newly started HTTP request.
We could also have problems with connect, but we don't have them since we
closes the fd in HTTP layer.
This is not so good that this is done in be_sock, but it is internal, so we can
change without pain. Plus I don't like that callback-via-evutil, but since we
have event_extra we need do like that.
And after this patch the following tests doesn't report leaks:
$ valgrind --leak-check=full --show-reachable=yes --track-fds=yes --error-exitcode=1 regress --no-fork http/cancel..
...
==10469== FILE DESCRIPTORS: 2309 open at exit.
...
==10469== HEAP SUMMARY:
==10469== in use at exit: 0 bytes in 0 blocks
==10469== total heap usage: 33,846 allocs, 33,846 frees, 4,617,651 bytes allocated
==10469==
==10469== All heap blocks were freed -- no leaks are possible
v2: do under lock
v3: reset dns request
v4: ignore EVUTIL_EAI_CANCEL in regular callback
2016-03-21 17:09:17 +03:00
|
|
|
evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
|
|
|
|
|
2009-04-13 03:17:19 +00:00
|
|
|
BEV_UNLOCK(bufev);
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 13:19:57 +00:00
|
|
|
/* XXXX Should non-socket bufferevents support this? */
|
2009-02-02 19:22:13 +00:00
|
|
|
int
|
|
|
|
bufferevent_priority_set(struct bufferevent *bufev, int priority)
|
|
|
|
{
|
2009-04-13 03:17:19 +00:00
|
|
|
int r = -1;
|
2018-11-30 22:25:41 +03:00
|
|
|
struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
|
2009-04-13 03:17:19 +00:00
|
|
|
|
|
|
|
BEV_LOCK(bufev);
|
2020-05-03 00:32:10 +00:00
|
|
|
if (BEV_IS_ASYNC(bufev) || BEV_IS_FILTER(bufev) || BEV_IS_PAIR(bufev))
|
2009-04-13 03:17:19 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
if (event_priority_set(&bufev->ev_read, priority) == -1)
|
2009-04-13 03:17:19 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
if (event_priority_set(&bufev->ev_write, priority) == -1)
|
2009-04-13 03:17:19 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
Restore our priority-inversion-prevention code with deferreds
Back when deferred_cb stuff had its own queue, the queue was always
executed, but we never ran more than 16 callbacks per iteration.
That made for two problems:
1: Because deferred_cb stuff would always run, and had no priority,
it could cause priority inversion.
2: It doesn't respect the max_dispatch_interval code.
Then, when I refactored deferred_cb to be a special case of
event_callback, that solved the above issues, but made for two more
issues:
3: Because deferred_cb stuff would always get the default priority,
it could could low-priority bufferevents to get too much priority.
4: With code like bufferevent_pair, it's easy to get into a
situation where two deferreds keep adding one another, preventing
the event loop from ever actually scanning for more events.
This commit fixes the above by giving deferreds a better notion of
priorities, and by limiting the number of deferreds that can be
added to the _current_ loop iteration's active queues. (Extra
deferreds are put into the active_later state.)
That isn't an all-purpose priority inversion solution, of course: for
that, you may need to mess around with max_dispatch_interval.
2012-05-09 11:06:06 -04:00
|
|
|
event_deferred_cb_set_priority_(&bufev_p->deferred, priority);
|
|
|
|
|
2009-04-13 03:17:19 +00:00
|
|
|
r = 0;
|
|
|
|
done:
|
|
|
|
BEV_UNLOCK(bufev);
|
|
|
|
return r;
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 13:19:57 +00:00
|
|
|
/* XXXX Should non-socket bufferevents support this? */
|
2009-02-02 19:22:13 +00:00
|
|
|
int
|
|
|
|
bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
|
|
|
|
{
|
2009-04-13 03:17:19 +00:00
|
|
|
int res = -1;
|
|
|
|
|
|
|
|
BEV_LOCK(bufev);
|
2017-04-13 14:58:13 -04:00
|
|
|
if (!BEV_IS_SOCKET(bufev))
|
2009-04-13 03:17:19 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
bufev->ev_base = base;
|
|
|
|
|
|
|
|
res = event_base_set(base, &bufev->ev_read);
|
|
|
|
if (res == -1)
|
2009-04-13 03:17:19 +00:00
|
|
|
goto done;
|
2009-02-02 19:22:13 +00:00
|
|
|
|
|
|
|
res = event_base_set(base, &bufev->ev_write);
|
2009-04-13 03:17:19 +00:00
|
|
|
done:
|
|
|
|
BEV_UNLOCK(bufev);
|
|
|
|
return res;
|
2009-02-02 19:22:13 +00:00
|
|
|
}
|
2009-05-13 20:37:21 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
|
|
|
|
union bufferevent_ctrl_data *data)
|
|
|
|
{
|
|
|
|
switch (op) {
|
|
|
|
case BEV_CTRL_SET_FD:
|
|
|
|
be_socket_setfd(bev, data->fd);
|
|
|
|
return 0;
|
|
|
|
case BEV_CTRL_GET_FD:
|
|
|
|
data->fd = event_get_fd(&bev->ev_read);
|
|
|
|
return 0;
|
|
|
|
case BEV_CTRL_GET_UNDERLYING:
|
2011-08-24 21:39:28 -04:00
|
|
|
case BEV_CTRL_CANCEL_ALL:
|
2009-05-13 20:37:21 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|