xref: /freebsd/contrib/ntp/sntp/libevent/bufferevent_sock.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
32b15cb3dSCy Schubert  * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
42b15cb3dSCy Schubert  * All rights reserved.
52b15cb3dSCy Schubert  *
62b15cb3dSCy Schubert  * Redistribution and use in source and binary forms, with or without
72b15cb3dSCy Schubert  * modification, are permitted provided that the following conditions
82b15cb3dSCy Schubert  * are met:
92b15cb3dSCy Schubert  * 1. Redistributions of source code must retain the above copyright
102b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer.
112b15cb3dSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
122b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
132b15cb3dSCy Schubert  *    documentation and/or other materials provided with the distribution.
142b15cb3dSCy Schubert  * 3. The name of the author may not be used to endorse or promote products
152b15cb3dSCy Schubert  *    derived from this software without specific prior written permission.
162b15cb3dSCy Schubert  *
172b15cb3dSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
182b15cb3dSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
192b15cb3dSCy Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
202b15cb3dSCy Schubert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
212b15cb3dSCy Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
222b15cb3dSCy Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232b15cb3dSCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242b15cb3dSCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252b15cb3dSCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
262b15cb3dSCy Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272b15cb3dSCy Schubert  */
282b15cb3dSCy Schubert 
292b15cb3dSCy Schubert #include "event2/event-config.h"
302b15cb3dSCy Schubert #include "evconfig-private.h"
312b15cb3dSCy Schubert 
322b15cb3dSCy Schubert #include <sys/types.h>
332b15cb3dSCy Schubert 
342b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_TIME_H
352b15cb3dSCy Schubert #include <sys/time.h>
362b15cb3dSCy Schubert #endif
372b15cb3dSCy Schubert 
382b15cb3dSCy Schubert #include <errno.h>
392b15cb3dSCy Schubert #include <stdio.h>
402b15cb3dSCy Schubert #include <stdlib.h>
412b15cb3dSCy Schubert #include <string.h>
422b15cb3dSCy Schubert #ifdef EVENT__HAVE_STDARG_H
432b15cb3dSCy Schubert #include <stdarg.h>
442b15cb3dSCy Schubert #endif
452b15cb3dSCy Schubert #ifdef EVENT__HAVE_UNISTD_H
462b15cb3dSCy Schubert #include <unistd.h>
472b15cb3dSCy Schubert #endif
482b15cb3dSCy Schubert 
492b15cb3dSCy Schubert #ifdef _WIN32
502b15cb3dSCy Schubert #include <winsock2.h>
512b15cb3dSCy Schubert #include <ws2tcpip.h>
522b15cb3dSCy Schubert #endif
532b15cb3dSCy Schubert 
542b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_SOCKET_H
552b15cb3dSCy Schubert #include <sys/socket.h>
562b15cb3dSCy Schubert #endif
572b15cb3dSCy Schubert #ifdef EVENT__HAVE_NETINET_IN_H
582b15cb3dSCy Schubert #include <netinet/in.h>
592b15cb3dSCy Schubert #endif
602b15cb3dSCy Schubert #ifdef EVENT__HAVE_NETINET_IN6_H
612b15cb3dSCy Schubert #include <netinet/in6.h>
622b15cb3dSCy Schubert #endif
632b15cb3dSCy Schubert 
642b15cb3dSCy Schubert #include "event2/util.h"
652b15cb3dSCy Schubert #include "event2/bufferevent.h"
662b15cb3dSCy Schubert #include "event2/buffer.h"
672b15cb3dSCy Schubert #include "event2/bufferevent_struct.h"
682b15cb3dSCy Schubert #include "event2/bufferevent_compat.h"
692b15cb3dSCy Schubert #include "event2/event.h"
702b15cb3dSCy Schubert #include "log-internal.h"
712b15cb3dSCy Schubert #include "mm-internal.h"
722b15cb3dSCy Schubert #include "bufferevent-internal.h"
732b15cb3dSCy Schubert #include "util-internal.h"
742b15cb3dSCy Schubert #ifdef _WIN32
752b15cb3dSCy Schubert #include "iocp-internal.h"
762b15cb3dSCy Schubert #endif
772b15cb3dSCy Schubert 
782b15cb3dSCy Schubert /* prototypes */
792b15cb3dSCy Schubert static int be_socket_enable(struct bufferevent *, short);
802b15cb3dSCy Schubert static int be_socket_disable(struct bufferevent *, short);
812b15cb3dSCy Schubert static void be_socket_destruct(struct bufferevent *);
822b15cb3dSCy Schubert static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
832b15cb3dSCy Schubert static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
842b15cb3dSCy Schubert 
852b15cb3dSCy Schubert static void be_socket_setfd(struct bufferevent *, evutil_socket_t);
862b15cb3dSCy Schubert 
872b15cb3dSCy Schubert const struct bufferevent_ops bufferevent_ops_socket = {
882b15cb3dSCy Schubert 	"socket",
892b15cb3dSCy Schubert 	evutil_offsetof(struct bufferevent_private, bev),
902b15cb3dSCy Schubert 	be_socket_enable,
912b15cb3dSCy Schubert 	be_socket_disable,
922b15cb3dSCy Schubert 	NULL, /* unlink */
932b15cb3dSCy Schubert 	be_socket_destruct,
94*a466cc55SCy Schubert 	bufferevent_generic_adj_existing_timeouts_,
952b15cb3dSCy Schubert 	be_socket_flush,
962b15cb3dSCy Schubert 	be_socket_ctrl,
972b15cb3dSCy Schubert };
982b15cb3dSCy Schubert 
99*a466cc55SCy Schubert const struct sockaddr*
bufferevent_socket_get_conn_address_(struct bufferevent * bev)100*a466cc55SCy Schubert bufferevent_socket_get_conn_address_(struct bufferevent *bev)
101*a466cc55SCy Schubert {
102*a466cc55SCy Schubert 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
103*a466cc55SCy Schubert 	return (struct sockaddr *)&bev_p->conn_address;
104*a466cc55SCy Schubert }
105*a466cc55SCy Schubert 
106*a466cc55SCy Schubert void
bufferevent_socket_set_conn_address_fd_(struct bufferevent * bev,evutil_socket_t fd)107*a466cc55SCy Schubert bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev,
108*a466cc55SCy Schubert 	evutil_socket_t fd)
109*a466cc55SCy Schubert {
110*a466cc55SCy Schubert 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
111*a466cc55SCy Schubert 
112*a466cc55SCy Schubert 	socklen_t len = sizeof(bev_p->conn_address);
113*a466cc55SCy Schubert 
114*a466cc55SCy Schubert 	struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address;
115*a466cc55SCy Schubert 	if (addr->sa_family != AF_UNSPEC)
116*a466cc55SCy Schubert 		getpeername(fd, addr, &len);
117*a466cc55SCy Schubert }
118*a466cc55SCy Schubert 
119*a466cc55SCy Schubert void
bufferevent_socket_set_conn_address_(struct bufferevent * bev,struct sockaddr * addr,size_t addrlen)120*a466cc55SCy Schubert bufferevent_socket_set_conn_address_(struct bufferevent *bev,
121*a466cc55SCy Schubert 	struct sockaddr *addr, size_t addrlen)
122*a466cc55SCy Schubert {
123*a466cc55SCy Schubert 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
124*a466cc55SCy Schubert 	EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address));
125*a466cc55SCy Schubert 	memcpy(&bev_p->conn_address, addr, addrlen);
126*a466cc55SCy Schubert }
1272b15cb3dSCy Schubert 
1282b15cb3dSCy Schubert static void
bufferevent_socket_outbuf_cb(struct evbuffer * buf,const struct evbuffer_cb_info * cbinfo,void * arg)1292b15cb3dSCy Schubert bufferevent_socket_outbuf_cb(struct evbuffer *buf,
1302b15cb3dSCy Schubert     const struct evbuffer_cb_info *cbinfo,
1312b15cb3dSCy Schubert     void *arg)
1322b15cb3dSCy Schubert {
1332b15cb3dSCy Schubert 	struct bufferevent *bufev = arg;
134*a466cc55SCy Schubert 	struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
1352b15cb3dSCy Schubert 
1362b15cb3dSCy Schubert 	if (cbinfo->n_added &&
1372b15cb3dSCy Schubert 	    (bufev->enabled & EV_WRITE) &&
1382b15cb3dSCy Schubert 	    !event_pending(&bufev->ev_write, EV_WRITE, NULL) &&
1392b15cb3dSCy Schubert 	    !bufev_p->write_suspended) {
1402b15cb3dSCy Schubert 		/* Somebody added data to the buffer, and we would like to
1412b15cb3dSCy Schubert 		 * write, and we were not writing.  So, start writing. */
142*a466cc55SCy Schubert 		if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) {
1432b15cb3dSCy Schubert 		    /* Should we log this? */
1442b15cb3dSCy Schubert 		}
1452b15cb3dSCy Schubert 	}
1462b15cb3dSCy Schubert }
1472b15cb3dSCy Schubert 
1482b15cb3dSCy Schubert static void
bufferevent_readcb(evutil_socket_t fd,short event,void * arg)1492b15cb3dSCy Schubert bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
1502b15cb3dSCy Schubert {
1512b15cb3dSCy Schubert 	struct bufferevent *bufev = arg;
152*a466cc55SCy Schubert 	struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
1532b15cb3dSCy Schubert 	struct evbuffer *input;
1542b15cb3dSCy Schubert 	int res = 0;
1552b15cb3dSCy Schubert 	short what = BEV_EVENT_READING;
1562b15cb3dSCy Schubert 	ev_ssize_t howmuch = -1, readmax=-1;
1572b15cb3dSCy Schubert 
1582b15cb3dSCy Schubert 	bufferevent_incref_and_lock_(bufev);
1592b15cb3dSCy Schubert 
1602b15cb3dSCy Schubert 	if (event == EV_TIMEOUT) {
1612b15cb3dSCy Schubert 		/* Note that we only check for event==EV_TIMEOUT. If
1622b15cb3dSCy Schubert 		 * event==EV_TIMEOUT|EV_READ, we can safely ignore the
1632b15cb3dSCy Schubert 		 * timeout, since a read has occurred */
1642b15cb3dSCy Schubert 		what |= BEV_EVENT_TIMEOUT;
1652b15cb3dSCy Schubert 		goto error;
1662b15cb3dSCy Schubert 	}
1672b15cb3dSCy Schubert 
1682b15cb3dSCy Schubert 	input = bufev->input;
1692b15cb3dSCy Schubert 
1702b15cb3dSCy Schubert 	/*
1712b15cb3dSCy Schubert 	 * If we have a high watermark configured then we don't want to
1722b15cb3dSCy Schubert 	 * read more data than would make us reach the watermark.
1732b15cb3dSCy Schubert 	 */
1742b15cb3dSCy Schubert 	if (bufev->wm_read.high != 0) {
1752b15cb3dSCy Schubert 		howmuch = bufev->wm_read.high - evbuffer_get_length(input);
1762b15cb3dSCy Schubert 		/* we somehow lowered the watermark, stop reading */
1772b15cb3dSCy Schubert 		if (howmuch <= 0) {
1782b15cb3dSCy Schubert 			bufferevent_wm_suspend_read(bufev);
1792b15cb3dSCy Schubert 			goto done;
1802b15cb3dSCy Schubert 		}
1812b15cb3dSCy Schubert 	}
1822b15cb3dSCy Schubert 	readmax = bufferevent_get_read_max_(bufev_p);
1832b15cb3dSCy Schubert 	if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited"
1842b15cb3dSCy Schubert 					       * uglifies this code. XXXX */
1852b15cb3dSCy Schubert 		howmuch = readmax;
1862b15cb3dSCy Schubert 	if (bufev_p->read_suspended)
1872b15cb3dSCy Schubert 		goto done;
1882b15cb3dSCy Schubert 
1892b15cb3dSCy Schubert 	evbuffer_unfreeze(input, 0);
1902b15cb3dSCy Schubert 	res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */
1912b15cb3dSCy Schubert 	evbuffer_freeze(input, 0);
1922b15cb3dSCy Schubert 
1932b15cb3dSCy Schubert 	if (res == -1) {
1942b15cb3dSCy Schubert 		int err = evutil_socket_geterror(fd);
1952b15cb3dSCy Schubert 		if (EVUTIL_ERR_RW_RETRIABLE(err))
1962b15cb3dSCy Schubert 			goto reschedule;
197*a466cc55SCy Schubert 		if (EVUTIL_ERR_CONNECT_REFUSED(err)) {
198*a466cc55SCy Schubert 			bufev_p->connection_refused = 1;
199*a466cc55SCy Schubert 			goto done;
200*a466cc55SCy Schubert 		}
2012b15cb3dSCy Schubert 		/* error case */
2022b15cb3dSCy Schubert 		what |= BEV_EVENT_ERROR;
2032b15cb3dSCy Schubert 	} else if (res == 0) {
2042b15cb3dSCy Schubert 		/* eof case */
2052b15cb3dSCy Schubert 		what |= BEV_EVENT_EOF;
2062b15cb3dSCy Schubert 	}
2072b15cb3dSCy Schubert 
2082b15cb3dSCy Schubert 	if (res <= 0)
2092b15cb3dSCy Schubert 		goto error;
2102b15cb3dSCy Schubert 
2112b15cb3dSCy Schubert 	bufferevent_decrement_read_buckets_(bufev_p, res);
2122b15cb3dSCy Schubert 
2132b15cb3dSCy Schubert 	/* Invoke the user callback - must always be called last */
2142b15cb3dSCy Schubert 	bufferevent_trigger_nolock_(bufev, EV_READ, 0);
2152b15cb3dSCy Schubert 
2162b15cb3dSCy Schubert 	goto done;
2172b15cb3dSCy Schubert 
2182b15cb3dSCy Schubert  reschedule:
2192b15cb3dSCy Schubert 	goto done;
2202b15cb3dSCy Schubert 
2212b15cb3dSCy Schubert  error:
2222b15cb3dSCy Schubert 	bufferevent_disable(bufev, EV_READ);
2232b15cb3dSCy Schubert 	bufferevent_run_eventcb_(bufev, what, 0);
2242b15cb3dSCy Schubert 
2252b15cb3dSCy Schubert  done:
2262b15cb3dSCy Schubert 	bufferevent_decref_and_unlock_(bufev);
2272b15cb3dSCy Schubert }
2282b15cb3dSCy Schubert 
2292b15cb3dSCy Schubert static void
bufferevent_writecb(evutil_socket_t fd,short event,void * arg)2302b15cb3dSCy Schubert bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
2312b15cb3dSCy Schubert {
2322b15cb3dSCy Schubert 	struct bufferevent *bufev = arg;
233*a466cc55SCy Schubert 	struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
2342b15cb3dSCy Schubert 	int res = 0;
2352b15cb3dSCy Schubert 	short what = BEV_EVENT_WRITING;
2362b15cb3dSCy Schubert 	int connected = 0;
2372b15cb3dSCy Schubert 	ev_ssize_t atmost = -1;
2382b15cb3dSCy Schubert 
2392b15cb3dSCy Schubert 	bufferevent_incref_and_lock_(bufev);
2402b15cb3dSCy Schubert 
2412b15cb3dSCy Schubert 	if (event == EV_TIMEOUT) {
2422b15cb3dSCy Schubert 		/* Note that we only check for event==EV_TIMEOUT. If
2432b15cb3dSCy Schubert 		 * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the
2442b15cb3dSCy Schubert 		 * timeout, since a read has occurred */
2452b15cb3dSCy Schubert 		what |= BEV_EVENT_TIMEOUT;
2462b15cb3dSCy Schubert 		goto error;
2472b15cb3dSCy Schubert 	}
2482b15cb3dSCy Schubert 	if (bufev_p->connecting) {
2492b15cb3dSCy Schubert 		int c = evutil_socket_finished_connecting_(fd);
2502b15cb3dSCy Schubert 		/* we need to fake the error if the connection was refused
2512b15cb3dSCy Schubert 		 * immediately - usually connection to localhost on BSD */
2522b15cb3dSCy Schubert 		if (bufev_p->connection_refused) {
2532b15cb3dSCy Schubert 			bufev_p->connection_refused = 0;
2542b15cb3dSCy Schubert 			c = -1;
2552b15cb3dSCy Schubert 		}
2562b15cb3dSCy Schubert 
2572b15cb3dSCy Schubert 		if (c == 0)
2582b15cb3dSCy Schubert 			goto done;
2592b15cb3dSCy Schubert 
2602b15cb3dSCy Schubert 		bufev_p->connecting = 0;
2612b15cb3dSCy Schubert 		if (c < 0) {
2622b15cb3dSCy Schubert 			event_del(&bufev->ev_write);
2632b15cb3dSCy Schubert 			event_del(&bufev->ev_read);
2642b15cb3dSCy Schubert 			bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0);
2652b15cb3dSCy Schubert 			goto done;
2662b15cb3dSCy Schubert 		} else {
2672b15cb3dSCy Schubert 			connected = 1;
268*a466cc55SCy Schubert 			bufferevent_socket_set_conn_address_fd_(bufev, fd);
2692b15cb3dSCy Schubert #ifdef _WIN32
2702b15cb3dSCy Schubert 			if (BEV_IS_ASYNC(bufev)) {
2712b15cb3dSCy Schubert 				event_del(&bufev->ev_write);
2722b15cb3dSCy Schubert 				bufferevent_async_set_connected_(bufev);
2732b15cb3dSCy Schubert 				bufferevent_run_eventcb_(bufev,
2742b15cb3dSCy Schubert 						BEV_EVENT_CONNECTED, 0);
2752b15cb3dSCy Schubert 				goto done;
2762b15cb3dSCy Schubert 			}
2772b15cb3dSCy Schubert #endif
2782b15cb3dSCy Schubert 			bufferevent_run_eventcb_(bufev,
2792b15cb3dSCy Schubert 					BEV_EVENT_CONNECTED, 0);
2802b15cb3dSCy Schubert 			if (!(bufev->enabled & EV_WRITE) ||
2812b15cb3dSCy Schubert 			    bufev_p->write_suspended) {
2822b15cb3dSCy Schubert 				event_del(&bufev->ev_write);
2832b15cb3dSCy Schubert 				goto done;
2842b15cb3dSCy Schubert 			}
2852b15cb3dSCy Schubert 		}
2862b15cb3dSCy Schubert 	}
2872b15cb3dSCy Schubert 
2882b15cb3dSCy Schubert 	atmost = bufferevent_get_write_max_(bufev_p);
2892b15cb3dSCy Schubert 
2902b15cb3dSCy Schubert 	if (bufev_p->write_suspended)
2912b15cb3dSCy Schubert 		goto done;
2922b15cb3dSCy Schubert 
2932b15cb3dSCy Schubert 	if (evbuffer_get_length(bufev->output)) {
2942b15cb3dSCy Schubert 		evbuffer_unfreeze(bufev->output, 1);
2952b15cb3dSCy Schubert 		res = evbuffer_write_atmost(bufev->output, fd, atmost);
2962b15cb3dSCy Schubert 		evbuffer_freeze(bufev->output, 1);
2972b15cb3dSCy Schubert 		if (res == -1) {
2982b15cb3dSCy Schubert 			int err = evutil_socket_geterror(fd);
2992b15cb3dSCy Schubert 			if (EVUTIL_ERR_RW_RETRIABLE(err))
3002b15cb3dSCy Schubert 				goto reschedule;
3012b15cb3dSCy Schubert 			what |= BEV_EVENT_ERROR;
3022b15cb3dSCy Schubert 		} else if (res == 0) {
3032b15cb3dSCy Schubert 			/* eof case
3042b15cb3dSCy Schubert 			   XXXX Actually, a 0 on write doesn't indicate
3052b15cb3dSCy Schubert 			   an EOF. An ECONNRESET might be more typical.
3062b15cb3dSCy Schubert 			 */
3072b15cb3dSCy Schubert 			what |= BEV_EVENT_EOF;
3082b15cb3dSCy Schubert 		}
3092b15cb3dSCy Schubert 		if (res <= 0)
3102b15cb3dSCy Schubert 			goto error;
3112b15cb3dSCy Schubert 
3122b15cb3dSCy Schubert 		bufferevent_decrement_write_buckets_(bufev_p, res);
3132b15cb3dSCy Schubert 	}
3142b15cb3dSCy Schubert 
3152b15cb3dSCy Schubert 	if (evbuffer_get_length(bufev->output) == 0) {
3162b15cb3dSCy Schubert 		event_del(&bufev->ev_write);
3172b15cb3dSCy Schubert 	}
3182b15cb3dSCy Schubert 
3192b15cb3dSCy Schubert 	/*
3202b15cb3dSCy Schubert 	 * Invoke the user callback if our buffer is drained or below the
3212b15cb3dSCy Schubert 	 * low watermark.
3222b15cb3dSCy Schubert 	 */
3232b15cb3dSCy Schubert 	if (res || !connected) {
3242b15cb3dSCy Schubert 		bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
3252b15cb3dSCy Schubert 	}
3262b15cb3dSCy Schubert 
3272b15cb3dSCy Schubert 	goto done;
3282b15cb3dSCy Schubert 
3292b15cb3dSCy Schubert  reschedule:
3302b15cb3dSCy Schubert 	if (evbuffer_get_length(bufev->output) == 0) {
3312b15cb3dSCy Schubert 		event_del(&bufev->ev_write);
3322b15cb3dSCy Schubert 	}
3332b15cb3dSCy Schubert 	goto done;
3342b15cb3dSCy Schubert 
3352b15cb3dSCy Schubert  error:
3362b15cb3dSCy Schubert 	bufferevent_disable(bufev, EV_WRITE);
3372b15cb3dSCy Schubert 	bufferevent_run_eventcb_(bufev, what, 0);
3382b15cb3dSCy Schubert 
3392b15cb3dSCy Schubert  done:
3402b15cb3dSCy Schubert 	bufferevent_decref_and_unlock_(bufev);
3412b15cb3dSCy Schubert }
3422b15cb3dSCy Schubert 
3432b15cb3dSCy Schubert struct bufferevent *
bufferevent_socket_new(struct event_base * base,evutil_socket_t fd,int options)3442b15cb3dSCy Schubert bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
3452b15cb3dSCy Schubert     int options)
3462b15cb3dSCy Schubert {
3472b15cb3dSCy Schubert 	struct bufferevent_private *bufev_p;
3482b15cb3dSCy Schubert 	struct bufferevent *bufev;
3492b15cb3dSCy Schubert 
3502b15cb3dSCy Schubert #ifdef _WIN32
3512b15cb3dSCy Schubert 	if (base && event_base_get_iocp_(base))
3522b15cb3dSCy Schubert 		return bufferevent_async_new_(base, fd, options);
3532b15cb3dSCy Schubert #endif
3542b15cb3dSCy Schubert 
3552b15cb3dSCy Schubert 	if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL)
3562b15cb3dSCy Schubert 		return NULL;
3572b15cb3dSCy Schubert 
3582b15cb3dSCy Schubert 	if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket,
3592b15cb3dSCy Schubert 				    options) < 0) {
3602b15cb3dSCy Schubert 		mm_free(bufev_p);
3612b15cb3dSCy Schubert 		return NULL;
3622b15cb3dSCy Schubert 	}
3632b15cb3dSCy Schubert 	bufev = &bufev_p->bev;
3642b15cb3dSCy Schubert 	evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD);
3652b15cb3dSCy Schubert 
3662b15cb3dSCy Schubert 	event_assign(&bufev->ev_read, bufev->ev_base, fd,
3672b15cb3dSCy Schubert 	    EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
3682b15cb3dSCy Schubert 	event_assign(&bufev->ev_write, bufev->ev_base, fd,
3692b15cb3dSCy Schubert 	    EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
3702b15cb3dSCy Schubert 
3712b15cb3dSCy Schubert 	evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev);
3722b15cb3dSCy Schubert 
3732b15cb3dSCy Schubert 	evbuffer_freeze(bufev->input, 0);
3742b15cb3dSCy Schubert 	evbuffer_freeze(bufev->output, 1);
3752b15cb3dSCy Schubert 
3762b15cb3dSCy Schubert 	return bufev;
3772b15cb3dSCy Schubert }
3782b15cb3dSCy Schubert 
3792b15cb3dSCy Schubert int
bufferevent_socket_connect(struct bufferevent * bev,const struct sockaddr * sa,int socklen)3802b15cb3dSCy Schubert bufferevent_socket_connect(struct bufferevent *bev,
381*a466cc55SCy Schubert     const struct sockaddr *sa, int socklen)
3822b15cb3dSCy Schubert {
383*a466cc55SCy Schubert 	struct bufferevent_private *bufev_p = BEV_UPCAST(bev);
3842b15cb3dSCy Schubert 
3852b15cb3dSCy Schubert 	evutil_socket_t fd;
3862b15cb3dSCy Schubert 	int r = 0;
3872b15cb3dSCy Schubert 	int result=-1;
3882b15cb3dSCy Schubert 	int ownfd = 0;
3892b15cb3dSCy Schubert 
3902b15cb3dSCy Schubert 	bufferevent_incref_and_lock_(bev);
3912b15cb3dSCy Schubert 
3922b15cb3dSCy Schubert 	fd = bufferevent_getfd(bev);
3932b15cb3dSCy Schubert 	if (fd < 0) {
3942b15cb3dSCy Schubert 		if (!sa)
3952b15cb3dSCy Schubert 			goto done;
3962b15cb3dSCy Schubert 		fd = evutil_socket_(sa->sa_family,
3972b15cb3dSCy Schubert 		    SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0);
3982b15cb3dSCy Schubert 		if (fd < 0)
399*a466cc55SCy Schubert 			goto freesock;
4002b15cb3dSCy Schubert 		ownfd = 1;
4012b15cb3dSCy Schubert 	}
4022b15cb3dSCy Schubert 	if (sa) {
4032b15cb3dSCy Schubert #ifdef _WIN32
4042b15cb3dSCy Schubert 		if (bufferevent_async_can_connect_(bev)) {
4052b15cb3dSCy Schubert 			bufferevent_setfd(bev, fd);
4062b15cb3dSCy Schubert 			r = bufferevent_async_connect_(bev, fd, sa, socklen);
4072b15cb3dSCy Schubert 			if (r < 0)
4082b15cb3dSCy Schubert 				goto freesock;
4092b15cb3dSCy Schubert 			bufev_p->connecting = 1;
4102b15cb3dSCy Schubert 			result = 0;
4112b15cb3dSCy Schubert 			goto done;
4122b15cb3dSCy Schubert 		} else
4132b15cb3dSCy Schubert #endif
4142b15cb3dSCy Schubert 		r = evutil_socket_connect_(&fd, sa, socklen);
4152b15cb3dSCy Schubert 		if (r < 0)
4162b15cb3dSCy Schubert 			goto freesock;
4172b15cb3dSCy Schubert 	}
4182b15cb3dSCy Schubert #ifdef _WIN32
4192b15cb3dSCy Schubert 	/* ConnectEx() isn't always around, even when IOCP is enabled.
4202b15cb3dSCy Schubert 	 * Here, we borrow the socket object's write handler to fall back
4212b15cb3dSCy Schubert 	 * on a non-blocking connect() when ConnectEx() is unavailable. */
4222b15cb3dSCy Schubert 	if (BEV_IS_ASYNC(bev)) {
4232b15cb3dSCy Schubert 		event_assign(&bev->ev_write, bev->ev_base, fd,
4242b15cb3dSCy Schubert 		    EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bev);
4252b15cb3dSCy Schubert 	}
4262b15cb3dSCy Schubert #endif
4272b15cb3dSCy Schubert 	bufferevent_setfd(bev, fd);
4282b15cb3dSCy Schubert 	if (r == 0) {
4292b15cb3dSCy Schubert 		if (! be_socket_enable(bev, EV_WRITE)) {
4302b15cb3dSCy Schubert 			bufev_p->connecting = 1;
4312b15cb3dSCy Schubert 			result = 0;
4322b15cb3dSCy Schubert 			goto done;
4332b15cb3dSCy Schubert 		}
4342b15cb3dSCy Schubert 	} else if (r == 1) {
4352b15cb3dSCy Schubert 		/* The connect succeeded already. How very BSD of it. */
4362b15cb3dSCy Schubert 		result = 0;
4372b15cb3dSCy Schubert 		bufev_p->connecting = 1;
438*a466cc55SCy Schubert 		bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
4392b15cb3dSCy Schubert 	} else {
4402b15cb3dSCy Schubert 		/* The connect failed already.  How very BSD of it. */
4412b15cb3dSCy Schubert 		result = 0;
442*a466cc55SCy Schubert 		bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS);
443*a466cc55SCy Schubert 		bufferevent_disable(bev, EV_WRITE|EV_READ);
4442b15cb3dSCy Schubert 	}
4452b15cb3dSCy Schubert 
4462b15cb3dSCy Schubert 	goto done;
4472b15cb3dSCy Schubert 
4482b15cb3dSCy Schubert freesock:
4492b15cb3dSCy Schubert 	if (ownfd)
4502b15cb3dSCy Schubert 		evutil_closesocket(fd);
4512b15cb3dSCy Schubert done:
4522b15cb3dSCy Schubert 	bufferevent_decref_and_unlock_(bev);
4532b15cb3dSCy Schubert 	return result;
4542b15cb3dSCy Schubert }
4552b15cb3dSCy Schubert 
4562b15cb3dSCy Schubert static void
bufferevent_connect_getaddrinfo_cb(int result,struct evutil_addrinfo * ai,void * arg)4572b15cb3dSCy Schubert bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
4582b15cb3dSCy Schubert     void *arg)
4592b15cb3dSCy Schubert {
4602b15cb3dSCy Schubert 	struct bufferevent *bev = arg;
461*a466cc55SCy Schubert 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
4622b15cb3dSCy Schubert 	int r;
4632b15cb3dSCy Schubert 	BEV_LOCK(bev);
4642b15cb3dSCy Schubert 
4652b15cb3dSCy Schubert 	bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP);
4662b15cb3dSCy Schubert 	bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP);
4672b15cb3dSCy Schubert 
468*a466cc55SCy Schubert 	bev_p->dns_request = NULL;
469*a466cc55SCy Schubert 
470*a466cc55SCy Schubert 	if (result == EVUTIL_EAI_CANCEL) {
471*a466cc55SCy Schubert 		bev_p->dns_error = result;
472*a466cc55SCy Schubert 		bufferevent_decref_and_unlock_(bev);
473*a466cc55SCy Schubert 		return;
474*a466cc55SCy Schubert 	}
4752b15cb3dSCy Schubert 	if (result != 0) {
4762b15cb3dSCy Schubert 		bev_p->dns_error = result;
4772b15cb3dSCy Schubert 		bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
4782b15cb3dSCy Schubert 		bufferevent_decref_and_unlock_(bev);
4792b15cb3dSCy Schubert 		if (ai)
4802b15cb3dSCy Schubert 			evutil_freeaddrinfo(ai);
4812b15cb3dSCy Schubert 		return;
4822b15cb3dSCy Schubert 	}
4832b15cb3dSCy Schubert 
4842b15cb3dSCy Schubert 	/* XXX use the other addrinfos? */
485*a466cc55SCy Schubert 	bufferevent_socket_set_conn_address_(bev, ai->ai_addr, (int)ai->ai_addrlen);
4862b15cb3dSCy Schubert 	r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
487*a466cc55SCy Schubert 	if (r < 0)
488*a466cc55SCy Schubert 		bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
4892b15cb3dSCy Schubert 	bufferevent_decref_and_unlock_(bev);
4902b15cb3dSCy Schubert 	evutil_freeaddrinfo(ai);
4912b15cb3dSCy Schubert }
4922b15cb3dSCy Schubert 
4932b15cb3dSCy Schubert int
bufferevent_socket_connect_hostname(struct bufferevent * bev,struct evdns_base * evdns_base,int family,const char * hostname,int port)4942b15cb3dSCy Schubert bufferevent_socket_connect_hostname(struct bufferevent *bev,
4952b15cb3dSCy Schubert     struct evdns_base *evdns_base, int family, const char *hostname, int port)
4962b15cb3dSCy Schubert {
4972b15cb3dSCy Schubert 	char portbuf[10];
4982b15cb3dSCy Schubert 	struct evutil_addrinfo hint;
499*a466cc55SCy Schubert 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
5002b15cb3dSCy Schubert 
5012b15cb3dSCy Schubert 	if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
5022b15cb3dSCy Schubert 		return -1;
5032b15cb3dSCy Schubert 	if (port < 1 || port > 65535)
5042b15cb3dSCy Schubert 		return -1;
5052b15cb3dSCy Schubert 
5062b15cb3dSCy Schubert 	memset(&hint, 0, sizeof(hint));
5072b15cb3dSCy Schubert 	hint.ai_family = family;
5082b15cb3dSCy Schubert 	hint.ai_protocol = IPPROTO_TCP;
5092b15cb3dSCy Schubert 	hint.ai_socktype = SOCK_STREAM;
5102b15cb3dSCy Schubert 
511*a466cc55SCy Schubert 	evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
512*a466cc55SCy Schubert 
513*a466cc55SCy Schubert 	BEV_LOCK(bev);
514*a466cc55SCy Schubert 	bev_p->dns_error = 0;
515*a466cc55SCy Schubert 
5162b15cb3dSCy Schubert 	bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP);
5172b15cb3dSCy Schubert 	bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP);
5182b15cb3dSCy Schubert 
5192b15cb3dSCy Schubert 	bufferevent_incref_(bev);
520*a466cc55SCy Schubert 	bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname,
521*a466cc55SCy Schubert 	    portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev);
522*a466cc55SCy Schubert 	BEV_UNLOCK(bev);
5232b15cb3dSCy Schubert 
5242b15cb3dSCy Schubert 	return 0;
5252b15cb3dSCy Schubert }
5262b15cb3dSCy Schubert 
5272b15cb3dSCy Schubert int
bufferevent_socket_get_dns_error(struct bufferevent * bev)5282b15cb3dSCy Schubert bufferevent_socket_get_dns_error(struct bufferevent *bev)
5292b15cb3dSCy Schubert {
5302b15cb3dSCy Schubert 	int rv;
531*a466cc55SCy Schubert 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
5322b15cb3dSCy Schubert 
5332b15cb3dSCy Schubert 	BEV_LOCK(bev);
5342b15cb3dSCy Schubert 	rv = bev_p->dns_error;
5352b15cb3dSCy Schubert 	BEV_UNLOCK(bev);
5362b15cb3dSCy Schubert 
5372b15cb3dSCy Schubert 	return rv;
5382b15cb3dSCy Schubert }
5392b15cb3dSCy Schubert 
5402b15cb3dSCy Schubert /*
5412b15cb3dSCy Schubert  * Create a new buffered event object.
5422b15cb3dSCy Schubert  *
5432b15cb3dSCy Schubert  * The read callback is invoked whenever we read new data.
5442b15cb3dSCy Schubert  * The write callback is invoked whenever the output buffer is drained.
5452b15cb3dSCy Schubert  * The error callback is invoked on a write/read error or on EOF.
5462b15cb3dSCy Schubert  *
5472b15cb3dSCy Schubert  * Both read and write callbacks maybe NULL.  The error callback is not
5482b15cb3dSCy Schubert  * allowed to be NULL and have to be provided always.
5492b15cb3dSCy Schubert  */
5502b15cb3dSCy Schubert 
5512b15cb3dSCy Schubert struct bufferevent *
bufferevent_new(evutil_socket_t fd,bufferevent_data_cb readcb,bufferevent_data_cb writecb,bufferevent_event_cb eventcb,void * cbarg)5522b15cb3dSCy Schubert bufferevent_new(evutil_socket_t fd,
5532b15cb3dSCy Schubert     bufferevent_data_cb readcb, bufferevent_data_cb writecb,
5542b15cb3dSCy Schubert     bufferevent_event_cb eventcb, void *cbarg)
5552b15cb3dSCy Schubert {
5562b15cb3dSCy Schubert 	struct bufferevent *bufev;
5572b15cb3dSCy Schubert 
5582b15cb3dSCy Schubert 	if (!(bufev = bufferevent_socket_new(NULL, fd, 0)))
5592b15cb3dSCy Schubert 		return NULL;
5602b15cb3dSCy Schubert 
5612b15cb3dSCy Schubert 	bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg);
5622b15cb3dSCy Schubert 
5632b15cb3dSCy Schubert 	return bufev;
5642b15cb3dSCy Schubert }
5652b15cb3dSCy Schubert 
5662b15cb3dSCy Schubert 
5672b15cb3dSCy Schubert static int
be_socket_enable(struct bufferevent * bufev,short event)5682b15cb3dSCy Schubert be_socket_enable(struct bufferevent *bufev, short event)
5692b15cb3dSCy Schubert {
570*a466cc55SCy Schubert 	if (event & EV_READ &&
571*a466cc55SCy Schubert 	    bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1)
5722b15cb3dSCy Schubert 			return -1;
573*a466cc55SCy Schubert 	if (event & EV_WRITE &&
574*a466cc55SCy Schubert 	    bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1)
5752b15cb3dSCy Schubert 			return -1;
5762b15cb3dSCy Schubert 	return 0;
5772b15cb3dSCy Schubert }
5782b15cb3dSCy Schubert 
5792b15cb3dSCy Schubert static int
be_socket_disable(struct bufferevent * bufev,short event)5802b15cb3dSCy Schubert be_socket_disable(struct bufferevent *bufev, short event)
5812b15cb3dSCy Schubert {
582*a466cc55SCy Schubert 	struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
5832b15cb3dSCy Schubert 	if (event & EV_READ) {
5842b15cb3dSCy Schubert 		if (event_del(&bufev->ev_read) == -1)
5852b15cb3dSCy Schubert 			return -1;
5862b15cb3dSCy Schubert 	}
5872b15cb3dSCy Schubert 	/* Don't actually disable the write if we are trying to connect. */
5882b15cb3dSCy Schubert 	if ((event & EV_WRITE) && ! bufev_p->connecting) {
5892b15cb3dSCy Schubert 		if (event_del(&bufev->ev_write) == -1)
5902b15cb3dSCy Schubert 			return -1;
5912b15cb3dSCy Schubert 	}
5922b15cb3dSCy Schubert 	return 0;
5932b15cb3dSCy Schubert }
5942b15cb3dSCy Schubert 
5952b15cb3dSCy Schubert static void
be_socket_destruct(struct bufferevent * bufev)5962b15cb3dSCy Schubert be_socket_destruct(struct bufferevent *bufev)
5972b15cb3dSCy Schubert {
598*a466cc55SCy Schubert 	struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
5992b15cb3dSCy Schubert 	evutil_socket_t fd;
600*a466cc55SCy Schubert 	EVUTIL_ASSERT(BEV_IS_SOCKET(bufev));
6012b15cb3dSCy Schubert 
6022b15cb3dSCy Schubert 	fd = event_get_fd(&bufev->ev_read);
6032b15cb3dSCy Schubert 
6042b15cb3dSCy Schubert 	if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0)
6052b15cb3dSCy Schubert 		EVUTIL_CLOSESOCKET(fd);
6062b15cb3dSCy Schubert 
607*a466cc55SCy Schubert 	evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
6082b15cb3dSCy Schubert }
6092b15cb3dSCy Schubert 
6102b15cb3dSCy Schubert static int
be_socket_flush(struct bufferevent * bev,short iotype,enum bufferevent_flush_mode mode)6112b15cb3dSCy Schubert be_socket_flush(struct bufferevent *bev, short iotype,
6122b15cb3dSCy Schubert     enum bufferevent_flush_mode mode)
6132b15cb3dSCy Schubert {
6142b15cb3dSCy Schubert 	return 0;
6152b15cb3dSCy Schubert }
6162b15cb3dSCy Schubert 
6172b15cb3dSCy Schubert 
6182b15cb3dSCy Schubert static void
be_socket_setfd(struct bufferevent * bufev,evutil_socket_t fd)6192b15cb3dSCy Schubert be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd)
6202b15cb3dSCy Schubert {
621*a466cc55SCy Schubert 	struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
622*a466cc55SCy Schubert 
6232b15cb3dSCy Schubert 	BEV_LOCK(bufev);
624*a466cc55SCy Schubert 	EVUTIL_ASSERT(BEV_IS_SOCKET(bufev));
6252b15cb3dSCy Schubert 
6262b15cb3dSCy Schubert 	event_del(&bufev->ev_read);
6272b15cb3dSCy Schubert 	event_del(&bufev->ev_write);
6282b15cb3dSCy Schubert 
629*a466cc55SCy Schubert 	evbuffer_unfreeze(bufev->input, 0);
630*a466cc55SCy Schubert 	evbuffer_unfreeze(bufev->output, 1);
631*a466cc55SCy Schubert 
6322b15cb3dSCy Schubert 	event_assign(&bufev->ev_read, bufev->ev_base, fd,
6332b15cb3dSCy Schubert 	    EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
6342b15cb3dSCy Schubert 	event_assign(&bufev->ev_write, bufev->ev_base, fd,
6352b15cb3dSCy Schubert 	    EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
6362b15cb3dSCy Schubert 
6372b15cb3dSCy Schubert 	if (fd >= 0)
6382b15cb3dSCy Schubert 		bufferevent_enable(bufev, bufev->enabled);
6392b15cb3dSCy Schubert 
640*a466cc55SCy Schubert 	evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
641*a466cc55SCy Schubert 
6422b15cb3dSCy Schubert 	BEV_UNLOCK(bufev);
6432b15cb3dSCy Schubert }
6442b15cb3dSCy Schubert 
6452b15cb3dSCy Schubert /* XXXX Should non-socket bufferevents support this? */
6462b15cb3dSCy Schubert int
bufferevent_priority_set(struct bufferevent * bufev,int priority)6472b15cb3dSCy Schubert bufferevent_priority_set(struct bufferevent *bufev, int priority)
6482b15cb3dSCy Schubert {
6492b15cb3dSCy Schubert 	int r = -1;
650*a466cc55SCy Schubert 	struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
6512b15cb3dSCy Schubert 
6522b15cb3dSCy Schubert 	BEV_LOCK(bufev);
653*a466cc55SCy Schubert 	if (BEV_IS_ASYNC(bufev) || BEV_IS_FILTER(bufev) || BEV_IS_PAIR(bufev))
6542b15cb3dSCy Schubert 		goto done;
6552b15cb3dSCy Schubert 
6562b15cb3dSCy Schubert 	if (event_priority_set(&bufev->ev_read, priority) == -1)
6572b15cb3dSCy Schubert 		goto done;
6582b15cb3dSCy Schubert 	if (event_priority_set(&bufev->ev_write, priority) == -1)
6592b15cb3dSCy Schubert 		goto done;
6602b15cb3dSCy Schubert 
6612b15cb3dSCy Schubert 	event_deferred_cb_set_priority_(&bufev_p->deferred, priority);
6622b15cb3dSCy Schubert 
6632b15cb3dSCy Schubert 	r = 0;
6642b15cb3dSCy Schubert done:
6652b15cb3dSCy Schubert 	BEV_UNLOCK(bufev);
6662b15cb3dSCy Schubert 	return r;
6672b15cb3dSCy Schubert }
6682b15cb3dSCy Schubert 
6692b15cb3dSCy Schubert /* XXXX Should non-socket bufferevents support this? */
6702b15cb3dSCy Schubert int
bufferevent_base_set(struct event_base * base,struct bufferevent * bufev)6712b15cb3dSCy Schubert bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
6722b15cb3dSCy Schubert {
6732b15cb3dSCy Schubert 	int res = -1;
6742b15cb3dSCy Schubert 
6752b15cb3dSCy Schubert 	BEV_LOCK(bufev);
676*a466cc55SCy Schubert 	if (!BEV_IS_SOCKET(bufev))
6772b15cb3dSCy Schubert 		goto done;
6782b15cb3dSCy Schubert 
6792b15cb3dSCy Schubert 	bufev->ev_base = base;
6802b15cb3dSCy Schubert 
6812b15cb3dSCy Schubert 	res = event_base_set(base, &bufev->ev_read);
6822b15cb3dSCy Schubert 	if (res == -1)
6832b15cb3dSCy Schubert 		goto done;
6842b15cb3dSCy Schubert 
6852b15cb3dSCy Schubert 	res = event_base_set(base, &bufev->ev_write);
6862b15cb3dSCy Schubert done:
6872b15cb3dSCy Schubert 	BEV_UNLOCK(bufev);
6882b15cb3dSCy Schubert 	return res;
6892b15cb3dSCy Schubert }
6902b15cb3dSCy Schubert 
6912b15cb3dSCy Schubert static int
be_socket_ctrl(struct bufferevent * bev,enum bufferevent_ctrl_op op,union bufferevent_ctrl_data * data)6922b15cb3dSCy Schubert be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
6932b15cb3dSCy Schubert     union bufferevent_ctrl_data *data)
6942b15cb3dSCy Schubert {
6952b15cb3dSCy Schubert 	switch (op) {
6962b15cb3dSCy Schubert 	case BEV_CTRL_SET_FD:
6972b15cb3dSCy Schubert 		be_socket_setfd(bev, data->fd);
6982b15cb3dSCy Schubert 		return 0;
6992b15cb3dSCy Schubert 	case BEV_CTRL_GET_FD:
7002b15cb3dSCy Schubert 		data->fd = event_get_fd(&bev->ev_read);
7012b15cb3dSCy Schubert 		return 0;
7022b15cb3dSCy Schubert 	case BEV_CTRL_GET_UNDERLYING:
7032b15cb3dSCy Schubert 	case BEV_CTRL_CANCEL_ALL:
7042b15cb3dSCy Schubert 	default:
7052b15cb3dSCy Schubert 		return -1;
7062b15cb3dSCy Schubert 	}
7072b15cb3dSCy Schubert }
708