xref: /libevent-2.1.12/bufferevent.c (revision bb0f8fe7)
136d7ab50SNiels Provos /*
2b85b710cSNick Mathewson  * Copyright (c) 2002-2007 Niels Provos <[email protected]>
3e49e2891SNick Mathewson  * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson
436d7ab50SNiels Provos  *
536d7ab50SNiels Provos  * Redistribution and use in source and binary forms, with or without
636d7ab50SNiels Provos  * modification, are permitted provided that the following conditions
736d7ab50SNiels Provos  * are met:
836d7ab50SNiels Provos  * 1. Redistributions of source code must retain the above copyright
936d7ab50SNiels Provos  *    notice, this list of conditions and the following disclaimer.
1036d7ab50SNiels Provos  * 2. Redistributions in binary form must reproduce the above copyright
1136d7ab50SNiels Provos  *    notice, this list of conditions and the following disclaimer in the
1236d7ab50SNiels Provos  *    documentation and/or other materials provided with the distribution.
1336d7ab50SNiels Provos  * 3. The name of the author may not be used to endorse or promote products
1436d7ab50SNiels Provos  *    derived from this software without specific prior written permission.
1536d7ab50SNiels Provos  *
1636d7ab50SNiels Provos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1736d7ab50SNiels Provos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1836d7ab50SNiels Provos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1936d7ab50SNiels Provos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2036d7ab50SNiels Provos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2136d7ab50SNiels Provos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2236d7ab50SNiels Provos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2336d7ab50SNiels Provos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2436d7ab50SNiels Provos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2536d7ab50SNiels Provos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2636d7ab50SNiels Provos  */
2736d7ab50SNiels Provos 
28ec347b92SNick Mathewson #include "event2/event-config.h"
290915ca0aSKevin Bowling #include "evconfig-private.h"
300915ca0aSKevin Bowling 
310915ca0aSKevin Bowling #include <sys/types.h>
3236d7ab50SNiels Provos 
3368120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TIME_H
3436d7ab50SNiels Provos #include <sys/time.h>
3536d7ab50SNiels Provos #endif
3636d7ab50SNiels Provos 
3736d7ab50SNiels Provos #include <errno.h>
3836d7ab50SNiels Provos #include <stdio.h>
3936d7ab50SNiels Provos #include <stdlib.h>
4036d7ab50SNiels Provos #include <string.h>
4168120d9bSNick Mathewson #ifdef EVENT__HAVE_STDARG_H
4236d7ab50SNiels Provos #include <stdarg.h>
4336d7ab50SNiels Provos #endif
4436d7ab50SNiels Provos 
459f560bfaSNick Mathewson #ifdef _WIN32
4636d7ab50SNiels Provos #include <winsock2.h>
4736d7ab50SNiels Provos #endif
4836d7ab50SNiels Provos 
4936d7ab50SNiels Provos #include "event2/util.h"
5036d7ab50SNiels Provos #include "event2/buffer.h"
51d7d1f1daSNick Mathewson #include "event2/buffer_compat.h"
52d7d1f1daSNick Mathewson #include "event2/bufferevent.h"
5336d7ab50SNiels Provos #include "event2/bufferevent_struct.h"
54ea4b8724SNick Mathewson #include "event2/bufferevent_compat.h"
5536d7ab50SNiels Provos #include "event2/event.h"
5602fbf687SNick Mathewson #include "event-internal.h"
57169321c9SNick Mathewson #include "log-internal.h"
5836d7ab50SNiels Provos #include "mm-internal.h"
5936d7ab50SNiels Provos #include "bufferevent-internal.h"
60d7d1f1daSNick Mathewson #include "evbuffer-internal.h"
6181ab45adSNick Mathewson #include "util-internal.h"
6236d7ab50SNiels Provos 
63cb9da0bfSNick Mathewson static void bufferevent_cancel_all_(struct bufferevent *bev);
6402fbf687SNick Mathewson static void bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_);
65e6af35d7SNick Mathewson 
66ea4b8724SNick Mathewson void
bufferevent_suspend_read_(struct bufferevent * bufev,bufferevent_suspend_flags what)678ac3c4c2SNick Mathewson bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
6836d7ab50SNiels Provos {
6974517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
70915193e7SNick Mathewson 	BEV_LOCK(bufev);
710d744aa1SNick Mathewson 	if (!bufev_private->read_suspended)
72ea4b8724SNick Mathewson 		bufev->be_ops->disable(bufev, EV_READ);
730d744aa1SNick Mathewson 	bufev_private->read_suspended |= what;
7459484297SNick Mathewson 	BEV_UNLOCK(bufev);
7536d7ab50SNiels Provos }
7636d7ab50SNiels Provos 
77ea4b8724SNick Mathewson void
bufferevent_unsuspend_read_(struct bufferevent * bufev,bufferevent_suspend_flags what)788ac3c4c2SNick Mathewson bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
79ea4b8724SNick Mathewson {
8074517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
81915193e7SNick Mathewson 	BEV_LOCK(bufev);
820d744aa1SNick Mathewson 	bufev_private->read_suspended &= ~what;
83040a019fSSimon Perreault 	if (!bufev_private->read_suspended && (bufev->enabled & EV_READ))
84ea4b8724SNick Mathewson 		bufev->be_ops->enable(bufev, EV_READ);
8559484297SNick Mathewson 	BEV_UNLOCK(bufev);
8636d7ab50SNiels Provos }
8736d7ab50SNiels Provos 
880d744aa1SNick Mathewson void
bufferevent_suspend_write_(struct bufferevent * bufev,bufferevent_suspend_flags what)898ac3c4c2SNick Mathewson bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
900d744aa1SNick Mathewson {
9174517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
920d744aa1SNick Mathewson 	BEV_LOCK(bufev);
930d744aa1SNick Mathewson 	if (!bufev_private->write_suspended)
940d744aa1SNick Mathewson 		bufev->be_ops->disable(bufev, EV_WRITE);
950d744aa1SNick Mathewson 	bufev_private->write_suspended |= what;
960d744aa1SNick Mathewson 	BEV_UNLOCK(bufev);
970d744aa1SNick Mathewson }
980d744aa1SNick Mathewson 
990d744aa1SNick Mathewson void
bufferevent_unsuspend_write_(struct bufferevent * bufev,bufferevent_suspend_flags what)1008ac3c4c2SNick Mathewson bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
1010d744aa1SNick Mathewson {
10274517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
1030d744aa1SNick Mathewson 	BEV_LOCK(bufev);
1040d744aa1SNick Mathewson 	bufev_private->write_suspended &= ~what;
105040a019fSSimon Perreault 	if (!bufev_private->write_suspended && (bufev->enabled & EV_WRITE))
1060d744aa1SNick Mathewson 		bufev->be_ops->enable(bufev, EV_WRITE);
1070d744aa1SNick Mathewson 	BEV_UNLOCK(bufev);
1080d744aa1SNick Mathewson }
1090d744aa1SNick Mathewson 
1103f692fffSAzat Khuzhin /**
1113f692fffSAzat Khuzhin  * Sometimes bufferevent's implementation can overrun high watermarks
1123f692fffSAzat Khuzhin  * (one of examples is openssl) and in this case if the read callback
1133f692fffSAzat Khuzhin  * will not handle enough data do over condition above the read
1143f692fffSAzat Khuzhin  * callback will never be called again (due to suspend above).
1153f692fffSAzat Khuzhin  *
1163f692fffSAzat Khuzhin  * To avoid this we are scheduling read callback again here, but only
1173f692fffSAzat Khuzhin  * from the user callback to avoid multiple scheduling:
1183f692fffSAzat Khuzhin  * - when the data had been added to it
1193f692fffSAzat Khuzhin  * - when the data had been drained from it (user specified read callback)
1203f692fffSAzat Khuzhin  */
bufferevent_inbuf_wm_check(struct bufferevent * bev)1213f692fffSAzat Khuzhin static void bufferevent_inbuf_wm_check(struct bufferevent *bev)
1223f692fffSAzat Khuzhin {
1233f692fffSAzat Khuzhin 	if (!bev->wm_read.high)
1243f692fffSAzat Khuzhin 		return;
1253f692fffSAzat Khuzhin 	if (!(bev->enabled & EV_READ))
1263f692fffSAzat Khuzhin 		return;
1273f692fffSAzat Khuzhin 	if (evbuffer_get_length(bev->input) < bev->wm_read.high)
1283f692fffSAzat Khuzhin 		return;
1293f692fffSAzat Khuzhin 
1303f692fffSAzat Khuzhin 	bufferevent_trigger(bev, EV_READ, BEV_OPT_DEFER_CALLBACKS);
1313f692fffSAzat Khuzhin }
1320d744aa1SNick Mathewson 
133ea4b8724SNick Mathewson /* Callback to implement watermarks on the input buffer.  Only enabled
134ea4b8724SNick Mathewson  * if the watermark is set. */
13536d7ab50SNiels Provos static void
bufferevent_inbuf_wm_cb(struct evbuffer * buf,const struct evbuffer_cb_info * cbinfo,void * arg)136f1b1bad4SNick Mathewson bufferevent_inbuf_wm_cb(struct evbuffer *buf,
137f1b1bad4SNick Mathewson     const struct evbuffer_cb_info *cbinfo,
138ea4b8724SNick Mathewson     void *arg)
13936d7ab50SNiels Provos {
14036d7ab50SNiels Provos 	struct bufferevent *bufev = arg;
141915193e7SNick Mathewson 	size_t size;
142915193e7SNick Mathewson 
143915193e7SNick Mathewson 	size = evbuffer_get_length(buf);
14436d7ab50SNiels Provos 
145f1b1bad4SNick Mathewson 	if (size >= bufev->wm_read.high)
146ea4b8724SNick Mathewson 		bufferevent_wm_suspend_read(bufev);
1475846bf6cSNick Mathewson 	else
148ea4b8724SNick Mathewson 		bufferevent_wm_unsuspend_read(bufev);
14936d7ab50SNiels Provos }
15036d7ab50SNiels Provos 
151a98a512bSNick Mathewson static void
bufferevent_run_deferred_callbacks_locked(struct event_callback * cb,void * arg)152a4079aa8SNick Mathewson bufferevent_run_deferred_callbacks_locked(struct event_callback *cb, void *arg)
153a98a512bSNick Mathewson {
154a98a512bSNick Mathewson 	struct bufferevent_private *bufev_private = arg;
155a98a512bSNick Mathewson 	struct bufferevent *bufev = &bufev_private->bev;
156a98a512bSNick Mathewson 
157a98a512bSNick Mathewson 	BEV_LOCK(bufev);
158bd26baceSNick Mathewson 	if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) &&
159bd26baceSNick Mathewson 	    bufev->errorcb) {
160bd26baceSNick Mathewson 		/* The "connected" happened before any reads or writes, so
161bd26baceSNick Mathewson 		   send it first. */
162bd26baceSNick Mathewson 		bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED;
163bd26baceSNick Mathewson 		bufev->errorcb(bufev, BEV_EVENT_CONNECTED, bufev->cbarg);
164bd26baceSNick Mathewson 	}
165a98a512bSNick Mathewson 	if (bufev_private->readcb_pending && bufev->readcb) {
166a98a512bSNick Mathewson 		bufev_private->readcb_pending = 0;
167a98a512bSNick Mathewson 		bufev->readcb(bufev, bufev->cbarg);
1683f692fffSAzat Khuzhin 		bufferevent_inbuf_wm_check(bufev);
169a98a512bSNick Mathewson 	}
170a98a512bSNick Mathewson 	if (bufev_private->writecb_pending && bufev->writecb) {
171a98a512bSNick Mathewson 		bufev_private->writecb_pending = 0;
172a98a512bSNick Mathewson 		bufev->writecb(bufev, bufev->cbarg);
173a98a512bSNick Mathewson 	}
1745232cfa3SNick Mathewson 	if (bufev_private->eventcb_pending && bufev->errorcb) {
1755232cfa3SNick Mathewson 		short what = bufev_private->eventcb_pending;
176a98a512bSNick Mathewson 		int err = bufev_private->errno_pending;
1775232cfa3SNick Mathewson 		bufev_private->eventcb_pending = 0;
178a98a512bSNick Mathewson 		bufev_private->errno_pending = 0;
179a98a512bSNick Mathewson 		EVUTIL_SET_SOCKET_ERROR(err);
180a98a512bSNick Mathewson 		bufev->errorcb(bufev, what, bufev->cbarg);
181a98a512bSNick Mathewson 	}
182cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bufev);
183a98a512bSNick Mathewson }
184a98a512bSNick Mathewson 
185a5208fe4SJoachim Bauch static void
bufferevent_run_deferred_callbacks_unlocked(struct event_callback * cb,void * arg)186a4079aa8SNick Mathewson bufferevent_run_deferred_callbacks_unlocked(struct event_callback *cb, void *arg)
187a5208fe4SJoachim Bauch {
188a5208fe4SJoachim Bauch 	struct bufferevent_private *bufev_private = arg;
189a5208fe4SJoachim Bauch 	struct bufferevent *bufev = &bufev_private->bev;
190a5208fe4SJoachim Bauch 
191a5208fe4SJoachim Bauch 	BEV_LOCK(bufev);
192a5208fe4SJoachim Bauch #define UNLOCKED(stmt) \
193a5208fe4SJoachim Bauch 	do { BEV_UNLOCK(bufev); stmt; BEV_LOCK(bufev); } while(0)
194a5208fe4SJoachim Bauch 
195a5208fe4SJoachim Bauch 	if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) &&
196a5208fe4SJoachim Bauch 	    bufev->errorcb) {
197a5208fe4SJoachim Bauch 		/* The "connected" happened before any reads or writes, so
198a5208fe4SJoachim Bauch 		   send it first. */
199a5208fe4SJoachim Bauch 		bufferevent_event_cb errorcb = bufev->errorcb;
200a5208fe4SJoachim Bauch 		void *cbarg = bufev->cbarg;
201a5208fe4SJoachim Bauch 		bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED;
202a5208fe4SJoachim Bauch 		UNLOCKED(errorcb(bufev, BEV_EVENT_CONNECTED, cbarg));
203a5208fe4SJoachim Bauch 	}
204a5208fe4SJoachim Bauch 	if (bufev_private->readcb_pending && bufev->readcb) {
205a5208fe4SJoachim Bauch 		bufferevent_data_cb readcb = bufev->readcb;
206a5208fe4SJoachim Bauch 		void *cbarg = bufev->cbarg;
207a5208fe4SJoachim Bauch 		bufev_private->readcb_pending = 0;
208a5208fe4SJoachim Bauch 		UNLOCKED(readcb(bufev, cbarg));
2093f692fffSAzat Khuzhin 		bufferevent_inbuf_wm_check(bufev);
210a5208fe4SJoachim Bauch 	}
211a5208fe4SJoachim Bauch 	if (bufev_private->writecb_pending && bufev->writecb) {
212a5208fe4SJoachim Bauch 		bufferevent_data_cb writecb = bufev->writecb;
213a5208fe4SJoachim Bauch 		void *cbarg = bufev->cbarg;
214a5208fe4SJoachim Bauch 		bufev_private->writecb_pending = 0;
215a5208fe4SJoachim Bauch 		UNLOCKED(writecb(bufev, cbarg));
216a5208fe4SJoachim Bauch 	}
217a5208fe4SJoachim Bauch 	if (bufev_private->eventcb_pending && bufev->errorcb) {
218a5208fe4SJoachim Bauch 		bufferevent_event_cb errorcb = bufev->errorcb;
219a5208fe4SJoachim Bauch 		void *cbarg = bufev->cbarg;
220a5208fe4SJoachim Bauch 		short what = bufev_private->eventcb_pending;
221a5208fe4SJoachim Bauch 		int err = bufev_private->errno_pending;
222a5208fe4SJoachim Bauch 		bufev_private->eventcb_pending = 0;
223a5208fe4SJoachim Bauch 		bufev_private->errno_pending = 0;
224a5208fe4SJoachim Bauch 		EVUTIL_SET_SOCKET_ERROR(err);
225a5208fe4SJoachim Bauch 		UNLOCKED(errorcb(bufev,what,cbarg));
226a5208fe4SJoachim Bauch 	}
227cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bufev);
228a5208fe4SJoachim Bauch #undef UNLOCKED
229a5208fe4SJoachim Bauch }
230a5208fe4SJoachim Bauch 
231b06b2649SNick Mathewson #define SCHEDULE_DEFERRED(bevp)						\
232b06b2649SNick Mathewson 	do {								\
233ae2b84b2SNick Mathewson 		if (event_deferred_cb_schedule_(			\
234a4079aa8SNick Mathewson 			    (bevp)->bev.ev_base,			\
235ae2b84b2SNick Mathewson 			&(bevp)->deferred))				\
236ae2b84b2SNick Mathewson 			bufferevent_incref_(&(bevp)->bev);		\
23717a14f1aSChristopher Davis 	} while (0)
238b06b2649SNick Mathewson 
239b06b2649SNick Mathewson 
240a98a512bSNick Mathewson void
bufferevent_run_readcb_(struct bufferevent * bufev,int options)24161ee18b8SOndřej Kuzník bufferevent_run_readcb_(struct bufferevent *bufev, int options)
242a98a512bSNick Mathewson {
243a62283a9SNick Mathewson 	/* Requires that we hold the lock and a reference */
24474517b2aSAzat Khuzhin 	struct bufferevent_private *p = BEV_UPCAST(bufev);
2452e8eeea3SNick Mathewson 	if (bufev->readcb == NULL)
2462e8eeea3SNick Mathewson 		return;
247a3172a41SNick Mathewson 	if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
248a98a512bSNick Mathewson 		p->readcb_pending = 1;
249b06b2649SNick Mathewson 		SCHEDULE_DEFERRED(p);
250a98a512bSNick Mathewson 	} else {
251a98a512bSNick Mathewson 		bufev->readcb(bufev, bufev->cbarg);
2523f692fffSAzat Khuzhin 		bufferevent_inbuf_wm_check(bufev);
253a98a512bSNick Mathewson 	}
254a98a512bSNick Mathewson }
255a98a512bSNick Mathewson 
256a98a512bSNick Mathewson void
bufferevent_run_writecb_(struct bufferevent * bufev,int options)25761ee18b8SOndřej Kuzník bufferevent_run_writecb_(struct bufferevent *bufev, int options)
258a98a512bSNick Mathewson {
259a62283a9SNick Mathewson 	/* Requires that we hold the lock and a reference */
26074517b2aSAzat Khuzhin 	struct bufferevent_private *p = BEV_UPCAST(bufev);
2612e8eeea3SNick Mathewson 	if (bufev->writecb == NULL)
2622e8eeea3SNick Mathewson 		return;
263a3172a41SNick Mathewson 	if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
264a98a512bSNick Mathewson 		p->writecb_pending = 1;
265b06b2649SNick Mathewson 		SCHEDULE_DEFERRED(p);
266a98a512bSNick Mathewson 	} else {
267a98a512bSNick Mathewson 		bufev->writecb(bufev, bufev->cbarg);
268a98a512bSNick Mathewson 	}
269a98a512bSNick Mathewson }
270a98a512bSNick Mathewson 
271a3172a41SNick Mathewson #define BEV_TRIG_ALL_OPTS (			\
272a3172a41SNick Mathewson 		BEV_TRIG_IGNORE_WATERMARKS|	\
273a3172a41SNick Mathewson 		BEV_TRIG_DEFER_CALLBACKS	\
274a3172a41SNick Mathewson 	)
275a3172a41SNick Mathewson 
276a98a512bSNick Mathewson void
bufferevent_trigger(struct bufferevent * bufev,short iotype,int options)27761ee18b8SOndřej Kuzník bufferevent_trigger(struct bufferevent *bufev, short iotype, int options)
27861ee18b8SOndřej Kuzník {
27961ee18b8SOndřej Kuzník 	bufferevent_incref_and_lock_(bufev);
280a3172a41SNick Mathewson 	bufferevent_trigger_nolock_(bufev, iotype, options&BEV_TRIG_ALL_OPTS);
28161ee18b8SOndřej Kuzník 	bufferevent_decref_and_unlock_(bufev);
28261ee18b8SOndřej Kuzník }
28361ee18b8SOndřej Kuzník 
28461ee18b8SOndřej Kuzník void
bufferevent_run_eventcb_(struct bufferevent * bufev,short what,int options)285a7384c78SOndřej Kuzník bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options)
286a98a512bSNick Mathewson {
287a62283a9SNick Mathewson 	/* Requires that we hold the lock and a reference */
28874517b2aSAzat Khuzhin 	struct bufferevent_private *p = BEV_UPCAST(bufev);
2892e8eeea3SNick Mathewson 	if (bufev->errorcb == NULL)
2902e8eeea3SNick Mathewson 		return;
291a3172a41SNick Mathewson 	if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
2925232cfa3SNick Mathewson 		p->eventcb_pending |= what;
293a98a512bSNick Mathewson 		p->errno_pending = EVUTIL_SOCKET_ERROR();
294b06b2649SNick Mathewson 		SCHEDULE_DEFERRED(p);
295a98a512bSNick Mathewson 	} else {
296a98a512bSNick Mathewson 		bufev->errorcb(bufev, what, bufev->cbarg);
297a98a512bSNick Mathewson 	}
298a98a512bSNick Mathewson }
299a98a512bSNick Mathewson 
300a7384c78SOndřej Kuzník void
bufferevent_trigger_event(struct bufferevent * bufev,short what,int options)301a7384c78SOndřej Kuzník bufferevent_trigger_event(struct bufferevent *bufev, short what, int options)
302a7384c78SOndřej Kuzník {
303a7384c78SOndřej Kuzník 	bufferevent_incref_and_lock_(bufev);
304a3172a41SNick Mathewson 	bufferevent_run_eventcb_(bufev, what, options&BEV_TRIG_ALL_OPTS);
305a7384c78SOndřej Kuzník 	bufferevent_decref_and_unlock_(bufev);
306a7384c78SOndřej Kuzník }
307a7384c78SOndřej Kuzník 
308ea4b8724SNick Mathewson int
bufferevent_init_common_(struct bufferevent_private * bufev_private,struct event_base * base,const struct bufferevent_ops * ops,enum bufferevent_options options)3098ac3c4c2SNick Mathewson bufferevent_init_common_(struct bufferevent_private *bufev_private,
3101becc4c4SNick Mathewson     struct event_base *base,
311ea4b8724SNick Mathewson     const struct bufferevent_ops *ops,
312ea4b8724SNick Mathewson     enum bufferevent_options options)
31336d7ab50SNiels Provos {
3141becc4c4SNick Mathewson 	struct bufferevent *bufev = &bufev_private->bev;
3151becc4c4SNick Mathewson 
316b69d03b5SNick Mathewson 	if (!bufev->input) {
317ea4b8724SNick Mathewson 		if ((bufev->input = evbuffer_new()) == NULL)
318*bb0f8fe7SAzat Khuzhin 			goto err;
319b69d03b5SNick Mathewson 	}
32036d7ab50SNiels Provos 
321b69d03b5SNick Mathewson 	if (!bufev->output) {
322*bb0f8fe7SAzat Khuzhin 		if ((bufev->output = evbuffer_new()) == NULL)
323*bb0f8fe7SAzat Khuzhin 			goto err;
324b69d03b5SNick Mathewson 	}
32536d7ab50SNiels Provos 
32691039e4dSNick Mathewson 	bufev_private->refcnt = 1;
327ea4b8724SNick Mathewson 	bufev->ev_base = base;
32836d7ab50SNiels Provos 
329ea4b8724SNick Mathewson 	/* Disable timeouts. */
330ea4b8724SNick Mathewson 	evutil_timerclear(&bufev->timeout_read);
331ea4b8724SNick Mathewson 	evutil_timerclear(&bufev->timeout_write);
332ea4b8724SNick Mathewson 
333ea4b8724SNick Mathewson 	bufev->be_ops = ops;
33436d7ab50SNiels Provos 
335*bb0f8fe7SAzat Khuzhin 	if (bufferevent_ratelim_init_(bufev_private))
336*bb0f8fe7SAzat Khuzhin 		goto err;
337998c8138SAlexander Drozdov 
33836d7ab50SNiels Provos 	/*
33936d7ab50SNiels Provos 	 * Set to EV_WRITE so that using bufferevent_write is going to
34036d7ab50SNiels Provos 	 * trigger a callback.  Reading needs to be explicitly enabled
34136d7ab50SNiels Provos 	 * because otherwise no data will be available.
34236d7ab50SNiels Provos 	 */
34336d7ab50SNiels Provos 	bufev->enabled = EV_WRITE;
34436d7ab50SNiels Provos 
34568120d9bSNick Mathewson #ifndef EVENT__DISABLE_THREAD_SUPPORT
346915193e7SNick Mathewson 	if (options & BEV_OPT_THREADSAFE) {
347*bb0f8fe7SAzat Khuzhin 		if (bufferevent_enable_locking_(bufev, NULL) < 0)
348*bb0f8fe7SAzat Khuzhin 			goto err;
349915193e7SNick Mathewson 	}
350915193e7SNick Mathewson #endif
351a5208fe4SJoachim Bauch 	if ((options & (BEV_OPT_DEFER_CALLBACKS|BEV_OPT_UNLOCK_CALLBACKS))
352a5208fe4SJoachim Bauch 	    == BEV_OPT_UNLOCK_CALLBACKS) {
353a5208fe4SJoachim Bauch 		event_warnx("UNLOCK_CALLBACKS requires DEFER_CALLBACKS");
354*bb0f8fe7SAzat Khuzhin 		goto err;
355a5208fe4SJoachim Bauch 	}
356a5208fe4SJoachim Bauch 	if (options & BEV_OPT_UNLOCK_CALLBACKS)
357ae2b84b2SNick Mathewson 		event_deferred_cb_init_(
358ae2b84b2SNick Mathewson 		    &bufev_private->deferred,
359c0e425abSNick Mathewson 		    event_base_get_npriorities(base) / 2,
360a5208fe4SJoachim Bauch 		    bufferevent_run_deferred_callbacks_unlocked,
361a5208fe4SJoachim Bauch 		    bufev_private);
362a5208fe4SJoachim Bauch 	else
363ae2b84b2SNick Mathewson 		event_deferred_cb_init_(
364ae2b84b2SNick Mathewson 		    &bufev_private->deferred,
365c0e425abSNick Mathewson 		    event_base_get_npriorities(base) / 2,
366a5208fe4SJoachim Bauch 		    bufferevent_run_deferred_callbacks_locked,
367a98a512bSNick Mathewson 		    bufev_private);
368915193e7SNick Mathewson 
3691becc4c4SNick Mathewson 	bufev_private->options = options;
37036d7ab50SNiels Provos 
3718ac3c4c2SNick Mathewson 	evbuffer_set_parent_(bufev->input, bufev);
3728ac3c4c2SNick Mathewson 	evbuffer_set_parent_(bufev->output, bufev);
373d7d1f1daSNick Mathewson 
374ea4b8724SNick Mathewson 	return 0;
375*bb0f8fe7SAzat Khuzhin 
376*bb0f8fe7SAzat Khuzhin err:
377*bb0f8fe7SAzat Khuzhin 	if (bufev->input) {
378*bb0f8fe7SAzat Khuzhin 		evbuffer_free(bufev->input);
379*bb0f8fe7SAzat Khuzhin 		bufev->input = NULL;
380*bb0f8fe7SAzat Khuzhin 	}
381*bb0f8fe7SAzat Khuzhin 	if (bufev->output) {
382*bb0f8fe7SAzat Khuzhin 		evbuffer_free(bufev->output);
383*bb0f8fe7SAzat Khuzhin 		bufev->output = NULL;
384*bb0f8fe7SAzat Khuzhin 	}
385*bb0f8fe7SAzat Khuzhin 	return -1;
38636d7ab50SNiels Provos }
38736d7ab50SNiels Provos 
38836d7ab50SNiels Provos void
bufferevent_setcb(struct bufferevent * bufev,bufferevent_data_cb readcb,bufferevent_data_cb writecb,bufferevent_event_cb eventcb,void * cbarg)38936d7ab50SNiels Provos bufferevent_setcb(struct bufferevent *bufev,
39083f46e51SNick Mathewson     bufferevent_data_cb readcb, bufferevent_data_cb writecb,
3915232cfa3SNick Mathewson     bufferevent_event_cb eventcb, void *cbarg)
39236d7ab50SNiels Provos {
393915193e7SNick Mathewson 	BEV_LOCK(bufev);
394915193e7SNick Mathewson 
39536d7ab50SNiels Provos 	bufev->readcb = readcb;
39636d7ab50SNiels Provos 	bufev->writecb = writecb;
3975232cfa3SNick Mathewson 	bufev->errorcb = eventcb;
39836d7ab50SNiels Provos 
39936d7ab50SNiels Provos 	bufev->cbarg = cbarg;
400915193e7SNick Mathewson 	BEV_UNLOCK(bufev);
40136d7ab50SNiels Provos }
40236d7ab50SNiels Provos 
403a6503944SNick Mathewson void
bufferevent_getcb(struct bufferevent * bufev,bufferevent_data_cb * readcb_ptr,bufferevent_data_cb * writecb_ptr,bufferevent_event_cb * eventcb_ptr,void ** cbarg_ptr)404a6503944SNick Mathewson bufferevent_getcb(struct bufferevent *bufev,
405a6503944SNick Mathewson     bufferevent_data_cb *readcb_ptr,
406a6503944SNick Mathewson     bufferevent_data_cb *writecb_ptr,
407a6503944SNick Mathewson     bufferevent_event_cb *eventcb_ptr,
408a6503944SNick Mathewson     void **cbarg_ptr)
409a6503944SNick Mathewson {
410a6503944SNick Mathewson 	BEV_LOCK(bufev);
411a6503944SNick Mathewson 	if (readcb_ptr)
412a6503944SNick Mathewson 		*readcb_ptr = bufev->readcb;
413a6503944SNick Mathewson 	if (writecb_ptr)
414a6503944SNick Mathewson 		*writecb_ptr = bufev->writecb;
415a6503944SNick Mathewson 	if (eventcb_ptr)
416a6503944SNick Mathewson 		*eventcb_ptr = bufev->errorcb;
417a6503944SNick Mathewson 	if (cbarg_ptr)
418a6503944SNick Mathewson 		*cbarg_ptr = bufev->cbarg;
419a6503944SNick Mathewson 
420a6503944SNick Mathewson 	BEV_UNLOCK(bufev);
421a6503944SNick Mathewson }
422a6503944SNick Mathewson 
42336d7ab50SNiels Provos struct evbuffer *
bufferevent_get_input(struct bufferevent * bufev)4248acb80b4SNick Mathewson bufferevent_get_input(struct bufferevent *bufev)
42536d7ab50SNiels Provos {
426ea4b8724SNick Mathewson 	return bufev->input;
42736d7ab50SNiels Provos }
42836d7ab50SNiels Provos 
42936d7ab50SNiels Provos struct evbuffer *
bufferevent_get_output(struct bufferevent * bufev)4308acb80b4SNick Mathewson bufferevent_get_output(struct bufferevent *bufev)
43136d7ab50SNiels Provos {
432ea4b8724SNick Mathewson 	return bufev->output;
43336d7ab50SNiels Provos }
43436d7ab50SNiels Provos 
435aab49b60SNick Mathewson struct event_base *
bufferevent_get_base(struct bufferevent * bufev)436aab49b60SNick Mathewson bufferevent_get_base(struct bufferevent *bufev)
437aab49b60SNick Mathewson {
438aab49b60SNick Mathewson 	return bufev->ev_base;
439aab49b60SNick Mathewson }
440aab49b60SNick Mathewson 
44136d7ab50SNiels Provos int
bufferevent_get_priority(const struct bufferevent * bufev)442060c409eSNick Mathewson bufferevent_get_priority(const struct bufferevent *bufev)
443bd395549SNick Mathewson {
444bd395549SNick Mathewson 	if (event_initialized(&bufev->ev_read)) {
445bd395549SNick Mathewson 		return event_get_priority(&bufev->ev_read);
446bd395549SNick Mathewson 	} else {
447bd395549SNick Mathewson 		return event_base_get_npriorities(bufev->ev_base) / 2;
448bd395549SNick Mathewson 	}
449bd395549SNick Mathewson }
450bd395549SNick Mathewson 
451bd395549SNick Mathewson int
bufferevent_write(struct bufferevent * bufev,const void * data,size_t size)45236d7ab50SNiels Provos bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
45336d7ab50SNiels Provos {
454ea4b8724SNick Mathewson 	if (evbuffer_add(bufev->output, data, size) == -1)
45536d7ab50SNiels Provos 		return (-1);
45636d7ab50SNiels Provos 
457ea4b8724SNick Mathewson 	return 0;
45836d7ab50SNiels Provos }
45936d7ab50SNiels Provos 
46036d7ab50SNiels Provos int
bufferevent_write_buffer(struct bufferevent * bufev,struct evbuffer * buf)46136d7ab50SNiels Provos bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
46236d7ab50SNiels Provos {
463ea4b8724SNick Mathewson 	if (evbuffer_add_buffer(bufev->output, buf) == -1)
46436d7ab50SNiels Provos 		return (-1);
46536d7ab50SNiels Provos 
466ea4b8724SNick Mathewson 	return 0;
46736d7ab50SNiels Provos }
46836d7ab50SNiels Provos 
46936d7ab50SNiels Provos size_t
bufferevent_read(struct bufferevent * bufev,void * data,size_t size)47036d7ab50SNiels Provos bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
47136d7ab50SNiels Provos {
47236d7ab50SNiels Provos 	return (evbuffer_remove(bufev->input, data, size));
47336d7ab50SNiels Provos }
47436d7ab50SNiels Provos 
47536d7ab50SNiels Provos int
bufferevent_read_buffer(struct bufferevent * bufev,struct evbuffer * buf)47636d7ab50SNiels Provos bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf)
47736d7ab50SNiels Provos {
47836d7ab50SNiels Provos 	return (evbuffer_add_buffer(buf, bufev->input));
47936d7ab50SNiels Provos }
48036d7ab50SNiels Provos 
48136d7ab50SNiels Provos int
bufferevent_enable(struct bufferevent * bufev,short event)48236d7ab50SNiels Provos bufferevent_enable(struct bufferevent *bufev, short event)
48336d7ab50SNiels Provos {
48474517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
485ea4b8724SNick Mathewson 	short impl_events = event;
486915193e7SNick Mathewson 	int r = 0;
487915193e7SNick Mathewson 
488cb9da0bfSNick Mathewson 	bufferevent_incref_and_lock_(bufev);
4891becc4c4SNick Mathewson 	if (bufev_private->read_suspended)
490ea4b8724SNick Mathewson 		impl_events &= ~EV_READ;
4910d744aa1SNick Mathewson 	if (bufev_private->write_suspended)
4920d744aa1SNick Mathewson 		impl_events &= ~EV_WRITE;
49336d7ab50SNiels Provos 
49436d7ab50SNiels Provos 	bufev->enabled |= event;
495ea4b8724SNick Mathewson 
4960d744aa1SNick Mathewson 	if (impl_events && bufev->be_ops->enable(bufev, impl_events) < 0)
497915193e7SNick Mathewson 		r = -1;
49822609d66SAzat Khuzhin 	if (r)
49922609d66SAzat Khuzhin 		event_debug(("%s: cannot enable 0x%hx on %p", __func__, event, bufev));
500ea4b8724SNick Mathewson 
501cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bufev);
502915193e7SNick Mathewson 	return r;
50336d7ab50SNiels Provos }
50436d7ab50SNiels Provos 
505ff3f6cd4SNick Mathewson int
bufferevent_set_timeouts(struct bufferevent * bufev,const struct timeval * tv_read,const struct timeval * tv_write)506ea4b8724SNick Mathewson bufferevent_set_timeouts(struct bufferevent *bufev,
507ea4b8724SNick Mathewson 			 const struct timeval *tv_read,
508ea4b8724SNick Mathewson 			 const struct timeval *tv_write)
509ea4b8724SNick Mathewson {
510ff3f6cd4SNick Mathewson 	int r = 0;
511915193e7SNick Mathewson 	BEV_LOCK(bufev);
512ea4b8724SNick Mathewson 	if (tv_read) {
513ea4b8724SNick Mathewson 		bufev->timeout_read = *tv_read;
514ea4b8724SNick Mathewson 	} else {
515ea4b8724SNick Mathewson 		evutil_timerclear(&bufev->timeout_read);
516ea4b8724SNick Mathewson 	}
517ea4b8724SNick Mathewson 	if (tv_write) {
518ea4b8724SNick Mathewson 		bufev->timeout_write = *tv_write;
519ea4b8724SNick Mathewson 	} else {
520ea4b8724SNick Mathewson 		evutil_timerclear(&bufev->timeout_write);
521ea4b8724SNick Mathewson 	}
522ea4b8724SNick Mathewson 
523ea4b8724SNick Mathewson 	if (bufev->be_ops->adj_timeouts)
524ff3f6cd4SNick Mathewson 		r = bufev->be_ops->adj_timeouts(bufev);
525915193e7SNick Mathewson 	BEV_UNLOCK(bufev);
526ff3f6cd4SNick Mathewson 
527ff3f6cd4SNick Mathewson 	return r;
528ea4b8724SNick Mathewson }
529ea4b8724SNick Mathewson 
530ea4b8724SNick Mathewson 
531ea4b8724SNick Mathewson /* Obsolete; use bufferevent_set_timeouts */
532ea4b8724SNick Mathewson void
bufferevent_settimeout(struct bufferevent * bufev,int timeout_read,int timeout_write)533ea4b8724SNick Mathewson bufferevent_settimeout(struct bufferevent *bufev,
534ea4b8724SNick Mathewson 		       int timeout_read, int timeout_write)
535ea4b8724SNick Mathewson {
536ea4b8724SNick Mathewson 	struct timeval tv_read, tv_write;
537ea4b8724SNick Mathewson 	struct timeval *ptv_read = NULL, *ptv_write = NULL;
538ea4b8724SNick Mathewson 
539ea4b8724SNick Mathewson 	memset(&tv_read, 0, sizeof(tv_read));
540ea4b8724SNick Mathewson 	memset(&tv_write, 0, sizeof(tv_write));
541ea4b8724SNick Mathewson 
542ea4b8724SNick Mathewson 	if (timeout_read) {
543ea4b8724SNick Mathewson 		tv_read.tv_sec = timeout_read;
544ea4b8724SNick Mathewson 		ptv_read = &tv_read;
545ea4b8724SNick Mathewson 	}
546ea4b8724SNick Mathewson 	if (timeout_write) {
547ea4b8724SNick Mathewson 		tv_write.tv_sec = timeout_write;
548ea4b8724SNick Mathewson 		ptv_write = &tv_write;
549ea4b8724SNick Mathewson 	}
550ea4b8724SNick Mathewson 
551ea4b8724SNick Mathewson 	bufferevent_set_timeouts(bufev, ptv_read, ptv_write);
552ea4b8724SNick Mathewson }
553ea4b8724SNick Mathewson 
554ea4b8724SNick Mathewson 
55536d7ab50SNiels Provos int
bufferevent_disable_hard_(struct bufferevent * bufev,short event)5568ac3c4c2SNick Mathewson bufferevent_disable_hard_(struct bufferevent *bufev, short event)
5575dc56628STomash Brechko {
5585dc56628STomash Brechko 	int r = 0;
55974517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
5605dc56628STomash Brechko 
5615dc56628STomash Brechko 	BEV_LOCK(bufev);
5625dc56628STomash Brechko 	bufev->enabled &= ~event;
5635dc56628STomash Brechko 
5645dc56628STomash Brechko 	bufev_private->connecting = 0;
5655dc56628STomash Brechko 	if (bufev->be_ops->disable(bufev, event) < 0)
5665dc56628STomash Brechko 		r = -1;
5675dc56628STomash Brechko 
5685dc56628STomash Brechko 	BEV_UNLOCK(bufev);
5695dc56628STomash Brechko 	return r;
5705dc56628STomash Brechko }
5715dc56628STomash Brechko 
5725dc56628STomash Brechko int
bufferevent_disable(struct bufferevent * bufev,short event)57336d7ab50SNiels Provos bufferevent_disable(struct bufferevent *bufev, short event)
57436d7ab50SNiels Provos {
575915193e7SNick Mathewson 	int r = 0;
576915193e7SNick Mathewson 
577915193e7SNick Mathewson 	BEV_LOCK(bufev);
57836d7ab50SNiels Provos 	bufev->enabled &= ~event;
579ea4b8724SNick Mathewson 
580ea4b8724SNick Mathewson 	if (bufev->be_ops->disable(bufev, event) < 0)
581915193e7SNick Mathewson 		r = -1;
58222609d66SAzat Khuzhin 	if (r)
58322609d66SAzat Khuzhin 		event_debug(("%s: cannot disable 0x%hx on %p", __func__, event, bufev));
584ea4b8724SNick Mathewson 
585915193e7SNick Mathewson 	BEV_UNLOCK(bufev);
586915193e7SNick Mathewson 	return r;
58736d7ab50SNiels Provos }
58836d7ab50SNiels Provos 
58936d7ab50SNiels Provos /*
59036d7ab50SNiels Provos  * Sets the water marks
59136d7ab50SNiels Provos  */
59236d7ab50SNiels Provos 
59336d7ab50SNiels Provos void
bufferevent_setwatermark(struct bufferevent * bufev,short events,size_t lowmark,size_t highmark)59436d7ab50SNiels Provos bufferevent_setwatermark(struct bufferevent *bufev, short events,
59536d7ab50SNiels Provos     size_t lowmark, size_t highmark)
59636d7ab50SNiels Provos {
59774517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
59836d7ab50SNiels Provos 
599915193e7SNick Mathewson 	BEV_LOCK(bufev);
60036d7ab50SNiels Provos 	if (events & EV_WRITE) {
60136d7ab50SNiels Provos 		bufev->wm_write.low = lowmark;
60236d7ab50SNiels Provos 		bufev->wm_write.high = highmark;
60336d7ab50SNiels Provos 	}
60436d7ab50SNiels Provos 
605ea4b8724SNick Mathewson 	if (events & EV_READ) {
606ea4b8724SNick Mathewson 		bufev->wm_read.low = lowmark;
607ea4b8724SNick Mathewson 		bufev->wm_read.high = highmark;
608ea4b8724SNick Mathewson 
609ea4b8724SNick Mathewson 		if (highmark) {
610ea4b8724SNick Mathewson 			/* There is now a new high-water mark for read.
611ea4b8724SNick Mathewson 			   enable the callback if needed, and see if we should
612ea4b8724SNick Mathewson 			   suspend/bufferevent_wm_unsuspend. */
613ea4b8724SNick Mathewson 
6141becc4c4SNick Mathewson 			if (bufev_private->read_watermarks_cb == NULL) {
6151becc4c4SNick Mathewson 				bufev_private->read_watermarks_cb =
616ea4b8724SNick Mathewson 				    evbuffer_add_cb(bufev->input,
617ea4b8724SNick Mathewson 						    bufferevent_inbuf_wm_cb,
618ea4b8724SNick Mathewson 						    bufev);
619ea4b8724SNick Mathewson 			}
620ea4b8724SNick Mathewson 			evbuffer_cb_set_flags(bufev->input,
6211becc4c4SNick Mathewson 				      bufev_private->read_watermarks_cb,
622438f9ed2SNick Mathewson 				      EVBUFFER_CB_ENABLED|EVBUFFER_CB_NODEFER);
623ea4b8724SNick Mathewson 
624b34e4ac3Sufo2243 			if (evbuffer_get_length(bufev->input) >= highmark)
625ea4b8724SNick Mathewson 				bufferevent_wm_suspend_read(bufev);
626a8f6d961SNick Mathewson 			else if (evbuffer_get_length(bufev->input) < highmark)
627ea4b8724SNick Mathewson 				bufferevent_wm_unsuspend_read(bufev);
628ea4b8724SNick Mathewson 		} else {
629ea4b8724SNick Mathewson 			/* There is now no high-water mark for read. */
6301becc4c4SNick Mathewson 			if (bufev_private->read_watermarks_cb)
631bba69e03SNick Mathewson 				evbuffer_cb_clear_flags(bufev->input,
6321becc4c4SNick Mathewson 				    bufev_private->read_watermarks_cb,
633bba69e03SNick Mathewson 				    EVBUFFER_CB_ENABLED);
634ea4b8724SNick Mathewson 			bufferevent_wm_unsuspend_read(bufev);
635ea4b8724SNick Mathewson 		}
636ea4b8724SNick Mathewson 	}
637915193e7SNick Mathewson 	BEV_UNLOCK(bufev);
63836d7ab50SNiels Provos }
63936d7ab50SNiels Provos 
640a21e5108Sufo2243 int
bufferevent_getwatermark(struct bufferevent * bufev,short events,size_t * lowmark,size_t * highmark)6414ce242bdSOndřej Kuzník bufferevent_getwatermark(struct bufferevent *bufev, short events,
6424ce242bdSOndřej Kuzník     size_t *lowmark, size_t *highmark)
6434ce242bdSOndřej Kuzník {
644bd419471SOndřej Kuzník 	if (events == EV_WRITE) {
645a21e5108Sufo2243 		BEV_LOCK(bufev);
6464ce242bdSOndřej Kuzník 		if (lowmark)
6474ce242bdSOndřej Kuzník 			*lowmark = bufev->wm_write.low;
6484ce242bdSOndřej Kuzník 		if (highmark)
6494ce242bdSOndřej Kuzník 			*highmark = bufev->wm_write.high;
650a21e5108Sufo2243 		BEV_UNLOCK(bufev);
651a21e5108Sufo2243 		return 0;
6524ce242bdSOndřej Kuzník 	}
6534ce242bdSOndřej Kuzník 
654bd419471SOndřej Kuzník 	if (events == EV_READ) {
655a21e5108Sufo2243 		BEV_LOCK(bufev);
6564ce242bdSOndřej Kuzník 		if (lowmark)
6574ce242bdSOndřej Kuzník 			*lowmark = bufev->wm_read.low;
6584ce242bdSOndřej Kuzník 		if (highmark)
6594ce242bdSOndřej Kuzník 			*highmark = bufev->wm_read.high;
6604ce242bdSOndřej Kuzník 		BEV_UNLOCK(bufev);
661a21e5108Sufo2243 		return 0;
662a21e5108Sufo2243 	}
663a21e5108Sufo2243 	return -1;
6644ce242bdSOndřej Kuzník }
6654ce242bdSOndřej Kuzník 
66636d7ab50SNiels Provos int
bufferevent_flush(struct bufferevent * bufev,short iotype,enum bufferevent_flush_mode mode)667ea4b8724SNick Mathewson bufferevent_flush(struct bufferevent *bufev,
668ea4b8724SNick Mathewson     short iotype,
669ea4b8724SNick Mathewson     enum bufferevent_flush_mode mode)
67036d7ab50SNiels Provos {
671915193e7SNick Mathewson 	int r = -1;
672915193e7SNick Mathewson 	BEV_LOCK(bufev);
673ea4b8724SNick Mathewson 	if (bufev->be_ops->flush)
674915193e7SNick Mathewson 		r = bufev->be_ops->flush(bufev, iotype, mode);
675915193e7SNick Mathewson 	BEV_UNLOCK(bufev);
676915193e7SNick Mathewson 	return r;
67736d7ab50SNiels Provos }
67836d7ab50SNiels Provos 
67936d7ab50SNiels Provos void
bufferevent_incref_and_lock_(struct bufferevent * bufev)680cb9da0bfSNick Mathewson bufferevent_incref_and_lock_(struct bufferevent *bufev)
681a62283a9SNick Mathewson {
68274517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
683a62283a9SNick Mathewson 	BEV_LOCK(bufev);
684a62283a9SNick Mathewson 	++bufev_private->refcnt;
685a62283a9SNick Mathewson }
686a62283a9SNick Mathewson 
687f1bc125eSNick Mathewson #if 0
688f1bc125eSNick Mathewson static void
689946b5841SNick Mathewson bufferevent_transfer_lock_ownership_(struct bufferevent *donor,
690f1bc125eSNick Mathewson     struct bufferevent *recipient)
691f1bc125eSNick Mathewson {
692f1bc125eSNick Mathewson 	struct bufferevent_private *d = BEV_UPCAST(donor);
693f1bc125eSNick Mathewson 	struct bufferevent_private *r = BEV_UPCAST(recipient);
694f1bc125eSNick Mathewson 	if (d->lock != r->lock)
695f1bc125eSNick Mathewson 		return;
696f1bc125eSNick Mathewson 	if (r->own_lock)
697f1bc125eSNick Mathewson 		return;
698f1bc125eSNick Mathewson 	if (d->own_lock) {
699f1bc125eSNick Mathewson 		d->own_lock = 0;
700f1bc125eSNick Mathewson 		r->own_lock = 1;
701f1bc125eSNick Mathewson 	}
702f1bc125eSNick Mathewson }
703f1bc125eSNick Mathewson #endif
704f1bc125eSNick Mathewson 
705f1bc125eSNick Mathewson int
bufferevent_decref_and_unlock_(struct bufferevent * bufev)706cb9da0bfSNick Mathewson bufferevent_decref_and_unlock_(struct bufferevent *bufev)
70736d7ab50SNiels Provos {
70874517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
70902fbf687SNick Mathewson 	int n_cbs = 0;
71002fbf687SNick Mathewson #define MAX_CBS 16
71102fbf687SNick Mathewson 	struct event_callback *cbs[MAX_CBS];
71291039e4dSNick Mathewson 
713f1bc125eSNick Mathewson 	EVUTIL_ASSERT(bufev_private->refcnt > 0);
714f1bc125eSNick Mathewson 
71591039e4dSNick Mathewson 	if (--bufev_private->refcnt) {
71691039e4dSNick Mathewson 		BEV_UNLOCK(bufev);
717f1bc125eSNick Mathewson 		return 0;
71891039e4dSNick Mathewson 	}
71991039e4dSNick Mathewson 
72002fbf687SNick Mathewson 	if (bufev->be_ops->unlink)
72102fbf687SNick Mathewson 		bufev->be_ops->unlink(bufev);
72202fbf687SNick Mathewson 
72302fbf687SNick Mathewson 	/* Okay, we're out of references. Let's finalize this once all the
72402fbf687SNick Mathewson 	 * callbacks are done running. */
72502fbf687SNick Mathewson 	cbs[0] = &bufev->ev_read.ev_evcallback;
72602fbf687SNick Mathewson 	cbs[1] = &bufev->ev_write.ev_evcallback;
72702fbf687SNick Mathewson 	cbs[2] = &bufev_private->deferred;
72802fbf687SNick Mathewson 	n_cbs = 3;
72902fbf687SNick Mathewson 	if (bufev_private->rate_limiting) {
73002fbf687SNick Mathewson 		struct event *e = &bufev_private->rate_limiting->refill_bucket_event;
73102fbf687SNick Mathewson 		if (event_initialized(e))
73202fbf687SNick Mathewson 			cbs[n_cbs++] = &e->ev_evcallback;
73302fbf687SNick Mathewson 	}
73402fbf687SNick Mathewson 	n_cbs += evbuffer_get_callbacks_(bufev->input, cbs+n_cbs, MAX_CBS-n_cbs);
73502fbf687SNick Mathewson 	n_cbs += evbuffer_get_callbacks_(bufev->output, cbs+n_cbs, MAX_CBS-n_cbs);
73602fbf687SNick Mathewson 
73702fbf687SNick Mathewson 	event_callback_finalize_many_(bufev->ev_base, n_cbs, cbs,
73802fbf687SNick Mathewson 	    bufferevent_finalize_cb_);
73902fbf687SNick Mathewson 
74002fbf687SNick Mathewson #undef MAX_CBS
74102fbf687SNick Mathewson 	BEV_UNLOCK(bufev);
74202fbf687SNick Mathewson 
74302fbf687SNick Mathewson 	return 1;
74402fbf687SNick Mathewson }
74502fbf687SNick Mathewson 
74602fbf687SNick Mathewson static void
bufferevent_finalize_cb_(struct event_callback * evcb,void * arg_)74702fbf687SNick Mathewson bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_)
74802fbf687SNick Mathewson {
74902fbf687SNick Mathewson 	struct bufferevent *bufev = arg_;
75002fbf687SNick Mathewson 	struct bufferevent *underlying;
75174517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
75202fbf687SNick Mathewson 
75302fbf687SNick Mathewson 	BEV_LOCK(bufev);
754a773df54SJoachim Bauch 	underlying = bufferevent_get_underlying(bufev);
755a773df54SJoachim Bauch 
756ea4b8724SNick Mathewson 	/* Clean up the shared info */
757ea4b8724SNick Mathewson 	if (bufev->be_ops->destruct)
758ea4b8724SNick Mathewson 		bufev->be_ops->destruct(bufev);
759ea4b8724SNick Mathewson 
760d7d1f1daSNick Mathewson 	/* XXX what happens if refcnt for these buffers is > 1?
761d7d1f1daSNick Mathewson 	 * The buffers can share a lock with this bufferevent object,
762d7d1f1daSNick Mathewson 	 * but the lock might be destroyed below. */
763ea4b8724SNick Mathewson 	/* evbuffer will free the callbacks */
764ea4b8724SNick Mathewson 	evbuffer_free(bufev->input);
765ea4b8724SNick Mathewson 	evbuffer_free(bufev->output);
766ea4b8724SNick Mathewson 
767737c9cd8SNick Mathewson 	if (bufev_private->rate_limiting) {
768737c9cd8SNick Mathewson 		if (bufev_private->rate_limiting->group)
7698ac3c4c2SNick Mathewson 			bufferevent_remove_from_rate_limit_group_internal_(bufev,0);
770737c9cd8SNick Mathewson 		mm_free(bufev_private->rate_limiting);
771737c9cd8SNick Mathewson 		bufev_private->rate_limiting = NULL;
772737c9cd8SNick Mathewson 	}
773737c9cd8SNick Mathewson 
774a19b4a05SNick Mathewson 
77591039e4dSNick Mathewson 	BEV_UNLOCK(bufev);
77602fbf687SNick Mathewson 
77791039e4dSNick Mathewson 	if (bufev_private->own_lock)
778347952ffSNick Mathewson 		EVTHREAD_FREE_LOCK(bufev_private->lock,
779347952ffSNick Mathewson 		    EVTHREAD_LOCKTYPE_RECURSIVE);
78091039e4dSNick Mathewson 
781ea4b8724SNick Mathewson 	/* Free the actual allocated memory. */
7820cf1431eSNick Mathewson 	mm_free(((char*)bufev) - bufev->be_ops->mem_offset);
783a773df54SJoachim Bauch 
784f1bc125eSNick Mathewson 	/* Release the reference to underlying now that we no longer need the
785f1bc125eSNick Mathewson 	 * reference to it.  We wait this long mainly in case our lock is
786f1bc125eSNick Mathewson 	 * shared with underlying.
787f1bc125eSNick Mathewson 	 *
788f1bc125eSNick Mathewson 	 * The 'destruct' function will also drop a reference to underlying
789f1bc125eSNick Mathewson 	 * if BEV_OPT_CLOSE_ON_FREE is set.
790f1bc125eSNick Mathewson 	 *
791a773df54SJoachim Bauch 	 * XXX Should we/can we just refcount evbuffer/bufferevent locks?
792a773df54SJoachim Bauch 	 * It would probably save us some headaches.
793a773df54SJoachim Bauch 	 */
794a773df54SJoachim Bauch 	if (underlying)
7958ac3c4c2SNick Mathewson 		bufferevent_decref_(underlying);
79691039e4dSNick Mathewson }
79791039e4dSNick Mathewson 
798f1bc125eSNick Mathewson int
bufferevent_decref(struct bufferevent * bufev)7991ed6718dSMark Ellzey bufferevent_decref(struct bufferevent *bufev)
800b2fbeb3fSNick Mathewson {
801b2fbeb3fSNick Mathewson 	BEV_LOCK(bufev);
802cb9da0bfSNick Mathewson 	return bufferevent_decref_and_unlock_(bufev);
803b2fbeb3fSNick Mathewson }
804b2fbeb3fSNick Mathewson 
805b2fbeb3fSNick Mathewson void
bufferevent_free(struct bufferevent * bufev)80691039e4dSNick Mathewson bufferevent_free(struct bufferevent *bufev)
80791039e4dSNick Mathewson {
80891039e4dSNick Mathewson 	BEV_LOCK(bufev);
809b2fbeb3fSNick Mathewson 	bufferevent_setcb(bufev, NULL, NULL, NULL, NULL);
810cb9da0bfSNick Mathewson 	bufferevent_cancel_all_(bufev);
811cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bufev);
81291039e4dSNick Mathewson }
81391039e4dSNick Mathewson 
81491039e4dSNick Mathewson void
bufferevent_incref(struct bufferevent * bufev)8151ed6718dSMark Ellzey bufferevent_incref(struct bufferevent *bufev)
81691039e4dSNick Mathewson {
81774517b2aSAzat Khuzhin 	struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
81891039e4dSNick Mathewson 
8191ed6718dSMark Ellzey 	/* XXX: now that this function is public, we might want to
8201ed6718dSMark Ellzey 	 * - return the count from this function
8211ed6718dSMark Ellzey 	 * - create a new function to atomically grab the current refcount
8221ed6718dSMark Ellzey 	 */
82391039e4dSNick Mathewson 	BEV_LOCK(bufev);
82491039e4dSNick Mathewson 	++bufev_private->refcnt;
82591039e4dSNick Mathewson 	BEV_UNLOCK(bufev);
826915193e7SNick Mathewson }
827915193e7SNick Mathewson 
828915193e7SNick Mathewson int
bufferevent_enable_locking_(struct bufferevent * bufev,void * lock)8298ac3c4c2SNick Mathewson bufferevent_enable_locking_(struct bufferevent *bufev, void *lock)
830915193e7SNick Mathewson {
83168120d9bSNick Mathewson #ifdef EVENT__DISABLE_THREAD_SUPPORT
832915193e7SNick Mathewson 	return -1;
833915193e7SNick Mathewson #else
834709c21c4SNick Mathewson 	struct bufferevent *underlying;
835709c21c4SNick Mathewson 
836915193e7SNick Mathewson 	if (BEV_UPCAST(bufev)->lock)
837915193e7SNick Mathewson 		return -1;
838709c21c4SNick Mathewson 	underlying = bufferevent_get_underlying(bufev);
839915193e7SNick Mathewson 
840709c21c4SNick Mathewson 	if (!lock && underlying && BEV_UPCAST(underlying)->lock) {
841709c21c4SNick Mathewson 		lock = BEV_UPCAST(underlying)->lock;
842709c21c4SNick Mathewson 		BEV_UPCAST(bufev)->lock = lock;
843709c21c4SNick Mathewson 		BEV_UPCAST(bufev)->own_lock = 0;
844709c21c4SNick Mathewson 	} else if (!lock) {
845347952ffSNick Mathewson 		EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
846915193e7SNick Mathewson 		if (!lock)
847915193e7SNick Mathewson 			return -1;
848915193e7SNick Mathewson 		BEV_UPCAST(bufev)->lock = lock;
849915193e7SNick Mathewson 		BEV_UPCAST(bufev)->own_lock = 1;
850915193e7SNick Mathewson 	} else {
851915193e7SNick Mathewson 		BEV_UPCAST(bufev)->lock = lock;
852915193e7SNick Mathewson 		BEV_UPCAST(bufev)->own_lock = 0;
853915193e7SNick Mathewson 	}
854915193e7SNick Mathewson 	evbuffer_enable_locking(bufev->input, lock);
855915193e7SNick Mathewson 	evbuffer_enable_locking(bufev->output, lock);
856915193e7SNick Mathewson 
857709c21c4SNick Mathewson 	if (underlying && !BEV_UPCAST(underlying)->lock)
8588ac3c4c2SNick Mathewson 		bufferevent_enable_locking_(underlying, lock);
859709c21c4SNick Mathewson 
860915193e7SNick Mathewson 	return 0;
861915193e7SNick Mathewson #endif
86236d7ab50SNiels Provos }
86336d7ab50SNiels Provos 
86431d89f27SNick Mathewson int
bufferevent_setfd(struct bufferevent * bev,evutil_socket_t fd)86531d89f27SNick Mathewson bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd)
86631d89f27SNick Mathewson {
86731d89f27SNick Mathewson 	union bufferevent_ctrl_data d;
86831d89f27SNick Mathewson 	int res = -1;
86931d89f27SNick Mathewson 	d.fd = fd;
87031d89f27SNick Mathewson 	BEV_LOCK(bev);
87131d89f27SNick Mathewson 	if (bev->be_ops->ctrl)
87231d89f27SNick Mathewson 		res = bev->be_ops->ctrl(bev, BEV_CTRL_SET_FD, &d);
87322609d66SAzat Khuzhin 	if (res)
87422609d66SAzat Khuzhin 		event_debug(("%s: cannot set fd for %p to "EV_SOCK_FMT, __func__, bev, fd));
87531d89f27SNick Mathewson 	BEV_UNLOCK(bev);
87631d89f27SNick Mathewson 	return res;
87731d89f27SNick Mathewson }
87831d89f27SNick Mathewson 
87931d89f27SNick Mathewson evutil_socket_t
bufferevent_getfd(struct bufferevent * bev)88031d89f27SNick Mathewson bufferevent_getfd(struct bufferevent *bev)
88131d89f27SNick Mathewson {
88231d89f27SNick Mathewson 	union bufferevent_ctrl_data d;
88331d89f27SNick Mathewson 	int res = -1;
88431d89f27SNick Mathewson 	d.fd = -1;
88531d89f27SNick Mathewson 	BEV_LOCK(bev);
88631d89f27SNick Mathewson 	if (bev->be_ops->ctrl)
88731d89f27SNick Mathewson 		res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_FD, &d);
88822609d66SAzat Khuzhin 	if (res)
88922609d66SAzat Khuzhin 		event_debug(("%s: cannot get fd for %p", __func__, bev));
89031d89f27SNick Mathewson 	BEV_UNLOCK(bev);
89131d89f27SNick Mathewson 	return (res<0) ? -1 : d.fd;
89231d89f27SNick Mathewson }
89331d89f27SNick Mathewson 
89431db8a02SMaxime Henrion enum bufferevent_options
bufferevent_get_options_(struct bufferevent * bev)89531db8a02SMaxime Henrion bufferevent_get_options_(struct bufferevent *bev)
89631db8a02SMaxime Henrion {
89774517b2aSAzat Khuzhin 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
898dbc9cd4dSMaxime Henrion 	enum bufferevent_options options;
89931db8a02SMaxime Henrion 
90031db8a02SMaxime Henrion 	BEV_LOCK(bev);
901dbc9cd4dSMaxime Henrion 	options = bev_p->options;
90231db8a02SMaxime Henrion 	BEV_UNLOCK(bev);
903dbc9cd4dSMaxime Henrion 	return options;
90431db8a02SMaxime Henrion }
90531db8a02SMaxime Henrion 
90631db8a02SMaxime Henrion 
907e6af35d7SNick Mathewson static void
bufferevent_cancel_all_(struct bufferevent * bev)908cb9da0bfSNick Mathewson bufferevent_cancel_all_(struct bufferevent *bev)
909e6af35d7SNick Mathewson {
910e6af35d7SNick Mathewson 	union bufferevent_ctrl_data d;
911e6af35d7SNick Mathewson 	memset(&d, 0, sizeof(d));
912e6af35d7SNick Mathewson 	BEV_LOCK(bev);
913e6af35d7SNick Mathewson 	if (bev->be_ops->ctrl)
914e6af35d7SNick Mathewson 		bev->be_ops->ctrl(bev, BEV_CTRL_CANCEL_ALL, &d);
915e6af35d7SNick Mathewson 	BEV_UNLOCK(bev);
916e6af35d7SNick Mathewson }
917e6af35d7SNick Mathewson 
9187c688dd9SNick Mathewson short
bufferevent_get_enabled(struct bufferevent * bufev)9197c688dd9SNick Mathewson bufferevent_get_enabled(struct bufferevent *bufev)
9207c688dd9SNick Mathewson {
9217c688dd9SNick Mathewson 	short r;
9227c688dd9SNick Mathewson 	BEV_LOCK(bufev);
9237c688dd9SNick Mathewson 	r = bufev->enabled;
9247c688dd9SNick Mathewson 	BEV_UNLOCK(bufev);
9257c688dd9SNick Mathewson 	return r;
9267c688dd9SNick Mathewson }
9277c688dd9SNick Mathewson 
92831d89f27SNick Mathewson struct bufferevent *
bufferevent_get_underlying(struct bufferevent * bev)92931d89f27SNick Mathewson bufferevent_get_underlying(struct bufferevent *bev)
93031d89f27SNick Mathewson {
93131d89f27SNick Mathewson 	union bufferevent_ctrl_data d;
93231d89f27SNick Mathewson 	int res = -1;
93331d89f27SNick Mathewson 	d.ptr = NULL;
93431d89f27SNick Mathewson 	BEV_LOCK(bev);
93531d89f27SNick Mathewson 	if (bev->be_ops->ctrl)
93631d89f27SNick Mathewson 		res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_UNDERLYING, &d);
93731d89f27SNick Mathewson 	BEV_UNLOCK(bev);
93831d89f27SNick Mathewson 	return (res<0) ? NULL : d.ptr;
93931d89f27SNick Mathewson }
94034574db0SNick Mathewson 
94134574db0SNick Mathewson static void
bufferevent_generic_read_timeout_cb(evutil_socket_t fd,short event,void * ctx)94234574db0SNick Mathewson bufferevent_generic_read_timeout_cb(evutil_socket_t fd, short event, void *ctx)
94334574db0SNick Mathewson {
94434574db0SNick Mathewson 	struct bufferevent *bev = ctx;
945cb9da0bfSNick Mathewson 	bufferevent_incref_and_lock_(bev);
946d3288293SNick Mathewson 	bufferevent_disable(bev, EV_READ);
947a7384c78SOndřej Kuzník 	bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
948cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bev);
94934574db0SNick Mathewson }
95034574db0SNick Mathewson static void
bufferevent_generic_write_timeout_cb(evutil_socket_t fd,short event,void * ctx)95134574db0SNick Mathewson bufferevent_generic_write_timeout_cb(evutil_socket_t fd, short event, void *ctx)
95234574db0SNick Mathewson {
95334574db0SNick Mathewson 	struct bufferevent *bev = ctx;
954cb9da0bfSNick Mathewson 	bufferevent_incref_and_lock_(bev);
955d3288293SNick Mathewson 	bufferevent_disable(bev, EV_WRITE);
956a7384c78SOndřej Kuzník 	bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
957cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bev);
95834574db0SNick Mathewson }
95934574db0SNick Mathewson 
96034574db0SNick Mathewson void
bufferevent_init_generic_timeout_cbs_(struct bufferevent * bev)961cb9da0bfSNick Mathewson bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev)
96234574db0SNick Mathewson {
96302fbf687SNick Mathewson 	event_assign(&bev->ev_read, bev->ev_base, -1, EV_FINALIZE,
96434574db0SNick Mathewson 	    bufferevent_generic_read_timeout_cb, bev);
96502fbf687SNick Mathewson 	event_assign(&bev->ev_write, bev->ev_base, -1, EV_FINALIZE,
96634574db0SNick Mathewson 	    bufferevent_generic_write_timeout_cb, bev);
96734574db0SNick Mathewson }
96834574db0SNick Mathewson 
969ff3f6cd4SNick Mathewson int
bufferevent_generic_adj_timeouts_(struct bufferevent * bev)970cb9da0bfSNick Mathewson bufferevent_generic_adj_timeouts_(struct bufferevent *bev)
97134574db0SNick Mathewson {
97234574db0SNick Mathewson 	const short enabled = bev->enabled;
97374517b2aSAzat Khuzhin 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
974ff3f6cd4SNick Mathewson 	int r1=0, r2=0;
975d3288293SNick Mathewson 	if ((enabled & EV_READ) && !bev_p->read_suspended &&
976d3288293SNick Mathewson 	    evutil_timerisset(&bev->timeout_read))
977ff3f6cd4SNick Mathewson 		r1 = event_add(&bev->ev_read, &bev->timeout_read);
97834574db0SNick Mathewson 	else
979ff3f6cd4SNick Mathewson 		r1 = event_del(&bev->ev_read);
98034574db0SNick Mathewson 
981d3288293SNick Mathewson 	if ((enabled & EV_WRITE) && !bev_p->write_suspended &&
982d3288293SNick Mathewson 	    evutil_timerisset(&bev->timeout_write) &&
983d3288293SNick Mathewson 	    evbuffer_get_length(bev->output))
984ff3f6cd4SNick Mathewson 		r2 = event_add(&bev->ev_write, &bev->timeout_write);
98534574db0SNick Mathewson 	else
986ff3f6cd4SNick Mathewson 		r2 = event_del(&bev->ev_write);
987ff3f6cd4SNick Mathewson 	if (r1 < 0 || r2 < 0)
988ff3f6cd4SNick Mathewson 		return -1;
989ff3f6cd4SNick Mathewson 	return 0;
99034574db0SNick Mathewson }
99134574db0SNick Mathewson 
992709c21c4SNick Mathewson int
bufferevent_generic_adj_existing_timeouts_(struct bufferevent * bev)9933c1f58f5SAzat Khuzhin bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev)
9943c1f58f5SAzat Khuzhin {
9953c1f58f5SAzat Khuzhin 	int r = 0;
9963c1f58f5SAzat Khuzhin 	if (event_pending(&bev->ev_read, EV_READ, NULL)) {
9973c1f58f5SAzat Khuzhin 		if (evutil_timerisset(&bev->timeout_read)) {
9983c1f58f5SAzat Khuzhin 			    if (bufferevent_add_event_(&bev->ev_read, &bev->timeout_read) < 0)
9993c1f58f5SAzat Khuzhin 				    r = -1;
10003c1f58f5SAzat Khuzhin 		} else {
10013c1f58f5SAzat Khuzhin 			event_remove_timer(&bev->ev_read);
10023c1f58f5SAzat Khuzhin 		}
10033c1f58f5SAzat Khuzhin 	}
10043c1f58f5SAzat Khuzhin 	if (event_pending(&bev->ev_write, EV_WRITE, NULL)) {
10053c1f58f5SAzat Khuzhin 		if (evutil_timerisset(&bev->timeout_write)) {
10063c1f58f5SAzat Khuzhin 			if (bufferevent_add_event_(&bev->ev_write, &bev->timeout_write) < 0)
10073c1f58f5SAzat Khuzhin 				r = -1;
10083c1f58f5SAzat Khuzhin 		} else {
10093c1f58f5SAzat Khuzhin 			event_remove_timer(&bev->ev_write);
10103c1f58f5SAzat Khuzhin 		}
10113c1f58f5SAzat Khuzhin 	}
10123c1f58f5SAzat Khuzhin 	return r;
10133c1f58f5SAzat Khuzhin }
10143c1f58f5SAzat Khuzhin 
10153c1f58f5SAzat Khuzhin int
bufferevent_add_event_(struct event * ev,const struct timeval * tv)1016cb9da0bfSNick Mathewson bufferevent_add_event_(struct event *ev, const struct timeval *tv)
1017709c21c4SNick Mathewson {
1018a96b73b9SAzat Khuzhin 	if (!evutil_timerisset(tv))
1019709c21c4SNick Mathewson 		return event_add(ev, NULL);
1020709c21c4SNick Mathewson 	else
1021709c21c4SNick Mathewson 		return event_add(ev, tv);
1022709c21c4SNick Mathewson }
1023215e629cSNick Mathewson 
1024215e629cSNick Mathewson /* For use by user programs only; internally, we should be calling
1025cb9da0bfSNick Mathewson    either bufferevent_incref_and_lock_(), or BEV_LOCK. */
1026215e629cSNick Mathewson void
bufferevent_lock(struct bufferevent * bev)1027215e629cSNick Mathewson bufferevent_lock(struct bufferevent *bev)
1028215e629cSNick Mathewson {
1029cb9da0bfSNick Mathewson 	bufferevent_incref_and_lock_(bev);
1030215e629cSNick Mathewson }
1031215e629cSNick Mathewson 
1032215e629cSNick Mathewson void
bufferevent_unlock(struct bufferevent * bev)1033215e629cSNick Mathewson bufferevent_unlock(struct bufferevent *bev)
1034215e629cSNick Mathewson {
1035cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bev);
1036215e629cSNick Mathewson }
1037