xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/bufferevent.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: bufferevent.c,v 1.1.1.1 2013/12/27 23:31:18 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
5  * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "event2/event-config.h"
31 #include "evconfig-private.h"
32 
33 #include <sys/types.h>
34 
35 #ifdef EVENT__HAVE_SYS_TIME_H
36 #include <sys/time.h>
37 #endif
38 
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #ifdef EVENT__HAVE_STDARG_H
44 #include <stdarg.h>
45 #endif
46 
47 #ifdef _WIN32
48 #include <winsock2.h>
49 #endif
50 #include <errno.h>
51 
52 #include "event2/util.h"
53 #include "event2/buffer.h"
54 #include "event2/buffer_compat.h"
55 #include "event2/bufferevent.h"
56 #include "event2/bufferevent_struct.h"
57 #include "event2/bufferevent_compat.h"
58 #include "event2/event.h"
59 #include "log-internal.h"
60 #include "mm-internal.h"
61 #include "bufferevent-internal.h"
62 #include "evbuffer-internal.h"
63 #include "util-internal.h"
64 
65 static void bufferevent_cancel_all_(struct bufferevent *bev);
66 
67 
68 void
69 bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
70 {
71 	struct bufferevent_private *bufev_private =
72 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
73 	BEV_LOCK(bufev);
74 	if (!bufev_private->read_suspended)
75 		bufev->be_ops->disable(bufev, EV_READ);
76 	bufev_private->read_suspended |= what;
77 	BEV_UNLOCK(bufev);
78 }
79 
80 void
81 bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
82 {
83 	struct bufferevent_private *bufev_private =
84 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
85 	BEV_LOCK(bufev);
86 	bufev_private->read_suspended &= ~what;
87 	if (!bufev_private->read_suspended && (bufev->enabled & EV_READ))
88 		bufev->be_ops->enable(bufev, EV_READ);
89 	BEV_UNLOCK(bufev);
90 }
91 
92 void
93 bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
94 {
95 	struct bufferevent_private *bufev_private =
96 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
97 	BEV_LOCK(bufev);
98 	if (!bufev_private->write_suspended)
99 		bufev->be_ops->disable(bufev, EV_WRITE);
100 	bufev_private->write_suspended |= what;
101 	BEV_UNLOCK(bufev);
102 }
103 
104 void
105 bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
106 {
107 	struct bufferevent_private *bufev_private =
108 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
109 	BEV_LOCK(bufev);
110 	bufev_private->write_suspended &= ~what;
111 	if (!bufev_private->write_suspended && (bufev->enabled & EV_WRITE))
112 		bufev->be_ops->enable(bufev, EV_WRITE);
113 	BEV_UNLOCK(bufev);
114 }
115 
116 
117 /* Callback to implement watermarks on the input buffer.  Only enabled
118  * if the watermark is set. */
119 static void
120 bufferevent_inbuf_wm_cb(struct evbuffer *buf,
121     const struct evbuffer_cb_info *cbinfo,
122     void *arg)
123 {
124 	struct bufferevent *bufev = arg;
125 	size_t size;
126 
127 	size = evbuffer_get_length(buf);
128 
129 	if (size >= bufev->wm_read.high)
130 		bufferevent_wm_suspend_read(bufev);
131 	else
132 		bufferevent_wm_unsuspend_read(bufev);
133 }
134 
135 static void
136 bufferevent_run_deferred_callbacks_locked(struct event_callback *cb, void *arg)
137 {
138 	struct bufferevent_private *bufev_private = arg;
139 	struct bufferevent *bufev = &bufev_private->bev;
140 
141 	BEV_LOCK(bufev);
142 	if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) &&
143 	    bufev->errorcb) {
144 		/* The "connected" happened before any reads or writes, so
145 		   send it first. */
146 		bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED;
147 		bufev->errorcb(bufev, BEV_EVENT_CONNECTED, bufev->cbarg);
148 	}
149 	if (bufev_private->readcb_pending && bufev->readcb) {
150 		bufev_private->readcb_pending = 0;
151 		bufev->readcb(bufev, bufev->cbarg);
152 	}
153 	if (bufev_private->writecb_pending && bufev->writecb) {
154 		bufev_private->writecb_pending = 0;
155 		bufev->writecb(bufev, bufev->cbarg);
156 	}
157 	if (bufev_private->eventcb_pending && bufev->errorcb) {
158 		short what = bufev_private->eventcb_pending;
159 		int err = bufev_private->errno_pending;
160 		bufev_private->eventcb_pending = 0;
161 		bufev_private->errno_pending = 0;
162 		EVUTIL_SET_SOCKET_ERROR(err);
163 		bufev->errorcb(bufev, what, bufev->cbarg);
164 	}
165 	bufferevent_decref_and_unlock_(bufev);
166 }
167 
168 static void
169 bufferevent_run_deferred_callbacks_unlocked(struct event_callback *cb, void *arg)
170 {
171 	struct bufferevent_private *bufev_private = arg;
172 	struct bufferevent *bufev = &bufev_private->bev;
173 
174 	BEV_LOCK(bufev);
175 #define UNLOCKED(stmt) \
176 	do { BEV_UNLOCK(bufev); stmt; BEV_LOCK(bufev); } while(0)
177 
178 	if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) &&
179 	    bufev->errorcb) {
180 		/* The "connected" happened before any reads or writes, so
181 		   send it first. */
182 		bufferevent_event_cb errorcb = bufev->errorcb;
183 		void *cbarg = bufev->cbarg;
184 		bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED;
185 		UNLOCKED(errorcb(bufev, BEV_EVENT_CONNECTED, cbarg));
186 	}
187 	if (bufev_private->readcb_pending && bufev->readcb) {
188 		bufferevent_data_cb readcb = bufev->readcb;
189 		void *cbarg = bufev->cbarg;
190 		bufev_private->readcb_pending = 0;
191 		UNLOCKED(readcb(bufev, cbarg));
192 	}
193 	if (bufev_private->writecb_pending && bufev->writecb) {
194 		bufferevent_data_cb writecb = bufev->writecb;
195 		void *cbarg = bufev->cbarg;
196 		bufev_private->writecb_pending = 0;
197 		UNLOCKED(writecb(bufev, cbarg));
198 	}
199 	if (bufev_private->eventcb_pending && bufev->errorcb) {
200 		bufferevent_event_cb errorcb = bufev->errorcb;
201 		void *cbarg = bufev->cbarg;
202 		short what = bufev_private->eventcb_pending;
203 		int err = bufev_private->errno_pending;
204 		bufev_private->eventcb_pending = 0;
205 		bufev_private->errno_pending = 0;
206 		EVUTIL_SET_SOCKET_ERROR(err);
207 		UNLOCKED(errorcb(bufev,what,cbarg));
208 	}
209 	bufferevent_decref_and_unlock_(bufev);
210 #undef UNLOCKED
211 }
212 
213 #define SCHEDULE_DEFERRED(bevp)						\
214 	do {								\
215 		if (event_deferred_cb_schedule_(			\
216 			    (bevp)->bev.ev_base,			\
217 			&(bevp)->deferred))				\
218 			bufferevent_incref_(&(bevp)->bev);		\
219 	} while (0)
220 
221 
222 void
223 bufferevent_run_readcb_(struct bufferevent *bufev)
224 {
225 	/* Requires that we hold the lock and a reference */
226 	struct bufferevent_private *p =
227 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
228 	if (bufev->readcb == NULL)
229 		return;
230 	if (p->options & BEV_OPT_DEFER_CALLBACKS) {
231 		p->readcb_pending = 1;
232 		SCHEDULE_DEFERRED(p);
233 	} else {
234 		bufev->readcb(bufev, bufev->cbarg);
235 	}
236 }
237 
238 void
239 bufferevent_run_writecb_(struct bufferevent *bufev)
240 {
241 	/* Requires that we hold the lock and a reference */
242 	struct bufferevent_private *p =
243 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
244 	if (bufev->writecb == NULL)
245 		return;
246 	if (p->options & BEV_OPT_DEFER_CALLBACKS) {
247 		p->writecb_pending = 1;
248 		SCHEDULE_DEFERRED(p);
249 	} else {
250 		bufev->writecb(bufev, bufev->cbarg);
251 	}
252 }
253 
254 void
255 bufferevent_run_eventcb_(struct bufferevent *bufev, short what)
256 {
257 	/* Requires that we hold the lock and a reference */
258 	struct bufferevent_private *p =
259 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
260 	if (bufev->errorcb == NULL)
261 		return;
262 	if (p->options & BEV_OPT_DEFER_CALLBACKS) {
263 		p->eventcb_pending |= what;
264 		p->errno_pending = EVUTIL_SOCKET_ERROR();
265 		SCHEDULE_DEFERRED(p);
266 	} else {
267 		bufev->errorcb(bufev, what, bufev->cbarg);
268 	}
269 }
270 
271 int
272 bufferevent_init_common_(struct bufferevent_private *bufev_private,
273     struct event_base *base,
274     const struct bufferevent_ops *ops,
275     enum bufferevent_options options)
276 {
277 	struct bufferevent *bufev = &bufev_private->bev;
278 
279 	if (!bufev->input) {
280 		if ((bufev->input = evbuffer_new()) == NULL)
281 			return -1;
282 	}
283 
284 	if (!bufev->output) {
285 		if ((bufev->output = evbuffer_new()) == NULL) {
286 			evbuffer_free(bufev->input);
287 			return -1;
288 		}
289 	}
290 
291 	bufev_private->refcnt = 1;
292 	bufev->ev_base = base;
293 
294 	/* Disable timeouts. */
295 	evutil_timerclear(&bufev->timeout_read);
296 	evutil_timerclear(&bufev->timeout_write);
297 
298 	bufev->be_ops = ops;
299 
300 	bufferevent_ratelim_init_(bufev_private);
301 
302 	/*
303 	 * Set to EV_WRITE so that using bufferevent_write is going to
304 	 * trigger a callback.  Reading needs to be explicitly enabled
305 	 * because otherwise no data will be available.
306 	 */
307 	bufev->enabled = EV_WRITE;
308 
309 #ifndef EVENT__DISABLE_THREAD_SUPPORT
310 	if (options & BEV_OPT_THREADSAFE) {
311 		if (bufferevent_enable_locking_(bufev, NULL) < 0) {
312 			/* cleanup */
313 			evbuffer_free(bufev->input);
314 			evbuffer_free(bufev->output);
315 			bufev->input = NULL;
316 			bufev->output = NULL;
317 			return -1;
318 		}
319 	}
320 #endif
321 	if ((options & (BEV_OPT_DEFER_CALLBACKS|BEV_OPT_UNLOCK_CALLBACKS))
322 	    == BEV_OPT_UNLOCK_CALLBACKS) {
323 		event_warnx("UNLOCK_CALLBACKS requires DEFER_CALLBACKS");
324 		return -1;
325 	}
326 	if (options & BEV_OPT_DEFER_CALLBACKS) {
327 		if (options & BEV_OPT_UNLOCK_CALLBACKS)
328 			event_deferred_cb_init_(
329 			    &bufev_private->deferred,
330 			    event_base_get_npriorities(base) / 2,
331 			    bufferevent_run_deferred_callbacks_unlocked,
332 			    bufev_private);
333 		else
334 			event_deferred_cb_init_(
335 			    &bufev_private->deferred,
336 			    event_base_get_npriorities(base) / 2,
337 			    bufferevent_run_deferred_callbacks_locked,
338 			    bufev_private);
339 	}
340 
341 	bufev_private->options = options;
342 
343 	evbuffer_set_parent_(bufev->input, bufev);
344 	evbuffer_set_parent_(bufev->output, bufev);
345 
346 	return 0;
347 }
348 
349 void
350 bufferevent_setcb(struct bufferevent *bufev,
351     bufferevent_data_cb readcb, bufferevent_data_cb writecb,
352     bufferevent_event_cb eventcb, void *cbarg)
353 {
354 	BEV_LOCK(bufev);
355 
356 	bufev->readcb = readcb;
357 	bufev->writecb = writecb;
358 	bufev->errorcb = eventcb;
359 
360 	bufev->cbarg = cbarg;
361 	BEV_UNLOCK(bufev);
362 }
363 
364 void
365 bufferevent_getcb(struct bufferevent *bufev,
366     bufferevent_data_cb *readcb_ptr,
367     bufferevent_data_cb *writecb_ptr,
368     bufferevent_event_cb *eventcb_ptr,
369     void **cbarg_ptr)
370 {
371 	BEV_LOCK(bufev);
372 	if (readcb_ptr)
373 		*readcb_ptr = bufev->readcb;
374 	if (writecb_ptr)
375 		*writecb_ptr = bufev->writecb;
376 	if (eventcb_ptr)
377 		*eventcb_ptr = bufev->errorcb;
378 	if (cbarg_ptr)
379 		*cbarg_ptr = bufev->cbarg;
380 
381 	BEV_UNLOCK(bufev);
382 }
383 
384 struct evbuffer *
385 bufferevent_get_input(struct bufferevent *bufev)
386 {
387 	return bufev->input;
388 }
389 
390 struct evbuffer *
391 bufferevent_get_output(struct bufferevent *bufev)
392 {
393 	return bufev->output;
394 }
395 
396 struct event_base *
397 bufferevent_get_base(struct bufferevent *bufev)
398 {
399 	return bufev->ev_base;
400 }
401 
402 int
403 bufferevent_get_priority(const struct bufferevent *bufev)
404 {
405 	if (event_initialized(&bufev->ev_read)) {
406 		return event_get_priority(&bufev->ev_read);
407 	} else {
408 		return event_base_get_npriorities(bufev->ev_base) / 2;
409 	}
410 }
411 
412 int
413 bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
414 {
415 	if (evbuffer_add(bufev->output, data, size) == -1)
416 		return (-1);
417 
418 	return 0;
419 }
420 
421 int
422 bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
423 {
424 	if (evbuffer_add_buffer(bufev->output, buf) == -1)
425 		return (-1);
426 
427 	return 0;
428 }
429 
430 size_t
431 bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
432 {
433 	return (evbuffer_remove(bufev->input, data, size));
434 }
435 
436 int
437 bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf)
438 {
439 	return (evbuffer_add_buffer(buf, bufev->input));
440 }
441 
442 int
443 bufferevent_enable(struct bufferevent *bufev, short event)
444 {
445 	struct bufferevent_private *bufev_private =
446 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
447 	short impl_events = event;
448 	int r = 0;
449 
450 	bufferevent_incref_and_lock_(bufev);
451 	if (bufev_private->read_suspended)
452 		impl_events &= ~EV_READ;
453 	if (bufev_private->write_suspended)
454 		impl_events &= ~EV_WRITE;
455 
456 	bufev->enabled |= event;
457 
458 	if (impl_events && bufev->be_ops->enable(bufev, impl_events) < 0)
459 		r = -1;
460 
461 	bufferevent_decref_and_unlock_(bufev);
462 	return r;
463 }
464 
465 int
466 bufferevent_set_timeouts(struct bufferevent *bufev,
467 			 const struct timeval *tv_read,
468 			 const struct timeval *tv_write)
469 {
470 	int r = 0;
471 	BEV_LOCK(bufev);
472 	if (tv_read) {
473 		bufev->timeout_read = *tv_read;
474 	} else {
475 		evutil_timerclear(&bufev->timeout_read);
476 	}
477 	if (tv_write) {
478 		bufev->timeout_write = *tv_write;
479 	} else {
480 		evutil_timerclear(&bufev->timeout_write);
481 	}
482 
483 	if (bufev->be_ops->adj_timeouts)
484 		r = bufev->be_ops->adj_timeouts(bufev);
485 	BEV_UNLOCK(bufev);
486 
487 	return r;
488 }
489 
490 
491 /* Obsolete; use bufferevent_set_timeouts */
492 void
493 bufferevent_settimeout(struct bufferevent *bufev,
494 		       int timeout_read, int timeout_write)
495 {
496 	struct timeval tv_read, tv_write;
497 	struct timeval *ptv_read = NULL, *ptv_write = NULL;
498 
499 	memset(&tv_read, 0, sizeof(tv_read));
500 	memset(&tv_write, 0, sizeof(tv_write));
501 
502 	if (timeout_read) {
503 		tv_read.tv_sec = timeout_read;
504 		ptv_read = &tv_read;
505 	}
506 	if (timeout_write) {
507 		tv_write.tv_sec = timeout_write;
508 		ptv_write = &tv_write;
509 	}
510 
511 	bufferevent_set_timeouts(bufev, ptv_read, ptv_write);
512 }
513 
514 
515 int
516 bufferevent_disable_hard_(struct bufferevent *bufev, short event)
517 {
518 	int r = 0;
519 	struct bufferevent_private *bufev_private =
520 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
521 
522 	BEV_LOCK(bufev);
523 	bufev->enabled &= ~event;
524 
525 	bufev_private->connecting = 0;
526 	if (bufev->be_ops->disable(bufev, event) < 0)
527 		r = -1;
528 
529 	BEV_UNLOCK(bufev);
530 	return r;
531 }
532 
533 int
534 bufferevent_disable(struct bufferevent *bufev, short event)
535 {
536 	int r = 0;
537 
538 	BEV_LOCK(bufev);
539 	bufev->enabled &= ~event;
540 
541 	if (bufev->be_ops->disable(bufev, event) < 0)
542 		r = -1;
543 
544 	BEV_UNLOCK(bufev);
545 	return r;
546 }
547 
548 /*
549  * Sets the water marks
550  */
551 
552 void
553 bufferevent_setwatermark(struct bufferevent *bufev, short events,
554     size_t lowmark, size_t highmark)
555 {
556 	struct bufferevent_private *bufev_private =
557 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
558 
559 	BEV_LOCK(bufev);
560 	if (events & EV_WRITE) {
561 		bufev->wm_write.low = lowmark;
562 		bufev->wm_write.high = highmark;
563 	}
564 
565 	if (events & EV_READ) {
566 		bufev->wm_read.low = lowmark;
567 		bufev->wm_read.high = highmark;
568 
569 		if (highmark) {
570 			/* There is now a new high-water mark for read.
571 			   enable the callback if needed, and see if we should
572 			   suspend/bufferevent_wm_unsuspend. */
573 
574 			if (bufev_private->read_watermarks_cb == NULL) {
575 				bufev_private->read_watermarks_cb =
576 				    evbuffer_add_cb(bufev->input,
577 						    bufferevent_inbuf_wm_cb,
578 						    bufev);
579 			}
580 			evbuffer_cb_set_flags(bufev->input,
581 				      bufev_private->read_watermarks_cb,
582 				      EVBUFFER_CB_ENABLED|EVBUFFER_CB_NODEFER);
583 
584 			if (evbuffer_get_length(bufev->input) > highmark)
585 				bufferevent_wm_suspend_read(bufev);
586 			else if (evbuffer_get_length(bufev->input) < highmark)
587 				bufferevent_wm_unsuspend_read(bufev);
588 		} else {
589 			/* There is now no high-water mark for read. */
590 			if (bufev_private->read_watermarks_cb)
591 				evbuffer_cb_clear_flags(bufev->input,
592 				    bufev_private->read_watermarks_cb,
593 				    EVBUFFER_CB_ENABLED);
594 			bufferevent_wm_unsuspend_read(bufev);
595 		}
596 	}
597 	BEV_UNLOCK(bufev);
598 }
599 
600 int
601 bufferevent_flush(struct bufferevent *bufev,
602     short iotype,
603     enum bufferevent_flush_mode mode)
604 {
605 	int r = -1;
606 	BEV_LOCK(bufev);
607 	if (bufev->be_ops->flush)
608 		r = bufev->be_ops->flush(bufev, iotype, mode);
609 	BEV_UNLOCK(bufev);
610 	return r;
611 }
612 
613 void
614 bufferevent_incref_and_lock_(struct bufferevent *bufev)
615 {
616 	struct bufferevent_private *bufev_private =
617 	    BEV_UPCAST(bufev);
618 	BEV_LOCK(bufev);
619 	++bufev_private->refcnt;
620 }
621 
622 #if 0
623 static void
624 bufferevent_transfer_lock_ownership_(struct bufferevent *donor,
625     struct bufferevent *recipient)
626 {
627 	struct bufferevent_private *d = BEV_UPCAST(donor);
628 	struct bufferevent_private *r = BEV_UPCAST(recipient);
629 	if (d->lock != r->lock)
630 		return;
631 	if (r->own_lock)
632 		return;
633 	if (d->own_lock) {
634 		d->own_lock = 0;
635 		r->own_lock = 1;
636 	}
637 }
638 #endif
639 
640 int
641 bufferevent_decref_and_unlock_(struct bufferevent *bufev)
642 {
643 	struct bufferevent_private *bufev_private =
644 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
645 	struct bufferevent *underlying;
646 
647 	EVUTIL_ASSERT(bufev_private->refcnt > 0);
648 
649 	if (--bufev_private->refcnt) {
650 		BEV_UNLOCK(bufev);
651 		return 0;
652 	}
653 
654 	underlying = bufferevent_get_underlying(bufev);
655 
656 	/* Clean up the shared info */
657 	if (bufev->be_ops->destruct)
658 		bufev->be_ops->destruct(bufev);
659 
660 	/* XXX what happens if refcnt for these buffers is > 1?
661 	 * The buffers can share a lock with this bufferevent object,
662 	 * but the lock might be destroyed below. */
663 	/* evbuffer will free the callbacks */
664 	evbuffer_free(bufev->input);
665 	evbuffer_free(bufev->output);
666 
667 	if (bufev_private->rate_limiting) {
668 		if (bufev_private->rate_limiting->group)
669 			bufferevent_remove_from_rate_limit_group_internal_(bufev,0);
670 		if (event_initialized(&bufev_private->rate_limiting->refill_bucket_event))
671 			event_del(&bufev_private->rate_limiting->refill_bucket_event);
672 		event_debug_unassign(&bufev_private->rate_limiting->refill_bucket_event);
673 		mm_free(bufev_private->rate_limiting);
674 		bufev_private->rate_limiting = NULL;
675 	}
676 
677 	event_debug_unassign(&bufev->ev_read);
678 	event_debug_unassign(&bufev->ev_write);
679 
680 	BEV_UNLOCK(bufev);
681 	if (bufev_private->own_lock)
682 		EVTHREAD_FREE_LOCK(bufev_private->lock,
683 		    EVTHREAD_LOCKTYPE_RECURSIVE);
684 
685 	/* Free the actual allocated memory. */
686 	mm_free(((char*)bufev) - bufev->be_ops->mem_offset);
687 
688 	/* Release the reference to underlying now that we no longer need the
689 	 * reference to it.  We wait this long mainly in case our lock is
690 	 * shared with underlying.
691 	 *
692 	 * The 'destruct' function will also drop a reference to underlying
693 	 * if BEV_OPT_CLOSE_ON_FREE is set.
694 	 *
695 	 * XXX Should we/can we just refcount evbuffer/bufferevent locks?
696 	 * It would probably save us some headaches.
697 	 */
698 	if (underlying)
699 		bufferevent_decref_(underlying);
700 
701 	return 1;
702 }
703 
704 int
705 bufferevent_decref_(struct bufferevent *bufev)
706 {
707 	BEV_LOCK(bufev);
708 	return bufferevent_decref_and_unlock_(bufev);
709 }
710 
711 void
712 bufferevent_free(struct bufferevent *bufev)
713 {
714 	BEV_LOCK(bufev);
715 	bufferevent_setcb(bufev, NULL, NULL, NULL, NULL);
716 	bufferevent_cancel_all_(bufev);
717 	bufferevent_decref_and_unlock_(bufev);
718 }
719 
720 void
721 bufferevent_incref_(struct bufferevent *bufev)
722 {
723 	struct bufferevent_private *bufev_private =
724 	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
725 
726 	BEV_LOCK(bufev);
727 	++bufev_private->refcnt;
728 	BEV_UNLOCK(bufev);
729 }
730 
731 int
732 bufferevent_enable_locking_(struct bufferevent *bufev, void *lock)
733 {
734 #ifdef EVENT__DISABLE_THREAD_SUPPORT
735 	return -1;
736 #else
737 	struct bufferevent *underlying;
738 
739 	if (BEV_UPCAST(bufev)->lock)
740 		return -1;
741 	underlying = bufferevent_get_underlying(bufev);
742 
743 	if (!lock && underlying && BEV_UPCAST(underlying)->lock) {
744 		lock = BEV_UPCAST(underlying)->lock;
745 		BEV_UPCAST(bufev)->lock = lock;
746 		BEV_UPCAST(bufev)->own_lock = 0;
747 	} else if (!lock) {
748 		EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
749 		if (!lock)
750 			return -1;
751 		BEV_UPCAST(bufev)->lock = lock;
752 		BEV_UPCAST(bufev)->own_lock = 1;
753 	} else {
754 		BEV_UPCAST(bufev)->lock = lock;
755 		BEV_UPCAST(bufev)->own_lock = 0;
756 	}
757 	evbuffer_enable_locking(bufev->input, lock);
758 	evbuffer_enable_locking(bufev->output, lock);
759 
760 	if (underlying && !BEV_UPCAST(underlying)->lock)
761 		bufferevent_enable_locking_(underlying, lock);
762 
763 	return 0;
764 #endif
765 }
766 
767 int
768 bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd)
769 {
770 	union bufferevent_ctrl_data d;
771 	int res = -1;
772 	d.fd = fd;
773 	BEV_LOCK(bev);
774 	if (bev->be_ops->ctrl)
775 		res = bev->be_ops->ctrl(bev, BEV_CTRL_SET_FD, &d);
776 	BEV_UNLOCK(bev);
777 	return res;
778 }
779 
780 evutil_socket_t
781 bufferevent_getfd(struct bufferevent *bev)
782 {
783 	union bufferevent_ctrl_data d;
784 	int res = -1;
785 	d.fd = -1;
786 	BEV_LOCK(bev);
787 	if (bev->be_ops->ctrl)
788 		res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_FD, &d);
789 	BEV_UNLOCK(bev);
790 	return (res<0) ? -1 : d.fd;
791 }
792 
793 static void
794 bufferevent_cancel_all_(struct bufferevent *bev)
795 {
796 	union bufferevent_ctrl_data d;
797 	memset(&d, 0, sizeof(d));
798 	BEV_LOCK(bev);
799 	if (bev->be_ops->ctrl)
800 		bev->be_ops->ctrl(bev, BEV_CTRL_CANCEL_ALL, &d);
801 	BEV_UNLOCK(bev);
802 }
803 
804 short
805 bufferevent_get_enabled(struct bufferevent *bufev)
806 {
807 	short r;
808 	BEV_LOCK(bufev);
809 	r = bufev->enabled;
810 	BEV_UNLOCK(bufev);
811 	return r;
812 }
813 
814 struct bufferevent *
815 bufferevent_get_underlying(struct bufferevent *bev)
816 {
817 	union bufferevent_ctrl_data d;
818 	int res = -1;
819 	d.ptr = NULL;
820 	BEV_LOCK(bev);
821 	if (bev->be_ops->ctrl)
822 		res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_UNDERLYING, &d);
823 	BEV_UNLOCK(bev);
824 	return (res<0) ? NULL : d.ptr;
825 }
826 
827 static void
828 bufferevent_generic_read_timeout_cb(evutil_socket_t fd, short event, void *ctx)
829 {
830 	struct bufferevent *bev = ctx;
831 	bufferevent_incref_and_lock_(bev);
832 	bufferevent_disable(bev, EV_READ);
833 	bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING);
834 	bufferevent_decref_and_unlock_(bev);
835 }
836 static void
837 bufferevent_generic_write_timeout_cb(evutil_socket_t fd, short event, void *ctx)
838 {
839 	struct bufferevent *bev = ctx;
840 	bufferevent_incref_and_lock_(bev);
841 	bufferevent_disable(bev, EV_WRITE);
842 	bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING);
843 	bufferevent_decref_and_unlock_(bev);
844 }
845 
846 void
847 bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev)
848 {
849 	evtimer_assign(&bev->ev_read, bev->ev_base,
850 	    bufferevent_generic_read_timeout_cb, bev);
851 	evtimer_assign(&bev->ev_write, bev->ev_base,
852 	    bufferevent_generic_write_timeout_cb, bev);
853 }
854 
855 int
856 bufferevent_del_generic_timeout_cbs_(struct bufferevent *bev)
857 {
858 	int r1,r2;
859 	r1 = event_del(&bev->ev_read);
860 	r2 = event_del(&bev->ev_write);
861 	if (r1<0 || r2<0)
862 		return -1;
863 	return 0;
864 }
865 
866 int
867 bufferevent_generic_adj_timeouts_(struct bufferevent *bev)
868 {
869 	const short enabled = bev->enabled;
870 	struct bufferevent_private *bev_p =
871 	    EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
872 	int r1=0, r2=0;
873 	if ((enabled & EV_READ) && !bev_p->read_suspended &&
874 	    evutil_timerisset(&bev->timeout_read))
875 		r1 = event_add(&bev->ev_read, &bev->timeout_read);
876 	else
877 		r1 = event_del(&bev->ev_read);
878 
879 	if ((enabled & EV_WRITE) && !bev_p->write_suspended &&
880 	    evutil_timerisset(&bev->timeout_write) &&
881 	    evbuffer_get_length(bev->output))
882 		r2 = event_add(&bev->ev_write, &bev->timeout_write);
883 	else
884 		r2 = event_del(&bev->ev_write);
885 	if (r1 < 0 || r2 < 0)
886 		return -1;
887 	return 0;
888 }
889 
890 int
891 bufferevent_add_event_(struct event *ev, const struct timeval *tv)
892 {
893 	if (tv->tv_sec == 0 && tv->tv_usec == 0)
894 		return event_add(ev, NULL);
895 	else
896 		return event_add(ev, tv);
897 }
898 
899 /* For use by user programs only; internally, we should be calling
900    either bufferevent_incref_and_lock_(), or BEV_LOCK. */
901 void
902 bufferevent_lock(struct bufferevent *bev)
903 {
904 	bufferevent_incref_and_lock_(bev);
905 }
906 
907 void
908 bufferevent_unlock(struct bufferevent *bev)
909 {
910 	bufferevent_decref_and_unlock_(bev);
911 }
912