1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/third_party/libevent/bufferevent_sock.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,699 @@ 1.4 +/* 1.5 + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 1.6 + * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu> 1.7 + * All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions 1.11 + * are met: 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 2. Redistributions in binary form must reproduce the above copyright 1.15 + * notice, this list of conditions and the following disclaimer in the 1.16 + * documentation and/or other materials provided with the distribution. 1.17 + * 3. The name of the author may not be used to endorse or promote products 1.18 + * derived from this software without specific prior written permission. 1.19 + * 1.20 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1.21 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1.22 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1.23 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1.24 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1.25 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.26 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.27 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.28 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 1.29 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.30 + */ 1.31 + 1.32 +#include <sys/types.h> 1.33 + 1.34 +#include "event2/event-config.h" 1.35 + 1.36 +#ifdef _EVENT_HAVE_SYS_TIME_H 1.37 +#include <sys/time.h> 1.38 +#endif 1.39 + 1.40 +#include <errno.h> 1.41 +#include <stdio.h> 1.42 +#include <stdlib.h> 1.43 +#include <string.h> 1.44 +#ifdef _EVENT_HAVE_STDARG_H 1.45 +#include <stdarg.h> 1.46 +#endif 1.47 +#ifdef _EVENT_HAVE_UNISTD_H 1.48 +#include <unistd.h> 1.49 +#endif 1.50 + 1.51 +#ifdef WIN32 1.52 +#include <winsock2.h> 1.53 +#include <ws2tcpip.h> 1.54 +#endif 1.55 + 1.56 +#ifdef _EVENT_HAVE_SYS_SOCKET_H 1.57 +#include <sys/socket.h> 1.58 +#endif 1.59 +#ifdef _EVENT_HAVE_NETINET_IN_H 1.60 +#include <netinet/in.h> 1.61 +#endif 1.62 +#ifdef _EVENT_HAVE_NETINET_IN6_H 1.63 +#include <netinet/in6.h> 1.64 +#endif 1.65 + 1.66 +#include "event2/util.h" 1.67 +#include "event2/bufferevent.h" 1.68 +#include "event2/buffer.h" 1.69 +#include "event2/bufferevent_struct.h" 1.70 +#include "event2/bufferevent_compat.h" 1.71 +#include "event2/event.h" 1.72 +#include "log-internal.h" 1.73 +#include "mm-internal.h" 1.74 +#include "bufferevent-internal.h" 1.75 +#include "util-internal.h" 1.76 +#ifdef WIN32 1.77 +#include "iocp-internal.h" 1.78 +#endif 1.79 + 1.80 +/* prototypes */ 1.81 +static int be_socket_enable(struct bufferevent *, short); 1.82 +static int be_socket_disable(struct bufferevent *, short); 1.83 +static void be_socket_destruct(struct bufferevent *); 1.84 +static int be_socket_adj_timeouts(struct bufferevent *); 1.85 +static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode); 1.86 +static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *); 1.87 + 1.88 +static void be_socket_setfd(struct bufferevent *, evutil_socket_t); 1.89 + 1.90 +const struct bufferevent_ops bufferevent_ops_socket = { 1.91 + "socket", 1.92 + evutil_offsetof(struct bufferevent_private, bev), 1.93 + be_socket_enable, 1.94 + be_socket_disable, 1.95 + be_socket_destruct, 1.96 + be_socket_adj_timeouts, 1.97 + be_socket_flush, 1.98 + be_socket_ctrl, 1.99 +}; 1.100 + 1.101 +#define be_socket_add(ev, t) \ 1.102 + _bufferevent_add_event((ev), (t)) 1.103 + 1.104 +static void 1.105 +bufferevent_socket_outbuf_cb(struct evbuffer *buf, 1.106 + const struct evbuffer_cb_info *cbinfo, 1.107 + void *arg) 1.108 +{ 1.109 + struct bufferevent *bufev = arg; 1.110 + struct bufferevent_private *bufev_p = 1.111 + EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 1.112 + 1.113 + if (cbinfo->n_added && 1.114 + (bufev->enabled & EV_WRITE) && 1.115 + !event_pending(&bufev->ev_write, EV_WRITE, NULL) && 1.116 + !bufev_p->write_suspended) { 1.117 + /* Somebody added data to the buffer, and we would like to 1.118 + * write, and we were not writing. So, start writing. */ 1.119 + if (be_socket_add(&bufev->ev_write, &bufev->timeout_write) == -1) { 1.120 + /* Should we log this? */ 1.121 + } 1.122 + } 1.123 +} 1.124 + 1.125 +static void 1.126 +bufferevent_readcb(evutil_socket_t fd, short event, void *arg) 1.127 +{ 1.128 + struct bufferevent *bufev = arg; 1.129 + struct bufferevent_private *bufev_p = 1.130 + EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 1.131 + struct evbuffer *input; 1.132 + int res = 0; 1.133 + short what = BEV_EVENT_READING; 1.134 + ev_ssize_t howmuch = -1, readmax=-1; 1.135 + 1.136 + _bufferevent_incref_and_lock(bufev); 1.137 + 1.138 + if (event == EV_TIMEOUT) { 1.139 + /* Note that we only check for event==EV_TIMEOUT. If 1.140 + * event==EV_TIMEOUT|EV_READ, we can safely ignore the 1.141 + * timeout, since a read has occurred */ 1.142 + what |= BEV_EVENT_TIMEOUT; 1.143 + goto error; 1.144 + } 1.145 + 1.146 + input = bufev->input; 1.147 + 1.148 + /* 1.149 + * If we have a high watermark configured then we don't want to 1.150 + * read more data than would make us reach the watermark. 1.151 + */ 1.152 + if (bufev->wm_read.high != 0) { 1.153 + howmuch = bufev->wm_read.high - evbuffer_get_length(input); 1.154 + /* we somehow lowered the watermark, stop reading */ 1.155 + if (howmuch <= 0) { 1.156 + bufferevent_wm_suspend_read(bufev); 1.157 + goto done; 1.158 + } 1.159 + } 1.160 + readmax = _bufferevent_get_read_max(bufev_p); 1.161 + if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" 1.162 + * uglifies this code. XXXX */ 1.163 + howmuch = readmax; 1.164 + if (bufev_p->read_suspended) 1.165 + goto done; 1.166 + 1.167 + evbuffer_unfreeze(input, 0); 1.168 + res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ 1.169 + evbuffer_freeze(input, 0); 1.170 + 1.171 + if (res == -1) { 1.172 + int err = evutil_socket_geterror(fd); 1.173 + if (EVUTIL_ERR_RW_RETRIABLE(err)) 1.174 + goto reschedule; 1.175 + /* error case */ 1.176 + what |= BEV_EVENT_ERROR; 1.177 + } else if (res == 0) { 1.178 + /* eof case */ 1.179 + what |= BEV_EVENT_EOF; 1.180 + } 1.181 + 1.182 + if (res <= 0) 1.183 + goto error; 1.184 + 1.185 + _bufferevent_decrement_read_buckets(bufev_p, res); 1.186 + 1.187 + /* Invoke the user callback - must always be called last */ 1.188 + if (evbuffer_get_length(input) >= bufev->wm_read.low) 1.189 + _bufferevent_run_readcb(bufev); 1.190 + 1.191 + goto done; 1.192 + 1.193 + reschedule: 1.194 + goto done; 1.195 + 1.196 + error: 1.197 + bufferevent_disable(bufev, EV_READ); 1.198 + _bufferevent_run_eventcb(bufev, what); 1.199 + 1.200 + done: 1.201 + _bufferevent_decref_and_unlock(bufev); 1.202 +} 1.203 + 1.204 +static void 1.205 +bufferevent_writecb(evutil_socket_t fd, short event, void *arg) 1.206 +{ 1.207 + struct bufferevent *bufev = arg; 1.208 + struct bufferevent_private *bufev_p = 1.209 + EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 1.210 + int res = 0; 1.211 + short what = BEV_EVENT_WRITING; 1.212 + int connected = 0; 1.213 + ev_ssize_t atmost = -1; 1.214 + 1.215 + _bufferevent_incref_and_lock(bufev); 1.216 + 1.217 + if (event == EV_TIMEOUT) { 1.218 + /* Note that we only check for event==EV_TIMEOUT. If 1.219 + * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the 1.220 + * timeout, since a read has occurred */ 1.221 + what |= BEV_EVENT_TIMEOUT; 1.222 + goto error; 1.223 + } 1.224 + if (bufev_p->connecting) { 1.225 + int c = evutil_socket_finished_connecting(fd); 1.226 + /* we need to fake the error if the connection was refused 1.227 + * immediately - usually connection to localhost on BSD */ 1.228 + if (bufev_p->connection_refused) { 1.229 + bufev_p->connection_refused = 0; 1.230 + c = -1; 1.231 + } 1.232 + 1.233 + if (c == 0) 1.234 + goto done; 1.235 + 1.236 + bufev_p->connecting = 0; 1.237 + if (c < 0) { 1.238 + event_del(&bufev->ev_write); 1.239 + event_del(&bufev->ev_read); 1.240 + _bufferevent_run_eventcb(bufev, BEV_EVENT_ERROR); 1.241 + goto done; 1.242 + } else { 1.243 + connected = 1; 1.244 +#ifdef WIN32 1.245 + if (BEV_IS_ASYNC(bufev)) { 1.246 + event_del(&bufev->ev_write); 1.247 + bufferevent_async_set_connected(bufev); 1.248 + _bufferevent_run_eventcb(bufev, 1.249 + BEV_EVENT_CONNECTED); 1.250 + goto done; 1.251 + } 1.252 +#endif 1.253 + _bufferevent_run_eventcb(bufev, 1.254 + BEV_EVENT_CONNECTED); 1.255 + if (!(bufev->enabled & EV_WRITE) || 1.256 + bufev_p->write_suspended) { 1.257 + event_del(&bufev->ev_write); 1.258 + goto done; 1.259 + } 1.260 + } 1.261 + } 1.262 + 1.263 + atmost = _bufferevent_get_write_max(bufev_p); 1.264 + 1.265 + if (bufev_p->write_suspended) 1.266 + goto done; 1.267 + 1.268 + if (evbuffer_get_length(bufev->output)) { 1.269 + evbuffer_unfreeze(bufev->output, 1); 1.270 + res = evbuffer_write_atmost(bufev->output, fd, atmost); 1.271 + evbuffer_freeze(bufev->output, 1); 1.272 + if (res == -1) { 1.273 + int err = evutil_socket_geterror(fd); 1.274 + if (EVUTIL_ERR_RW_RETRIABLE(err)) 1.275 + goto reschedule; 1.276 + what |= BEV_EVENT_ERROR; 1.277 + } else if (res == 0) { 1.278 + /* eof case 1.279 + XXXX Actually, a 0 on write doesn't indicate 1.280 + an EOF. An ECONNRESET might be more typical. 1.281 + */ 1.282 + what |= BEV_EVENT_EOF; 1.283 + } 1.284 + if (res <= 0) 1.285 + goto error; 1.286 + 1.287 + _bufferevent_decrement_write_buckets(bufev_p, res); 1.288 + } 1.289 + 1.290 + if (evbuffer_get_length(bufev->output) == 0) { 1.291 + event_del(&bufev->ev_write); 1.292 + } 1.293 + 1.294 + /* 1.295 + * Invoke the user callback if our buffer is drained or below the 1.296 + * low watermark. 1.297 + */ 1.298 + if ((res || !connected) && 1.299 + evbuffer_get_length(bufev->output) <= bufev->wm_write.low) { 1.300 + _bufferevent_run_writecb(bufev); 1.301 + } 1.302 + 1.303 + goto done; 1.304 + 1.305 + reschedule: 1.306 + if (evbuffer_get_length(bufev->output) == 0) { 1.307 + event_del(&bufev->ev_write); 1.308 + } 1.309 + goto done; 1.310 + 1.311 + error: 1.312 + bufferevent_disable(bufev, EV_WRITE); 1.313 + _bufferevent_run_eventcb(bufev, what); 1.314 + 1.315 + done: 1.316 + _bufferevent_decref_and_unlock(bufev); 1.317 +} 1.318 + 1.319 +struct bufferevent * 1.320 +bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, 1.321 + int options) 1.322 +{ 1.323 + struct bufferevent_private *bufev_p; 1.324 + struct bufferevent *bufev; 1.325 + 1.326 +#ifdef WIN32 1.327 + if (base && event_base_get_iocp(base)) 1.328 + return bufferevent_async_new(base, fd, options); 1.329 +#endif 1.330 + 1.331 + if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) 1.332 + return NULL; 1.333 + 1.334 + if (bufferevent_init_common(bufev_p, base, &bufferevent_ops_socket, 1.335 + options) < 0) { 1.336 + mm_free(bufev_p); 1.337 + return NULL; 1.338 + } 1.339 + bufev = &bufev_p->bev; 1.340 + evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); 1.341 + 1.342 + event_assign(&bufev->ev_read, bufev->ev_base, fd, 1.343 + EV_READ|EV_PERSIST, bufferevent_readcb, bufev); 1.344 + event_assign(&bufev->ev_write, bufev->ev_base, fd, 1.345 + EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev); 1.346 + 1.347 + evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); 1.348 + 1.349 + evbuffer_freeze(bufev->input, 0); 1.350 + evbuffer_freeze(bufev->output, 1); 1.351 + 1.352 + return bufev; 1.353 +} 1.354 + 1.355 +int 1.356 +bufferevent_socket_connect(struct bufferevent *bev, 1.357 + struct sockaddr *sa, int socklen) 1.358 +{ 1.359 + struct bufferevent_private *bufev_p = 1.360 + EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 1.361 + 1.362 + evutil_socket_t fd; 1.363 + int r = 0; 1.364 + int result=-1; 1.365 + int ownfd = 0; 1.366 + 1.367 + _bufferevent_incref_and_lock(bev); 1.368 + 1.369 + if (!bufev_p) 1.370 + goto done; 1.371 + 1.372 + fd = bufferevent_getfd(bev); 1.373 + if (fd < 0) { 1.374 + if (!sa) 1.375 + goto done; 1.376 + fd = socket(sa->sa_family, SOCK_STREAM, 0); 1.377 + if (fd < 0) 1.378 + goto done; 1.379 + if (evutil_make_socket_nonblocking(fd)<0) 1.380 + goto done; 1.381 + ownfd = 1; 1.382 + } 1.383 + if (sa) { 1.384 +#ifdef WIN32 1.385 + if (bufferevent_async_can_connect(bev)) { 1.386 + bufferevent_setfd(bev, fd); 1.387 + r = bufferevent_async_connect(bev, fd, sa, socklen); 1.388 + if (r < 0) 1.389 + goto freesock; 1.390 + bufev_p->connecting = 1; 1.391 + result = 0; 1.392 + goto done; 1.393 + } else 1.394 +#endif 1.395 + r = evutil_socket_connect(&fd, sa, socklen); 1.396 + if (r < 0) 1.397 + goto freesock; 1.398 + } 1.399 +#ifdef WIN32 1.400 + /* ConnectEx() isn't always around, even when IOCP is enabled. 1.401 + * Here, we borrow the socket object's write handler to fall back 1.402 + * on a non-blocking connect() when ConnectEx() is unavailable. */ 1.403 + if (BEV_IS_ASYNC(bev)) { 1.404 + event_assign(&bev->ev_write, bev->ev_base, fd, 1.405 + EV_WRITE|EV_PERSIST, bufferevent_writecb, bev); 1.406 + } 1.407 +#endif 1.408 + bufferevent_setfd(bev, fd); 1.409 + if (r == 0) { 1.410 + if (! be_socket_enable(bev, EV_WRITE)) { 1.411 + bufev_p->connecting = 1; 1.412 + result = 0; 1.413 + goto done; 1.414 + } 1.415 + } else if (r == 1) { 1.416 + /* The connect succeeded already. How very BSD of it. */ 1.417 + result = 0; 1.418 + bufev_p->connecting = 1; 1.419 + event_active(&bev->ev_write, EV_WRITE, 1); 1.420 + } else { 1.421 + /* The connect failed already. How very BSD of it. */ 1.422 + bufev_p->connection_refused = 1; 1.423 + bufev_p->connecting = 1; 1.424 + result = 0; 1.425 + event_active(&bev->ev_write, EV_WRITE, 1); 1.426 + } 1.427 + 1.428 + goto done; 1.429 + 1.430 +freesock: 1.431 + _bufferevent_run_eventcb(bev, BEV_EVENT_ERROR); 1.432 + if (ownfd) 1.433 + evutil_closesocket(fd); 1.434 + /* do something about the error? */ 1.435 +done: 1.436 + _bufferevent_decref_and_unlock(bev); 1.437 + return result; 1.438 +} 1.439 + 1.440 +static void 1.441 +bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, 1.442 + void *arg) 1.443 +{ 1.444 + struct bufferevent *bev = arg; 1.445 + struct bufferevent_private *bev_p = 1.446 + EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 1.447 + int r; 1.448 + BEV_LOCK(bev); 1.449 + 1.450 + bufferevent_unsuspend_write(bev, BEV_SUSPEND_LOOKUP); 1.451 + bufferevent_unsuspend_read(bev, BEV_SUSPEND_LOOKUP); 1.452 + 1.453 + if (result != 0) { 1.454 + bev_p->dns_error = result; 1.455 + _bufferevent_run_eventcb(bev, BEV_EVENT_ERROR); 1.456 + _bufferevent_decref_and_unlock(bev); 1.457 + if (ai) 1.458 + evutil_freeaddrinfo(ai); 1.459 + return; 1.460 + } 1.461 + 1.462 + /* XXX use the other addrinfos? */ 1.463 + /* XXX use this return value */ 1.464 + r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen); 1.465 + (void)r; 1.466 + _bufferevent_decref_and_unlock(bev); 1.467 + evutil_freeaddrinfo(ai); 1.468 +} 1.469 + 1.470 +int 1.471 +bufferevent_socket_connect_hostname(struct bufferevent *bev, 1.472 + struct evdns_base *evdns_base, int family, const char *hostname, int port) 1.473 +{ 1.474 + char portbuf[10]; 1.475 + struct evutil_addrinfo hint; 1.476 + int err; 1.477 + struct bufferevent_private *bev_p = 1.478 + EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 1.479 + 1.480 + if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) 1.481 + return -1; 1.482 + if (port < 1 || port > 65535) 1.483 + return -1; 1.484 + 1.485 + BEV_LOCK(bev); 1.486 + bev_p->dns_error = 0; 1.487 + BEV_UNLOCK(bev); 1.488 + 1.489 + evutil_snprintf(portbuf, sizeof(portbuf), "%d", port); 1.490 + 1.491 + memset(&hint, 0, sizeof(hint)); 1.492 + hint.ai_family = family; 1.493 + hint.ai_protocol = IPPROTO_TCP; 1.494 + hint.ai_socktype = SOCK_STREAM; 1.495 + 1.496 + bufferevent_suspend_write(bev, BEV_SUSPEND_LOOKUP); 1.497 + bufferevent_suspend_read(bev, BEV_SUSPEND_LOOKUP); 1.498 + 1.499 + bufferevent_incref(bev); 1.500 + err = evutil_getaddrinfo_async(evdns_base, hostname, portbuf, 1.501 + &hint, bufferevent_connect_getaddrinfo_cb, bev); 1.502 + 1.503 + if (err == 0) { 1.504 + return 0; 1.505 + } else { 1.506 + bufferevent_unsuspend_write(bev, BEV_SUSPEND_LOOKUP); 1.507 + bufferevent_unsuspend_read(bev, BEV_SUSPEND_LOOKUP); 1.508 + return -1; 1.509 + } 1.510 +} 1.511 + 1.512 +int 1.513 +bufferevent_socket_get_dns_error(struct bufferevent *bev) 1.514 +{ 1.515 + int rv; 1.516 + struct bufferevent_private *bev_p = 1.517 + EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 1.518 + 1.519 + BEV_LOCK(bev); 1.520 + rv = bev_p->dns_error; 1.521 + BEV_LOCK(bev); 1.522 + 1.523 + return rv; 1.524 +} 1.525 + 1.526 +/* 1.527 + * Create a new buffered event object. 1.528 + * 1.529 + * The read callback is invoked whenever we read new data. 1.530 + * The write callback is invoked whenever the output buffer is drained. 1.531 + * The error callback is invoked on a write/read error or on EOF. 1.532 + * 1.533 + * Both read and write callbacks maybe NULL. The error callback is not 1.534 + * allowed to be NULL and have to be provided always. 1.535 + */ 1.536 + 1.537 +struct bufferevent * 1.538 +bufferevent_new(evutil_socket_t fd, 1.539 + bufferevent_data_cb readcb, bufferevent_data_cb writecb, 1.540 + bufferevent_event_cb eventcb, void *cbarg) 1.541 +{ 1.542 + struct bufferevent *bufev; 1.543 + 1.544 + if (!(bufev = bufferevent_socket_new(NULL, fd, 0))) 1.545 + return NULL; 1.546 + 1.547 + bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg); 1.548 + 1.549 + return bufev; 1.550 +} 1.551 + 1.552 + 1.553 +static int 1.554 +be_socket_enable(struct bufferevent *bufev, short event) 1.555 +{ 1.556 + if (event & EV_READ) { 1.557 + if (be_socket_add(&bufev->ev_read,&bufev->timeout_read) == -1) 1.558 + return -1; 1.559 + } 1.560 + if (event & EV_WRITE) { 1.561 + if (be_socket_add(&bufev->ev_write,&bufev->timeout_write) == -1) 1.562 + return -1; 1.563 + } 1.564 + return 0; 1.565 +} 1.566 + 1.567 +static int 1.568 +be_socket_disable(struct bufferevent *bufev, short event) 1.569 +{ 1.570 + struct bufferevent_private *bufev_p = 1.571 + EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 1.572 + if (event & EV_READ) { 1.573 + if (event_del(&bufev->ev_read) == -1) 1.574 + return -1; 1.575 + } 1.576 + /* Don't actually disable the write if we are trying to connect. */ 1.577 + if ((event & EV_WRITE) && ! bufev_p->connecting) { 1.578 + if (event_del(&bufev->ev_write) == -1) 1.579 + return -1; 1.580 + } 1.581 + return 0; 1.582 +} 1.583 + 1.584 +static void 1.585 +be_socket_destruct(struct bufferevent *bufev) 1.586 +{ 1.587 + struct bufferevent_private *bufev_p = 1.588 + EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 1.589 + evutil_socket_t fd; 1.590 + EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket); 1.591 + 1.592 + fd = event_get_fd(&bufev->ev_read); 1.593 + 1.594 + event_del(&bufev->ev_read); 1.595 + event_del(&bufev->ev_write); 1.596 + 1.597 + if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0) 1.598 + EVUTIL_CLOSESOCKET(fd); 1.599 +} 1.600 + 1.601 +static int 1.602 +be_socket_adj_timeouts(struct bufferevent *bufev) 1.603 +{ 1.604 + int r = 0; 1.605 + if (event_pending(&bufev->ev_read, EV_READ, NULL)) 1.606 + if (be_socket_add(&bufev->ev_read, &bufev->timeout_read) < 0) 1.607 + r = -1; 1.608 + if (event_pending(&bufev->ev_write, EV_WRITE, NULL)) { 1.609 + if (be_socket_add(&bufev->ev_write, &bufev->timeout_write) < 0) 1.610 + r = -1; 1.611 + } 1.612 + return r; 1.613 +} 1.614 + 1.615 +static int 1.616 +be_socket_flush(struct bufferevent *bev, short iotype, 1.617 + enum bufferevent_flush_mode mode) 1.618 +{ 1.619 + return 0; 1.620 +} 1.621 + 1.622 + 1.623 +static void 1.624 +be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd) 1.625 +{ 1.626 + BEV_LOCK(bufev); 1.627 + EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket); 1.628 + 1.629 + event_del(&bufev->ev_read); 1.630 + event_del(&bufev->ev_write); 1.631 + 1.632 + event_assign(&bufev->ev_read, bufev->ev_base, fd, 1.633 + EV_READ|EV_PERSIST, bufferevent_readcb, bufev); 1.634 + event_assign(&bufev->ev_write, bufev->ev_base, fd, 1.635 + EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev); 1.636 + 1.637 + if (fd >= 0) 1.638 + bufferevent_enable(bufev, bufev->enabled); 1.639 + 1.640 + BEV_UNLOCK(bufev); 1.641 +} 1.642 + 1.643 +/* XXXX Should non-socket bufferevents support this? */ 1.644 +int 1.645 +bufferevent_priority_set(struct bufferevent *bufev, int priority) 1.646 +{ 1.647 + int r = -1; 1.648 + 1.649 + BEV_LOCK(bufev); 1.650 + if (bufev->be_ops != &bufferevent_ops_socket) 1.651 + goto done; 1.652 + 1.653 + if (event_priority_set(&bufev->ev_read, priority) == -1) 1.654 + goto done; 1.655 + if (event_priority_set(&bufev->ev_write, priority) == -1) 1.656 + goto done; 1.657 + 1.658 + r = 0; 1.659 +done: 1.660 + BEV_UNLOCK(bufev); 1.661 + return r; 1.662 +} 1.663 + 1.664 +/* XXXX Should non-socket bufferevents support this? */ 1.665 +int 1.666 +bufferevent_base_set(struct event_base *base, struct bufferevent *bufev) 1.667 +{ 1.668 + int res = -1; 1.669 + 1.670 + BEV_LOCK(bufev); 1.671 + if (bufev->be_ops != &bufferevent_ops_socket) 1.672 + goto done; 1.673 + 1.674 + bufev->ev_base = base; 1.675 + 1.676 + res = event_base_set(base, &bufev->ev_read); 1.677 + if (res == -1) 1.678 + goto done; 1.679 + 1.680 + res = event_base_set(base, &bufev->ev_write); 1.681 +done: 1.682 + BEV_UNLOCK(bufev); 1.683 + return res; 1.684 +} 1.685 + 1.686 +static int 1.687 +be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op, 1.688 + union bufferevent_ctrl_data *data) 1.689 +{ 1.690 + switch (op) { 1.691 + case BEV_CTRL_SET_FD: 1.692 + be_socket_setfd(bev, data->fd); 1.693 + return 0; 1.694 + case BEV_CTRL_GET_FD: 1.695 + data->fd = event_get_fd(&bev->ev_read); 1.696 + return 0; 1.697 + case BEV_CTRL_GET_UNDERLYING: 1.698 + case BEV_CTRL_CANCEL_ALL: 1.699 + default: 1.700 + return -1; 1.701 + } 1.702 +}