ipc/chromium/src/third_party/libevent/bufferevent_pair.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
michael@0 3 *
michael@0 4 * Redistribution and use in source and binary forms, with or without
michael@0 5 * modification, are permitted provided that the following conditions
michael@0 6 * are met:
michael@0 7 * 1. Redistributions of source code must retain the above copyright
michael@0 8 * notice, this list of conditions and the following disclaimer.
michael@0 9 * 2. Redistributions in binary form must reproduce the above copyright
michael@0 10 * notice, this list of conditions and the following disclaimer in the
michael@0 11 * documentation and/or other materials provided with the distribution.
michael@0 12 * 3. The name of the author may not be used to endorse or promote products
michael@0 13 * derived from this software without specific prior written permission.
michael@0 14 *
michael@0 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
michael@0 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
michael@0 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
michael@0 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
michael@0 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
michael@0 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
michael@0 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 25 */
michael@0 26
michael@0 27 #include <sys/types.h>
michael@0 28
michael@0 29 #ifdef WIN32
michael@0 30 #include <winsock2.h>
michael@0 31 #endif
michael@0 32
michael@0 33 #include "event2/event-config.h"
michael@0 34
michael@0 35 #include "event2/util.h"
michael@0 36 #include "event2/buffer.h"
michael@0 37 #include "event2/bufferevent.h"
michael@0 38 #include "event2/bufferevent_struct.h"
michael@0 39 #include "event2/event.h"
michael@0 40 #include "defer-internal.h"
michael@0 41 #include "bufferevent-internal.h"
michael@0 42 #include "mm-internal.h"
michael@0 43 #include "util-internal.h"
michael@0 44
michael@0 45 struct bufferevent_pair {
michael@0 46 struct bufferevent_private bev;
michael@0 47 struct bufferevent_pair *partner;
michael@0 48 };
michael@0 49
michael@0 50
michael@0 51 /* Given a bufferevent that's really a bev part of a bufferevent_pair,
michael@0 52 * return that bufferevent_filtered. Returns NULL otherwise.*/
michael@0 53 static inline struct bufferevent_pair *
michael@0 54 upcast(struct bufferevent *bev)
michael@0 55 {
michael@0 56 struct bufferevent_pair *bev_p;
michael@0 57 if (bev->be_ops != &bufferevent_ops_pair)
michael@0 58 return NULL;
michael@0 59 bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev.bev);
michael@0 60 EVUTIL_ASSERT(bev_p->bev.bev.be_ops == &bufferevent_ops_pair);
michael@0 61 return bev_p;
michael@0 62 }
michael@0 63
michael@0 64 #define downcast(bev_pair) (&(bev_pair)->bev.bev)
michael@0 65
michael@0 66 static inline void
michael@0 67 incref_and_lock(struct bufferevent *b)
michael@0 68 {
michael@0 69 struct bufferevent_pair *bevp;
michael@0 70 _bufferevent_incref_and_lock(b);
michael@0 71 bevp = upcast(b);
michael@0 72 if (bevp->partner)
michael@0 73 _bufferevent_incref_and_lock(downcast(bevp->partner));
michael@0 74 }
michael@0 75
michael@0 76 static inline void
michael@0 77 decref_and_unlock(struct bufferevent *b)
michael@0 78 {
michael@0 79 struct bufferevent_pair *bevp = upcast(b);
michael@0 80 if (bevp->partner)
michael@0 81 _bufferevent_decref_and_unlock(downcast(bevp->partner));
michael@0 82 _bufferevent_decref_and_unlock(b);
michael@0 83 }
michael@0 84
michael@0 85 /* XXX Handle close */
michael@0 86
michael@0 87 static void be_pair_outbuf_cb(struct evbuffer *,
michael@0 88 const struct evbuffer_cb_info *, void *);
michael@0 89
michael@0 90 static struct bufferevent_pair *
michael@0 91 bufferevent_pair_elt_new(struct event_base *base,
michael@0 92 int options)
michael@0 93 {
michael@0 94 struct bufferevent_pair *bufev;
michael@0 95 if (! (bufev = mm_calloc(1, sizeof(struct bufferevent_pair))))
michael@0 96 return NULL;
michael@0 97 if (bufferevent_init_common(&bufev->bev, base, &bufferevent_ops_pair,
michael@0 98 options)) {
michael@0 99 mm_free(bufev);
michael@0 100 return NULL;
michael@0 101 }
michael@0 102 if (!evbuffer_add_cb(bufev->bev.bev.output, be_pair_outbuf_cb, bufev)) {
michael@0 103 bufferevent_free(downcast(bufev));
michael@0 104 return NULL;
michael@0 105 }
michael@0 106
michael@0 107 _bufferevent_init_generic_timeout_cbs(&bufev->bev.bev);
michael@0 108
michael@0 109 return bufev;
michael@0 110 }
michael@0 111
michael@0 112 int
michael@0 113 bufferevent_pair_new(struct event_base *base, int options,
michael@0 114 struct bufferevent *pair[2])
michael@0 115 {
michael@0 116 struct bufferevent_pair *bufev1 = NULL, *bufev2 = NULL;
michael@0 117 int tmp_options;
michael@0 118
michael@0 119 options |= BEV_OPT_DEFER_CALLBACKS;
michael@0 120 tmp_options = options & ~BEV_OPT_THREADSAFE;
michael@0 121
michael@0 122 bufev1 = bufferevent_pair_elt_new(base, options);
michael@0 123 if (!bufev1)
michael@0 124 return -1;
michael@0 125 bufev2 = bufferevent_pair_elt_new(base, tmp_options);
michael@0 126 if (!bufev2) {
michael@0 127 bufferevent_free(downcast(bufev1));
michael@0 128 return -1;
michael@0 129 }
michael@0 130
michael@0 131 if (options & BEV_OPT_THREADSAFE) {
michael@0 132 /*XXXX check return */
michael@0 133 bufferevent_enable_locking(downcast(bufev2), bufev1->bev.lock);
michael@0 134 }
michael@0 135
michael@0 136 bufev1->partner = bufev2;
michael@0 137 bufev2->partner = bufev1;
michael@0 138
michael@0 139 evbuffer_freeze(downcast(bufev1)->input, 0);
michael@0 140 evbuffer_freeze(downcast(bufev1)->output, 1);
michael@0 141 evbuffer_freeze(downcast(bufev2)->input, 0);
michael@0 142 evbuffer_freeze(downcast(bufev2)->output, 1);
michael@0 143
michael@0 144 pair[0] = downcast(bufev1);
michael@0 145 pair[1] = downcast(bufev2);
michael@0 146
michael@0 147 return 0;
michael@0 148 }
michael@0 149
michael@0 150 static void
michael@0 151 be_pair_transfer(struct bufferevent *src, struct bufferevent *dst,
michael@0 152 int ignore_wm)
michael@0 153 {
michael@0 154 size_t src_size, dst_size;
michael@0 155 size_t n;
michael@0 156
michael@0 157 evbuffer_unfreeze(src->output, 1);
michael@0 158 evbuffer_unfreeze(dst->input, 0);
michael@0 159
michael@0 160 if (dst->wm_read.high) {
michael@0 161 dst_size = evbuffer_get_length(dst->input);
michael@0 162 if (dst_size < dst->wm_read.high) {
michael@0 163 n = dst->wm_read.high - dst_size;
michael@0 164 evbuffer_remove_buffer(src->output, dst->input, n);
michael@0 165 } else {
michael@0 166 if (!ignore_wm)
michael@0 167 goto done;
michael@0 168 n = evbuffer_get_length(src->output);
michael@0 169 evbuffer_add_buffer(dst->input, src->output);
michael@0 170 }
michael@0 171 } else {
michael@0 172 n = evbuffer_get_length(src->output);
michael@0 173 evbuffer_add_buffer(dst->input, src->output);
michael@0 174 }
michael@0 175
michael@0 176 if (n) {
michael@0 177 BEV_RESET_GENERIC_READ_TIMEOUT(dst);
michael@0 178
michael@0 179 if (evbuffer_get_length(dst->output))
michael@0 180 BEV_RESET_GENERIC_WRITE_TIMEOUT(dst);
michael@0 181 else
michael@0 182 BEV_DEL_GENERIC_WRITE_TIMEOUT(dst);
michael@0 183 }
michael@0 184
michael@0 185 src_size = evbuffer_get_length(src->output);
michael@0 186 dst_size = evbuffer_get_length(dst->input);
michael@0 187
michael@0 188 if (dst_size >= dst->wm_read.low) {
michael@0 189 _bufferevent_run_readcb(dst);
michael@0 190 }
michael@0 191 if (src_size <= src->wm_write.low) {
michael@0 192 _bufferevent_run_writecb(src);
michael@0 193 }
michael@0 194 done:
michael@0 195 evbuffer_freeze(src->output, 1);
michael@0 196 evbuffer_freeze(dst->input, 0);
michael@0 197 }
michael@0 198
michael@0 199 static inline int
michael@0 200 be_pair_wants_to_talk(struct bufferevent_pair *src,
michael@0 201 struct bufferevent_pair *dst)
michael@0 202 {
michael@0 203 return (downcast(src)->enabled & EV_WRITE) &&
michael@0 204 (downcast(dst)->enabled & EV_READ) &&
michael@0 205 !dst->bev.read_suspended &&
michael@0 206 evbuffer_get_length(downcast(src)->output);
michael@0 207 }
michael@0 208
michael@0 209 static void
michael@0 210 be_pair_outbuf_cb(struct evbuffer *outbuf,
michael@0 211 const struct evbuffer_cb_info *info, void *arg)
michael@0 212 {
michael@0 213 struct bufferevent_pair *bev_pair = arg;
michael@0 214 struct bufferevent_pair *partner = bev_pair->partner;
michael@0 215
michael@0 216 incref_and_lock(downcast(bev_pair));
michael@0 217
michael@0 218 if (info->n_added > info->n_deleted && partner) {
michael@0 219 /* We got more data. If the other side's reading, then
michael@0 220 hand it over. */
michael@0 221 if (be_pair_wants_to_talk(bev_pair, partner)) {
michael@0 222 be_pair_transfer(downcast(bev_pair), downcast(partner), 0);
michael@0 223 }
michael@0 224 }
michael@0 225
michael@0 226 decref_and_unlock(downcast(bev_pair));
michael@0 227 }
michael@0 228
michael@0 229 static int
michael@0 230 be_pair_enable(struct bufferevent *bufev, short events)
michael@0 231 {
michael@0 232 struct bufferevent_pair *bev_p = upcast(bufev);
michael@0 233 struct bufferevent_pair *partner = bev_p->partner;
michael@0 234
michael@0 235 incref_and_lock(bufev);
michael@0 236
michael@0 237 if (events & EV_READ) {
michael@0 238 BEV_RESET_GENERIC_READ_TIMEOUT(bufev);
michael@0 239 }
michael@0 240 if ((events & EV_WRITE) && evbuffer_get_length(bufev->output))
michael@0 241 BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev);
michael@0 242
michael@0 243 /* We're starting to read! Does the other side have anything to write?*/
michael@0 244 if ((events & EV_READ) && partner &&
michael@0 245 be_pair_wants_to_talk(partner, bev_p)) {
michael@0 246 be_pair_transfer(downcast(partner), bufev, 0);
michael@0 247 }
michael@0 248 /* We're starting to write! Does the other side want to read? */
michael@0 249 if ((events & EV_WRITE) && partner &&
michael@0 250 be_pair_wants_to_talk(bev_p, partner)) {
michael@0 251 be_pair_transfer(bufev, downcast(partner), 0);
michael@0 252 }
michael@0 253 decref_and_unlock(bufev);
michael@0 254 return 0;
michael@0 255 }
michael@0 256
michael@0 257 static int
michael@0 258 be_pair_disable(struct bufferevent *bev, short events)
michael@0 259 {
michael@0 260 if (events & EV_READ) {
michael@0 261 BEV_DEL_GENERIC_READ_TIMEOUT(bev);
michael@0 262 }
michael@0 263 if (events & EV_WRITE)
michael@0 264 BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
michael@0 265 return 0;
michael@0 266 }
michael@0 267
michael@0 268 static void
michael@0 269 be_pair_destruct(struct bufferevent *bev)
michael@0 270 {
michael@0 271 struct bufferevent_pair *bev_p = upcast(bev);
michael@0 272
michael@0 273 if (bev_p->partner) {
michael@0 274 bev_p->partner->partner = NULL;
michael@0 275 bev_p->partner = NULL;
michael@0 276 }
michael@0 277
michael@0 278 _bufferevent_del_generic_timeout_cbs(bev);
michael@0 279 }
michael@0 280
michael@0 281 static int
michael@0 282 be_pair_flush(struct bufferevent *bev, short iotype,
michael@0 283 enum bufferevent_flush_mode mode)
michael@0 284 {
michael@0 285 struct bufferevent_pair *bev_p = upcast(bev);
michael@0 286 struct bufferevent *partner;
michael@0 287 incref_and_lock(bev);
michael@0 288 if (!bev_p->partner)
michael@0 289 return -1;
michael@0 290
michael@0 291 partner = downcast(bev_p->partner);
michael@0 292
michael@0 293 if (mode == BEV_NORMAL)
michael@0 294 return 0;
michael@0 295
michael@0 296 if ((iotype & EV_READ) != 0)
michael@0 297 be_pair_transfer(partner, bev, 1);
michael@0 298
michael@0 299 if ((iotype & EV_WRITE) != 0)
michael@0 300 be_pair_transfer(bev, partner, 1);
michael@0 301
michael@0 302 if (mode == BEV_FINISHED) {
michael@0 303 _bufferevent_run_eventcb(partner, iotype|BEV_EVENT_EOF);
michael@0 304 }
michael@0 305 decref_and_unlock(bev);
michael@0 306 return 0;
michael@0 307 }
michael@0 308
michael@0 309 struct bufferevent *
michael@0 310 bufferevent_pair_get_partner(struct bufferevent *bev)
michael@0 311 {
michael@0 312 struct bufferevent_pair *bev_p;
michael@0 313 struct bufferevent *partner;
michael@0 314 bev_p = upcast(bev);
michael@0 315 if (! bev_p)
michael@0 316 return NULL;
michael@0 317
michael@0 318 incref_and_lock(bev);
michael@0 319 partner = downcast(bev_p->partner);
michael@0 320 decref_and_unlock(bev);
michael@0 321 return partner;
michael@0 322 }
michael@0 323
michael@0 324 const struct bufferevent_ops bufferevent_ops_pair = {
michael@0 325 "pair_elt",
michael@0 326 evutil_offsetof(struct bufferevent_pair, bev.bev),
michael@0 327 be_pair_enable,
michael@0 328 be_pair_disable,
michael@0 329 be_pair_destruct,
michael@0 330 _bufferevent_generic_adj_timeouts,
michael@0 331 be_pair_flush,
michael@0 332 NULL, /* ctrl */
michael@0 333 };

mercurial