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