xref: /libevent-2.1.12/bufferevent_async.c (revision 9559349c)
11aebcd50SNick Mathewson /*
2e49e2891SNick Mathewson  * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
31aebcd50SNick Mathewson  *
41aebcd50SNick Mathewson  * All rights reserved.
51aebcd50SNick Mathewson  *
61aebcd50SNick Mathewson  * Redistribution and use in source and binary forms, with or without
71aebcd50SNick Mathewson  * modification, are permitted provided that the following conditions
81aebcd50SNick Mathewson  * are met:
91aebcd50SNick Mathewson  * 1. Redistributions of source code must retain the above copyright
101aebcd50SNick Mathewson  *    notice, this list of conditions and the following disclaimer.
111aebcd50SNick Mathewson  * 2. Redistributions in binary form must reproduce the above copyright
121aebcd50SNick Mathewson  *    notice, this list of conditions and the following disclaimer in the
131aebcd50SNick Mathewson  *    documentation and/or other materials provided with the distribution.
141aebcd50SNick Mathewson  * 3. The name of the author may not be used to endorse or promote products
151aebcd50SNick Mathewson  *    derived from this software without specific prior written permission.
161aebcd50SNick Mathewson  *
171aebcd50SNick Mathewson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
181aebcd50SNick Mathewson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
191aebcd50SNick Mathewson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
201aebcd50SNick Mathewson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
211aebcd50SNick Mathewson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
221aebcd50SNick Mathewson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231aebcd50SNick Mathewson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241aebcd50SNick Mathewson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251aebcd50SNick Mathewson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
261aebcd50SNick Mathewson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271aebcd50SNick Mathewson  */
281aebcd50SNick Mathewson 
29ec347b92SNick Mathewson #include "event2/event-config.h"
300915ca0aSKevin Bowling #include "evconfig-private.h"
311aebcd50SNick Mathewson 
3268120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TIME_H
331aebcd50SNick Mathewson #include <sys/time.h>
341aebcd50SNick Mathewson #endif
351aebcd50SNick Mathewson 
361aebcd50SNick Mathewson #include <errno.h>
371aebcd50SNick Mathewson #include <stdio.h>
381aebcd50SNick Mathewson #include <stdlib.h>
391aebcd50SNick Mathewson #include <string.h>
4068120d9bSNick Mathewson #ifdef EVENT__HAVE_STDARG_H
411aebcd50SNick Mathewson #include <stdarg.h>
421aebcd50SNick Mathewson #endif
4368120d9bSNick Mathewson #ifdef EVENT__HAVE_UNISTD_H
441aebcd50SNick Mathewson #include <unistd.h>
451aebcd50SNick Mathewson #endif
461aebcd50SNick Mathewson 
479f560bfaSNick Mathewson #ifdef _WIN32
481aebcd50SNick Mathewson #include <winsock2.h>
49*9559349cSyuangongji #include <winerror.h>
5086db1c85SNick Mathewson #include <ws2tcpip.h>
511aebcd50SNick Mathewson #endif
521aebcd50SNick Mathewson 
5376f7e7aeSChristopher Davis #include <sys/queue.h>
5476f7e7aeSChristopher Davis 
551aebcd50SNick Mathewson #include "event2/util.h"
561aebcd50SNick Mathewson #include "event2/bufferevent.h"
571aebcd50SNick Mathewson #include "event2/buffer.h"
581aebcd50SNick Mathewson #include "event2/bufferevent_struct.h"
591aebcd50SNick Mathewson #include "event2/event.h"
6076f7e7aeSChristopher Davis #include "event2/util.h"
6176f7e7aeSChristopher Davis #include "event-internal.h"
621aebcd50SNick Mathewson #include "log-internal.h"
631aebcd50SNick Mathewson #include "mm-internal.h"
641aebcd50SNick Mathewson #include "bufferevent-internal.h"
651aebcd50SNick Mathewson #include "util-internal.h"
661aebcd50SNick Mathewson #include "iocp-internal.h"
671aebcd50SNick Mathewson 
6852f9baeeSNick Mathewson #ifndef SO_UPDATE_CONNECT_CONTEXT
6952f9baeeSNick Mathewson /* Mingw is sometimes missing this */
7052f9baeeSNick Mathewson #define SO_UPDATE_CONNECT_CONTEXT 0x7010
7152f9baeeSNick Mathewson #endif
7252f9baeeSNick Mathewson 
731aebcd50SNick Mathewson /* prototypes */
741aebcd50SNick Mathewson static int be_async_enable(struct bufferevent *, short);
751aebcd50SNick Mathewson static int be_async_disable(struct bufferevent *, short);
761aebcd50SNick Mathewson static void be_async_destruct(struct bufferevent *);
771aebcd50SNick Mathewson static int be_async_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
7831d89f27SNick Mathewson static int be_async_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
791aebcd50SNick Mathewson 
801aebcd50SNick Mathewson struct bufferevent_async {
811aebcd50SNick Mathewson 	struct bufferevent_private bev;
8286db1c85SNick Mathewson 	struct event_overlapped connect_overlapped;
83d7d1f1daSNick Mathewson 	struct event_overlapped read_overlapped;
84d7d1f1daSNick Mathewson 	struct event_overlapped write_overlapped;
85a98da7bfSNick Mathewson 	size_t read_in_progress;
86a98da7bfSNick Mathewson 	size_t write_in_progress;
87d7d1f1daSNick Mathewson 	unsigned ok : 1;
8876f7e7aeSChristopher Davis 	unsigned read_added : 1;
8976f7e7aeSChristopher Davis 	unsigned write_added : 1;
901aebcd50SNick Mathewson };
911aebcd50SNick Mathewson 
92657d1b6dSNick Mathewson const struct bufferevent_ops bufferevent_ops_async = {
93657d1b6dSNick Mathewson 	"socket_async",
94657d1b6dSNick Mathewson 	evutil_offsetof(struct bufferevent_async, bev.bev),
95657d1b6dSNick Mathewson 	be_async_enable,
96657d1b6dSNick Mathewson 	be_async_disable,
9702fbf687SNick Mathewson 	NULL, /* Unlink */
98657d1b6dSNick Mathewson 	be_async_destruct,
99cb9da0bfSNick Mathewson 	bufferevent_generic_adj_timeouts_,
100657d1b6dSNick Mathewson 	be_async_flush,
101657d1b6dSNick Mathewson 	be_async_ctrl,
102657d1b6dSNick Mathewson };
103657d1b6dSNick Mathewson 
1046bfac964SAzat Khuzhin static inline void
be_async_run_eventcb(struct bufferevent * bev,short what,int options)1056bfac964SAzat Khuzhin be_async_run_eventcb(struct bufferevent *bev, short what, int options)
1066bfac964SAzat Khuzhin { bufferevent_run_eventcb_(bev, what, options|BEV_TRIG_DEFER_CALLBACKS); }
1076bfac964SAzat Khuzhin 
1086bfac964SAzat Khuzhin static inline void
be_async_trigger_nolock(struct bufferevent * bev,short what,int options)1096bfac964SAzat Khuzhin be_async_trigger_nolock(struct bufferevent *bev, short what, int options)
1106bfac964SAzat Khuzhin { bufferevent_trigger_nolock_(bev, what, options|BEV_TRIG_DEFER_CALLBACKS); }
1116bfac964SAzat Khuzhin 
1126bfac964SAzat Khuzhin static inline int
fatal_error(int err)1136bfac964SAzat Khuzhin fatal_error(int err)
1146bfac964SAzat Khuzhin {
1156bfac964SAzat Khuzhin 	switch (err) {
1166bfac964SAzat Khuzhin 		/* We may have already associated this fd with a port.
1176bfac964SAzat Khuzhin 		 * Let's hope it's this port, and that the error code
1186bfac964SAzat Khuzhin 		 * for doing this neer changes. */
1196bfac964SAzat Khuzhin 		case ERROR_INVALID_PARAMETER:
1206bfac964SAzat Khuzhin 			return 0;
1216bfac964SAzat Khuzhin 	}
1226bfac964SAzat Khuzhin 	return 1;
1236bfac964SAzat Khuzhin }
1246bfac964SAzat Khuzhin 
1251aebcd50SNick Mathewson static inline struct bufferevent_async *
upcast(struct bufferevent * bev)1261aebcd50SNick Mathewson upcast(struct bufferevent *bev)
1271aebcd50SNick Mathewson {
1281aebcd50SNick Mathewson 	struct bufferevent_async *bev_a;
12956faf02bSDominic Chen 	if (!BEV_IS_ASYNC(bev))
1301aebcd50SNick Mathewson 		return NULL;
1311aebcd50SNick Mathewson 	bev_a = EVUTIL_UPCAST(bev, struct bufferevent_async, bev.bev);
1321aebcd50SNick Mathewson 	return bev_a;
1331aebcd50SNick Mathewson }
1341aebcd50SNick Mathewson 
13586db1c85SNick Mathewson static inline struct bufferevent_async *
upcast_connect(struct event_overlapped * eo)136d7d1f1daSNick Mathewson upcast_connect(struct event_overlapped *eo)
13786db1c85SNick Mathewson {
13886db1c85SNick Mathewson 	struct bufferevent_async *bev_a;
13986db1c85SNick Mathewson 	bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, connect_overlapped);
140d7d1f1daSNick Mathewson 	EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
141d7d1f1daSNick Mathewson 	return bev_a;
142d7d1f1daSNick Mathewson }
143d7d1f1daSNick Mathewson 
144d7d1f1daSNick Mathewson static inline struct bufferevent_async *
upcast_read(struct event_overlapped * eo)145d7d1f1daSNick Mathewson upcast_read(struct event_overlapped *eo)
146d7d1f1daSNick Mathewson {
147d7d1f1daSNick Mathewson 	struct bufferevent_async *bev_a;
148d7d1f1daSNick Mathewson 	bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, read_overlapped);
149d7d1f1daSNick Mathewson 	EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
150d7d1f1daSNick Mathewson 	return bev_a;
151d7d1f1daSNick Mathewson }
152d7d1f1daSNick Mathewson 
153d7d1f1daSNick Mathewson static inline struct bufferevent_async *
upcast_write(struct event_overlapped * eo)154d7d1f1daSNick Mathewson upcast_write(struct event_overlapped *eo)
155d7d1f1daSNick Mathewson {
156d7d1f1daSNick Mathewson 	struct bufferevent_async *bev_a;
157d7d1f1daSNick Mathewson 	bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, write_overlapped);
158d7d1f1daSNick Mathewson 	EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
15986db1c85SNick Mathewson 	return bev_a;
16086db1c85SNick Mathewson }
16186db1c85SNick Mathewson 
1621aebcd50SNick Mathewson static void
bev_async_del_write(struct bufferevent_async * beva)16376f7e7aeSChristopher Davis bev_async_del_write(struct bufferevent_async *beva)
1641aebcd50SNick Mathewson {
16576f7e7aeSChristopher Davis 	struct bufferevent *bev = &beva->bev.bev;
1661aebcd50SNick Mathewson 
16776f7e7aeSChristopher Davis 	if (beva->write_added) {
16876f7e7aeSChristopher Davis 		beva->write_added = 0;
1698ac3c4c2SNick Mathewson 		event_base_del_virtual_(bev->ev_base);
1701aebcd50SNick Mathewson 	}
1711aebcd50SNick Mathewson }
1721aebcd50SNick Mathewson 
1731aebcd50SNick Mathewson static void
bev_async_del_read(struct bufferevent_async * beva)17476f7e7aeSChristopher Davis bev_async_del_read(struct bufferevent_async *beva)
17576f7e7aeSChristopher Davis {
17676f7e7aeSChristopher Davis 	struct bufferevent *bev = &beva->bev.bev;
17776f7e7aeSChristopher Davis 
17876f7e7aeSChristopher Davis 	if (beva->read_added) {
17976f7e7aeSChristopher Davis 		beva->read_added = 0;
1808ac3c4c2SNick Mathewson 		event_base_del_virtual_(bev->ev_base);
18176f7e7aeSChristopher Davis 	}
18276f7e7aeSChristopher Davis }
18376f7e7aeSChristopher Davis 
18476f7e7aeSChristopher Davis static void
bev_async_add_write(struct bufferevent_async * beva)18576f7e7aeSChristopher Davis bev_async_add_write(struct bufferevent_async *beva)
18676f7e7aeSChristopher Davis {
18776f7e7aeSChristopher Davis 	struct bufferevent *bev = &beva->bev.bev;
18876f7e7aeSChristopher Davis 
18976f7e7aeSChristopher Davis 	if (!beva->write_added) {
19076f7e7aeSChristopher Davis 		beva->write_added = 1;
1918ac3c4c2SNick Mathewson 		event_base_add_virtual_(bev->ev_base);
19276f7e7aeSChristopher Davis 	}
19376f7e7aeSChristopher Davis }
19476f7e7aeSChristopher Davis 
19576f7e7aeSChristopher Davis static void
bev_async_add_read(struct bufferevent_async * beva)19676f7e7aeSChristopher Davis bev_async_add_read(struct bufferevent_async *beva)
19776f7e7aeSChristopher Davis {
19876f7e7aeSChristopher Davis 	struct bufferevent *bev = &beva->bev.bev;
19976f7e7aeSChristopher Davis 
20076f7e7aeSChristopher Davis 	if (!beva->read_added) {
20176f7e7aeSChristopher Davis 		beva->read_added = 1;
2028ac3c4c2SNick Mathewson 		event_base_add_virtual_(bev->ev_base);
20376f7e7aeSChristopher Davis 	}
20476f7e7aeSChristopher Davis }
20576f7e7aeSChristopher Davis 
20676f7e7aeSChristopher Davis static void
bev_async_consider_writing(struct bufferevent_async * beva)20776f7e7aeSChristopher Davis bev_async_consider_writing(struct bufferevent_async *beva)
20876f7e7aeSChristopher Davis {
20976f7e7aeSChristopher Davis 	size_t at_most;
21076f7e7aeSChristopher Davis 	int limit;
21176f7e7aeSChristopher Davis 	struct bufferevent *bev = &beva->bev.bev;
21276f7e7aeSChristopher Davis 
21376f7e7aeSChristopher Davis 	/* Don't write if there's a write in progress, or we do not
21476f7e7aeSChristopher Davis 	 * want to write, or when there's nothing left to write. */
215495c227fSNick Mathewson 	if (beva->write_in_progress || beva->bev.connecting)
21676f7e7aeSChristopher Davis 		return;
21776f7e7aeSChristopher Davis 	if (!beva->ok || !(bev->enabled&EV_WRITE) ||
21876f7e7aeSChristopher Davis 	    !evbuffer_get_length(bev->output)) {
21976f7e7aeSChristopher Davis 		bev_async_del_write(beva);
22076f7e7aeSChristopher Davis 		return;
22176f7e7aeSChristopher Davis 	}
22276f7e7aeSChristopher Davis 
22376f7e7aeSChristopher Davis 	at_most = evbuffer_get_length(bev->output);
22476f7e7aeSChristopher Davis 
2257484df61SNick Mathewson 	/* This is safe so long as bufferevent_get_write_max never returns
2267484df61SNick Mathewson 	 * more than INT_MAX.  That's true for now. XXXX */
227cb9da0bfSNick Mathewson 	limit = (int)bufferevent_get_write_max_(&beva->bev);
228e06f514dSNick Mathewson 	if (at_most >= (size_t)limit && limit >= 0)
22976f7e7aeSChristopher Davis 		at_most = limit;
23076f7e7aeSChristopher Davis 
23176f7e7aeSChristopher Davis 	if (beva->bev.write_suspended) {
23276f7e7aeSChristopher Davis 		bev_async_del_write(beva);
23376f7e7aeSChristopher Davis 		return;
23476f7e7aeSChristopher Davis 	}
23576f7e7aeSChristopher Davis 
23676f7e7aeSChristopher Davis 	/*  XXXX doesn't respect low-water mark very well. */
2378ac3c4c2SNick Mathewson 	bufferevent_incref_(bev);
2388ac3c4c2SNick Mathewson 	if (evbuffer_launch_write_(bev->output, at_most,
23976f7e7aeSChristopher Davis 	    &beva->write_overlapped)) {
2408ac3c4c2SNick Mathewson 		bufferevent_decref_(bev);
24176f7e7aeSChristopher Davis 		beva->ok = 0;
2426bfac964SAzat Khuzhin 		be_async_run_eventcb(bev, BEV_EVENT_ERROR, 0);
24376f7e7aeSChristopher Davis 	} else {
244a98da7bfSNick Mathewson 		beva->write_in_progress = at_most;
245cb9da0bfSNick Mathewson 		bufferevent_decrement_write_buckets_(&beva->bev, at_most);
24676f7e7aeSChristopher Davis 		bev_async_add_write(beva);
24776f7e7aeSChristopher Davis 	}
24876f7e7aeSChristopher Davis }
24976f7e7aeSChristopher Davis 
25076f7e7aeSChristopher Davis static void
bev_async_consider_reading(struct bufferevent_async * beva)25176f7e7aeSChristopher Davis bev_async_consider_reading(struct bufferevent_async *beva)
2521aebcd50SNick Mathewson {
2531aebcd50SNick Mathewson 	size_t cur_size;
2541aebcd50SNick Mathewson 	size_t read_high;
255fe47003dSNick Mathewson 	size_t at_most;
256737c9cd8SNick Mathewson 	int limit;
25776f7e7aeSChristopher Davis 	struct bufferevent *bev = &beva->bev.bev;
25876f7e7aeSChristopher Davis 
2591aebcd50SNick Mathewson 	/* Don't read if there is a read in progress, or we do not
2601aebcd50SNick Mathewson 	 * want to read. */
261495c227fSNick Mathewson 	if (beva->read_in_progress || beva->bev.connecting)
2621aebcd50SNick Mathewson 		return;
26376f7e7aeSChristopher Davis 	if (!beva->ok || !(bev->enabled&EV_READ)) {
26476f7e7aeSChristopher Davis 		bev_async_del_read(beva);
26576f7e7aeSChristopher Davis 		return;
26676f7e7aeSChristopher Davis 	}
2671aebcd50SNick Mathewson 
2681aebcd50SNick Mathewson 	/* Don't read if we're full */
26976f7e7aeSChristopher Davis 	cur_size = evbuffer_get_length(bev->input);
27076f7e7aeSChristopher Davis 	read_high = bev->wm_read.high;
271fe47003dSNick Mathewson 	if (read_high) {
27276f7e7aeSChristopher Davis 		if (cur_size >= read_high) {
27376f7e7aeSChristopher Davis 			bev_async_del_read(beva);
2741aebcd50SNick Mathewson 			return;
27576f7e7aeSChristopher Davis 		}
276fe47003dSNick Mathewson 		at_most = read_high - cur_size;
277fe47003dSNick Mathewson 	} else {
278fe47003dSNick Mathewson 		at_most = 16384; /* FIXME totally magic. */
279fe47003dSNick Mathewson 	}
2801aebcd50SNick Mathewson 
281737c9cd8SNick Mathewson 	/* XXXX This over-commits. */
282cb9da0bfSNick Mathewson 	/* XXXX see also not above on cast on bufferevent_get_write_max_() */
283cb9da0bfSNick Mathewson 	limit = (int)bufferevent_get_read_max_(&beva->bev);
284e06f514dSNick Mathewson 	if (at_most >= (size_t)limit && limit >= 0)
285737c9cd8SNick Mathewson 		at_most = limit;
286737c9cd8SNick Mathewson 
28776f7e7aeSChristopher Davis 	if (beva->bev.read_suspended) {
28876f7e7aeSChristopher Davis 		bev_async_del_read(beva);
289737c9cd8SNick Mathewson 		return;
2901aebcd50SNick Mathewson 	}
29176f7e7aeSChristopher Davis 
2928ac3c4c2SNick Mathewson 	bufferevent_incref_(bev);
2938ac3c4c2SNick Mathewson 	if (evbuffer_launch_read_(bev->input, at_most, &beva->read_overlapped)) {
29476f7e7aeSChristopher Davis 		beva->ok = 0;
2956bfac964SAzat Khuzhin 		be_async_run_eventcb(bev, BEV_EVENT_ERROR, 0);
2968ac3c4c2SNick Mathewson 		bufferevent_decref_(bev);
29776f7e7aeSChristopher Davis 	} else {
298a98da7bfSNick Mathewson 		beva->read_in_progress = at_most;
299cb9da0bfSNick Mathewson 		bufferevent_decrement_read_buckets_(&beva->bev, at_most);
30076f7e7aeSChristopher Davis 		bev_async_add_read(beva);
30176f7e7aeSChristopher Davis 	}
30276f7e7aeSChristopher Davis 
30376f7e7aeSChristopher Davis 	return;
3041aebcd50SNick Mathewson }
3051aebcd50SNick Mathewson 
3061aebcd50SNick Mathewson static void
be_async_outbuf_callback(struct evbuffer * buf,const struct evbuffer_cb_info * cbinfo,void * arg)3071aebcd50SNick Mathewson be_async_outbuf_callback(struct evbuffer *buf,
3081aebcd50SNick Mathewson     const struct evbuffer_cb_info *cbinfo,
3091aebcd50SNick Mathewson     void *arg)
3101aebcd50SNick Mathewson {
3111aebcd50SNick Mathewson 	struct bufferevent *bev = arg;
3121aebcd50SNick Mathewson 	struct bufferevent_async *bev_async = upcast(bev);
313d7d1f1daSNick Mathewson 
314d7d1f1daSNick Mathewson 	/* If we added data to the outbuf and were not writing before,
315d7d1f1daSNick Mathewson 	 * we may want to write now. */
3161aebcd50SNick Mathewson 
317cb9da0bfSNick Mathewson 	bufferevent_incref_and_lock_(bev);
3181aebcd50SNick Mathewson 
319d7d1f1daSNick Mathewson 	if (cbinfo->n_added)
3201aebcd50SNick Mathewson 		bev_async_consider_writing(bev_async);
3211aebcd50SNick Mathewson 
322cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bev);
3231aebcd50SNick Mathewson }
3241aebcd50SNick Mathewson 
3251aebcd50SNick Mathewson static void
be_async_inbuf_callback(struct evbuffer * buf,const struct evbuffer_cb_info * cbinfo,void * arg)3261aebcd50SNick Mathewson be_async_inbuf_callback(struct evbuffer *buf,
3271aebcd50SNick Mathewson     const struct evbuffer_cb_info *cbinfo,
3281aebcd50SNick Mathewson     void *arg)
3291aebcd50SNick Mathewson {
3301aebcd50SNick Mathewson 	struct bufferevent *bev = arg;
3311aebcd50SNick Mathewson 	struct bufferevent_async *bev_async = upcast(bev);
3321aebcd50SNick Mathewson 
333d7d1f1daSNick Mathewson 	/* If we drained data from the inbuf and were not reading before,
334d7d1f1daSNick Mathewson 	 * we may want to read now */
3351aebcd50SNick Mathewson 
336cb9da0bfSNick Mathewson 	bufferevent_incref_and_lock_(bev);
3371aebcd50SNick Mathewson 
338d7d1f1daSNick Mathewson 	if (cbinfo->n_deleted)
3391aebcd50SNick Mathewson 		bev_async_consider_reading(bev_async);
3401aebcd50SNick Mathewson 
341cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bev);
3421aebcd50SNick Mathewson }
3431aebcd50SNick Mathewson 
3441aebcd50SNick Mathewson static int
be_async_enable(struct bufferevent * buf,short what)3451aebcd50SNick Mathewson be_async_enable(struct bufferevent *buf, short what)
3461aebcd50SNick Mathewson {
3471aebcd50SNick Mathewson 	struct bufferevent_async *bev_async = upcast(buf);
3481aebcd50SNick Mathewson 
349d7d1f1daSNick Mathewson 	if (!bev_async->ok)
350d7d1f1daSNick Mathewson 		return -1;
351d7d1f1daSNick Mathewson 
352495c227fSNick Mathewson 	if (bev_async->bev.connecting) {
353495c227fSNick Mathewson 		/* Don't launch anything during connection attempts. */
354495c227fSNick Mathewson 		return 0;
355495c227fSNick Mathewson 	}
356495c227fSNick Mathewson 
35723170a69SNick Mathewson 	if (what & EV_READ)
35823170a69SNick Mathewson 		BEV_RESET_GENERIC_READ_TIMEOUT(buf);
35923170a69SNick Mathewson 	if (what & EV_WRITE)
36023170a69SNick Mathewson 		BEV_RESET_GENERIC_WRITE_TIMEOUT(buf);
36134574db0SNick Mathewson 
3621aebcd50SNick Mathewson 	/* If we newly enable reading or writing, and we aren't reading or
3631aebcd50SNick Mathewson 	   writing already, consider launching a new read or write. */
3641aebcd50SNick Mathewson 
3651aebcd50SNick Mathewson 	if (what & EV_READ)
3661aebcd50SNick Mathewson 		bev_async_consider_reading(bev_async);
3671aebcd50SNick Mathewson 	if (what & EV_WRITE)
3681aebcd50SNick Mathewson 		bev_async_consider_writing(bev_async);
3691aebcd50SNick Mathewson 	return 0;
3701aebcd50SNick Mathewson }
3711aebcd50SNick Mathewson 
3721aebcd50SNick Mathewson static int
be_async_disable(struct bufferevent * bev,short what)3731aebcd50SNick Mathewson be_async_disable(struct bufferevent *bev, short what)
3741aebcd50SNick Mathewson {
37576f7e7aeSChristopher Davis 	struct bufferevent_async *bev_async = upcast(bev);
3761aebcd50SNick Mathewson 	/* XXXX If we disable reading or writing, we may want to consider
3771aebcd50SNick Mathewson 	 * canceling any in-progress read or write operation, though it might
3781aebcd50SNick Mathewson 	 * not work. */
37934574db0SNick Mathewson 
38076f7e7aeSChristopher Davis 	if (what & EV_READ) {
381d3288293SNick Mathewson 		BEV_DEL_GENERIC_READ_TIMEOUT(bev);
38276f7e7aeSChristopher Davis 		bev_async_del_read(bev_async);
38376f7e7aeSChristopher Davis 	}
38476f7e7aeSChristopher Davis 	if (what & EV_WRITE) {
385d3288293SNick Mathewson 		BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
38676f7e7aeSChristopher Davis 		bev_async_del_write(bev_async);
38776f7e7aeSChristopher Davis 	}
38834574db0SNick Mathewson 
3891aebcd50SNick Mathewson 	return 0;
3901aebcd50SNick Mathewson }
3911aebcd50SNick Mathewson 
3921aebcd50SNick Mathewson static void
be_async_destruct(struct bufferevent * bev)3931aebcd50SNick Mathewson be_async_destruct(struct bufferevent *bev)
3941aebcd50SNick Mathewson {
39576f7e7aeSChristopher Davis 	struct bufferevent_async *bev_async = upcast(bev);
396d7d1f1daSNick Mathewson 	struct bufferevent_private *bev_p = BEV_UPCAST(bev);
397d7d1f1daSNick Mathewson 	evutil_socket_t fd;
398d7d1f1daSNick Mathewson 
39976f7e7aeSChristopher Davis 	EVUTIL_ASSERT(!upcast(bev)->write_in_progress &&
40076f7e7aeSChristopher Davis 			!upcast(bev)->read_in_progress);
401d7d1f1daSNick Mathewson 
40276f7e7aeSChristopher Davis 	bev_async_del_read(bev_async);
40376f7e7aeSChristopher Davis 	bev_async_del_write(bev_async);
40476f7e7aeSChristopher Davis 
405cb9da0bfSNick Mathewson 	fd = evbuffer_overlapped_get_fd_(bev->input);
406e66078a0SAzat Khuzhin 	if (fd != (evutil_socket_t)EVUTIL_INVALID_SOCKET &&
407f133b869SAzat Khuzhin 		(bev_p->options & BEV_OPT_CLOSE_ON_FREE)) {
408899c1dccSSebastian Sjöberg 		evutil_closesocket(fd);
409e66078a0SAzat Khuzhin 		evbuffer_overlapped_set_fd_(bev->input, EVUTIL_INVALID_SOCKET);
410e6af35d7SNick Mathewson 	}
41176f7e7aeSChristopher Davis }
41276f7e7aeSChristopher Davis 
41376f7e7aeSChristopher Davis /* GetQueuedCompletionStatus doesn't reliably yield WSA error codes, so
41476f7e7aeSChristopher Davis  * we use WSAGetOverlappedResult to translate. */
41576f7e7aeSChristopher Davis static void
bev_async_set_wsa_error(struct bufferevent * bev,struct event_overlapped * eo)41676f7e7aeSChristopher Davis bev_async_set_wsa_error(struct bufferevent *bev, struct event_overlapped *eo)
41776f7e7aeSChristopher Davis {
41876f7e7aeSChristopher Davis 	DWORD bytes, flags;
41976f7e7aeSChristopher Davis 	evutil_socket_t fd;
42076f7e7aeSChristopher Davis 
421cb9da0bfSNick Mathewson 	fd = evbuffer_overlapped_get_fd_(bev->input);
42276f7e7aeSChristopher Davis 	WSAGetOverlappedResult(fd, &eo->overlapped, &bytes, FALSE, &flags);
42376f7e7aeSChristopher Davis }
42434574db0SNick Mathewson 
4251aebcd50SNick Mathewson static int
be_async_flush(struct bufferevent * bev,short what,enum bufferevent_flush_mode mode)4261aebcd50SNick Mathewson be_async_flush(struct bufferevent *bev, short what,
4271aebcd50SNick Mathewson     enum bufferevent_flush_mode mode)
4281aebcd50SNick Mathewson {
4291aebcd50SNick Mathewson 	return 0;
4301aebcd50SNick Mathewson }
431b69d03b5SNick Mathewson 
43286db1c85SNick Mathewson static void
connect_complete(struct event_overlapped * eo,ev_uintptr_t key,ev_ssize_t nbytes,int ok)433cef61a2fSNick Mathewson connect_complete(struct event_overlapped *eo, ev_uintptr_t key,
43486db1c85SNick Mathewson     ev_ssize_t nbytes, int ok)
43586db1c85SNick Mathewson {
436d7d1f1daSNick Mathewson 	struct bufferevent_async *bev_a = upcast_connect(eo);
437d7d1f1daSNick Mathewson 	struct bufferevent *bev = &bev_a->bev.bev;
43852f9baeeSNick Mathewson 	evutil_socket_t sock;
43986db1c85SNick Mathewson 
44076f7e7aeSChristopher Davis 	BEV_LOCK(bev);
44186db1c85SNick Mathewson 
44286db1c85SNick Mathewson 	EVUTIL_ASSERT(bev_a->bev.connecting);
44386db1c85SNick Mathewson 	bev_a->bev.connecting = 0;
444cb9da0bfSNick Mathewson 	sock = evbuffer_overlapped_get_fd_(bev_a->bev.bev.input);
44552f9baeeSNick Mathewson 	/* XXXX Handle error? */
44652f9baeeSNick Mathewson 	setsockopt(sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
44786db1c85SNick Mathewson 
44876f7e7aeSChristopher Davis 	if (ok)
4498ac3c4c2SNick Mathewson 		bufferevent_async_set_connected_(bev);
45076f7e7aeSChristopher Davis 	else
45176f7e7aeSChristopher Davis 		bev_async_set_wsa_error(bev, eo);
45276f7e7aeSChristopher Davis 
4536bfac964SAzat Khuzhin 	be_async_run_eventcb(bev, ok ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0);
45486db1c85SNick Mathewson 
4558ac3c4c2SNick Mathewson 	event_base_del_virtual_(bev->ev_base);
45676f7e7aeSChristopher Davis 
457cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bev);
45886db1c85SNick Mathewson }
45986db1c85SNick Mathewson 
460d7d1f1daSNick Mathewson static void
read_complete(struct event_overlapped * eo,ev_uintptr_t key,ev_ssize_t nbytes,int ok)461cef61a2fSNick Mathewson read_complete(struct event_overlapped *eo, ev_uintptr_t key,
462d7d1f1daSNick Mathewson     ev_ssize_t nbytes, int ok)
463d7d1f1daSNick Mathewson {
464d7d1f1daSNick Mathewson 	struct bufferevent_async *bev_a = upcast_read(eo);
465d7d1f1daSNick Mathewson 	struct bufferevent *bev = &bev_a->bev.bev;
466d7d1f1daSNick Mathewson 	short what = BEV_EVENT_READING;
467a98da7bfSNick Mathewson 	ev_ssize_t amount_unread;
46876f7e7aeSChristopher Davis 	BEV_LOCK(bev);
46976f7e7aeSChristopher Davis 	EVUTIL_ASSERT(bev_a->read_in_progress);
470d7d1f1daSNick Mathewson 
471a98da7bfSNick Mathewson 	amount_unread = bev_a->read_in_progress - nbytes;
4728ac3c4c2SNick Mathewson 	evbuffer_commit_read_(bev->input, nbytes);
473d7d1f1daSNick Mathewson 	bev_a->read_in_progress = 0;
474a98da7bfSNick Mathewson 	if (amount_unread)
475cb9da0bfSNick Mathewson 		bufferevent_decrement_read_buckets_(&bev_a->bev, -amount_unread);
476d7d1f1daSNick Mathewson 
47776f7e7aeSChristopher Davis 	if (!ok)
47876f7e7aeSChristopher Davis 		bev_async_set_wsa_error(bev, eo);
47976f7e7aeSChristopher Davis 
48076f7e7aeSChristopher Davis 	if (bev_a->ok) {
481d7d1f1daSNick Mathewson 		if (ok && nbytes) {
482d7d1f1daSNick Mathewson 			BEV_RESET_GENERIC_READ_TIMEOUT(bev);
4836bfac964SAzat Khuzhin 			be_async_trigger_nolock(bev, EV_READ, 0);
484d7d1f1daSNick Mathewson 			bev_async_consider_reading(bev_a);
485d7d1f1daSNick Mathewson 		} else if (!ok) {
486d7d1f1daSNick Mathewson 			what |= BEV_EVENT_ERROR;
487d7d1f1daSNick Mathewson 			bev_a->ok = 0;
4886bfac964SAzat Khuzhin 			be_async_run_eventcb(bev, what, 0);
489d7d1f1daSNick Mathewson 		} else if (!nbytes) {
490d7d1f1daSNick Mathewson 			what |= BEV_EVENT_EOF;
491d7d1f1daSNick Mathewson 			bev_a->ok = 0;
4926bfac964SAzat Khuzhin 			be_async_run_eventcb(bev, what, 0);
493d7d1f1daSNick Mathewson 		}
49476f7e7aeSChristopher Davis 	}
495d7d1f1daSNick Mathewson 
496cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bev);
497d7d1f1daSNick Mathewson }
498d7d1f1daSNick Mathewson 
499d7d1f1daSNick Mathewson static void
write_complete(struct event_overlapped * eo,ev_uintptr_t key,ev_ssize_t nbytes,int ok)500cef61a2fSNick Mathewson write_complete(struct event_overlapped *eo, ev_uintptr_t key,
501d7d1f1daSNick Mathewson     ev_ssize_t nbytes, int ok)
502d7d1f1daSNick Mathewson {
503d7d1f1daSNick Mathewson 	struct bufferevent_async *bev_a = upcast_write(eo);
504d7d1f1daSNick Mathewson 	struct bufferevent *bev = &bev_a->bev.bev;
505d7d1f1daSNick Mathewson 	short what = BEV_EVENT_WRITING;
506a98da7bfSNick Mathewson 	ev_ssize_t amount_unwritten;
507d7d1f1daSNick Mathewson 
50876f7e7aeSChristopher Davis 	BEV_LOCK(bev);
50976f7e7aeSChristopher Davis 	EVUTIL_ASSERT(bev_a->write_in_progress);
510a98da7bfSNick Mathewson 
511a98da7bfSNick Mathewson 	amount_unwritten = bev_a->write_in_progress - nbytes;
5128ac3c4c2SNick Mathewson 	evbuffer_commit_write_(bev->output, nbytes);
513d7d1f1daSNick Mathewson 	bev_a->write_in_progress = 0;
514d7d1f1daSNick Mathewson 
515a98da7bfSNick Mathewson 	if (amount_unwritten)
516cb9da0bfSNick Mathewson 		bufferevent_decrement_write_buckets_(&bev_a->bev,
517a98da7bfSNick Mathewson 		                                     -amount_unwritten);
518a98da7bfSNick Mathewson 
519a98da7bfSNick Mathewson 
52076f7e7aeSChristopher Davis 	if (!ok)
52176f7e7aeSChristopher Davis 		bev_async_set_wsa_error(bev, eo);
52276f7e7aeSChristopher Davis 
52376f7e7aeSChristopher Davis 	if (bev_a->ok) {
524d7d1f1daSNick Mathewson 		if (ok && nbytes) {
525d7d1f1daSNick Mathewson 			BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
5266bfac964SAzat Khuzhin 			be_async_trigger_nolock(bev, EV_WRITE, 0);
527d7d1f1daSNick Mathewson 			bev_async_consider_writing(bev_a);
528d7d1f1daSNick Mathewson 		} else if (!ok) {
529d7d1f1daSNick Mathewson 			what |= BEV_EVENT_ERROR;
530d7d1f1daSNick Mathewson 			bev_a->ok = 0;
5316bfac964SAzat Khuzhin 			be_async_run_eventcb(bev, what, 0);
532d7d1f1daSNick Mathewson 		} else if (!nbytes) {
533d7d1f1daSNick Mathewson 			what |= BEV_EVENT_EOF;
534d7d1f1daSNick Mathewson 			bev_a->ok = 0;
5356bfac964SAzat Khuzhin 			be_async_run_eventcb(bev, what, 0);
536d7d1f1daSNick Mathewson 		}
53776f7e7aeSChristopher Davis 	}
538d7d1f1daSNick Mathewson 
539cb9da0bfSNick Mathewson 	bufferevent_decref_and_unlock_(bev);
540d7d1f1daSNick Mathewson }
541d7d1f1daSNick Mathewson 
542b69d03b5SNick Mathewson struct bufferevent *
bufferevent_async_new_(struct event_base * base,evutil_socket_t fd,int options)5438ac3c4c2SNick Mathewson bufferevent_async_new_(struct event_base *base,
544879420a7SNick Mathewson     evutil_socket_t fd, int options)
545b69d03b5SNick Mathewson {
546b69d03b5SNick Mathewson 	struct bufferevent_async *bev_a;
547b69d03b5SNick Mathewson 	struct bufferevent *bev;
548b69d03b5SNick Mathewson 	struct event_iocp_port *iocp;
549b69d03b5SNick Mathewson 
550b69d03b5SNick Mathewson 	options |= BEV_OPT_THREADSAFE;
551b69d03b5SNick Mathewson 
5528ac3c4c2SNick Mathewson 	if (!(iocp = event_base_get_iocp_(base)))
553b69d03b5SNick Mathewson 		return NULL;
554b69d03b5SNick Mathewson 
5558ac3c4c2SNick Mathewson 	if (fd >= 0 && event_iocp_port_associate_(iocp, fd, 1)<0) {
5566bfac964SAzat Khuzhin 		if (fatal_error(GetLastError()))
557b69d03b5SNick Mathewson 			return NULL;
55886db1c85SNick Mathewson 	}
559b69d03b5SNick Mathewson 
560b69d03b5SNick Mathewson 	if (!(bev_a = mm_calloc(1, sizeof(struct bufferevent_async))))
561b69d03b5SNick Mathewson 		return NULL;
562b69d03b5SNick Mathewson 
563b69d03b5SNick Mathewson 	bev = &bev_a->bev.bev;
5648ac3c4c2SNick Mathewson 	if (!(bev->input = evbuffer_overlapped_new_(fd))) {
565b69d03b5SNick Mathewson 		mm_free(bev_a);
566b69d03b5SNick Mathewson 		return NULL;
567b69d03b5SNick Mathewson 	}
5688ac3c4c2SNick Mathewson 	if (!(bev->output = evbuffer_overlapped_new_(fd))) {
569b69d03b5SNick Mathewson 		evbuffer_free(bev->input);
570b69d03b5SNick Mathewson 		mm_free(bev_a);
571b69d03b5SNick Mathewson 		return NULL;
572b69d03b5SNick Mathewson 	}
573b69d03b5SNick Mathewson 
5748ac3c4c2SNick Mathewson 	if (bufferevent_init_common_(&bev_a->bev, base, &bufferevent_ops_async,
575b69d03b5SNick Mathewson 		options)<0)
576b69d03b5SNick Mathewson 		goto err;
577b69d03b5SNick Mathewson 
578b69d03b5SNick Mathewson 	evbuffer_add_cb(bev->input, be_async_inbuf_callback, bev);
579b69d03b5SNick Mathewson 	evbuffer_add_cb(bev->output, be_async_outbuf_callback, bev);
580b69d03b5SNick Mathewson 
5818ac3c4c2SNick Mathewson 	event_overlapped_init_(&bev_a->connect_overlapped, connect_complete);
5828ac3c4c2SNick Mathewson 	event_overlapped_init_(&bev_a->read_overlapped, read_complete);
5838ac3c4c2SNick Mathewson 	event_overlapped_init_(&bev_a->write_overlapped, write_complete);
584d7d1f1daSNick Mathewson 
585cb9da0bfSNick Mathewson 	bufferevent_init_generic_timeout_cbs_(bev);
58686db1c85SNick Mathewson 
587af9b2a7aSNick Mathewson 	bev_a->ok = fd >= 0;
588af9b2a7aSNick Mathewson 
589b69d03b5SNick Mathewson 	return bev;
590b69d03b5SNick Mathewson err:
591b69d03b5SNick Mathewson 	bufferevent_free(&bev_a->bev.bev);
592b69d03b5SNick Mathewson 	return NULL;
593b69d03b5SNick Mathewson }
59431d89f27SNick Mathewson 
595d7d1f1daSNick Mathewson void
bufferevent_async_set_connected_(struct bufferevent * bev)5968ac3c4c2SNick Mathewson bufferevent_async_set_connected_(struct bufferevent *bev)
597d7d1f1daSNick Mathewson {
598d7d1f1daSNick Mathewson 	struct bufferevent_async *bev_async = upcast(bev);
599d7d1f1daSNick Mathewson 	bev_async->ok = 1;
600d7d1f1daSNick Mathewson 	/* Now's a good time to consider reading/writing */
601d7d1f1daSNick Mathewson 	be_async_enable(bev, bev->enabled);
602d7d1f1daSNick Mathewson }
603d7d1f1daSNick Mathewson 
60486db1c85SNick Mathewson int
bufferevent_async_can_connect_(struct bufferevent * bev)6058ac3c4c2SNick Mathewson bufferevent_async_can_connect_(struct bufferevent *bev)
60686db1c85SNick Mathewson {
60786db1c85SNick Mathewson 	const struct win32_extension_fns *ext =
6088ac3c4c2SNick Mathewson 	    event_get_win32_extension_fns_();
60986db1c85SNick Mathewson 
61086db1c85SNick Mathewson 	if (BEV_IS_ASYNC(bev) &&
6118ac3c4c2SNick Mathewson 	    event_base_get_iocp_(bev->ev_base) &&
61286db1c85SNick Mathewson 	    ext && ext->ConnectEx)
61386db1c85SNick Mathewson 		return 1;
61486db1c85SNick Mathewson 
61586db1c85SNick Mathewson 	return 0;
61686db1c85SNick Mathewson }
61786db1c85SNick Mathewson 
61886db1c85SNick Mathewson int
bufferevent_async_connect_(struct bufferevent * bev,evutil_socket_t fd,const struct sockaddr * sa,int socklen)6198ac3c4c2SNick Mathewson bufferevent_async_connect_(struct bufferevent *bev, evutil_socket_t fd,
62086db1c85SNick Mathewson 	const struct sockaddr *sa, int socklen)
62186db1c85SNick Mathewson {
62286db1c85SNick Mathewson 	BOOL rc;
62386db1c85SNick Mathewson 	struct bufferevent_async *bev_async = upcast(bev);
62486db1c85SNick Mathewson 	struct sockaddr_storage ss;
62586db1c85SNick Mathewson 	const struct win32_extension_fns *ext =
6268ac3c4c2SNick Mathewson 	    event_get_win32_extension_fns_();
62786db1c85SNick Mathewson 
62886db1c85SNick Mathewson 	EVUTIL_ASSERT(ext && ext->ConnectEx && fd >= 0 && sa != NULL);
62986db1c85SNick Mathewson 
63086db1c85SNick Mathewson 	/* ConnectEx() requires that the socket be bound to an address
63186db1c85SNick Mathewson 	 * with bind() before using, otherwise it will fail. We attempt
63286db1c85SNick Mathewson 	 * to issue a bind() here, taking into account that the error
63386db1c85SNick Mathewson 	 * code is set to WSAEINVAL when the socket is already bound. */
63486db1c85SNick Mathewson 	memset(&ss, 0, sizeof(ss));
63586db1c85SNick Mathewson 	if (sa->sa_family == AF_INET) {
63686db1c85SNick Mathewson 		struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
63786db1c85SNick Mathewson 		sin->sin_family = AF_INET;
63886db1c85SNick Mathewson 		sin->sin_addr.s_addr = INADDR_ANY;
63986db1c85SNick Mathewson 	} else if (sa->sa_family == AF_INET6) {
64086db1c85SNick Mathewson 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
64186db1c85SNick Mathewson 		sin6->sin6_family = AF_INET6;
64286db1c85SNick Mathewson 		sin6->sin6_addr = in6addr_any;
64386db1c85SNick Mathewson 	} else {
644d7d1f1daSNick Mathewson 		/* Well, the user will have to bind() */
64586db1c85SNick Mathewson 		return -1;
64686db1c85SNick Mathewson 	}
64786db1c85SNick Mathewson 	if (bind(fd, (struct sockaddr *)&ss, sizeof(ss)) < 0 &&
64886db1c85SNick Mathewson 	    WSAGetLastError() != WSAEINVAL)
64986db1c85SNick Mathewson 		return -1;
65086db1c85SNick Mathewson 
6518ac3c4c2SNick Mathewson 	event_base_add_virtual_(bev->ev_base);
6528ac3c4c2SNick Mathewson 	bufferevent_incref_(bev);
65386db1c85SNick Mathewson 	rc = ext->ConnectEx(fd, sa, socklen, NULL, 0, NULL,
65486db1c85SNick Mathewson 			    &bev_async->connect_overlapped.overlapped);
65586db1c85SNick Mathewson 	if (rc || WSAGetLastError() == ERROR_IO_PENDING)
65686db1c85SNick Mathewson 		return 0;
65786db1c85SNick Mathewson 
6588ac3c4c2SNick Mathewson 	event_base_del_virtual_(bev->ev_base);
6598ac3c4c2SNick Mathewson 	bufferevent_decref_(bev);
66076f7e7aeSChristopher Davis 
66186db1c85SNick Mathewson 	return -1;
66286db1c85SNick Mathewson }
66386db1c85SNick Mathewson 
66431d89f27SNick Mathewson static int
be_async_ctrl(struct bufferevent * bev,enum bufferevent_ctrl_op op,union bufferevent_ctrl_data * data)66531d89f27SNick Mathewson be_async_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
66631d89f27SNick Mathewson     union bufferevent_ctrl_data *data)
66731d89f27SNick Mathewson {
66831d89f27SNick Mathewson 	switch (op) {
66931d89f27SNick Mathewson 	case BEV_CTRL_GET_FD:
670cb9da0bfSNick Mathewson 		data->fd = evbuffer_overlapped_get_fd_(bev->input);
67131d89f27SNick Mathewson 		return 0;
67286db1c85SNick Mathewson 	case BEV_CTRL_SET_FD: {
6736bfac964SAzat Khuzhin 		struct bufferevent_async *bev_a = upcast(bev);
67486db1c85SNick Mathewson 		struct event_iocp_port *iocp;
67586db1c85SNick Mathewson 
676cb9da0bfSNick Mathewson 		if (data->fd == evbuffer_overlapped_get_fd_(bev->input))
67786db1c85SNick Mathewson 			return 0;
6788ac3c4c2SNick Mathewson 		if (!(iocp = event_base_get_iocp_(bev->ev_base)))
67986db1c85SNick Mathewson 			return -1;
6806bfac964SAzat Khuzhin 		if (event_iocp_port_associate_(iocp, data->fd, 1) < 0) {
6816bfac964SAzat Khuzhin 			if (fatal_error(GetLastError()))
68286db1c85SNick Mathewson 				return -1;
6836bfac964SAzat Khuzhin 		}
684cb9da0bfSNick Mathewson 		evbuffer_overlapped_set_fd_(bev->input, data->fd);
685cb9da0bfSNick Mathewson 		evbuffer_overlapped_set_fd_(bev->output, data->fd);
6866bfac964SAzat Khuzhin 		bev_a->ok = data->fd >= 0;
68786db1c85SNick Mathewson 		return 0;
68886db1c85SNick Mathewson 	}
689e6af35d7SNick Mathewson 	case BEV_CTRL_CANCEL_ALL: {
690e6af35d7SNick Mathewson 		struct bufferevent_async *bev_a = upcast(bev);
691cb9da0bfSNick Mathewson 		evutil_socket_t fd = evbuffer_overlapped_get_fd_(bev->input);
692e66078a0SAzat Khuzhin 		if (fd != (evutil_socket_t)EVUTIL_INVALID_SOCKET &&
693e6af35d7SNick Mathewson 		    (bev_a->bev.options & BEV_OPT_CLOSE_ON_FREE)) {
694e6af35d7SNick Mathewson 			closesocket(fd);
695e66078a0SAzat Khuzhin 			evbuffer_overlapped_set_fd_(bev->input, EVUTIL_INVALID_SOCKET);
696e6af35d7SNick Mathewson 		}
697e6af35d7SNick Mathewson 		bev_a->ok = 0;
698e6af35d7SNick Mathewson 		return 0;
699e6af35d7SNick Mathewson 	}
70031d89f27SNick Mathewson 	case BEV_CTRL_GET_UNDERLYING:
70131d89f27SNick Mathewson 	default:
70231d89f27SNick Mathewson 		return -1;
70331d89f27SNick Mathewson 	}
70431d89f27SNick Mathewson }
705e6af35d7SNick Mathewson 
706e6af35d7SNick Mathewson 
707