1*eabc0478Schristos /* $NetBSD: bufferevent_sock.c,v 1.6 2024/08/18 20:47:21 christos Exp $ */ 28585484eSchristos 38585484eSchristos /* 48585484eSchristos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 58585484eSchristos * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu> 68585484eSchristos * All rights reserved. 78585484eSchristos * 88585484eSchristos * Redistribution and use in source and binary forms, with or without 98585484eSchristos * modification, are permitted provided that the following conditions 108585484eSchristos * are met: 118585484eSchristos * 1. Redistributions of source code must retain the above copyright 128585484eSchristos * notice, this list of conditions and the following disclaimer. 138585484eSchristos * 2. Redistributions in binary form must reproduce the above copyright 148585484eSchristos * notice, this list of conditions and the following disclaimer in the 158585484eSchristos * documentation and/or other materials provided with the distribution. 168585484eSchristos * 3. The name of the author may not be used to endorse or promote products 178585484eSchristos * derived from this software without specific prior written permission. 188585484eSchristos * 198585484eSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 208585484eSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 218585484eSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 228585484eSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 238585484eSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 248585484eSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 258585484eSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 268585484eSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 278585484eSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 288585484eSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 298585484eSchristos */ 308585484eSchristos 318585484eSchristos #include "event2/event-config.h" 328585484eSchristos #include "evconfig-private.h" 338585484eSchristos 348585484eSchristos #include <sys/types.h> 358585484eSchristos 368585484eSchristos #ifdef EVENT__HAVE_SYS_TIME_H 378585484eSchristos #include <sys/time.h> 388585484eSchristos #endif 398585484eSchristos 408585484eSchristos #include <errno.h> 418585484eSchristos #include <stdio.h> 428585484eSchristos #include <stdlib.h> 438585484eSchristos #include <string.h> 448585484eSchristos #ifdef EVENT__HAVE_STDARG_H 458585484eSchristos #include <stdarg.h> 468585484eSchristos #endif 478585484eSchristos #ifdef EVENT__HAVE_UNISTD_H 488585484eSchristos #include <unistd.h> 498585484eSchristos #endif 508585484eSchristos 518585484eSchristos #ifdef _WIN32 528585484eSchristos #include <winsock2.h> 538585484eSchristos #include <ws2tcpip.h> 548585484eSchristos #endif 558585484eSchristos 568585484eSchristos #ifdef EVENT__HAVE_SYS_SOCKET_H 578585484eSchristos #include <sys/socket.h> 588585484eSchristos #endif 598585484eSchristos #ifdef EVENT__HAVE_NETINET_IN_H 608585484eSchristos #include <netinet/in.h> 618585484eSchristos #endif 628585484eSchristos #ifdef EVENT__HAVE_NETINET_IN6_H 638585484eSchristos #include <netinet/in6.h> 648585484eSchristos #endif 658585484eSchristos 668585484eSchristos #include "event2/util.h" 678585484eSchristos #include "event2/bufferevent.h" 688585484eSchristos #include "event2/buffer.h" 698585484eSchristos #include "event2/bufferevent_struct.h" 708585484eSchristos #include "event2/bufferevent_compat.h" 718585484eSchristos #include "event2/event.h" 728585484eSchristos #include "log-internal.h" 738585484eSchristos #include "mm-internal.h" 748585484eSchristos #include "bufferevent-internal.h" 758585484eSchristos #include "util-internal.h" 768585484eSchristos #ifdef _WIN32 778585484eSchristos #include "iocp-internal.h" 788585484eSchristos #endif 798585484eSchristos 808585484eSchristos /* prototypes */ 818585484eSchristos static int be_socket_enable(struct bufferevent *, short); 828585484eSchristos static int be_socket_disable(struct bufferevent *, short); 838585484eSchristos static void be_socket_destruct(struct bufferevent *); 848585484eSchristos static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode); 858585484eSchristos static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *); 868585484eSchristos 878585484eSchristos static void be_socket_setfd(struct bufferevent *, evutil_socket_t); 888585484eSchristos 898585484eSchristos const struct bufferevent_ops bufferevent_ops_socket = { 908585484eSchristos "socket", 918585484eSchristos evutil_offsetof(struct bufferevent_private, bev), 928585484eSchristos be_socket_enable, 938585484eSchristos be_socket_disable, 94b8ecfcfeSchristos NULL, /* unlink */ 958585484eSchristos be_socket_destruct, 96*eabc0478Schristos bufferevent_generic_adj_existing_timeouts_, 978585484eSchristos be_socket_flush, 988585484eSchristos be_socket_ctrl, 998585484eSchristos }; 1008585484eSchristos 101*eabc0478Schristos const struct sockaddr* 102*eabc0478Schristos bufferevent_socket_get_conn_address_(struct bufferevent *bev) 103*eabc0478Schristos { 104*eabc0478Schristos struct bufferevent_private *bev_p = BEV_UPCAST(bev); 105*eabc0478Schristos return (struct sockaddr *)&bev_p->conn_address; 106*eabc0478Schristos } 107*eabc0478Schristos 108*eabc0478Schristos void 109*eabc0478Schristos bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev, 110*eabc0478Schristos evutil_socket_t fd) 111*eabc0478Schristos { 112*eabc0478Schristos struct bufferevent_private *bev_p = BEV_UPCAST(bev); 113*eabc0478Schristos 114*eabc0478Schristos socklen_t len = sizeof(bev_p->conn_address); 115*eabc0478Schristos 116*eabc0478Schristos struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address; 117*eabc0478Schristos if (addr->sa_family != AF_UNSPEC) 118*eabc0478Schristos getpeername(fd, addr, &len); 119*eabc0478Schristos } 120*eabc0478Schristos 121*eabc0478Schristos void 122*eabc0478Schristos bufferevent_socket_set_conn_address_(struct bufferevent *bev, 123*eabc0478Schristos struct sockaddr *addr, size_t addrlen) 124*eabc0478Schristos { 125*eabc0478Schristos struct bufferevent_private *bev_p = BEV_UPCAST(bev); 126*eabc0478Schristos EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address)); 127*eabc0478Schristos memcpy(&bev_p->conn_address, addr, addrlen); 128*eabc0478Schristos } 1298585484eSchristos 1308585484eSchristos static void 1318585484eSchristos bufferevent_socket_outbuf_cb(struct evbuffer *buf, 1328585484eSchristos const struct evbuffer_cb_info *cbinfo, 1338585484eSchristos void *arg) 1348585484eSchristos { 1358585484eSchristos struct bufferevent *bufev = arg; 136*eabc0478Schristos struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); 1378585484eSchristos 1388585484eSchristos if (cbinfo->n_added && 1398585484eSchristos (bufev->enabled & EV_WRITE) && 1408585484eSchristos !event_pending(&bufev->ev_write, EV_WRITE, NULL) && 1418585484eSchristos !bufev_p->write_suspended) { 1428585484eSchristos /* Somebody added data to the buffer, and we would like to 1438585484eSchristos * write, and we were not writing. So, start writing. */ 144*eabc0478Schristos if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) { 1458585484eSchristos /* Should we log this? */ 1468585484eSchristos } 1478585484eSchristos } 1488585484eSchristos } 1498585484eSchristos 1508585484eSchristos static void 1518585484eSchristos bufferevent_readcb(evutil_socket_t fd, short event, void *arg) 1528585484eSchristos { 1538585484eSchristos struct bufferevent *bufev = arg; 154*eabc0478Schristos struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); 1558585484eSchristos struct evbuffer *input; 1568585484eSchristos int res = 0; 1578585484eSchristos short what = BEV_EVENT_READING; 1588585484eSchristos ev_ssize_t howmuch = -1, readmax=-1; 1598585484eSchristos 1608585484eSchristos bufferevent_incref_and_lock_(bufev); 1618585484eSchristos 1628585484eSchristos if (event == EV_TIMEOUT) { 1638585484eSchristos /* Note that we only check for event==EV_TIMEOUT. If 1648585484eSchristos * event==EV_TIMEOUT|EV_READ, we can safely ignore the 1658585484eSchristos * timeout, since a read has occurred */ 1668585484eSchristos what |= BEV_EVENT_TIMEOUT; 1678585484eSchristos goto error; 1688585484eSchristos } 1698585484eSchristos 1708585484eSchristos input = bufev->input; 1718585484eSchristos 1728585484eSchristos /* 1738585484eSchristos * If we have a high watermark configured then we don't want to 1748585484eSchristos * read more data than would make us reach the watermark. 1758585484eSchristos */ 1768585484eSchristos if (bufev->wm_read.high != 0) { 1778585484eSchristos howmuch = bufev->wm_read.high - evbuffer_get_length(input); 1788585484eSchristos /* we somehow lowered the watermark, stop reading */ 1798585484eSchristos if (howmuch <= 0) { 1808585484eSchristos bufferevent_wm_suspend_read(bufev); 1818585484eSchristos goto done; 1828585484eSchristos } 1838585484eSchristos } 1848585484eSchristos readmax = bufferevent_get_read_max_(bufev_p); 1858585484eSchristos if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" 1868585484eSchristos * uglifies this code. XXXX */ 1878585484eSchristos howmuch = readmax; 1888585484eSchristos if (bufev_p->read_suspended) 1898585484eSchristos goto done; 1908585484eSchristos 1918585484eSchristos evbuffer_unfreeze(input, 0); 1928585484eSchristos res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ 1938585484eSchristos evbuffer_freeze(input, 0); 1948585484eSchristos 1958585484eSchristos if (res == -1) { 1968585484eSchristos int err = evutil_socket_geterror(fd); 1978585484eSchristos if (EVUTIL_ERR_RW_RETRIABLE(err)) 1988585484eSchristos goto reschedule; 199*eabc0478Schristos if (EVUTIL_ERR_CONNECT_REFUSED(err)) { 200*eabc0478Schristos bufev_p->connection_refused = 1; 201*eabc0478Schristos goto done; 202*eabc0478Schristos } 2038585484eSchristos /* error case */ 2048585484eSchristos what |= BEV_EVENT_ERROR; 2058585484eSchristos } else if (res == 0) { 2068585484eSchristos /* eof case */ 2078585484eSchristos what |= BEV_EVENT_EOF; 2088585484eSchristos } 2098585484eSchristos 2108585484eSchristos if (res <= 0) 2118585484eSchristos goto error; 2128585484eSchristos 2138585484eSchristos bufferevent_decrement_read_buckets_(bufev_p, res); 2148585484eSchristos 2158585484eSchristos /* Invoke the user callback - must always be called last */ 216b8ecfcfeSchristos bufferevent_trigger_nolock_(bufev, EV_READ, 0); 2178585484eSchristos 2188585484eSchristos goto done; 2198585484eSchristos 2208585484eSchristos reschedule: 2218585484eSchristos goto done; 2228585484eSchristos 2238585484eSchristos error: 2248585484eSchristos bufferevent_disable(bufev, EV_READ); 225b8ecfcfeSchristos bufferevent_run_eventcb_(bufev, what, 0); 2268585484eSchristos 2278585484eSchristos done: 2288585484eSchristos bufferevent_decref_and_unlock_(bufev); 2298585484eSchristos } 2308585484eSchristos 2318585484eSchristos static void 2328585484eSchristos bufferevent_writecb(evutil_socket_t fd, short event, void *arg) 2338585484eSchristos { 2348585484eSchristos struct bufferevent *bufev = arg; 235*eabc0478Schristos struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); 2368585484eSchristos int res = 0; 2378585484eSchristos short what = BEV_EVENT_WRITING; 2388585484eSchristos int connected = 0; 2398585484eSchristos ev_ssize_t atmost = -1; 2408585484eSchristos 2418585484eSchristos bufferevent_incref_and_lock_(bufev); 2428585484eSchristos 2438585484eSchristos if (event == EV_TIMEOUT) { 2448585484eSchristos /* Note that we only check for event==EV_TIMEOUT. If 2458585484eSchristos * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the 2468585484eSchristos * timeout, since a read has occurred */ 2478585484eSchristos what |= BEV_EVENT_TIMEOUT; 2488585484eSchristos goto error; 2498585484eSchristos } 2508585484eSchristos if (bufev_p->connecting) { 2518585484eSchristos int c = evutil_socket_finished_connecting_(fd); 2528585484eSchristos /* we need to fake the error if the connection was refused 2538585484eSchristos * immediately - usually connection to localhost on BSD */ 2548585484eSchristos if (bufev_p->connection_refused) { 2558585484eSchristos bufev_p->connection_refused = 0; 2568585484eSchristos c = -1; 2578585484eSchristos } 2588585484eSchristos 2598585484eSchristos if (c == 0) 2608585484eSchristos goto done; 2618585484eSchristos 2628585484eSchristos bufev_p->connecting = 0; 2638585484eSchristos if (c < 0) { 2648585484eSchristos event_del(&bufev->ev_write); 2658585484eSchristos event_del(&bufev->ev_read); 266b8ecfcfeSchristos bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0); 2678585484eSchristos goto done; 2688585484eSchristos } else { 2698585484eSchristos connected = 1; 270*eabc0478Schristos bufferevent_socket_set_conn_address_fd_(bufev, fd); 2718585484eSchristos #ifdef _WIN32 2728585484eSchristos if (BEV_IS_ASYNC(bufev)) { 2738585484eSchristos event_del(&bufev->ev_write); 2748585484eSchristos bufferevent_async_set_connected_(bufev); 2758585484eSchristos bufferevent_run_eventcb_(bufev, 276b8ecfcfeSchristos BEV_EVENT_CONNECTED, 0); 2778585484eSchristos goto done; 2788585484eSchristos } 2798585484eSchristos #endif 2808585484eSchristos bufferevent_run_eventcb_(bufev, 281b8ecfcfeSchristos BEV_EVENT_CONNECTED, 0); 2828585484eSchristos if (!(bufev->enabled & EV_WRITE) || 2838585484eSchristos bufev_p->write_suspended) { 2848585484eSchristos event_del(&bufev->ev_write); 2858585484eSchristos goto done; 2868585484eSchristos } 2878585484eSchristos } 2888585484eSchristos } 2898585484eSchristos 2908585484eSchristos atmost = bufferevent_get_write_max_(bufev_p); 2918585484eSchristos 2928585484eSchristos if (bufev_p->write_suspended) 2938585484eSchristos goto done; 2948585484eSchristos 2958585484eSchristos if (evbuffer_get_length(bufev->output)) { 2968585484eSchristos evbuffer_unfreeze(bufev->output, 1); 2978585484eSchristos res = evbuffer_write_atmost(bufev->output, fd, atmost); 2988585484eSchristos evbuffer_freeze(bufev->output, 1); 2998585484eSchristos if (res == -1) { 3008585484eSchristos int err = evutil_socket_geterror(fd); 3018585484eSchristos if (EVUTIL_ERR_RW_RETRIABLE(err)) 3028585484eSchristos goto reschedule; 3038585484eSchristos what |= BEV_EVENT_ERROR; 3048585484eSchristos } else if (res == 0) { 3058585484eSchristos /* eof case 3068585484eSchristos XXXX Actually, a 0 on write doesn't indicate 3078585484eSchristos an EOF. An ECONNRESET might be more typical. 3088585484eSchristos */ 3098585484eSchristos what |= BEV_EVENT_EOF; 3108585484eSchristos } 3118585484eSchristos if (res <= 0) 3128585484eSchristos goto error; 3138585484eSchristos 3148585484eSchristos bufferevent_decrement_write_buckets_(bufev_p, res); 3158585484eSchristos } 3168585484eSchristos 3178585484eSchristos if (evbuffer_get_length(bufev->output) == 0) { 3188585484eSchristos event_del(&bufev->ev_write); 3198585484eSchristos } 3208585484eSchristos 3218585484eSchristos /* 3228585484eSchristos * Invoke the user callback if our buffer is drained or below the 3238585484eSchristos * low watermark. 3248585484eSchristos */ 325b8ecfcfeSchristos if (res || !connected) { 326b8ecfcfeSchristos bufferevent_trigger_nolock_(bufev, EV_WRITE, 0); 3278585484eSchristos } 3288585484eSchristos 3298585484eSchristos goto done; 3308585484eSchristos 3318585484eSchristos reschedule: 3328585484eSchristos if (evbuffer_get_length(bufev->output) == 0) { 3338585484eSchristos event_del(&bufev->ev_write); 3348585484eSchristos } 3358585484eSchristos goto done; 3368585484eSchristos 3378585484eSchristos error: 3388585484eSchristos bufferevent_disable(bufev, EV_WRITE); 339b8ecfcfeSchristos bufferevent_run_eventcb_(bufev, what, 0); 3408585484eSchristos 3418585484eSchristos done: 3428585484eSchristos bufferevent_decref_and_unlock_(bufev); 3438585484eSchristos } 3448585484eSchristos 3458585484eSchristos struct bufferevent * 3468585484eSchristos bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, 3478585484eSchristos int options) 3488585484eSchristos { 3498585484eSchristos struct bufferevent_private *bufev_p; 3508585484eSchristos struct bufferevent *bufev; 3518585484eSchristos 3528585484eSchristos #ifdef _WIN32 3538585484eSchristos if (base && event_base_get_iocp_(base)) 3548585484eSchristos return bufferevent_async_new_(base, fd, options); 3558585484eSchristos #endif 3568585484eSchristos 3578585484eSchristos if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) 3588585484eSchristos return NULL; 3598585484eSchristos 3608585484eSchristos if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket, 3618585484eSchristos options) < 0) { 3628585484eSchristos mm_free(bufev_p); 3638585484eSchristos return NULL; 3648585484eSchristos } 3658585484eSchristos bufev = &bufev_p->bev; 3668585484eSchristos evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); 3678585484eSchristos 3688585484eSchristos event_assign(&bufev->ev_read, bufev->ev_base, fd, 369b8ecfcfeSchristos EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev); 3708585484eSchristos event_assign(&bufev->ev_write, bufev->ev_base, fd, 371b8ecfcfeSchristos EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev); 3728585484eSchristos 3738585484eSchristos evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); 3748585484eSchristos 3758585484eSchristos evbuffer_freeze(bufev->input, 0); 3768585484eSchristos evbuffer_freeze(bufev->output, 1); 3778585484eSchristos 3788585484eSchristos return bufev; 3798585484eSchristos } 3808585484eSchristos 3818585484eSchristos int 3828585484eSchristos bufferevent_socket_connect(struct bufferevent *bev, 383*eabc0478Schristos const struct sockaddr *sa, int socklen) 3848585484eSchristos { 385*eabc0478Schristos struct bufferevent_private *bufev_p = BEV_UPCAST(bev); 3868585484eSchristos 3878585484eSchristos evutil_socket_t fd; 3888585484eSchristos int r = 0; 3898585484eSchristos int result=-1; 3908585484eSchristos int ownfd = 0; 3918585484eSchristos 3928585484eSchristos bufferevent_incref_and_lock_(bev); 3938585484eSchristos 3948585484eSchristos fd = bufferevent_getfd(bev); 3958585484eSchristos if (fd < 0) { 3968585484eSchristos if (!sa) 3978585484eSchristos goto done; 3988585484eSchristos fd = evutil_socket_(sa->sa_family, 3998585484eSchristos SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0); 4008585484eSchristos if (fd < 0) 401*eabc0478Schristos goto freesock; 4028585484eSchristos ownfd = 1; 4038585484eSchristos } 4048585484eSchristos if (sa) { 4058585484eSchristos #ifdef _WIN32 4068585484eSchristos if (bufferevent_async_can_connect_(bev)) { 4078585484eSchristos bufferevent_setfd(bev, fd); 4088585484eSchristos r = bufferevent_async_connect_(bev, fd, sa, socklen); 4098585484eSchristos if (r < 0) 4108585484eSchristos goto freesock; 4118585484eSchristos bufev_p->connecting = 1; 4128585484eSchristos result = 0; 4138585484eSchristos goto done; 4148585484eSchristos } else 4158585484eSchristos #endif 4168585484eSchristos r = evutil_socket_connect_(&fd, sa, socklen); 4178585484eSchristos if (r < 0) 4188585484eSchristos goto freesock; 4198585484eSchristos } 4208585484eSchristos #ifdef _WIN32 4218585484eSchristos /* ConnectEx() isn't always around, even when IOCP is enabled. 4228585484eSchristos * Here, we borrow the socket object's write handler to fall back 4238585484eSchristos * on a non-blocking connect() when ConnectEx() is unavailable. */ 4248585484eSchristos if (BEV_IS_ASYNC(bev)) { 4258585484eSchristos event_assign(&bev->ev_write, bev->ev_base, fd, 426b8ecfcfeSchristos EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bev); 4278585484eSchristos } 4288585484eSchristos #endif 4298585484eSchristos bufferevent_setfd(bev, fd); 4308585484eSchristos if (r == 0) { 4318585484eSchristos if (! be_socket_enable(bev, EV_WRITE)) { 4328585484eSchristos bufev_p->connecting = 1; 4338585484eSchristos result = 0; 4348585484eSchristos goto done; 4358585484eSchristos } 4368585484eSchristos } else if (r == 1) { 4378585484eSchristos /* The connect succeeded already. How very BSD of it. */ 4388585484eSchristos result = 0; 4398585484eSchristos bufev_p->connecting = 1; 440*eabc0478Schristos bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS); 4418585484eSchristos } else { 4428585484eSchristos /* The connect failed already. How very BSD of it. */ 4438585484eSchristos result = 0; 444*eabc0478Schristos bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS); 445*eabc0478Schristos bufferevent_disable(bev, EV_WRITE|EV_READ); 4468585484eSchristos } 4478585484eSchristos 4488585484eSchristos goto done; 4498585484eSchristos 4508585484eSchristos freesock: 4518585484eSchristos if (ownfd) 4528585484eSchristos evutil_closesocket(fd); 4538585484eSchristos done: 4548585484eSchristos bufferevent_decref_and_unlock_(bev); 4558585484eSchristos return result; 4568585484eSchristos } 4578585484eSchristos 4588585484eSchristos static void 4598585484eSchristos bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, 4608585484eSchristos void *arg) 4618585484eSchristos { 4628585484eSchristos struct bufferevent *bev = arg; 463*eabc0478Schristos struct bufferevent_private *bev_p = BEV_UPCAST(bev); 4648585484eSchristos int r; 4658585484eSchristos BEV_LOCK(bev); 4668585484eSchristos 4678585484eSchristos bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP); 4688585484eSchristos bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP); 4698585484eSchristos 470*eabc0478Schristos bev_p->dns_request = NULL; 471*eabc0478Schristos 472*eabc0478Schristos if (result == EVUTIL_EAI_CANCEL) { 473*eabc0478Schristos bev_p->dns_error = result; 474*eabc0478Schristos bufferevent_decref_and_unlock_(bev); 475*eabc0478Schristos return; 476*eabc0478Schristos } 4778585484eSchristos if (result != 0) { 4788585484eSchristos bev_p->dns_error = result; 479b8ecfcfeSchristos bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0); 4808585484eSchristos bufferevent_decref_and_unlock_(bev); 4818585484eSchristos if (ai) 4828585484eSchristos evutil_freeaddrinfo(ai); 4838585484eSchristos return; 4848585484eSchristos } 4858585484eSchristos 4868585484eSchristos /* XXX use the other addrinfos? */ 487*eabc0478Schristos bufferevent_socket_set_conn_address_(bev, ai->ai_addr, (int)ai->ai_addrlen); 4888585484eSchristos r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen); 489*eabc0478Schristos if (r < 0) 490*eabc0478Schristos bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0); 4918585484eSchristos bufferevent_decref_and_unlock_(bev); 4928585484eSchristos evutil_freeaddrinfo(ai); 4938585484eSchristos } 4948585484eSchristos 4958585484eSchristos int 4968585484eSchristos bufferevent_socket_connect_hostname(struct bufferevent *bev, 4978585484eSchristos struct evdns_base *evdns_base, int family, const char *hostname, int port) 4988585484eSchristos { 4998585484eSchristos char portbuf[10]; 5008585484eSchristos struct evutil_addrinfo hint; 501*eabc0478Schristos struct bufferevent_private *bev_p = BEV_UPCAST(bev); 5028585484eSchristos 5038585484eSchristos if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) 5048585484eSchristos return -1; 5058585484eSchristos if (port < 1 || port > 65535) 5068585484eSchristos return -1; 5078585484eSchristos 5088585484eSchristos memset(&hint, 0, sizeof(hint)); 5098585484eSchristos hint.ai_family = family; 5108585484eSchristos hint.ai_protocol = IPPROTO_TCP; 5118585484eSchristos hint.ai_socktype = SOCK_STREAM; 5128585484eSchristos 513*eabc0478Schristos evutil_snprintf(portbuf, sizeof(portbuf), "%d", port); 514*eabc0478Schristos 515*eabc0478Schristos BEV_LOCK(bev); 516*eabc0478Schristos bev_p->dns_error = 0; 517*eabc0478Schristos 5188585484eSchristos bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP); 5198585484eSchristos bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP); 5208585484eSchristos 5218585484eSchristos bufferevent_incref_(bev); 522*eabc0478Schristos bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname, 523*eabc0478Schristos portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev); 524*eabc0478Schristos BEV_UNLOCK(bev); 5258585484eSchristos 5268585484eSchristos return 0; 5278585484eSchristos } 5288585484eSchristos 5298585484eSchristos int 5308585484eSchristos bufferevent_socket_get_dns_error(struct bufferevent *bev) 5318585484eSchristos { 5328585484eSchristos int rv; 533*eabc0478Schristos struct bufferevent_private *bev_p = BEV_UPCAST(bev); 5348585484eSchristos 5358585484eSchristos BEV_LOCK(bev); 5368585484eSchristos rv = bev_p->dns_error; 5378585484eSchristos BEV_UNLOCK(bev); 5388585484eSchristos 5398585484eSchristos return rv; 5408585484eSchristos } 5418585484eSchristos 5428585484eSchristos /* 5438585484eSchristos * Create a new buffered event object. 5448585484eSchristos * 5458585484eSchristos * The read callback is invoked whenever we read new data. 5468585484eSchristos * The write callback is invoked whenever the output buffer is drained. 5478585484eSchristos * The error callback is invoked on a write/read error or on EOF. 5488585484eSchristos * 5498585484eSchristos * Both read and write callbacks maybe NULL. The error callback is not 5508585484eSchristos * allowed to be NULL and have to be provided always. 5518585484eSchristos */ 5528585484eSchristos 5538585484eSchristos struct bufferevent * 5548585484eSchristos bufferevent_new(evutil_socket_t fd, 5558585484eSchristos bufferevent_data_cb readcb, bufferevent_data_cb writecb, 5568585484eSchristos bufferevent_event_cb eventcb, void *cbarg) 5578585484eSchristos { 5588585484eSchristos struct bufferevent *bufev; 5598585484eSchristos 5608585484eSchristos if (!(bufev = bufferevent_socket_new(NULL, fd, 0))) 5618585484eSchristos return NULL; 5628585484eSchristos 5638585484eSchristos bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg); 5648585484eSchristos 5658585484eSchristos return bufev; 5668585484eSchristos } 5678585484eSchristos 5688585484eSchristos 5698585484eSchristos static int 5708585484eSchristos be_socket_enable(struct bufferevent *bufev, short event) 5718585484eSchristos { 572*eabc0478Schristos if (event & EV_READ && 573*eabc0478Schristos bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1) 5748585484eSchristos return -1; 575*eabc0478Schristos if (event & EV_WRITE && 576*eabc0478Schristos bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) 5778585484eSchristos return -1; 5788585484eSchristos return 0; 5798585484eSchristos } 5808585484eSchristos 5818585484eSchristos static int 5828585484eSchristos be_socket_disable(struct bufferevent *bufev, short event) 5838585484eSchristos { 584*eabc0478Schristos struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); 5858585484eSchristos if (event & EV_READ) { 5868585484eSchristos if (event_del(&bufev->ev_read) == -1) 5878585484eSchristos return -1; 5888585484eSchristos } 5898585484eSchristos /* Don't actually disable the write if we are trying to connect. */ 5908585484eSchristos if ((event & EV_WRITE) && ! bufev_p->connecting) { 5918585484eSchristos if (event_del(&bufev->ev_write) == -1) 5928585484eSchristos return -1; 5938585484eSchristos } 5948585484eSchristos return 0; 5958585484eSchristos } 5968585484eSchristos 5978585484eSchristos static void 5988585484eSchristos be_socket_destruct(struct bufferevent *bufev) 5998585484eSchristos { 600*eabc0478Schristos struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); 6018585484eSchristos evutil_socket_t fd; 602*eabc0478Schristos EVUTIL_ASSERT(BEV_IS_SOCKET(bufev)); 6038585484eSchristos 6048585484eSchristos fd = event_get_fd(&bufev->ev_read); 6058585484eSchristos 6068585484eSchristos if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0) 6078585484eSchristos EVUTIL_CLOSESOCKET(fd); 6088585484eSchristos 609*eabc0478Schristos evutil_getaddrinfo_cancel_async_(bufev_p->dns_request); 6108585484eSchristos } 6118585484eSchristos 6128585484eSchristos static int 6138585484eSchristos be_socket_flush(struct bufferevent *bev, short iotype, 6148585484eSchristos enum bufferevent_flush_mode mode) 6158585484eSchristos { 6168585484eSchristos return 0; 6178585484eSchristos } 6188585484eSchristos 6198585484eSchristos 6208585484eSchristos static void 6218585484eSchristos be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd) 6228585484eSchristos { 623*eabc0478Schristos struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); 624*eabc0478Schristos 6258585484eSchristos BEV_LOCK(bufev); 626*eabc0478Schristos EVUTIL_ASSERT(BEV_IS_SOCKET(bufev)); 6278585484eSchristos 6288585484eSchristos event_del(&bufev->ev_read); 6298585484eSchristos event_del(&bufev->ev_write); 6308585484eSchristos 631*eabc0478Schristos evbuffer_unfreeze(bufev->input, 0); 632*eabc0478Schristos evbuffer_unfreeze(bufev->output, 1); 633*eabc0478Schristos 6348585484eSchristos event_assign(&bufev->ev_read, bufev->ev_base, fd, 635b8ecfcfeSchristos EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev); 6368585484eSchristos event_assign(&bufev->ev_write, bufev->ev_base, fd, 637b8ecfcfeSchristos EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev); 6388585484eSchristos 6398585484eSchristos if (fd >= 0) 6408585484eSchristos bufferevent_enable(bufev, bufev->enabled); 6418585484eSchristos 642*eabc0478Schristos evutil_getaddrinfo_cancel_async_(bufev_p->dns_request); 643*eabc0478Schristos 6448585484eSchristos BEV_UNLOCK(bufev); 6458585484eSchristos } 6468585484eSchristos 6478585484eSchristos /* XXXX Should non-socket bufferevents support this? */ 6488585484eSchristos int 6498585484eSchristos bufferevent_priority_set(struct bufferevent *bufev, int priority) 6508585484eSchristos { 6518585484eSchristos int r = -1; 652*eabc0478Schristos struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); 6538585484eSchristos 6548585484eSchristos BEV_LOCK(bufev); 655*eabc0478Schristos if (BEV_IS_ASYNC(bufev) || BEV_IS_FILTER(bufev) || BEV_IS_PAIR(bufev)) 6568585484eSchristos goto done; 6578585484eSchristos 6588585484eSchristos if (event_priority_set(&bufev->ev_read, priority) == -1) 6598585484eSchristos goto done; 6608585484eSchristos if (event_priority_set(&bufev->ev_write, priority) == -1) 6618585484eSchristos goto done; 6628585484eSchristos 6638585484eSchristos event_deferred_cb_set_priority_(&bufev_p->deferred, priority); 6648585484eSchristos 6658585484eSchristos r = 0; 6668585484eSchristos done: 6678585484eSchristos BEV_UNLOCK(bufev); 6688585484eSchristos return r; 6698585484eSchristos } 6708585484eSchristos 6718585484eSchristos /* XXXX Should non-socket bufferevents support this? */ 6728585484eSchristos int 6738585484eSchristos bufferevent_base_set(struct event_base *base, struct bufferevent *bufev) 6748585484eSchristos { 6758585484eSchristos int res = -1; 6768585484eSchristos 6778585484eSchristos BEV_LOCK(bufev); 678*eabc0478Schristos if (!BEV_IS_SOCKET(bufev)) 6798585484eSchristos goto done; 6808585484eSchristos 6818585484eSchristos bufev->ev_base = base; 6828585484eSchristos 6838585484eSchristos res = event_base_set(base, &bufev->ev_read); 6848585484eSchristos if (res == -1) 6858585484eSchristos goto done; 6868585484eSchristos 6878585484eSchristos res = event_base_set(base, &bufev->ev_write); 6888585484eSchristos done: 6898585484eSchristos BEV_UNLOCK(bufev); 6908585484eSchristos return res; 6918585484eSchristos } 6928585484eSchristos 6938585484eSchristos static int 6948585484eSchristos be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op, 6958585484eSchristos union bufferevent_ctrl_data *data) 6968585484eSchristos { 6978585484eSchristos switch (op) { 6988585484eSchristos case BEV_CTRL_SET_FD: 6998585484eSchristos be_socket_setfd(bev, data->fd); 7008585484eSchristos return 0; 7018585484eSchristos case BEV_CTRL_GET_FD: 7028585484eSchristos data->fd = event_get_fd(&bev->ev_read); 7038585484eSchristos return 0; 7048585484eSchristos case BEV_CTRL_GET_UNDERLYING: 7058585484eSchristos case BEV_CTRL_CANCEL_ALL: 7068585484eSchristos default: 7078585484eSchristos return -1; 7088585484eSchristos } 7098585484eSchristos } 710