1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/third_party/libevent/bufferevent_pair.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,333 @@ 1.4 +/* 1.5 + * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson 1.6 + * 1.7 + * Redistribution and use in source and binary forms, with or without 1.8 + * modification, are permitted provided that the following conditions 1.9 + * are met: 1.10 + * 1. Redistributions of source code must retain the above copyright 1.11 + * notice, this list of conditions and the following disclaimer. 1.12 + * 2. Redistributions in binary form must reproduce the above copyright 1.13 + * notice, this list of conditions and the following disclaimer in the 1.14 + * documentation and/or other materials provided with the distribution. 1.15 + * 3. The name of the author may not be used to endorse or promote products 1.16 + * derived from this software without specific prior written permission. 1.17 + * 1.18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1.19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1.20 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1.21 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1.22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1.23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.24 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.25 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 1.27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.28 + */ 1.29 + 1.30 +#include <sys/types.h> 1.31 + 1.32 +#ifdef WIN32 1.33 +#include <winsock2.h> 1.34 +#endif 1.35 + 1.36 +#include "event2/event-config.h" 1.37 + 1.38 +#include "event2/util.h" 1.39 +#include "event2/buffer.h" 1.40 +#include "event2/bufferevent.h" 1.41 +#include "event2/bufferevent_struct.h" 1.42 +#include "event2/event.h" 1.43 +#include "defer-internal.h" 1.44 +#include "bufferevent-internal.h" 1.45 +#include "mm-internal.h" 1.46 +#include "util-internal.h" 1.47 + 1.48 +struct bufferevent_pair { 1.49 + struct bufferevent_private bev; 1.50 + struct bufferevent_pair *partner; 1.51 +}; 1.52 + 1.53 + 1.54 +/* Given a bufferevent that's really a bev part of a bufferevent_pair, 1.55 + * return that bufferevent_filtered. Returns NULL otherwise.*/ 1.56 +static inline struct bufferevent_pair * 1.57 +upcast(struct bufferevent *bev) 1.58 +{ 1.59 + struct bufferevent_pair *bev_p; 1.60 + if (bev->be_ops != &bufferevent_ops_pair) 1.61 + return NULL; 1.62 + bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev.bev); 1.63 + EVUTIL_ASSERT(bev_p->bev.bev.be_ops == &bufferevent_ops_pair); 1.64 + return bev_p; 1.65 +} 1.66 + 1.67 +#define downcast(bev_pair) (&(bev_pair)->bev.bev) 1.68 + 1.69 +static inline void 1.70 +incref_and_lock(struct bufferevent *b) 1.71 +{ 1.72 + struct bufferevent_pair *bevp; 1.73 + _bufferevent_incref_and_lock(b); 1.74 + bevp = upcast(b); 1.75 + if (bevp->partner) 1.76 + _bufferevent_incref_and_lock(downcast(bevp->partner)); 1.77 +} 1.78 + 1.79 +static inline void 1.80 +decref_and_unlock(struct bufferevent *b) 1.81 +{ 1.82 + struct bufferevent_pair *bevp = upcast(b); 1.83 + if (bevp->partner) 1.84 + _bufferevent_decref_and_unlock(downcast(bevp->partner)); 1.85 + _bufferevent_decref_and_unlock(b); 1.86 +} 1.87 + 1.88 +/* XXX Handle close */ 1.89 + 1.90 +static void be_pair_outbuf_cb(struct evbuffer *, 1.91 + const struct evbuffer_cb_info *, void *); 1.92 + 1.93 +static struct bufferevent_pair * 1.94 +bufferevent_pair_elt_new(struct event_base *base, 1.95 + int options) 1.96 +{ 1.97 + struct bufferevent_pair *bufev; 1.98 + if (! (bufev = mm_calloc(1, sizeof(struct bufferevent_pair)))) 1.99 + return NULL; 1.100 + if (bufferevent_init_common(&bufev->bev, base, &bufferevent_ops_pair, 1.101 + options)) { 1.102 + mm_free(bufev); 1.103 + return NULL; 1.104 + } 1.105 + if (!evbuffer_add_cb(bufev->bev.bev.output, be_pair_outbuf_cb, bufev)) { 1.106 + bufferevent_free(downcast(bufev)); 1.107 + return NULL; 1.108 + } 1.109 + 1.110 + _bufferevent_init_generic_timeout_cbs(&bufev->bev.bev); 1.111 + 1.112 + return bufev; 1.113 +} 1.114 + 1.115 +int 1.116 +bufferevent_pair_new(struct event_base *base, int options, 1.117 + struct bufferevent *pair[2]) 1.118 +{ 1.119 + struct bufferevent_pair *bufev1 = NULL, *bufev2 = NULL; 1.120 + int tmp_options; 1.121 + 1.122 + options |= BEV_OPT_DEFER_CALLBACKS; 1.123 + tmp_options = options & ~BEV_OPT_THREADSAFE; 1.124 + 1.125 + bufev1 = bufferevent_pair_elt_new(base, options); 1.126 + if (!bufev1) 1.127 + return -1; 1.128 + bufev2 = bufferevent_pair_elt_new(base, tmp_options); 1.129 + if (!bufev2) { 1.130 + bufferevent_free(downcast(bufev1)); 1.131 + return -1; 1.132 + } 1.133 + 1.134 + if (options & BEV_OPT_THREADSAFE) { 1.135 + /*XXXX check return */ 1.136 + bufferevent_enable_locking(downcast(bufev2), bufev1->bev.lock); 1.137 + } 1.138 + 1.139 + bufev1->partner = bufev2; 1.140 + bufev2->partner = bufev1; 1.141 + 1.142 + evbuffer_freeze(downcast(bufev1)->input, 0); 1.143 + evbuffer_freeze(downcast(bufev1)->output, 1); 1.144 + evbuffer_freeze(downcast(bufev2)->input, 0); 1.145 + evbuffer_freeze(downcast(bufev2)->output, 1); 1.146 + 1.147 + pair[0] = downcast(bufev1); 1.148 + pair[1] = downcast(bufev2); 1.149 + 1.150 + return 0; 1.151 +} 1.152 + 1.153 +static void 1.154 +be_pair_transfer(struct bufferevent *src, struct bufferevent *dst, 1.155 + int ignore_wm) 1.156 +{ 1.157 + size_t src_size, dst_size; 1.158 + size_t n; 1.159 + 1.160 + evbuffer_unfreeze(src->output, 1); 1.161 + evbuffer_unfreeze(dst->input, 0); 1.162 + 1.163 + if (dst->wm_read.high) { 1.164 + dst_size = evbuffer_get_length(dst->input); 1.165 + if (dst_size < dst->wm_read.high) { 1.166 + n = dst->wm_read.high - dst_size; 1.167 + evbuffer_remove_buffer(src->output, dst->input, n); 1.168 + } else { 1.169 + if (!ignore_wm) 1.170 + goto done; 1.171 + n = evbuffer_get_length(src->output); 1.172 + evbuffer_add_buffer(dst->input, src->output); 1.173 + } 1.174 + } else { 1.175 + n = evbuffer_get_length(src->output); 1.176 + evbuffer_add_buffer(dst->input, src->output); 1.177 + } 1.178 + 1.179 + if (n) { 1.180 + BEV_RESET_GENERIC_READ_TIMEOUT(dst); 1.181 + 1.182 + if (evbuffer_get_length(dst->output)) 1.183 + BEV_RESET_GENERIC_WRITE_TIMEOUT(dst); 1.184 + else 1.185 + BEV_DEL_GENERIC_WRITE_TIMEOUT(dst); 1.186 + } 1.187 + 1.188 + src_size = evbuffer_get_length(src->output); 1.189 + dst_size = evbuffer_get_length(dst->input); 1.190 + 1.191 + if (dst_size >= dst->wm_read.low) { 1.192 + _bufferevent_run_readcb(dst); 1.193 + } 1.194 + if (src_size <= src->wm_write.low) { 1.195 + _bufferevent_run_writecb(src); 1.196 + } 1.197 +done: 1.198 + evbuffer_freeze(src->output, 1); 1.199 + evbuffer_freeze(dst->input, 0); 1.200 +} 1.201 + 1.202 +static inline int 1.203 +be_pair_wants_to_talk(struct bufferevent_pair *src, 1.204 + struct bufferevent_pair *dst) 1.205 +{ 1.206 + return (downcast(src)->enabled & EV_WRITE) && 1.207 + (downcast(dst)->enabled & EV_READ) && 1.208 + !dst->bev.read_suspended && 1.209 + evbuffer_get_length(downcast(src)->output); 1.210 +} 1.211 + 1.212 +static void 1.213 +be_pair_outbuf_cb(struct evbuffer *outbuf, 1.214 + const struct evbuffer_cb_info *info, void *arg) 1.215 +{ 1.216 + struct bufferevent_pair *bev_pair = arg; 1.217 + struct bufferevent_pair *partner = bev_pair->partner; 1.218 + 1.219 + incref_and_lock(downcast(bev_pair)); 1.220 + 1.221 + if (info->n_added > info->n_deleted && partner) { 1.222 + /* We got more data. If the other side's reading, then 1.223 + hand it over. */ 1.224 + if (be_pair_wants_to_talk(bev_pair, partner)) { 1.225 + be_pair_transfer(downcast(bev_pair), downcast(partner), 0); 1.226 + } 1.227 + } 1.228 + 1.229 + decref_and_unlock(downcast(bev_pair)); 1.230 +} 1.231 + 1.232 +static int 1.233 +be_pair_enable(struct bufferevent *bufev, short events) 1.234 +{ 1.235 + struct bufferevent_pair *bev_p = upcast(bufev); 1.236 + struct bufferevent_pair *partner = bev_p->partner; 1.237 + 1.238 + incref_and_lock(bufev); 1.239 + 1.240 + if (events & EV_READ) { 1.241 + BEV_RESET_GENERIC_READ_TIMEOUT(bufev); 1.242 + } 1.243 + if ((events & EV_WRITE) && evbuffer_get_length(bufev->output)) 1.244 + BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev); 1.245 + 1.246 + /* We're starting to read! Does the other side have anything to write?*/ 1.247 + if ((events & EV_READ) && partner && 1.248 + be_pair_wants_to_talk(partner, bev_p)) { 1.249 + be_pair_transfer(downcast(partner), bufev, 0); 1.250 + } 1.251 + /* We're starting to write! Does the other side want to read? */ 1.252 + if ((events & EV_WRITE) && partner && 1.253 + be_pair_wants_to_talk(bev_p, partner)) { 1.254 + be_pair_transfer(bufev, downcast(partner), 0); 1.255 + } 1.256 + decref_and_unlock(bufev); 1.257 + return 0; 1.258 +} 1.259 + 1.260 +static int 1.261 +be_pair_disable(struct bufferevent *bev, short events) 1.262 +{ 1.263 + if (events & EV_READ) { 1.264 + BEV_DEL_GENERIC_READ_TIMEOUT(bev); 1.265 + } 1.266 + if (events & EV_WRITE) 1.267 + BEV_DEL_GENERIC_WRITE_TIMEOUT(bev); 1.268 + return 0; 1.269 +} 1.270 + 1.271 +static void 1.272 +be_pair_destruct(struct bufferevent *bev) 1.273 +{ 1.274 + struct bufferevent_pair *bev_p = upcast(bev); 1.275 + 1.276 + if (bev_p->partner) { 1.277 + bev_p->partner->partner = NULL; 1.278 + bev_p->partner = NULL; 1.279 + } 1.280 + 1.281 + _bufferevent_del_generic_timeout_cbs(bev); 1.282 +} 1.283 + 1.284 +static int 1.285 +be_pair_flush(struct bufferevent *bev, short iotype, 1.286 + enum bufferevent_flush_mode mode) 1.287 +{ 1.288 + struct bufferevent_pair *bev_p = upcast(bev); 1.289 + struct bufferevent *partner; 1.290 + incref_and_lock(bev); 1.291 + if (!bev_p->partner) 1.292 + return -1; 1.293 + 1.294 + partner = downcast(bev_p->partner); 1.295 + 1.296 + if (mode == BEV_NORMAL) 1.297 + return 0; 1.298 + 1.299 + if ((iotype & EV_READ) != 0) 1.300 + be_pair_transfer(partner, bev, 1); 1.301 + 1.302 + if ((iotype & EV_WRITE) != 0) 1.303 + be_pair_transfer(bev, partner, 1); 1.304 + 1.305 + if (mode == BEV_FINISHED) { 1.306 + _bufferevent_run_eventcb(partner, iotype|BEV_EVENT_EOF); 1.307 + } 1.308 + decref_and_unlock(bev); 1.309 + return 0; 1.310 +} 1.311 + 1.312 +struct bufferevent * 1.313 +bufferevent_pair_get_partner(struct bufferevent *bev) 1.314 +{ 1.315 + struct bufferevent_pair *bev_p; 1.316 + struct bufferevent *partner; 1.317 + bev_p = upcast(bev); 1.318 + if (! bev_p) 1.319 + return NULL; 1.320 + 1.321 + incref_and_lock(bev); 1.322 + partner = downcast(bev_p->partner); 1.323 + decref_and_unlock(bev); 1.324 + return partner; 1.325 +} 1.326 + 1.327 +const struct bufferevent_ops bufferevent_ops_pair = { 1.328 + "pair_elt", 1.329 + evutil_offsetof(struct bufferevent_pair, bev.bev), 1.330 + be_pair_enable, 1.331 + be_pair_disable, 1.332 + be_pair_destruct, 1.333 + _bufferevent_generic_adj_timeouts, 1.334 + be_pair_flush, 1.335 + NULL, /* ctrl */ 1.336 +};