xref: /freebsd/contrib/ntp/sntp/libevent/bufferevent_pair.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
32b15cb3dSCy Schubert  *
42b15cb3dSCy Schubert  * Redistribution and use in source and binary forms, with or without
52b15cb3dSCy Schubert  * modification, are permitted provided that the following conditions
62b15cb3dSCy Schubert  * are met:
72b15cb3dSCy Schubert  * 1. Redistributions of source code must retain the above copyright
82b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer.
92b15cb3dSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
102b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
112b15cb3dSCy Schubert  *    documentation and/or other materials provided with the distribution.
122b15cb3dSCy Schubert  * 3. The name of the author may not be used to endorse or promote products
132b15cb3dSCy Schubert  *    derived from this software without specific prior written permission.
142b15cb3dSCy Schubert  *
152b15cb3dSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162b15cb3dSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
172b15cb3dSCy Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
182b15cb3dSCy Schubert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
192b15cb3dSCy Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
202b15cb3dSCy Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
212b15cb3dSCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
222b15cb3dSCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
232b15cb3dSCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
242b15cb3dSCy Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
252b15cb3dSCy Schubert  */
262b15cb3dSCy Schubert #include "event2/event-config.h"
272b15cb3dSCy Schubert #include "evconfig-private.h"
282b15cb3dSCy Schubert 
292b15cb3dSCy Schubert #include <sys/types.h>
302b15cb3dSCy Schubert 
312b15cb3dSCy Schubert #ifdef _WIN32
322b15cb3dSCy Schubert #include <winsock2.h>
332b15cb3dSCy Schubert #endif
342b15cb3dSCy Schubert 
352b15cb3dSCy Schubert #include "event2/util.h"
362b15cb3dSCy Schubert #include "event2/buffer.h"
372b15cb3dSCy Schubert #include "event2/bufferevent.h"
382b15cb3dSCy Schubert #include "event2/bufferevent_struct.h"
392b15cb3dSCy Schubert #include "event2/event.h"
402b15cb3dSCy Schubert #include "defer-internal.h"
412b15cb3dSCy Schubert #include "bufferevent-internal.h"
422b15cb3dSCy Schubert #include "mm-internal.h"
432b15cb3dSCy Schubert #include "util-internal.h"
442b15cb3dSCy Schubert 
452b15cb3dSCy Schubert struct bufferevent_pair {
462b15cb3dSCy Schubert 	struct bufferevent_private bev;
472b15cb3dSCy Schubert 	struct bufferevent_pair *partner;
48a25439b6SCy Schubert 	/* For ->destruct() lock checking */
49a25439b6SCy Schubert 	struct bufferevent_pair *unlinked_partner;
502b15cb3dSCy Schubert };
512b15cb3dSCy Schubert 
522b15cb3dSCy Schubert 
532b15cb3dSCy Schubert /* Given a bufferevent that's really a bev part of a bufferevent_pair,
542b15cb3dSCy Schubert  * return that bufferevent_filtered. Returns NULL otherwise.*/
552b15cb3dSCy Schubert static inline struct bufferevent_pair *
upcast(struct bufferevent * bev)562b15cb3dSCy Schubert upcast(struct bufferevent *bev)
572b15cb3dSCy Schubert {
582b15cb3dSCy Schubert 	struct bufferevent_pair *bev_p;
59*a466cc55SCy Schubert 	if (!BEV_IS_PAIR(bev))
602b15cb3dSCy Schubert 		return NULL;
612b15cb3dSCy Schubert 	bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev.bev);
62*a466cc55SCy Schubert 	EVUTIL_ASSERT(BEV_IS_PAIR(&bev_p->bev.bev));
632b15cb3dSCy Schubert 	return bev_p;
642b15cb3dSCy Schubert }
652b15cb3dSCy Schubert 
662b15cb3dSCy Schubert #define downcast(bev_pair) (&(bev_pair)->bev.bev)
672b15cb3dSCy Schubert 
682b15cb3dSCy Schubert static inline void
incref_and_lock(struct bufferevent * b)692b15cb3dSCy Schubert incref_and_lock(struct bufferevent *b)
702b15cb3dSCy Schubert {
712b15cb3dSCy Schubert 	struct bufferevent_pair *bevp;
722b15cb3dSCy Schubert 	bufferevent_incref_and_lock_(b);
732b15cb3dSCy Schubert 	bevp = upcast(b);
742b15cb3dSCy Schubert 	if (bevp->partner)
752b15cb3dSCy Schubert 		bufferevent_incref_and_lock_(downcast(bevp->partner));
762b15cb3dSCy Schubert }
772b15cb3dSCy Schubert 
782b15cb3dSCy Schubert static inline void
decref_and_unlock(struct bufferevent * b)792b15cb3dSCy Schubert decref_and_unlock(struct bufferevent *b)
802b15cb3dSCy Schubert {
812b15cb3dSCy Schubert 	struct bufferevent_pair *bevp = upcast(b);
822b15cb3dSCy Schubert 	if (bevp->partner)
832b15cb3dSCy Schubert 		bufferevent_decref_and_unlock_(downcast(bevp->partner));
842b15cb3dSCy Schubert 	bufferevent_decref_and_unlock_(b);
852b15cb3dSCy Schubert }
862b15cb3dSCy Schubert 
872b15cb3dSCy Schubert /* XXX Handle close */
882b15cb3dSCy Schubert 
892b15cb3dSCy Schubert static void be_pair_outbuf_cb(struct evbuffer *,
902b15cb3dSCy Schubert     const struct evbuffer_cb_info *, void *);
912b15cb3dSCy Schubert 
922b15cb3dSCy Schubert static struct bufferevent_pair *
bufferevent_pair_elt_new(struct event_base * base,int options)932b15cb3dSCy Schubert bufferevent_pair_elt_new(struct event_base *base,
942b15cb3dSCy Schubert     int options)
952b15cb3dSCy Schubert {
962b15cb3dSCy Schubert 	struct bufferevent_pair *bufev;
972b15cb3dSCy Schubert 	if (! (bufev = mm_calloc(1, sizeof(struct bufferevent_pair))))
982b15cb3dSCy Schubert 		return NULL;
992b15cb3dSCy Schubert 	if (bufferevent_init_common_(&bufev->bev, base, &bufferevent_ops_pair,
1002b15cb3dSCy Schubert 		options)) {
1012b15cb3dSCy Schubert 		mm_free(bufev);
1022b15cb3dSCy Schubert 		return NULL;
1032b15cb3dSCy Schubert 	}
1042b15cb3dSCy Schubert 	if (!evbuffer_add_cb(bufev->bev.bev.output, be_pair_outbuf_cb, bufev)) {
1052b15cb3dSCy Schubert 		bufferevent_free(downcast(bufev));
1062b15cb3dSCy Schubert 		return NULL;
1072b15cb3dSCy Schubert 	}
1082b15cb3dSCy Schubert 
1092b15cb3dSCy Schubert 	bufferevent_init_generic_timeout_cbs_(&bufev->bev.bev);
1102b15cb3dSCy Schubert 
1112b15cb3dSCy Schubert 	return bufev;
1122b15cb3dSCy Schubert }
1132b15cb3dSCy Schubert 
1142b15cb3dSCy Schubert int
bufferevent_pair_new(struct event_base * base,int options,struct bufferevent * pair[2])1152b15cb3dSCy Schubert bufferevent_pair_new(struct event_base *base, int options,
1162b15cb3dSCy Schubert     struct bufferevent *pair[2])
1172b15cb3dSCy Schubert {
1182b15cb3dSCy Schubert 	struct bufferevent_pair *bufev1 = NULL, *bufev2 = NULL;
1192b15cb3dSCy Schubert 	int tmp_options;
1202b15cb3dSCy Schubert 
1212b15cb3dSCy Schubert 	options |= BEV_OPT_DEFER_CALLBACKS;
1222b15cb3dSCy Schubert 	tmp_options = options & ~BEV_OPT_THREADSAFE;
1232b15cb3dSCy Schubert 
1242b15cb3dSCy Schubert 	bufev1 = bufferevent_pair_elt_new(base, options);
1252b15cb3dSCy Schubert 	if (!bufev1)
1262b15cb3dSCy Schubert 		return -1;
1272b15cb3dSCy Schubert 	bufev2 = bufferevent_pair_elt_new(base, tmp_options);
1282b15cb3dSCy Schubert 	if (!bufev2) {
1292b15cb3dSCy Schubert 		bufferevent_free(downcast(bufev1));
1302b15cb3dSCy Schubert 		return -1;
1312b15cb3dSCy Schubert 	}
1322b15cb3dSCy Schubert 
1332b15cb3dSCy Schubert 	if (options & BEV_OPT_THREADSAFE) {
1342b15cb3dSCy Schubert 		/*XXXX check return */
1352b15cb3dSCy Schubert 		bufferevent_enable_locking_(downcast(bufev2), bufev1->bev.lock);
1362b15cb3dSCy Schubert 	}
1372b15cb3dSCy Schubert 
1382b15cb3dSCy Schubert 	bufev1->partner = bufev2;
1392b15cb3dSCy Schubert 	bufev2->partner = bufev1;
1402b15cb3dSCy Schubert 
1412b15cb3dSCy Schubert 	evbuffer_freeze(downcast(bufev1)->input, 0);
1422b15cb3dSCy Schubert 	evbuffer_freeze(downcast(bufev1)->output, 1);
1432b15cb3dSCy Schubert 	evbuffer_freeze(downcast(bufev2)->input, 0);
1442b15cb3dSCy Schubert 	evbuffer_freeze(downcast(bufev2)->output, 1);
1452b15cb3dSCy Schubert 
1462b15cb3dSCy Schubert 	pair[0] = downcast(bufev1);
1472b15cb3dSCy Schubert 	pair[1] = downcast(bufev2);
1482b15cb3dSCy Schubert 
1492b15cb3dSCy Schubert 	return 0;
1502b15cb3dSCy Schubert }
1512b15cb3dSCy Schubert 
1522b15cb3dSCy Schubert static void
be_pair_transfer(struct bufferevent * src,struct bufferevent * dst,int ignore_wm)1532b15cb3dSCy Schubert be_pair_transfer(struct bufferevent *src, struct bufferevent *dst,
1542b15cb3dSCy Schubert     int ignore_wm)
1552b15cb3dSCy Schubert {
1562b15cb3dSCy Schubert 	size_t dst_size;
1572b15cb3dSCy Schubert 	size_t n;
1582b15cb3dSCy Schubert 
1592b15cb3dSCy Schubert 	evbuffer_unfreeze(src->output, 1);
1602b15cb3dSCy Schubert 	evbuffer_unfreeze(dst->input, 0);
1612b15cb3dSCy Schubert 
1622b15cb3dSCy Schubert 	if (dst->wm_read.high) {
1632b15cb3dSCy Schubert 		dst_size = evbuffer_get_length(dst->input);
1642b15cb3dSCy Schubert 		if (dst_size < dst->wm_read.high) {
1652b15cb3dSCy Schubert 			n = dst->wm_read.high - dst_size;
1662b15cb3dSCy Schubert 			evbuffer_remove_buffer(src->output, dst->input, n);
1672b15cb3dSCy Schubert 		} else {
1682b15cb3dSCy Schubert 			if (!ignore_wm)
1692b15cb3dSCy Schubert 				goto done;
1702b15cb3dSCy Schubert 			n = evbuffer_get_length(src->output);
1712b15cb3dSCy Schubert 			evbuffer_add_buffer(dst->input, src->output);
1722b15cb3dSCy Schubert 		}
1732b15cb3dSCy Schubert 	} else {
1742b15cb3dSCy Schubert 		n = evbuffer_get_length(src->output);
1752b15cb3dSCy Schubert 		evbuffer_add_buffer(dst->input, src->output);
1762b15cb3dSCy Schubert 	}
1772b15cb3dSCy Schubert 
1782b15cb3dSCy Schubert 	if (n) {
1792b15cb3dSCy Schubert 		BEV_RESET_GENERIC_READ_TIMEOUT(dst);
1802b15cb3dSCy Schubert 
1812b15cb3dSCy Schubert 		if (evbuffer_get_length(dst->output))
1822b15cb3dSCy Schubert 			BEV_RESET_GENERIC_WRITE_TIMEOUT(dst);
1832b15cb3dSCy Schubert 		else
1842b15cb3dSCy Schubert 			BEV_DEL_GENERIC_WRITE_TIMEOUT(dst);
1852b15cb3dSCy Schubert 	}
1862b15cb3dSCy Schubert 
1872b15cb3dSCy Schubert 	bufferevent_trigger_nolock_(dst, EV_READ, 0);
1882b15cb3dSCy Schubert 	bufferevent_trigger_nolock_(src, EV_WRITE, 0);
1892b15cb3dSCy Schubert done:
1902b15cb3dSCy Schubert 	evbuffer_freeze(src->output, 1);
1912b15cb3dSCy Schubert 	evbuffer_freeze(dst->input, 0);
1922b15cb3dSCy Schubert }
1932b15cb3dSCy Schubert 
1942b15cb3dSCy Schubert static inline int
be_pair_wants_to_talk(struct bufferevent_pair * src,struct bufferevent_pair * dst)1952b15cb3dSCy Schubert be_pair_wants_to_talk(struct bufferevent_pair *src,
1962b15cb3dSCy Schubert     struct bufferevent_pair *dst)
1972b15cb3dSCy Schubert {
1982b15cb3dSCy Schubert 	return (downcast(src)->enabled & EV_WRITE) &&
1992b15cb3dSCy Schubert 	    (downcast(dst)->enabled & EV_READ) &&
2002b15cb3dSCy Schubert 	    !dst->bev.read_suspended &&
2012b15cb3dSCy Schubert 	    evbuffer_get_length(downcast(src)->output);
2022b15cb3dSCy Schubert }
2032b15cb3dSCy Schubert 
2042b15cb3dSCy Schubert static void
be_pair_outbuf_cb(struct evbuffer * outbuf,const struct evbuffer_cb_info * info,void * arg)2052b15cb3dSCy Schubert be_pair_outbuf_cb(struct evbuffer *outbuf,
2062b15cb3dSCy Schubert     const struct evbuffer_cb_info *info, void *arg)
2072b15cb3dSCy Schubert {
2082b15cb3dSCy Schubert 	struct bufferevent_pair *bev_pair = arg;
2092b15cb3dSCy Schubert 	struct bufferevent_pair *partner = bev_pair->partner;
2102b15cb3dSCy Schubert 
2112b15cb3dSCy Schubert 	incref_and_lock(downcast(bev_pair));
2122b15cb3dSCy Schubert 
2132b15cb3dSCy Schubert 	if (info->n_added > info->n_deleted && partner) {
2142b15cb3dSCy Schubert 		/* We got more data.  If the other side's reading, then
2152b15cb3dSCy Schubert 		   hand it over. */
2162b15cb3dSCy Schubert 		if (be_pair_wants_to_talk(bev_pair, partner)) {
2172b15cb3dSCy Schubert 			be_pair_transfer(downcast(bev_pair), downcast(partner), 0);
2182b15cb3dSCy Schubert 		}
2192b15cb3dSCy Schubert 	}
2202b15cb3dSCy Schubert 
2212b15cb3dSCy Schubert 	decref_and_unlock(downcast(bev_pair));
2222b15cb3dSCy Schubert }
2232b15cb3dSCy Schubert 
2242b15cb3dSCy Schubert static int
be_pair_enable(struct bufferevent * bufev,short events)2252b15cb3dSCy Schubert be_pair_enable(struct bufferevent *bufev, short events)
2262b15cb3dSCy Schubert {
2272b15cb3dSCy Schubert 	struct bufferevent_pair *bev_p = upcast(bufev);
2282b15cb3dSCy Schubert 	struct bufferevent_pair *partner = bev_p->partner;
2292b15cb3dSCy Schubert 
2302b15cb3dSCy Schubert 	incref_and_lock(bufev);
2312b15cb3dSCy Schubert 
2322b15cb3dSCy Schubert 	if (events & EV_READ) {
2332b15cb3dSCy Schubert 		BEV_RESET_GENERIC_READ_TIMEOUT(bufev);
2342b15cb3dSCy Schubert 	}
2352b15cb3dSCy Schubert 	if ((events & EV_WRITE) && evbuffer_get_length(bufev->output))
2362b15cb3dSCy Schubert 		BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev);
2372b15cb3dSCy Schubert 
2382b15cb3dSCy Schubert 	/* We're starting to read! Does the other side have anything to write?*/
2392b15cb3dSCy Schubert 	if ((events & EV_READ) && partner &&
2402b15cb3dSCy Schubert 	    be_pair_wants_to_talk(partner, bev_p)) {
2412b15cb3dSCy Schubert 		be_pair_transfer(downcast(partner), bufev, 0);
2422b15cb3dSCy Schubert 	}
2432b15cb3dSCy Schubert 	/* We're starting to write! Does the other side want to read? */
2442b15cb3dSCy Schubert 	if ((events & EV_WRITE) && partner &&
2452b15cb3dSCy Schubert 	    be_pair_wants_to_talk(bev_p, partner)) {
2462b15cb3dSCy Schubert 		be_pair_transfer(bufev, downcast(partner), 0);
2472b15cb3dSCy Schubert 	}
2482b15cb3dSCy Schubert 	decref_and_unlock(bufev);
2492b15cb3dSCy Schubert 	return 0;
2502b15cb3dSCy Schubert }
2512b15cb3dSCy Schubert 
2522b15cb3dSCy Schubert static int
be_pair_disable(struct bufferevent * bev,short events)2532b15cb3dSCy Schubert be_pair_disable(struct bufferevent *bev, short events)
2542b15cb3dSCy Schubert {
2552b15cb3dSCy Schubert 	if (events & EV_READ) {
2562b15cb3dSCy Schubert 		BEV_DEL_GENERIC_READ_TIMEOUT(bev);
2572b15cb3dSCy Schubert 	}
2582b15cb3dSCy Schubert 	if (events & EV_WRITE) {
2592b15cb3dSCy Schubert 		BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
2602b15cb3dSCy Schubert 	}
2612b15cb3dSCy Schubert 	return 0;
2622b15cb3dSCy Schubert }
2632b15cb3dSCy Schubert 
2642b15cb3dSCy Schubert static void
be_pair_unlink(struct bufferevent * bev)2652b15cb3dSCy Schubert be_pair_unlink(struct bufferevent *bev)
2662b15cb3dSCy Schubert {
2672b15cb3dSCy Schubert 	struct bufferevent_pair *bev_p = upcast(bev);
2682b15cb3dSCy Schubert 
2692b15cb3dSCy Schubert 	if (bev_p->partner) {
270a25439b6SCy Schubert 		bev_p->unlinked_partner = bev_p->partner;
2712b15cb3dSCy Schubert 		bev_p->partner->partner = NULL;
2722b15cb3dSCy Schubert 		bev_p->partner = NULL;
2732b15cb3dSCy Schubert 	}
2742b15cb3dSCy Schubert }
2752b15cb3dSCy Schubert 
276a25439b6SCy Schubert /* Free *shared* lock in the latest be (since we share it between two of them). */
277a25439b6SCy Schubert static void
be_pair_destruct(struct bufferevent * bev)278a25439b6SCy Schubert be_pair_destruct(struct bufferevent *bev)
279a25439b6SCy Schubert {
280a25439b6SCy Schubert 	struct bufferevent_pair *bev_p = upcast(bev);
281a25439b6SCy Schubert 
282a25439b6SCy Schubert 	/* Transfer ownership of the lock into partner, otherwise we will use
283a25439b6SCy Schubert 	 * already free'd lock during freeing second bev, see next example:
284a25439b6SCy Schubert 	 *
285a25439b6SCy Schubert 	 * bev1->own_lock = 1
286a25439b6SCy Schubert 	 * bev2->own_lock = 0
287a25439b6SCy Schubert 	 * bev2->lock = bev1->lock
288a25439b6SCy Schubert 	 *
289a25439b6SCy Schubert 	 * bufferevent_free(bev1) # refcnt == 0 -> unlink
290a25439b6SCy Schubert 	 * bufferevent_free(bev2) # refcnt == 0 -> unlink
291a25439b6SCy Schubert 	 *
292a25439b6SCy Schubert 	 * event_base_free() -> finilizers -> EVTHREAD_FREE_LOCK(bev1->lock)
293a25439b6SCy Schubert 	 *                                 -> BEV_LOCK(bev2->lock) <-- already freed
294a25439b6SCy Schubert 	 *
295a25439b6SCy Schubert 	 * Where bev1 == pair[0], bev2 == pair[1].
296a25439b6SCy Schubert 	 */
297a25439b6SCy Schubert 	if (bev_p->unlinked_partner && bev_p->bev.own_lock) {
298a25439b6SCy Schubert 		bev_p->unlinked_partner->bev.own_lock = 1;
299a25439b6SCy Schubert 		bev_p->bev.own_lock = 0;
300a25439b6SCy Schubert 	}
301a25439b6SCy Schubert 	bev_p->unlinked_partner = NULL;
302a25439b6SCy Schubert }
303a25439b6SCy Schubert 
3042b15cb3dSCy Schubert static int
be_pair_flush(struct bufferevent * bev,short iotype,enum bufferevent_flush_mode mode)3052b15cb3dSCy Schubert be_pair_flush(struct bufferevent *bev, short iotype,
3062b15cb3dSCy Schubert     enum bufferevent_flush_mode mode)
3072b15cb3dSCy Schubert {
3082b15cb3dSCy Schubert 	struct bufferevent_pair *bev_p = upcast(bev);
3092b15cb3dSCy Schubert 	struct bufferevent *partner;
310*a466cc55SCy Schubert 
3112b15cb3dSCy Schubert 	if (!bev_p->partner)
3122b15cb3dSCy Schubert 		return -1;
3132b15cb3dSCy Schubert 
3142b15cb3dSCy Schubert 	if (mode == BEV_NORMAL)
3152b15cb3dSCy Schubert 		return 0;
3162b15cb3dSCy Schubert 
317*a466cc55SCy Schubert 	incref_and_lock(bev);
318*a466cc55SCy Schubert 
319*a466cc55SCy Schubert 	partner = downcast(bev_p->partner);
320*a466cc55SCy Schubert 
3212b15cb3dSCy Schubert 	if ((iotype & EV_READ) != 0)
3222b15cb3dSCy Schubert 		be_pair_transfer(partner, bev, 1);
3232b15cb3dSCy Schubert 
3242b15cb3dSCy Schubert 	if ((iotype & EV_WRITE) != 0)
3252b15cb3dSCy Schubert 		be_pair_transfer(bev, partner, 1);
3262b15cb3dSCy Schubert 
3272b15cb3dSCy Schubert 	if (mode == BEV_FINISHED) {
328*a466cc55SCy Schubert 		short what = BEV_EVENT_EOF;
329*a466cc55SCy Schubert 		if (iotype & EV_READ)
330*a466cc55SCy Schubert 			what |= BEV_EVENT_WRITING;
331*a466cc55SCy Schubert 		if (iotype & EV_WRITE)
332*a466cc55SCy Schubert 			what |= BEV_EVENT_READING;
333*a466cc55SCy Schubert 		bufferevent_run_eventcb_(partner, what, 0);
3342b15cb3dSCy Schubert 	}
3352b15cb3dSCy Schubert 	decref_and_unlock(bev);
3362b15cb3dSCy Schubert 	return 0;
3372b15cb3dSCy Schubert }
3382b15cb3dSCy Schubert 
3392b15cb3dSCy Schubert struct bufferevent *
bufferevent_pair_get_partner(struct bufferevent * bev)3402b15cb3dSCy Schubert bufferevent_pair_get_partner(struct bufferevent *bev)
3412b15cb3dSCy Schubert {
3422b15cb3dSCy Schubert 	struct bufferevent_pair *bev_p;
3432b15cb3dSCy Schubert 	struct bufferevent *partner = NULL;
3442b15cb3dSCy Schubert 	bev_p = upcast(bev);
3452b15cb3dSCy Schubert 	if (! bev_p)
3462b15cb3dSCy Schubert 		return NULL;
3472b15cb3dSCy Schubert 
3482b15cb3dSCy Schubert 	incref_and_lock(bev);
3492b15cb3dSCy Schubert 	if (bev_p->partner)
3502b15cb3dSCy Schubert 		partner = downcast(bev_p->partner);
3512b15cb3dSCy Schubert 	decref_and_unlock(bev);
3522b15cb3dSCy Schubert 	return partner;
3532b15cb3dSCy Schubert }
3542b15cb3dSCy Schubert 
3552b15cb3dSCy Schubert const struct bufferevent_ops bufferevent_ops_pair = {
3562b15cb3dSCy Schubert 	"pair_elt",
3572b15cb3dSCy Schubert 	evutil_offsetof(struct bufferevent_pair, bev.bev),
3582b15cb3dSCy Schubert 	be_pair_enable,
3592b15cb3dSCy Schubert 	be_pair_disable,
3602b15cb3dSCy Schubert 	be_pair_unlink,
361a25439b6SCy Schubert 	be_pair_destruct,
3622b15cb3dSCy Schubert 	bufferevent_generic_adj_timeouts_,
3632b15cb3dSCy Schubert 	be_pair_flush,
3642b15cb3dSCy Schubert 	NULL, /* ctrl */
3652b15cb3dSCy Schubert };
366