1*eabc0478Schristos /* $NetBSD: bufferevent.c,v 1.7 2024/08/18 20:47:20 christos Exp $ */ 28585484eSchristos 38585484eSchristos /* 48585484eSchristos * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu> 58585484eSchristos * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson 68585484eSchristos * 78585484eSchristos * Redistribution and use in source and binary forms, with or without 88585484eSchristos * modification, are permitted provided that the following conditions 98585484eSchristos * are met: 108585484eSchristos * 1. Redistributions of source code must retain the above copyright 118585484eSchristos * notice, this list of conditions and the following disclaimer. 128585484eSchristos * 2. Redistributions in binary form must reproduce the above copyright 138585484eSchristos * notice, this list of conditions and the following disclaimer in the 148585484eSchristos * documentation and/or other materials provided with the distribution. 158585484eSchristos * 3. The name of the author may not be used to endorse or promote products 168585484eSchristos * derived from this software without specific prior written permission. 178585484eSchristos * 188585484eSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 198585484eSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 208585484eSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 218585484eSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 228585484eSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 238585484eSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 248585484eSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 258585484eSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 268585484eSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 278585484eSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 288585484eSchristos */ 298585484eSchristos 308585484eSchristos #include "event2/event-config.h" 318585484eSchristos #include "evconfig-private.h" 328585484eSchristos 338585484eSchristos #include <sys/types.h> 348585484eSchristos 358585484eSchristos #ifdef EVENT__HAVE_SYS_TIME_H 368585484eSchristos #include <sys/time.h> 378585484eSchristos #endif 388585484eSchristos 398585484eSchristos #include <errno.h> 408585484eSchristos #include <stdio.h> 418585484eSchristos #include <stdlib.h> 428585484eSchristos #include <string.h> 438585484eSchristos #ifdef EVENT__HAVE_STDARG_H 448585484eSchristos #include <stdarg.h> 458585484eSchristos #endif 468585484eSchristos 478585484eSchristos #ifdef _WIN32 488585484eSchristos #include <winsock2.h> 498585484eSchristos #endif 508585484eSchristos 518585484eSchristos #include "event2/util.h" 528585484eSchristos #include "event2/buffer.h" 538585484eSchristos #include "event2/buffer_compat.h" 548585484eSchristos #include "event2/bufferevent.h" 558585484eSchristos #include "event2/bufferevent_struct.h" 568585484eSchristos #include "event2/bufferevent_compat.h" 578585484eSchristos #include "event2/event.h" 58b8ecfcfeSchristos #include "event-internal.h" 598585484eSchristos #include "log-internal.h" 608585484eSchristos #include "mm-internal.h" 618585484eSchristos #include "bufferevent-internal.h" 628585484eSchristos #include "evbuffer-internal.h" 638585484eSchristos #include "util-internal.h" 648585484eSchristos 658585484eSchristos static void bufferevent_cancel_all_(struct bufferevent *bev); 66b8ecfcfeSchristos static void bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_); 678585484eSchristos 688585484eSchristos void 698585484eSchristos bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what) 708585484eSchristos { 71*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 728585484eSchristos BEV_LOCK(bufev); 738585484eSchristos if (!bufev_private->read_suspended) 748585484eSchristos bufev->be_ops->disable(bufev, EV_READ); 758585484eSchristos bufev_private->read_suspended |= what; 768585484eSchristos BEV_UNLOCK(bufev); 778585484eSchristos } 788585484eSchristos 798585484eSchristos void 808585484eSchristos bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what) 818585484eSchristos { 82*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 838585484eSchristos BEV_LOCK(bufev); 848585484eSchristos bufev_private->read_suspended &= ~what; 858585484eSchristos if (!bufev_private->read_suspended && (bufev->enabled & EV_READ)) 868585484eSchristos bufev->be_ops->enable(bufev, EV_READ); 878585484eSchristos BEV_UNLOCK(bufev); 888585484eSchristos } 898585484eSchristos 908585484eSchristos void 918585484eSchristos bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what) 928585484eSchristos { 93*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 948585484eSchristos BEV_LOCK(bufev); 958585484eSchristos if (!bufev_private->write_suspended) 968585484eSchristos bufev->be_ops->disable(bufev, EV_WRITE); 978585484eSchristos bufev_private->write_suspended |= what; 988585484eSchristos BEV_UNLOCK(bufev); 998585484eSchristos } 1008585484eSchristos 1018585484eSchristos void 1028585484eSchristos bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what) 1038585484eSchristos { 104*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 1058585484eSchristos BEV_LOCK(bufev); 1068585484eSchristos bufev_private->write_suspended &= ~what; 1078585484eSchristos if (!bufev_private->write_suspended && (bufev->enabled & EV_WRITE)) 1088585484eSchristos bufev->be_ops->enable(bufev, EV_WRITE); 1098585484eSchristos BEV_UNLOCK(bufev); 1108585484eSchristos } 1118585484eSchristos 112*eabc0478Schristos /** 113*eabc0478Schristos * Sometimes bufferevent's implementation can overrun high watermarks 114*eabc0478Schristos * (one of examples is openssl) and in this case if the read callback 115*eabc0478Schristos * will not handle enough data do over condition above the read 116*eabc0478Schristos * callback will never be called again (due to suspend above). 117*eabc0478Schristos * 118*eabc0478Schristos * To avoid this we are scheduling read callback again here, but only 119*eabc0478Schristos * from the user callback to avoid multiple scheduling: 120*eabc0478Schristos * - when the data had been added to it 121*eabc0478Schristos * - when the data had been drained from it (user specified read callback) 122*eabc0478Schristos */ 123*eabc0478Schristos static void bufferevent_inbuf_wm_check(struct bufferevent *bev) 124*eabc0478Schristos { 125*eabc0478Schristos if (!bev->wm_read.high) 126*eabc0478Schristos return; 127*eabc0478Schristos if (!(bev->enabled & EV_READ)) 128*eabc0478Schristos return; 129*eabc0478Schristos if (evbuffer_get_length(bev->input) < bev->wm_read.high) 130*eabc0478Schristos return; 131*eabc0478Schristos 132*eabc0478Schristos bufferevent_trigger(bev, EV_READ, BEV_OPT_DEFER_CALLBACKS); 133*eabc0478Schristos } 1348585484eSchristos 1358585484eSchristos /* Callback to implement watermarks on the input buffer. Only enabled 1368585484eSchristos * if the watermark is set. */ 1378585484eSchristos static void 1388585484eSchristos bufferevent_inbuf_wm_cb(struct evbuffer *buf, 1398585484eSchristos const struct evbuffer_cb_info *cbinfo, 1408585484eSchristos void *arg) 1418585484eSchristos { 1428585484eSchristos struct bufferevent *bufev = arg; 1438585484eSchristos size_t size; 1448585484eSchristos 1458585484eSchristos size = evbuffer_get_length(buf); 1468585484eSchristos 1478585484eSchristos if (size >= bufev->wm_read.high) 1488585484eSchristos bufferevent_wm_suspend_read(bufev); 1498585484eSchristos else 1508585484eSchristos bufferevent_wm_unsuspend_read(bufev); 1518585484eSchristos } 1528585484eSchristos 1538585484eSchristos static void 1548585484eSchristos bufferevent_run_deferred_callbacks_locked(struct event_callback *cb, void *arg) 1558585484eSchristos { 1568585484eSchristos struct bufferevent_private *bufev_private = arg; 1578585484eSchristos struct bufferevent *bufev = &bufev_private->bev; 1588585484eSchristos 1598585484eSchristos BEV_LOCK(bufev); 1608585484eSchristos if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) && 1618585484eSchristos bufev->errorcb) { 1628585484eSchristos /* The "connected" happened before any reads or writes, so 1638585484eSchristos send it first. */ 1648585484eSchristos bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED; 1658585484eSchristos bufev->errorcb(bufev, BEV_EVENT_CONNECTED, bufev->cbarg); 1668585484eSchristos } 1678585484eSchristos if (bufev_private->readcb_pending && bufev->readcb) { 1688585484eSchristos bufev_private->readcb_pending = 0; 1698585484eSchristos bufev->readcb(bufev, bufev->cbarg); 170*eabc0478Schristos bufferevent_inbuf_wm_check(bufev); 1718585484eSchristos } 1728585484eSchristos if (bufev_private->writecb_pending && bufev->writecb) { 1738585484eSchristos bufev_private->writecb_pending = 0; 1748585484eSchristos bufev->writecb(bufev, bufev->cbarg); 1758585484eSchristos } 1768585484eSchristos if (bufev_private->eventcb_pending && bufev->errorcb) { 1778585484eSchristos short what = bufev_private->eventcb_pending; 1788585484eSchristos int err = bufev_private->errno_pending; 1798585484eSchristos bufev_private->eventcb_pending = 0; 1808585484eSchristos bufev_private->errno_pending = 0; 1818585484eSchristos EVUTIL_SET_SOCKET_ERROR(err); 1828585484eSchristos bufev->errorcb(bufev, what, bufev->cbarg); 1838585484eSchristos } 1848585484eSchristos bufferevent_decref_and_unlock_(bufev); 1858585484eSchristos } 1868585484eSchristos 1878585484eSchristos static void 1888585484eSchristos bufferevent_run_deferred_callbacks_unlocked(struct event_callback *cb, void *arg) 1898585484eSchristos { 1908585484eSchristos struct bufferevent_private *bufev_private = arg; 1918585484eSchristos struct bufferevent *bufev = &bufev_private->bev; 1928585484eSchristos 1938585484eSchristos BEV_LOCK(bufev); 1948585484eSchristos #define UNLOCKED(stmt) \ 1958585484eSchristos do { BEV_UNLOCK(bufev); stmt; BEV_LOCK(bufev); } while(0) 1968585484eSchristos 1978585484eSchristos if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) && 1988585484eSchristos bufev->errorcb) { 1998585484eSchristos /* The "connected" happened before any reads or writes, so 2008585484eSchristos send it first. */ 2018585484eSchristos bufferevent_event_cb errorcb = bufev->errorcb; 2028585484eSchristos void *cbarg = bufev->cbarg; 2038585484eSchristos bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED; 2048585484eSchristos UNLOCKED(errorcb(bufev, BEV_EVENT_CONNECTED, cbarg)); 2058585484eSchristos } 2068585484eSchristos if (bufev_private->readcb_pending && bufev->readcb) { 2078585484eSchristos bufferevent_data_cb readcb = bufev->readcb; 2088585484eSchristos void *cbarg = bufev->cbarg; 2098585484eSchristos bufev_private->readcb_pending = 0; 2108585484eSchristos UNLOCKED(readcb(bufev, cbarg)); 211*eabc0478Schristos bufferevent_inbuf_wm_check(bufev); 2128585484eSchristos } 2138585484eSchristos if (bufev_private->writecb_pending && bufev->writecb) { 2148585484eSchristos bufferevent_data_cb writecb = bufev->writecb; 2158585484eSchristos void *cbarg = bufev->cbarg; 2168585484eSchristos bufev_private->writecb_pending = 0; 2178585484eSchristos UNLOCKED(writecb(bufev, cbarg)); 2188585484eSchristos } 2198585484eSchristos if (bufev_private->eventcb_pending && bufev->errorcb) { 2208585484eSchristos bufferevent_event_cb errorcb = bufev->errorcb; 2218585484eSchristos void *cbarg = bufev->cbarg; 2228585484eSchristos short what = bufev_private->eventcb_pending; 2238585484eSchristos int err = bufev_private->errno_pending; 2248585484eSchristos bufev_private->eventcb_pending = 0; 2258585484eSchristos bufev_private->errno_pending = 0; 2268585484eSchristos EVUTIL_SET_SOCKET_ERROR(err); 2278585484eSchristos UNLOCKED(errorcb(bufev,what,cbarg)); 2288585484eSchristos } 2298585484eSchristos bufferevent_decref_and_unlock_(bufev); 2308585484eSchristos #undef UNLOCKED 2318585484eSchristos } 2328585484eSchristos 2338585484eSchristos #define SCHEDULE_DEFERRED(bevp) \ 2348585484eSchristos do { \ 2358585484eSchristos if (event_deferred_cb_schedule_( \ 2368585484eSchristos (bevp)->bev.ev_base, \ 2378585484eSchristos &(bevp)->deferred)) \ 2388585484eSchristos bufferevent_incref_(&(bevp)->bev); \ 2398585484eSchristos } while (0) 2408585484eSchristos 2418585484eSchristos 2428585484eSchristos void 243b8ecfcfeSchristos bufferevent_run_readcb_(struct bufferevent *bufev, int options) 2448585484eSchristos { 2458585484eSchristos /* Requires that we hold the lock and a reference */ 246*eabc0478Schristos struct bufferevent_private *p = BEV_UPCAST(bufev); 2478585484eSchristos if (bufev->readcb == NULL) 2488585484eSchristos return; 249b8ecfcfeSchristos if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) { 2508585484eSchristos p->readcb_pending = 1; 2518585484eSchristos SCHEDULE_DEFERRED(p); 2528585484eSchristos } else { 2538585484eSchristos bufev->readcb(bufev, bufev->cbarg); 254*eabc0478Schristos bufferevent_inbuf_wm_check(bufev); 2558585484eSchristos } 2568585484eSchristos } 2578585484eSchristos 2588585484eSchristos void 259b8ecfcfeSchristos bufferevent_run_writecb_(struct bufferevent *bufev, int options) 2608585484eSchristos { 2618585484eSchristos /* Requires that we hold the lock and a reference */ 262*eabc0478Schristos struct bufferevent_private *p = BEV_UPCAST(bufev); 2638585484eSchristos if (bufev->writecb == NULL) 2648585484eSchristos return; 265b8ecfcfeSchristos if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) { 2668585484eSchristos p->writecb_pending = 1; 2678585484eSchristos SCHEDULE_DEFERRED(p); 2688585484eSchristos } else { 2698585484eSchristos bufev->writecb(bufev, bufev->cbarg); 2708585484eSchristos } 2718585484eSchristos } 2728585484eSchristos 273b8ecfcfeSchristos #define BEV_TRIG_ALL_OPTS ( \ 274b8ecfcfeSchristos BEV_TRIG_IGNORE_WATERMARKS| \ 275b8ecfcfeSchristos BEV_TRIG_DEFER_CALLBACKS \ 276b8ecfcfeSchristos ) 277b8ecfcfeSchristos 2788585484eSchristos void 279b8ecfcfeSchristos bufferevent_trigger(struct bufferevent *bufev, short iotype, int options) 280b8ecfcfeSchristos { 281b8ecfcfeSchristos bufferevent_incref_and_lock_(bufev); 282b8ecfcfeSchristos bufferevent_trigger_nolock_(bufev, iotype, options&BEV_TRIG_ALL_OPTS); 283b8ecfcfeSchristos bufferevent_decref_and_unlock_(bufev); 284b8ecfcfeSchristos } 285b8ecfcfeSchristos 286b8ecfcfeSchristos void 287b8ecfcfeSchristos bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options) 2888585484eSchristos { 2898585484eSchristos /* Requires that we hold the lock and a reference */ 290*eabc0478Schristos struct bufferevent_private *p = BEV_UPCAST(bufev); 2918585484eSchristos if (bufev->errorcb == NULL) 2928585484eSchristos return; 293b8ecfcfeSchristos if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) { 2948585484eSchristos p->eventcb_pending |= what; 2958585484eSchristos p->errno_pending = EVUTIL_SOCKET_ERROR(); 2968585484eSchristos SCHEDULE_DEFERRED(p); 2978585484eSchristos } else { 2988585484eSchristos bufev->errorcb(bufev, what, bufev->cbarg); 2998585484eSchristos } 3008585484eSchristos } 3018585484eSchristos 302b8ecfcfeSchristos void 303b8ecfcfeSchristos bufferevent_trigger_event(struct bufferevent *bufev, short what, int options) 304b8ecfcfeSchristos { 305b8ecfcfeSchristos bufferevent_incref_and_lock_(bufev); 306b8ecfcfeSchristos bufferevent_run_eventcb_(bufev, what, options&BEV_TRIG_ALL_OPTS); 307b8ecfcfeSchristos bufferevent_decref_and_unlock_(bufev); 308b8ecfcfeSchristos } 309b8ecfcfeSchristos 3108585484eSchristos int 3118585484eSchristos bufferevent_init_common_(struct bufferevent_private *bufev_private, 3128585484eSchristos struct event_base *base, 3138585484eSchristos const struct bufferevent_ops *ops, 3148585484eSchristos enum bufferevent_options options) 3158585484eSchristos { 3168585484eSchristos struct bufferevent *bufev = &bufev_private->bev; 3178585484eSchristos 3188585484eSchristos if (!bufev->input) { 3198585484eSchristos if ((bufev->input = evbuffer_new()) == NULL) 320*eabc0478Schristos goto err; 3218585484eSchristos } 3228585484eSchristos 3238585484eSchristos if (!bufev->output) { 324*eabc0478Schristos if ((bufev->output = evbuffer_new()) == NULL) 325*eabc0478Schristos goto err; 3268585484eSchristos } 3278585484eSchristos 3288585484eSchristos bufev_private->refcnt = 1; 3298585484eSchristos bufev->ev_base = base; 3308585484eSchristos 3318585484eSchristos /* Disable timeouts. */ 3328585484eSchristos evutil_timerclear(&bufev->timeout_read); 3338585484eSchristos evutil_timerclear(&bufev->timeout_write); 3348585484eSchristos 3358585484eSchristos bufev->be_ops = ops; 3368585484eSchristos 337*eabc0478Schristos if (bufferevent_ratelim_init_(bufev_private)) 338*eabc0478Schristos goto err; 3398585484eSchristos 3408585484eSchristos /* 3418585484eSchristos * Set to EV_WRITE so that using bufferevent_write is going to 3428585484eSchristos * trigger a callback. Reading needs to be explicitly enabled 3438585484eSchristos * because otherwise no data will be available. 3448585484eSchristos */ 3458585484eSchristos bufev->enabled = EV_WRITE; 3468585484eSchristos 3478585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT 3488585484eSchristos if (options & BEV_OPT_THREADSAFE) { 349*eabc0478Schristos if (bufferevent_enable_locking_(bufev, NULL) < 0) 350*eabc0478Schristos goto err; 3518585484eSchristos } 3528585484eSchristos #endif 3538585484eSchristos if ((options & (BEV_OPT_DEFER_CALLBACKS|BEV_OPT_UNLOCK_CALLBACKS)) 3548585484eSchristos == BEV_OPT_UNLOCK_CALLBACKS) { 3558585484eSchristos event_warnx("UNLOCK_CALLBACKS requires DEFER_CALLBACKS"); 356*eabc0478Schristos goto err; 3578585484eSchristos } 3588585484eSchristos if (options & BEV_OPT_UNLOCK_CALLBACKS) 3598585484eSchristos event_deferred_cb_init_( 3608585484eSchristos &bufev_private->deferred, 3618585484eSchristos event_base_get_npriorities(base) / 2, 3628585484eSchristos bufferevent_run_deferred_callbacks_unlocked, 3638585484eSchristos bufev_private); 3648585484eSchristos else 3658585484eSchristos event_deferred_cb_init_( 3668585484eSchristos &bufev_private->deferred, 3678585484eSchristos event_base_get_npriorities(base) / 2, 3688585484eSchristos bufferevent_run_deferred_callbacks_locked, 3698585484eSchristos bufev_private); 3708585484eSchristos 3718585484eSchristos bufev_private->options = options; 3728585484eSchristos 3738585484eSchristos evbuffer_set_parent_(bufev->input, bufev); 3748585484eSchristos evbuffer_set_parent_(bufev->output, bufev); 3758585484eSchristos 3768585484eSchristos return 0; 377*eabc0478Schristos 378*eabc0478Schristos err: 379*eabc0478Schristos if (bufev->input) { 380*eabc0478Schristos evbuffer_free(bufev->input); 381*eabc0478Schristos bufev->input = NULL; 382*eabc0478Schristos } 383*eabc0478Schristos if (bufev->output) { 384*eabc0478Schristos evbuffer_free(bufev->output); 385*eabc0478Schristos bufev->output = NULL; 386*eabc0478Schristos } 387*eabc0478Schristos return -1; 3888585484eSchristos } 3898585484eSchristos 3908585484eSchristos void 3918585484eSchristos bufferevent_setcb(struct bufferevent *bufev, 3928585484eSchristos bufferevent_data_cb readcb, bufferevent_data_cb writecb, 3938585484eSchristos bufferevent_event_cb eventcb, void *cbarg) 3948585484eSchristos { 3958585484eSchristos BEV_LOCK(bufev); 3968585484eSchristos 3978585484eSchristos bufev->readcb = readcb; 3988585484eSchristos bufev->writecb = writecb; 3998585484eSchristos bufev->errorcb = eventcb; 4008585484eSchristos 4018585484eSchristos bufev->cbarg = cbarg; 4028585484eSchristos BEV_UNLOCK(bufev); 4038585484eSchristos } 4048585484eSchristos 4058585484eSchristos void 4068585484eSchristos bufferevent_getcb(struct bufferevent *bufev, 4078585484eSchristos bufferevent_data_cb *readcb_ptr, 4088585484eSchristos bufferevent_data_cb *writecb_ptr, 4098585484eSchristos bufferevent_event_cb *eventcb_ptr, 4108585484eSchristos void **cbarg_ptr) 4118585484eSchristos { 4128585484eSchristos BEV_LOCK(bufev); 4138585484eSchristos if (readcb_ptr) 4148585484eSchristos *readcb_ptr = bufev->readcb; 4158585484eSchristos if (writecb_ptr) 4168585484eSchristos *writecb_ptr = bufev->writecb; 4178585484eSchristos if (eventcb_ptr) 4188585484eSchristos *eventcb_ptr = bufev->errorcb; 4198585484eSchristos if (cbarg_ptr) 4208585484eSchristos *cbarg_ptr = bufev->cbarg; 4218585484eSchristos 4228585484eSchristos BEV_UNLOCK(bufev); 4238585484eSchristos } 4248585484eSchristos 4258585484eSchristos struct evbuffer * 4268585484eSchristos bufferevent_get_input(struct bufferevent *bufev) 4278585484eSchristos { 4288585484eSchristos return bufev->input; 4298585484eSchristos } 4308585484eSchristos 4318585484eSchristos struct evbuffer * 4328585484eSchristos bufferevent_get_output(struct bufferevent *bufev) 4338585484eSchristos { 4348585484eSchristos return bufev->output; 4358585484eSchristos } 4368585484eSchristos 4378585484eSchristos struct event_base * 4388585484eSchristos bufferevent_get_base(struct bufferevent *bufev) 4398585484eSchristos { 4408585484eSchristos return bufev->ev_base; 4418585484eSchristos } 4428585484eSchristos 4438585484eSchristos int 4448585484eSchristos bufferevent_get_priority(const struct bufferevent *bufev) 4458585484eSchristos { 4468585484eSchristos if (event_initialized(&bufev->ev_read)) { 4478585484eSchristos return event_get_priority(&bufev->ev_read); 4488585484eSchristos } else { 4498585484eSchristos return event_base_get_npriorities(bufev->ev_base) / 2; 4508585484eSchristos } 4518585484eSchristos } 4528585484eSchristos 4538585484eSchristos int 4548585484eSchristos bufferevent_write(struct bufferevent *bufev, const void *data, size_t size) 4558585484eSchristos { 4568585484eSchristos if (evbuffer_add(bufev->output, data, size) == -1) 4578585484eSchristos return (-1); 4588585484eSchristos 4598585484eSchristos return 0; 4608585484eSchristos } 4618585484eSchristos 4628585484eSchristos int 4638585484eSchristos bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf) 4648585484eSchristos { 4658585484eSchristos if (evbuffer_add_buffer(bufev->output, buf) == -1) 4668585484eSchristos return (-1); 4678585484eSchristos 4688585484eSchristos return 0; 4698585484eSchristos } 4708585484eSchristos 4718585484eSchristos size_t 4728585484eSchristos bufferevent_read(struct bufferevent *bufev, void *data, size_t size) 4738585484eSchristos { 4748585484eSchristos return (evbuffer_remove(bufev->input, data, size)); 4758585484eSchristos } 4768585484eSchristos 4778585484eSchristos int 4788585484eSchristos bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf) 4798585484eSchristos { 4808585484eSchristos return (evbuffer_add_buffer(buf, bufev->input)); 4818585484eSchristos } 4828585484eSchristos 4838585484eSchristos int 4848585484eSchristos bufferevent_enable(struct bufferevent *bufev, short event) 4858585484eSchristos { 486*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 4878585484eSchristos short impl_events = event; 4888585484eSchristos int r = 0; 4898585484eSchristos 4908585484eSchristos bufferevent_incref_and_lock_(bufev); 4918585484eSchristos if (bufev_private->read_suspended) 4928585484eSchristos impl_events &= ~EV_READ; 4938585484eSchristos if (bufev_private->write_suspended) 4948585484eSchristos impl_events &= ~EV_WRITE; 4958585484eSchristos 4968585484eSchristos bufev->enabled |= event; 4978585484eSchristos 4988585484eSchristos if (impl_events && bufev->be_ops->enable(bufev, impl_events) < 0) 4998585484eSchristos r = -1; 500*eabc0478Schristos if (r) 501*eabc0478Schristos event_debug(("%s: cannot enable 0x%hx on %p", __func__, event, bufev)); 5028585484eSchristos 5038585484eSchristos bufferevent_decref_and_unlock_(bufev); 5048585484eSchristos return r; 5058585484eSchristos } 5068585484eSchristos 5078585484eSchristos int 5088585484eSchristos bufferevent_set_timeouts(struct bufferevent *bufev, 5098585484eSchristos const struct timeval *tv_read, 5108585484eSchristos const struct timeval *tv_write) 5118585484eSchristos { 5128585484eSchristos int r = 0; 5138585484eSchristos BEV_LOCK(bufev); 5148585484eSchristos if (tv_read) { 5158585484eSchristos bufev->timeout_read = *tv_read; 5168585484eSchristos } else { 5178585484eSchristos evutil_timerclear(&bufev->timeout_read); 5188585484eSchristos } 5198585484eSchristos if (tv_write) { 5208585484eSchristos bufev->timeout_write = *tv_write; 5218585484eSchristos } else { 5228585484eSchristos evutil_timerclear(&bufev->timeout_write); 5238585484eSchristos } 5248585484eSchristos 5258585484eSchristos if (bufev->be_ops->adj_timeouts) 5268585484eSchristos r = bufev->be_ops->adj_timeouts(bufev); 5278585484eSchristos BEV_UNLOCK(bufev); 5288585484eSchristos 5298585484eSchristos return r; 5308585484eSchristos } 5318585484eSchristos 5328585484eSchristos 5338585484eSchristos /* Obsolete; use bufferevent_set_timeouts */ 5348585484eSchristos void 5358585484eSchristos bufferevent_settimeout(struct bufferevent *bufev, 5368585484eSchristos int timeout_read, int timeout_write) 5378585484eSchristos { 5388585484eSchristos struct timeval tv_read, tv_write; 5398585484eSchristos struct timeval *ptv_read = NULL, *ptv_write = NULL; 5408585484eSchristos 5418585484eSchristos memset(&tv_read, 0, sizeof(tv_read)); 5428585484eSchristos memset(&tv_write, 0, sizeof(tv_write)); 5438585484eSchristos 5448585484eSchristos if (timeout_read) { 5458585484eSchristos tv_read.tv_sec = timeout_read; 5468585484eSchristos ptv_read = &tv_read; 5478585484eSchristos } 5488585484eSchristos if (timeout_write) { 5498585484eSchristos tv_write.tv_sec = timeout_write; 5508585484eSchristos ptv_write = &tv_write; 5518585484eSchristos } 5528585484eSchristos 5538585484eSchristos bufferevent_set_timeouts(bufev, ptv_read, ptv_write); 5548585484eSchristos } 5558585484eSchristos 5568585484eSchristos 5578585484eSchristos int 5588585484eSchristos bufferevent_disable_hard_(struct bufferevent *bufev, short event) 5598585484eSchristos { 5608585484eSchristos int r = 0; 561*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 5628585484eSchristos 5638585484eSchristos BEV_LOCK(bufev); 5648585484eSchristos bufev->enabled &= ~event; 5658585484eSchristos 5668585484eSchristos bufev_private->connecting = 0; 5678585484eSchristos if (bufev->be_ops->disable(bufev, event) < 0) 5688585484eSchristos r = -1; 5698585484eSchristos 5708585484eSchristos BEV_UNLOCK(bufev); 5718585484eSchristos return r; 5728585484eSchristos } 5738585484eSchristos 5748585484eSchristos int 5758585484eSchristos bufferevent_disable(struct bufferevent *bufev, short event) 5768585484eSchristos { 5778585484eSchristos int r = 0; 5788585484eSchristos 5798585484eSchristos BEV_LOCK(bufev); 5808585484eSchristos bufev->enabled &= ~event; 5818585484eSchristos 5828585484eSchristos if (bufev->be_ops->disable(bufev, event) < 0) 5838585484eSchristos r = -1; 584*eabc0478Schristos if (r) 585*eabc0478Schristos event_debug(("%s: cannot disable 0x%hx on %p", __func__, event, bufev)); 5868585484eSchristos 5878585484eSchristos BEV_UNLOCK(bufev); 5888585484eSchristos return r; 5898585484eSchristos } 5908585484eSchristos 5918585484eSchristos /* 5928585484eSchristos * Sets the water marks 5938585484eSchristos */ 5948585484eSchristos 5958585484eSchristos void 5968585484eSchristos bufferevent_setwatermark(struct bufferevent *bufev, short events, 5978585484eSchristos size_t lowmark, size_t highmark) 5988585484eSchristos { 599*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 6008585484eSchristos 6018585484eSchristos BEV_LOCK(bufev); 6028585484eSchristos if (events & EV_WRITE) { 6038585484eSchristos bufev->wm_write.low = lowmark; 6048585484eSchristos bufev->wm_write.high = highmark; 6058585484eSchristos } 6068585484eSchristos 6078585484eSchristos if (events & EV_READ) { 6088585484eSchristos bufev->wm_read.low = lowmark; 6098585484eSchristos bufev->wm_read.high = highmark; 6108585484eSchristos 6118585484eSchristos if (highmark) { 6128585484eSchristos /* There is now a new high-water mark for read. 6138585484eSchristos enable the callback if needed, and see if we should 6148585484eSchristos suspend/bufferevent_wm_unsuspend. */ 6158585484eSchristos 6168585484eSchristos if (bufev_private->read_watermarks_cb == NULL) { 6178585484eSchristos bufev_private->read_watermarks_cb = 6188585484eSchristos evbuffer_add_cb(bufev->input, 6198585484eSchristos bufferevent_inbuf_wm_cb, 6208585484eSchristos bufev); 6218585484eSchristos } 6228585484eSchristos evbuffer_cb_set_flags(bufev->input, 6238585484eSchristos bufev_private->read_watermarks_cb, 6248585484eSchristos EVBUFFER_CB_ENABLED|EVBUFFER_CB_NODEFER); 6258585484eSchristos 6267476e6e4Schristos if (evbuffer_get_length(bufev->input) >= highmark) 6278585484eSchristos bufferevent_wm_suspend_read(bufev); 6288585484eSchristos else if (evbuffer_get_length(bufev->input) < highmark) 6298585484eSchristos bufferevent_wm_unsuspend_read(bufev); 6308585484eSchristos } else { 6318585484eSchristos /* There is now no high-water mark for read. */ 6328585484eSchristos if (bufev_private->read_watermarks_cb) 6338585484eSchristos evbuffer_cb_clear_flags(bufev->input, 6348585484eSchristos bufev_private->read_watermarks_cb, 6358585484eSchristos EVBUFFER_CB_ENABLED); 6368585484eSchristos bufferevent_wm_unsuspend_read(bufev); 6378585484eSchristos } 6388585484eSchristos } 6398585484eSchristos BEV_UNLOCK(bufev); 6408585484eSchristos } 6418585484eSchristos 6427476e6e4Schristos int 643b8ecfcfeSchristos bufferevent_getwatermark(struct bufferevent *bufev, short events, 644b8ecfcfeSchristos size_t *lowmark, size_t *highmark) 645b8ecfcfeSchristos { 646b8ecfcfeSchristos if (events == EV_WRITE) { 6477476e6e4Schristos BEV_LOCK(bufev); 648b8ecfcfeSchristos if (lowmark) 649b8ecfcfeSchristos *lowmark = bufev->wm_write.low; 650b8ecfcfeSchristos if (highmark) 651b8ecfcfeSchristos *highmark = bufev->wm_write.high; 6527476e6e4Schristos BEV_UNLOCK(bufev); 6537476e6e4Schristos return 0; 654b8ecfcfeSchristos } 655b8ecfcfeSchristos 656b8ecfcfeSchristos if (events == EV_READ) { 6577476e6e4Schristos BEV_LOCK(bufev); 658b8ecfcfeSchristos if (lowmark) 659b8ecfcfeSchristos *lowmark = bufev->wm_read.low; 660b8ecfcfeSchristos if (highmark) 661b8ecfcfeSchristos *highmark = bufev->wm_read.high; 662b8ecfcfeSchristos BEV_UNLOCK(bufev); 6637476e6e4Schristos return 0; 6647476e6e4Schristos } 6657476e6e4Schristos return -1; 666b8ecfcfeSchristos } 667b8ecfcfeSchristos 6688585484eSchristos int 6698585484eSchristos bufferevent_flush(struct bufferevent *bufev, 6708585484eSchristos short iotype, 6718585484eSchristos enum bufferevent_flush_mode mode) 6728585484eSchristos { 6738585484eSchristos int r = -1; 6748585484eSchristos BEV_LOCK(bufev); 6758585484eSchristos if (bufev->be_ops->flush) 6768585484eSchristos r = bufev->be_ops->flush(bufev, iotype, mode); 6778585484eSchristos BEV_UNLOCK(bufev); 6788585484eSchristos return r; 6798585484eSchristos } 6808585484eSchristos 6818585484eSchristos void 6828585484eSchristos bufferevent_incref_and_lock_(struct bufferevent *bufev) 6838585484eSchristos { 684*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 6858585484eSchristos BEV_LOCK(bufev); 6868585484eSchristos ++bufev_private->refcnt; 6878585484eSchristos } 6888585484eSchristos 6898585484eSchristos #if 0 6908585484eSchristos static void 6918585484eSchristos bufferevent_transfer_lock_ownership_(struct bufferevent *donor, 6928585484eSchristos struct bufferevent *recipient) 6938585484eSchristos { 6948585484eSchristos struct bufferevent_private *d = BEV_UPCAST(donor); 6958585484eSchristos struct bufferevent_private *r = BEV_UPCAST(recipient); 6968585484eSchristos if (d->lock != r->lock) 6978585484eSchristos return; 6988585484eSchristos if (r->own_lock) 6998585484eSchristos return; 7008585484eSchristos if (d->own_lock) { 7018585484eSchristos d->own_lock = 0; 7028585484eSchristos r->own_lock = 1; 7038585484eSchristos } 7048585484eSchristos } 7058585484eSchristos #endif 7068585484eSchristos 7078585484eSchristos int 7088585484eSchristos bufferevent_decref_and_unlock_(struct bufferevent *bufev) 7098585484eSchristos { 710*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 711b8ecfcfeSchristos int n_cbs = 0; 712b8ecfcfeSchristos #define MAX_CBS 16 713b8ecfcfeSchristos struct event_callback *cbs[MAX_CBS]; 7148585484eSchristos 7158585484eSchristos EVUTIL_ASSERT(bufev_private->refcnt > 0); 7168585484eSchristos 7178585484eSchristos if (--bufev_private->refcnt) { 7188585484eSchristos BEV_UNLOCK(bufev); 7198585484eSchristos return 0; 7208585484eSchristos } 7218585484eSchristos 722b8ecfcfeSchristos if (bufev->be_ops->unlink) 723b8ecfcfeSchristos bufev->be_ops->unlink(bufev); 724b8ecfcfeSchristos 725b8ecfcfeSchristos /* Okay, we're out of references. Let's finalize this once all the 726b8ecfcfeSchristos * callbacks are done running. */ 727b8ecfcfeSchristos cbs[0] = &bufev->ev_read.ev_evcallback; 728b8ecfcfeSchristos cbs[1] = &bufev->ev_write.ev_evcallback; 729b8ecfcfeSchristos cbs[2] = &bufev_private->deferred; 730b8ecfcfeSchristos n_cbs = 3; 731b8ecfcfeSchristos if (bufev_private->rate_limiting) { 732b8ecfcfeSchristos struct event *e = &bufev_private->rate_limiting->refill_bucket_event; 733b8ecfcfeSchristos if (event_initialized(e)) 734b8ecfcfeSchristos cbs[n_cbs++] = &e->ev_evcallback; 735b8ecfcfeSchristos } 736b8ecfcfeSchristos n_cbs += evbuffer_get_callbacks_(bufev->input, cbs+n_cbs, MAX_CBS-n_cbs); 737b8ecfcfeSchristos n_cbs += evbuffer_get_callbacks_(bufev->output, cbs+n_cbs, MAX_CBS-n_cbs); 738b8ecfcfeSchristos 739b8ecfcfeSchristos event_callback_finalize_many_(bufev->ev_base, n_cbs, cbs, 740b8ecfcfeSchristos bufferevent_finalize_cb_); 741b8ecfcfeSchristos 742b8ecfcfeSchristos #undef MAX_CBS 743b8ecfcfeSchristos BEV_UNLOCK(bufev); 744b8ecfcfeSchristos 745b8ecfcfeSchristos return 1; 746b8ecfcfeSchristos } 747b8ecfcfeSchristos 748b8ecfcfeSchristos static void 749b8ecfcfeSchristos bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_) 750b8ecfcfeSchristos { 751b8ecfcfeSchristos struct bufferevent *bufev = arg_; 752b8ecfcfeSchristos struct bufferevent *underlying; 753*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 754b8ecfcfeSchristos 755b8ecfcfeSchristos BEV_LOCK(bufev); 7568585484eSchristos underlying = bufferevent_get_underlying(bufev); 7578585484eSchristos 7588585484eSchristos /* Clean up the shared info */ 7598585484eSchristos if (bufev->be_ops->destruct) 7608585484eSchristos bufev->be_ops->destruct(bufev); 7618585484eSchristos 7628585484eSchristos /* XXX what happens if refcnt for these buffers is > 1? 7638585484eSchristos * The buffers can share a lock with this bufferevent object, 7648585484eSchristos * but the lock might be destroyed below. */ 7658585484eSchristos /* evbuffer will free the callbacks */ 7668585484eSchristos evbuffer_free(bufev->input); 7678585484eSchristos evbuffer_free(bufev->output); 7688585484eSchristos 7698585484eSchristos if (bufev_private->rate_limiting) { 7708585484eSchristos if (bufev_private->rate_limiting->group) 7718585484eSchristos bufferevent_remove_from_rate_limit_group_internal_(bufev,0); 7728585484eSchristos mm_free(bufev_private->rate_limiting); 7738585484eSchristos bufev_private->rate_limiting = NULL; 7748585484eSchristos } 7758585484eSchristos 7768585484eSchristos 7778585484eSchristos BEV_UNLOCK(bufev); 778b8ecfcfeSchristos 7798585484eSchristos if (bufev_private->own_lock) 7808585484eSchristos EVTHREAD_FREE_LOCK(bufev_private->lock, 7818585484eSchristos EVTHREAD_LOCKTYPE_RECURSIVE); 7828585484eSchristos 7838585484eSchristos /* Free the actual allocated memory. */ 7848585484eSchristos mm_free(((char*)bufev) - bufev->be_ops->mem_offset); 7858585484eSchristos 7868585484eSchristos /* Release the reference to underlying now that we no longer need the 7878585484eSchristos * reference to it. We wait this long mainly in case our lock is 7888585484eSchristos * shared with underlying. 7898585484eSchristos * 7908585484eSchristos * The 'destruct' function will also drop a reference to underlying 7918585484eSchristos * if BEV_OPT_CLOSE_ON_FREE is set. 7928585484eSchristos * 7938585484eSchristos * XXX Should we/can we just refcount evbuffer/bufferevent locks? 7948585484eSchristos * It would probably save us some headaches. 7958585484eSchristos */ 7968585484eSchristos if (underlying) 7978585484eSchristos bufferevent_decref_(underlying); 7988585484eSchristos } 7998585484eSchristos 8008585484eSchristos int 801*eabc0478Schristos bufferevent_decref(struct bufferevent *bufev) 8028585484eSchristos { 8038585484eSchristos BEV_LOCK(bufev); 8048585484eSchristos return bufferevent_decref_and_unlock_(bufev); 8058585484eSchristos } 8068585484eSchristos 8078585484eSchristos void 8088585484eSchristos bufferevent_free(struct bufferevent *bufev) 8098585484eSchristos { 8108585484eSchristos BEV_LOCK(bufev); 8118585484eSchristos bufferevent_setcb(bufev, NULL, NULL, NULL, NULL); 8128585484eSchristos bufferevent_cancel_all_(bufev); 8138585484eSchristos bufferevent_decref_and_unlock_(bufev); 8148585484eSchristos } 8158585484eSchristos 8168585484eSchristos void 817*eabc0478Schristos bufferevent_incref(struct bufferevent *bufev) 8188585484eSchristos { 819*eabc0478Schristos struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); 8208585484eSchristos 821*eabc0478Schristos /* XXX: now that this function is public, we might want to 822*eabc0478Schristos * - return the count from this function 823*eabc0478Schristos * - create a new function to atomically grab the current refcount 824*eabc0478Schristos */ 8258585484eSchristos BEV_LOCK(bufev); 8268585484eSchristos ++bufev_private->refcnt; 8278585484eSchristos BEV_UNLOCK(bufev); 8288585484eSchristos } 8298585484eSchristos 8308585484eSchristos int 8318585484eSchristos bufferevent_enable_locking_(struct bufferevent *bufev, void *lock) 8328585484eSchristos { 8338585484eSchristos #ifdef EVENT__DISABLE_THREAD_SUPPORT 8348585484eSchristos return -1; 8358585484eSchristos #else 8368585484eSchristos struct bufferevent *underlying; 8378585484eSchristos 8388585484eSchristos if (BEV_UPCAST(bufev)->lock) 8398585484eSchristos return -1; 8408585484eSchristos underlying = bufferevent_get_underlying(bufev); 8418585484eSchristos 8428585484eSchristos if (!lock && underlying && BEV_UPCAST(underlying)->lock) { 8438585484eSchristos lock = BEV_UPCAST(underlying)->lock; 8448585484eSchristos BEV_UPCAST(bufev)->lock = lock; 8458585484eSchristos BEV_UPCAST(bufev)->own_lock = 0; 8468585484eSchristos } else if (!lock) { 8478585484eSchristos EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE); 8488585484eSchristos if (!lock) 8498585484eSchristos return -1; 8508585484eSchristos BEV_UPCAST(bufev)->lock = lock; 8518585484eSchristos BEV_UPCAST(bufev)->own_lock = 1; 8528585484eSchristos } else { 8538585484eSchristos BEV_UPCAST(bufev)->lock = lock; 8548585484eSchristos BEV_UPCAST(bufev)->own_lock = 0; 8558585484eSchristos } 8568585484eSchristos evbuffer_enable_locking(bufev->input, lock); 8578585484eSchristos evbuffer_enable_locking(bufev->output, lock); 8588585484eSchristos 8598585484eSchristos if (underlying && !BEV_UPCAST(underlying)->lock) 8608585484eSchristos bufferevent_enable_locking_(underlying, lock); 8618585484eSchristos 8628585484eSchristos return 0; 8638585484eSchristos #endif 8648585484eSchristos } 8658585484eSchristos 8668585484eSchristos int 8678585484eSchristos bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd) 8688585484eSchristos { 8698585484eSchristos union bufferevent_ctrl_data d; 8708585484eSchristos int res = -1; 8718585484eSchristos d.fd = fd; 8728585484eSchristos BEV_LOCK(bev); 8738585484eSchristos if (bev->be_ops->ctrl) 8748585484eSchristos res = bev->be_ops->ctrl(bev, BEV_CTRL_SET_FD, &d); 875*eabc0478Schristos if (res) 876*eabc0478Schristos event_debug(("%s: cannot set fd for %p to "EV_SOCK_FMT, __func__, bev, fd)); 8778585484eSchristos BEV_UNLOCK(bev); 8788585484eSchristos return res; 8798585484eSchristos } 8808585484eSchristos 8818585484eSchristos evutil_socket_t 8828585484eSchristos bufferevent_getfd(struct bufferevent *bev) 8838585484eSchristos { 8848585484eSchristos union bufferevent_ctrl_data d; 8858585484eSchristos int res = -1; 8868585484eSchristos d.fd = -1; 8878585484eSchristos BEV_LOCK(bev); 8888585484eSchristos if (bev->be_ops->ctrl) 8898585484eSchristos res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_FD, &d); 890*eabc0478Schristos if (res) 891*eabc0478Schristos event_debug(("%s: cannot get fd for %p", __func__, bev)); 8928585484eSchristos BEV_UNLOCK(bev); 8938585484eSchristos return (res<0) ? -1 : d.fd; 8948585484eSchristos } 8958585484eSchristos 896b8ecfcfeSchristos enum bufferevent_options 897b8ecfcfeSchristos bufferevent_get_options_(struct bufferevent *bev) 898b8ecfcfeSchristos { 899*eabc0478Schristos struct bufferevent_private *bev_p = BEV_UPCAST(bev); 900b8ecfcfeSchristos enum bufferevent_options options; 901b8ecfcfeSchristos 902b8ecfcfeSchristos BEV_LOCK(bev); 903b8ecfcfeSchristos options = bev_p->options; 904b8ecfcfeSchristos BEV_UNLOCK(bev); 905b8ecfcfeSchristos return options; 906b8ecfcfeSchristos } 907b8ecfcfeSchristos 908b8ecfcfeSchristos 9098585484eSchristos static void 9108585484eSchristos bufferevent_cancel_all_(struct bufferevent *bev) 9118585484eSchristos { 9128585484eSchristos union bufferevent_ctrl_data d; 9138585484eSchristos memset(&d, 0, sizeof(d)); 9148585484eSchristos BEV_LOCK(bev); 9158585484eSchristos if (bev->be_ops->ctrl) 9168585484eSchristos bev->be_ops->ctrl(bev, BEV_CTRL_CANCEL_ALL, &d); 9178585484eSchristos BEV_UNLOCK(bev); 9188585484eSchristos } 9198585484eSchristos 9208585484eSchristos short 9218585484eSchristos bufferevent_get_enabled(struct bufferevent *bufev) 9228585484eSchristos { 9238585484eSchristos short r; 9248585484eSchristos BEV_LOCK(bufev); 9258585484eSchristos r = bufev->enabled; 9268585484eSchristos BEV_UNLOCK(bufev); 9278585484eSchristos return r; 9288585484eSchristos } 9298585484eSchristos 9308585484eSchristos struct bufferevent * 9318585484eSchristos bufferevent_get_underlying(struct bufferevent *bev) 9328585484eSchristos { 9338585484eSchristos union bufferevent_ctrl_data d; 9348585484eSchristos int res = -1; 9358585484eSchristos d.ptr = NULL; 9368585484eSchristos BEV_LOCK(bev); 9378585484eSchristos if (bev->be_ops->ctrl) 9388585484eSchristos res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_UNDERLYING, &d); 9398585484eSchristos BEV_UNLOCK(bev); 9408585484eSchristos return (res<0) ? NULL : d.ptr; 9418585484eSchristos } 9428585484eSchristos 9438585484eSchristos static void 9448585484eSchristos bufferevent_generic_read_timeout_cb(evutil_socket_t fd, short event, void *ctx) 9458585484eSchristos { 9468585484eSchristos struct bufferevent *bev = ctx; 9478585484eSchristos bufferevent_incref_and_lock_(bev); 9488585484eSchristos bufferevent_disable(bev, EV_READ); 949b8ecfcfeSchristos bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0); 9508585484eSchristos bufferevent_decref_and_unlock_(bev); 9518585484eSchristos } 9528585484eSchristos static void 9538585484eSchristos bufferevent_generic_write_timeout_cb(evutil_socket_t fd, short event, void *ctx) 9548585484eSchristos { 9558585484eSchristos struct bufferevent *bev = ctx; 9568585484eSchristos bufferevent_incref_and_lock_(bev); 9578585484eSchristos bufferevent_disable(bev, EV_WRITE); 958b8ecfcfeSchristos bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0); 9598585484eSchristos bufferevent_decref_and_unlock_(bev); 9608585484eSchristos } 9618585484eSchristos 9628585484eSchristos void 9638585484eSchristos bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev) 9648585484eSchristos { 965b8ecfcfeSchristos event_assign(&bev->ev_read, bev->ev_base, -1, EV_FINALIZE, 9668585484eSchristos bufferevent_generic_read_timeout_cb, bev); 967b8ecfcfeSchristos event_assign(&bev->ev_write, bev->ev_base, -1, EV_FINALIZE, 9688585484eSchristos bufferevent_generic_write_timeout_cb, bev); 9698585484eSchristos } 9708585484eSchristos 9718585484eSchristos int 9728585484eSchristos bufferevent_generic_adj_timeouts_(struct bufferevent *bev) 9738585484eSchristos { 9748585484eSchristos const short enabled = bev->enabled; 975*eabc0478Schristos struct bufferevent_private *bev_p = BEV_UPCAST(bev); 9768585484eSchristos int r1=0, r2=0; 9778585484eSchristos if ((enabled & EV_READ) && !bev_p->read_suspended && 9788585484eSchristos evutil_timerisset(&bev->timeout_read)) 9798585484eSchristos r1 = event_add(&bev->ev_read, &bev->timeout_read); 9808585484eSchristos else 9818585484eSchristos r1 = event_del(&bev->ev_read); 9828585484eSchristos 9838585484eSchristos if ((enabled & EV_WRITE) && !bev_p->write_suspended && 9848585484eSchristos evutil_timerisset(&bev->timeout_write) && 9858585484eSchristos evbuffer_get_length(bev->output)) 9868585484eSchristos r2 = event_add(&bev->ev_write, &bev->timeout_write); 9878585484eSchristos else 9888585484eSchristos r2 = event_del(&bev->ev_write); 9898585484eSchristos if (r1 < 0 || r2 < 0) 9908585484eSchristos return -1; 9918585484eSchristos return 0; 9928585484eSchristos } 9938585484eSchristos 9948585484eSchristos int 995*eabc0478Schristos bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev) 996*eabc0478Schristos { 997*eabc0478Schristos int r = 0; 998*eabc0478Schristos if (event_pending(&bev->ev_read, EV_READ, NULL)) { 999*eabc0478Schristos if (evutil_timerisset(&bev->timeout_read)) { 1000*eabc0478Schristos if (bufferevent_add_event_(&bev->ev_read, &bev->timeout_read) < 0) 1001*eabc0478Schristos r = -1; 1002*eabc0478Schristos } else { 1003*eabc0478Schristos event_remove_timer(&bev->ev_read); 1004*eabc0478Schristos } 1005*eabc0478Schristos } 1006*eabc0478Schristos if (event_pending(&bev->ev_write, EV_WRITE, NULL)) { 1007*eabc0478Schristos if (evutil_timerisset(&bev->timeout_write)) { 1008*eabc0478Schristos if (bufferevent_add_event_(&bev->ev_write, &bev->timeout_write) < 0) 1009*eabc0478Schristos r = -1; 1010*eabc0478Schristos } else { 1011*eabc0478Schristos event_remove_timer(&bev->ev_write); 1012*eabc0478Schristos } 1013*eabc0478Schristos } 1014*eabc0478Schristos return r; 1015*eabc0478Schristos } 1016*eabc0478Schristos 1017*eabc0478Schristos int 10188585484eSchristos bufferevent_add_event_(struct event *ev, const struct timeval *tv) 10198585484eSchristos { 1020*eabc0478Schristos if (!evutil_timerisset(tv)) 10218585484eSchristos return event_add(ev, NULL); 10228585484eSchristos else 10238585484eSchristos return event_add(ev, tv); 10248585484eSchristos } 10258585484eSchristos 10268585484eSchristos /* For use by user programs only; internally, we should be calling 10278585484eSchristos either bufferevent_incref_and_lock_(), or BEV_LOCK. */ 10288585484eSchristos void 10298585484eSchristos bufferevent_lock(struct bufferevent *bev) 10308585484eSchristos { 10318585484eSchristos bufferevent_incref_and_lock_(bev); 10328585484eSchristos } 10338585484eSchristos 10348585484eSchristos void 10358585484eSchristos bufferevent_unlock(struct bufferevent *bev) 10368585484eSchristos { 10378585484eSchristos bufferevent_decref_and_unlock_(bev); 10388585484eSchristos } 1039