1*663afb9bSAndroid Build Coastguard Worker /*
2*663afb9bSAndroid Build Coastguard Worker * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
3*663afb9bSAndroid Build Coastguard Worker * Copyright (c) 2002-2006 Niels Provos <[email protected]>
4*663afb9bSAndroid Build Coastguard Worker * All rights reserved.
5*663afb9bSAndroid Build Coastguard Worker *
6*663afb9bSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
7*663afb9bSAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
8*663afb9bSAndroid Build Coastguard Worker * are met:
9*663afb9bSAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
10*663afb9bSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
11*663afb9bSAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
12*663afb9bSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
13*663afb9bSAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
14*663afb9bSAndroid Build Coastguard Worker * 3. The name of the author may not be used to endorse or promote products
15*663afb9bSAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
16*663afb9bSAndroid Build Coastguard Worker *
17*663afb9bSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18*663afb9bSAndroid Build Coastguard Worker * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19*663afb9bSAndroid Build Coastguard Worker * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*663afb9bSAndroid Build Coastguard Worker * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21*663afb9bSAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22*663afb9bSAndroid Build Coastguard Worker * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23*663afb9bSAndroid Build Coastguard Worker * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24*663afb9bSAndroid Build Coastguard Worker * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*663afb9bSAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26*663afb9bSAndroid Build Coastguard Worker * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*663afb9bSAndroid Build Coastguard Worker */
28*663afb9bSAndroid Build Coastguard Worker
29*663afb9bSAndroid Build Coastguard Worker #include "event2/event-config.h"
30*663afb9bSAndroid Build Coastguard Worker #include "evconfig-private.h"
31*663afb9bSAndroid Build Coastguard Worker
32*663afb9bSAndroid Build Coastguard Worker #include <sys/types.h>
33*663afb9bSAndroid Build Coastguard Worker
34*663afb9bSAndroid Build Coastguard Worker #ifdef EVENT__HAVE_SYS_TIME_H
35*663afb9bSAndroid Build Coastguard Worker #include <sys/time.h>
36*663afb9bSAndroid Build Coastguard Worker #endif
37*663afb9bSAndroid Build Coastguard Worker
38*663afb9bSAndroid Build Coastguard Worker #include <errno.h>
39*663afb9bSAndroid Build Coastguard Worker #include <stdio.h>
40*663afb9bSAndroid Build Coastguard Worker #include <stdlib.h>
41*663afb9bSAndroid Build Coastguard Worker #include <string.h>
42*663afb9bSAndroid Build Coastguard Worker #ifdef EVENT__HAVE_STDARG_H
43*663afb9bSAndroid Build Coastguard Worker #include <stdarg.h>
44*663afb9bSAndroid Build Coastguard Worker #endif
45*663afb9bSAndroid Build Coastguard Worker #ifdef EVENT__HAVE_UNISTD_H
46*663afb9bSAndroid Build Coastguard Worker #include <unistd.h>
47*663afb9bSAndroid Build Coastguard Worker #endif
48*663afb9bSAndroid Build Coastguard Worker
49*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
50*663afb9bSAndroid Build Coastguard Worker #include <winsock2.h>
51*663afb9bSAndroid Build Coastguard Worker #include <ws2tcpip.h>
52*663afb9bSAndroid Build Coastguard Worker #endif
53*663afb9bSAndroid Build Coastguard Worker
54*663afb9bSAndroid Build Coastguard Worker #ifdef EVENT__HAVE_SYS_SOCKET_H
55*663afb9bSAndroid Build Coastguard Worker #include <sys/socket.h>
56*663afb9bSAndroid Build Coastguard Worker #endif
57*663afb9bSAndroid Build Coastguard Worker #ifdef EVENT__HAVE_NETINET_IN_H
58*663afb9bSAndroid Build Coastguard Worker #include <netinet/in.h>
59*663afb9bSAndroid Build Coastguard Worker #endif
60*663afb9bSAndroid Build Coastguard Worker #ifdef EVENT__HAVE_NETINET_IN6_H
61*663afb9bSAndroid Build Coastguard Worker #include <netinet/in6.h>
62*663afb9bSAndroid Build Coastguard Worker #endif
63*663afb9bSAndroid Build Coastguard Worker
64*663afb9bSAndroid Build Coastguard Worker #include "event2/util.h"
65*663afb9bSAndroid Build Coastguard Worker #include "event2/bufferevent.h"
66*663afb9bSAndroid Build Coastguard Worker #include "event2/buffer.h"
67*663afb9bSAndroid Build Coastguard Worker #include "event2/bufferevent_struct.h"
68*663afb9bSAndroid Build Coastguard Worker #include "event2/bufferevent_compat.h"
69*663afb9bSAndroid Build Coastguard Worker #include "event2/event.h"
70*663afb9bSAndroid Build Coastguard Worker #include "log-internal.h"
71*663afb9bSAndroid Build Coastguard Worker #include "mm-internal.h"
72*663afb9bSAndroid Build Coastguard Worker #include "bufferevent-internal.h"
73*663afb9bSAndroid Build Coastguard Worker #include "util-internal.h"
74*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
75*663afb9bSAndroid Build Coastguard Worker #include "iocp-internal.h"
76*663afb9bSAndroid Build Coastguard Worker #endif
77*663afb9bSAndroid Build Coastguard Worker
78*663afb9bSAndroid Build Coastguard Worker /* prototypes */
79*663afb9bSAndroid Build Coastguard Worker static int be_socket_enable(struct bufferevent *, short);
80*663afb9bSAndroid Build Coastguard Worker static int be_socket_disable(struct bufferevent *, short);
81*663afb9bSAndroid Build Coastguard Worker static void be_socket_destruct(struct bufferevent *);
82*663afb9bSAndroid Build Coastguard Worker static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
83*663afb9bSAndroid Build Coastguard Worker static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
84*663afb9bSAndroid Build Coastguard Worker
85*663afb9bSAndroid Build Coastguard Worker static void be_socket_setfd(struct bufferevent *, evutil_socket_t);
86*663afb9bSAndroid Build Coastguard Worker
87*663afb9bSAndroid Build Coastguard Worker const struct bufferevent_ops bufferevent_ops_socket = {
88*663afb9bSAndroid Build Coastguard Worker "socket",
89*663afb9bSAndroid Build Coastguard Worker evutil_offsetof(struct bufferevent_private, bev),
90*663afb9bSAndroid Build Coastguard Worker be_socket_enable,
91*663afb9bSAndroid Build Coastguard Worker be_socket_disable,
92*663afb9bSAndroid Build Coastguard Worker NULL, /* unlink */
93*663afb9bSAndroid Build Coastguard Worker be_socket_destruct,
94*663afb9bSAndroid Build Coastguard Worker bufferevent_generic_adj_existing_timeouts_,
95*663afb9bSAndroid Build Coastguard Worker be_socket_flush,
96*663afb9bSAndroid Build Coastguard Worker be_socket_ctrl,
97*663afb9bSAndroid Build Coastguard Worker };
98*663afb9bSAndroid Build Coastguard Worker
99*663afb9bSAndroid Build Coastguard Worker const struct sockaddr*
bufferevent_socket_get_conn_address_(struct bufferevent * bev)100*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_get_conn_address_(struct bufferevent *bev)
101*663afb9bSAndroid Build Coastguard Worker {
102*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bev_p = BEV_UPCAST(bev);
103*663afb9bSAndroid Build Coastguard Worker return (struct sockaddr *)&bev_p->conn_address;
104*663afb9bSAndroid Build Coastguard Worker }
105*663afb9bSAndroid Build Coastguard Worker
106*663afb9bSAndroid Build Coastguard Worker void
bufferevent_socket_set_conn_address_fd_(struct bufferevent * bev,evutil_socket_t fd)107*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev,
108*663afb9bSAndroid Build Coastguard Worker evutil_socket_t fd)
109*663afb9bSAndroid Build Coastguard Worker {
110*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bev_p = BEV_UPCAST(bev);
111*663afb9bSAndroid Build Coastguard Worker
112*663afb9bSAndroid Build Coastguard Worker socklen_t len = sizeof(bev_p->conn_address);
113*663afb9bSAndroid Build Coastguard Worker
114*663afb9bSAndroid Build Coastguard Worker struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address;
115*663afb9bSAndroid Build Coastguard Worker if (addr->sa_family != AF_UNSPEC)
116*663afb9bSAndroid Build Coastguard Worker getpeername(fd, addr, &len);
117*663afb9bSAndroid Build Coastguard Worker }
118*663afb9bSAndroid Build Coastguard Worker
119*663afb9bSAndroid Build Coastguard Worker void
bufferevent_socket_set_conn_address_(struct bufferevent * bev,struct sockaddr * addr,size_t addrlen)120*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_set_conn_address_(struct bufferevent *bev,
121*663afb9bSAndroid Build Coastguard Worker struct sockaddr *addr, size_t addrlen)
122*663afb9bSAndroid Build Coastguard Worker {
123*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bev_p = BEV_UPCAST(bev);
124*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address));
125*663afb9bSAndroid Build Coastguard Worker memcpy(&bev_p->conn_address, addr, addrlen);
126*663afb9bSAndroid Build Coastguard Worker }
127*663afb9bSAndroid Build Coastguard Worker
128*663afb9bSAndroid Build Coastguard Worker static void
bufferevent_socket_outbuf_cb(struct evbuffer * buf,const struct evbuffer_cb_info * cbinfo,void * arg)129*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_outbuf_cb(struct evbuffer *buf,
130*663afb9bSAndroid Build Coastguard Worker const struct evbuffer_cb_info *cbinfo,
131*663afb9bSAndroid Build Coastguard Worker void *arg)
132*663afb9bSAndroid Build Coastguard Worker {
133*663afb9bSAndroid Build Coastguard Worker struct bufferevent *bufev = arg;
134*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
135*663afb9bSAndroid Build Coastguard Worker
136*663afb9bSAndroid Build Coastguard Worker if (cbinfo->n_added &&
137*663afb9bSAndroid Build Coastguard Worker (bufev->enabled & EV_WRITE) &&
138*663afb9bSAndroid Build Coastguard Worker !event_pending(&bufev->ev_write, EV_WRITE, NULL) &&
139*663afb9bSAndroid Build Coastguard Worker !bufev_p->write_suspended) {
140*663afb9bSAndroid Build Coastguard Worker /* Somebody added data to the buffer, and we would like to
141*663afb9bSAndroid Build Coastguard Worker * write, and we were not writing. So, start writing. */
142*663afb9bSAndroid Build Coastguard Worker if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) {
143*663afb9bSAndroid Build Coastguard Worker /* Should we log this? */
144*663afb9bSAndroid Build Coastguard Worker }
145*663afb9bSAndroid Build Coastguard Worker }
146*663afb9bSAndroid Build Coastguard Worker }
147*663afb9bSAndroid Build Coastguard Worker
148*663afb9bSAndroid Build Coastguard Worker static void
bufferevent_readcb(evutil_socket_t fd,short event,void * arg)149*663afb9bSAndroid Build Coastguard Worker bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
150*663afb9bSAndroid Build Coastguard Worker {
151*663afb9bSAndroid Build Coastguard Worker struct bufferevent *bufev = arg;
152*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
153*663afb9bSAndroid Build Coastguard Worker struct evbuffer *input;
154*663afb9bSAndroid Build Coastguard Worker int res = 0;
155*663afb9bSAndroid Build Coastguard Worker short what = BEV_EVENT_READING;
156*663afb9bSAndroid Build Coastguard Worker ev_ssize_t howmuch = -1, readmax=-1;
157*663afb9bSAndroid Build Coastguard Worker
158*663afb9bSAndroid Build Coastguard Worker bufferevent_incref_and_lock_(bufev);
159*663afb9bSAndroid Build Coastguard Worker
160*663afb9bSAndroid Build Coastguard Worker if (event == EV_TIMEOUT) {
161*663afb9bSAndroid Build Coastguard Worker /* Note that we only check for event==EV_TIMEOUT. If
162*663afb9bSAndroid Build Coastguard Worker * event==EV_TIMEOUT|EV_READ, we can safely ignore the
163*663afb9bSAndroid Build Coastguard Worker * timeout, since a read has occurred */
164*663afb9bSAndroid Build Coastguard Worker what |= BEV_EVENT_TIMEOUT;
165*663afb9bSAndroid Build Coastguard Worker goto error;
166*663afb9bSAndroid Build Coastguard Worker }
167*663afb9bSAndroid Build Coastguard Worker
168*663afb9bSAndroid Build Coastguard Worker input = bufev->input;
169*663afb9bSAndroid Build Coastguard Worker
170*663afb9bSAndroid Build Coastguard Worker /*
171*663afb9bSAndroid Build Coastguard Worker * If we have a high watermark configured then we don't want to
172*663afb9bSAndroid Build Coastguard Worker * read more data than would make us reach the watermark.
173*663afb9bSAndroid Build Coastguard Worker */
174*663afb9bSAndroid Build Coastguard Worker if (bufev->wm_read.high != 0) {
175*663afb9bSAndroid Build Coastguard Worker howmuch = bufev->wm_read.high - evbuffer_get_length(input);
176*663afb9bSAndroid Build Coastguard Worker /* we somehow lowered the watermark, stop reading */
177*663afb9bSAndroid Build Coastguard Worker if (howmuch <= 0) {
178*663afb9bSAndroid Build Coastguard Worker bufferevent_wm_suspend_read(bufev);
179*663afb9bSAndroid Build Coastguard Worker goto done;
180*663afb9bSAndroid Build Coastguard Worker }
181*663afb9bSAndroid Build Coastguard Worker }
182*663afb9bSAndroid Build Coastguard Worker readmax = bufferevent_get_read_max_(bufev_p);
183*663afb9bSAndroid Build Coastguard Worker if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited"
184*663afb9bSAndroid Build Coastguard Worker * uglifies this code. XXXX */
185*663afb9bSAndroid Build Coastguard Worker howmuch = readmax;
186*663afb9bSAndroid Build Coastguard Worker if (bufev_p->read_suspended)
187*663afb9bSAndroid Build Coastguard Worker goto done;
188*663afb9bSAndroid Build Coastguard Worker
189*663afb9bSAndroid Build Coastguard Worker evbuffer_unfreeze(input, 0);
190*663afb9bSAndroid Build Coastguard Worker res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */
191*663afb9bSAndroid Build Coastguard Worker evbuffer_freeze(input, 0);
192*663afb9bSAndroid Build Coastguard Worker
193*663afb9bSAndroid Build Coastguard Worker if (res == -1) {
194*663afb9bSAndroid Build Coastguard Worker int err = evutil_socket_geterror(fd);
195*663afb9bSAndroid Build Coastguard Worker if (EVUTIL_ERR_RW_RETRIABLE(err))
196*663afb9bSAndroid Build Coastguard Worker goto reschedule;
197*663afb9bSAndroid Build Coastguard Worker if (EVUTIL_ERR_CONNECT_REFUSED(err)) {
198*663afb9bSAndroid Build Coastguard Worker bufev_p->connection_refused = 1;
199*663afb9bSAndroid Build Coastguard Worker goto done;
200*663afb9bSAndroid Build Coastguard Worker }
201*663afb9bSAndroid Build Coastguard Worker /* error case */
202*663afb9bSAndroid Build Coastguard Worker what |= BEV_EVENT_ERROR;
203*663afb9bSAndroid Build Coastguard Worker } else if (res == 0) {
204*663afb9bSAndroid Build Coastguard Worker /* eof case */
205*663afb9bSAndroid Build Coastguard Worker what |= BEV_EVENT_EOF;
206*663afb9bSAndroid Build Coastguard Worker }
207*663afb9bSAndroid Build Coastguard Worker
208*663afb9bSAndroid Build Coastguard Worker if (res <= 0)
209*663afb9bSAndroid Build Coastguard Worker goto error;
210*663afb9bSAndroid Build Coastguard Worker
211*663afb9bSAndroid Build Coastguard Worker bufferevent_decrement_read_buckets_(bufev_p, res);
212*663afb9bSAndroid Build Coastguard Worker
213*663afb9bSAndroid Build Coastguard Worker /* Invoke the user callback - must always be called last */
214*663afb9bSAndroid Build Coastguard Worker bufferevent_trigger_nolock_(bufev, EV_READ, 0);
215*663afb9bSAndroid Build Coastguard Worker
216*663afb9bSAndroid Build Coastguard Worker goto done;
217*663afb9bSAndroid Build Coastguard Worker
218*663afb9bSAndroid Build Coastguard Worker reschedule:
219*663afb9bSAndroid Build Coastguard Worker goto done;
220*663afb9bSAndroid Build Coastguard Worker
221*663afb9bSAndroid Build Coastguard Worker error:
222*663afb9bSAndroid Build Coastguard Worker bufferevent_disable(bufev, EV_READ);
223*663afb9bSAndroid Build Coastguard Worker bufferevent_run_eventcb_(bufev, what, 0);
224*663afb9bSAndroid Build Coastguard Worker
225*663afb9bSAndroid Build Coastguard Worker done:
226*663afb9bSAndroid Build Coastguard Worker bufferevent_decref_and_unlock_(bufev);
227*663afb9bSAndroid Build Coastguard Worker }
228*663afb9bSAndroid Build Coastguard Worker
229*663afb9bSAndroid Build Coastguard Worker static void
bufferevent_writecb(evutil_socket_t fd,short event,void * arg)230*663afb9bSAndroid Build Coastguard Worker bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
231*663afb9bSAndroid Build Coastguard Worker {
232*663afb9bSAndroid Build Coastguard Worker struct bufferevent *bufev = arg;
233*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
234*663afb9bSAndroid Build Coastguard Worker int res = 0;
235*663afb9bSAndroid Build Coastguard Worker short what = BEV_EVENT_WRITING;
236*663afb9bSAndroid Build Coastguard Worker int connected = 0;
237*663afb9bSAndroid Build Coastguard Worker ev_ssize_t atmost = -1;
238*663afb9bSAndroid Build Coastguard Worker
239*663afb9bSAndroid Build Coastguard Worker bufferevent_incref_and_lock_(bufev);
240*663afb9bSAndroid Build Coastguard Worker
241*663afb9bSAndroid Build Coastguard Worker if (event == EV_TIMEOUT) {
242*663afb9bSAndroid Build Coastguard Worker /* Note that we only check for event==EV_TIMEOUT. If
243*663afb9bSAndroid Build Coastguard Worker * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the
244*663afb9bSAndroid Build Coastguard Worker * timeout, since a read has occurred */
245*663afb9bSAndroid Build Coastguard Worker what |= BEV_EVENT_TIMEOUT;
246*663afb9bSAndroid Build Coastguard Worker goto error;
247*663afb9bSAndroid Build Coastguard Worker }
248*663afb9bSAndroid Build Coastguard Worker if (bufev_p->connecting) {
249*663afb9bSAndroid Build Coastguard Worker int c = evutil_socket_finished_connecting_(fd);
250*663afb9bSAndroid Build Coastguard Worker /* we need to fake the error if the connection was refused
251*663afb9bSAndroid Build Coastguard Worker * immediately - usually connection to localhost on BSD */
252*663afb9bSAndroid Build Coastguard Worker if (bufev_p->connection_refused) {
253*663afb9bSAndroid Build Coastguard Worker bufev_p->connection_refused = 0;
254*663afb9bSAndroid Build Coastguard Worker c = -1;
255*663afb9bSAndroid Build Coastguard Worker }
256*663afb9bSAndroid Build Coastguard Worker
257*663afb9bSAndroid Build Coastguard Worker if (c == 0)
258*663afb9bSAndroid Build Coastguard Worker goto done;
259*663afb9bSAndroid Build Coastguard Worker
260*663afb9bSAndroid Build Coastguard Worker bufev_p->connecting = 0;
261*663afb9bSAndroid Build Coastguard Worker if (c < 0) {
262*663afb9bSAndroid Build Coastguard Worker event_del(&bufev->ev_write);
263*663afb9bSAndroid Build Coastguard Worker event_del(&bufev->ev_read);
264*663afb9bSAndroid Build Coastguard Worker bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0);
265*663afb9bSAndroid Build Coastguard Worker goto done;
266*663afb9bSAndroid Build Coastguard Worker } else {
267*663afb9bSAndroid Build Coastguard Worker connected = 1;
268*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_set_conn_address_fd_(bufev, fd);
269*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
270*663afb9bSAndroid Build Coastguard Worker if (BEV_IS_ASYNC(bufev)) {
271*663afb9bSAndroid Build Coastguard Worker event_del(&bufev->ev_write);
272*663afb9bSAndroid Build Coastguard Worker bufferevent_async_set_connected_(bufev);
273*663afb9bSAndroid Build Coastguard Worker bufferevent_run_eventcb_(bufev,
274*663afb9bSAndroid Build Coastguard Worker BEV_EVENT_CONNECTED, 0);
275*663afb9bSAndroid Build Coastguard Worker goto done;
276*663afb9bSAndroid Build Coastguard Worker }
277*663afb9bSAndroid Build Coastguard Worker #endif
278*663afb9bSAndroid Build Coastguard Worker bufferevent_run_eventcb_(bufev,
279*663afb9bSAndroid Build Coastguard Worker BEV_EVENT_CONNECTED, 0);
280*663afb9bSAndroid Build Coastguard Worker if (!(bufev->enabled & EV_WRITE) ||
281*663afb9bSAndroid Build Coastguard Worker bufev_p->write_suspended) {
282*663afb9bSAndroid Build Coastguard Worker event_del(&bufev->ev_write);
283*663afb9bSAndroid Build Coastguard Worker goto done;
284*663afb9bSAndroid Build Coastguard Worker }
285*663afb9bSAndroid Build Coastguard Worker }
286*663afb9bSAndroid Build Coastguard Worker }
287*663afb9bSAndroid Build Coastguard Worker
288*663afb9bSAndroid Build Coastguard Worker atmost = bufferevent_get_write_max_(bufev_p);
289*663afb9bSAndroid Build Coastguard Worker
290*663afb9bSAndroid Build Coastguard Worker if (bufev_p->write_suspended)
291*663afb9bSAndroid Build Coastguard Worker goto done;
292*663afb9bSAndroid Build Coastguard Worker
293*663afb9bSAndroid Build Coastguard Worker if (evbuffer_get_length(bufev->output)) {
294*663afb9bSAndroid Build Coastguard Worker evbuffer_unfreeze(bufev->output, 1);
295*663afb9bSAndroid Build Coastguard Worker res = evbuffer_write_atmost(bufev->output, fd, atmost);
296*663afb9bSAndroid Build Coastguard Worker evbuffer_freeze(bufev->output, 1);
297*663afb9bSAndroid Build Coastguard Worker if (res == -1) {
298*663afb9bSAndroid Build Coastguard Worker int err = evutil_socket_geterror(fd);
299*663afb9bSAndroid Build Coastguard Worker if (EVUTIL_ERR_RW_RETRIABLE(err))
300*663afb9bSAndroid Build Coastguard Worker goto reschedule;
301*663afb9bSAndroid Build Coastguard Worker what |= BEV_EVENT_ERROR;
302*663afb9bSAndroid Build Coastguard Worker } else if (res == 0) {
303*663afb9bSAndroid Build Coastguard Worker /* eof case
304*663afb9bSAndroid Build Coastguard Worker XXXX Actually, a 0 on write doesn't indicate
305*663afb9bSAndroid Build Coastguard Worker an EOF. An ECONNRESET might be more typical.
306*663afb9bSAndroid Build Coastguard Worker */
307*663afb9bSAndroid Build Coastguard Worker what |= BEV_EVENT_EOF;
308*663afb9bSAndroid Build Coastguard Worker }
309*663afb9bSAndroid Build Coastguard Worker if (res <= 0)
310*663afb9bSAndroid Build Coastguard Worker goto error;
311*663afb9bSAndroid Build Coastguard Worker
312*663afb9bSAndroid Build Coastguard Worker bufferevent_decrement_write_buckets_(bufev_p, res);
313*663afb9bSAndroid Build Coastguard Worker }
314*663afb9bSAndroid Build Coastguard Worker
315*663afb9bSAndroid Build Coastguard Worker if (evbuffer_get_length(bufev->output) == 0) {
316*663afb9bSAndroid Build Coastguard Worker event_del(&bufev->ev_write);
317*663afb9bSAndroid Build Coastguard Worker }
318*663afb9bSAndroid Build Coastguard Worker
319*663afb9bSAndroid Build Coastguard Worker /*
320*663afb9bSAndroid Build Coastguard Worker * Invoke the user callback if our buffer is drained or below the
321*663afb9bSAndroid Build Coastguard Worker * low watermark.
322*663afb9bSAndroid Build Coastguard Worker */
323*663afb9bSAndroid Build Coastguard Worker if (res || !connected) {
324*663afb9bSAndroid Build Coastguard Worker bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
325*663afb9bSAndroid Build Coastguard Worker }
326*663afb9bSAndroid Build Coastguard Worker
327*663afb9bSAndroid Build Coastguard Worker goto done;
328*663afb9bSAndroid Build Coastguard Worker
329*663afb9bSAndroid Build Coastguard Worker reschedule:
330*663afb9bSAndroid Build Coastguard Worker if (evbuffer_get_length(bufev->output) == 0) {
331*663afb9bSAndroid Build Coastguard Worker event_del(&bufev->ev_write);
332*663afb9bSAndroid Build Coastguard Worker }
333*663afb9bSAndroid Build Coastguard Worker goto done;
334*663afb9bSAndroid Build Coastguard Worker
335*663afb9bSAndroid Build Coastguard Worker error:
336*663afb9bSAndroid Build Coastguard Worker bufferevent_disable(bufev, EV_WRITE);
337*663afb9bSAndroid Build Coastguard Worker bufferevent_run_eventcb_(bufev, what, 0);
338*663afb9bSAndroid Build Coastguard Worker
339*663afb9bSAndroid Build Coastguard Worker done:
340*663afb9bSAndroid Build Coastguard Worker bufferevent_decref_and_unlock_(bufev);
341*663afb9bSAndroid Build Coastguard Worker }
342*663afb9bSAndroid Build Coastguard Worker
343*663afb9bSAndroid Build Coastguard Worker struct bufferevent *
bufferevent_socket_new(struct event_base * base,evutil_socket_t fd,int options)344*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
345*663afb9bSAndroid Build Coastguard Worker int options)
346*663afb9bSAndroid Build Coastguard Worker {
347*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p;
348*663afb9bSAndroid Build Coastguard Worker struct bufferevent *bufev;
349*663afb9bSAndroid Build Coastguard Worker
350*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
351*663afb9bSAndroid Build Coastguard Worker if (base && event_base_get_iocp_(base))
352*663afb9bSAndroid Build Coastguard Worker return bufferevent_async_new_(base, fd, options);
353*663afb9bSAndroid Build Coastguard Worker #endif
354*663afb9bSAndroid Build Coastguard Worker
355*663afb9bSAndroid Build Coastguard Worker if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL)
356*663afb9bSAndroid Build Coastguard Worker return NULL;
357*663afb9bSAndroid Build Coastguard Worker
358*663afb9bSAndroid Build Coastguard Worker if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket,
359*663afb9bSAndroid Build Coastguard Worker options) < 0) {
360*663afb9bSAndroid Build Coastguard Worker mm_free(bufev_p);
361*663afb9bSAndroid Build Coastguard Worker return NULL;
362*663afb9bSAndroid Build Coastguard Worker }
363*663afb9bSAndroid Build Coastguard Worker bufev = &bufev_p->bev;
364*663afb9bSAndroid Build Coastguard Worker evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD);
365*663afb9bSAndroid Build Coastguard Worker
366*663afb9bSAndroid Build Coastguard Worker event_assign(&bufev->ev_read, bufev->ev_base, fd,
367*663afb9bSAndroid Build Coastguard Worker EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
368*663afb9bSAndroid Build Coastguard Worker event_assign(&bufev->ev_write, bufev->ev_base, fd,
369*663afb9bSAndroid Build Coastguard Worker EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
370*663afb9bSAndroid Build Coastguard Worker
371*663afb9bSAndroid Build Coastguard Worker evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev);
372*663afb9bSAndroid Build Coastguard Worker
373*663afb9bSAndroid Build Coastguard Worker evbuffer_freeze(bufev->input, 0);
374*663afb9bSAndroid Build Coastguard Worker evbuffer_freeze(bufev->output, 1);
375*663afb9bSAndroid Build Coastguard Worker
376*663afb9bSAndroid Build Coastguard Worker return bufev;
377*663afb9bSAndroid Build Coastguard Worker }
378*663afb9bSAndroid Build Coastguard Worker
379*663afb9bSAndroid Build Coastguard Worker int
bufferevent_socket_connect(struct bufferevent * bev,const struct sockaddr * sa,int socklen)380*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_connect(struct bufferevent *bev,
381*663afb9bSAndroid Build Coastguard Worker const struct sockaddr *sa, int socklen)
382*663afb9bSAndroid Build Coastguard Worker {
383*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p = BEV_UPCAST(bev);
384*663afb9bSAndroid Build Coastguard Worker
385*663afb9bSAndroid Build Coastguard Worker evutil_socket_t fd;
386*663afb9bSAndroid Build Coastguard Worker int r = 0;
387*663afb9bSAndroid Build Coastguard Worker int result=-1;
388*663afb9bSAndroid Build Coastguard Worker int ownfd = 0;
389*663afb9bSAndroid Build Coastguard Worker
390*663afb9bSAndroid Build Coastguard Worker bufferevent_incref_and_lock_(bev);
391*663afb9bSAndroid Build Coastguard Worker
392*663afb9bSAndroid Build Coastguard Worker fd = bufferevent_getfd(bev);
393*663afb9bSAndroid Build Coastguard Worker if (fd < 0) {
394*663afb9bSAndroid Build Coastguard Worker if (!sa)
395*663afb9bSAndroid Build Coastguard Worker goto done;
396*663afb9bSAndroid Build Coastguard Worker fd = evutil_socket_(sa->sa_family,
397*663afb9bSAndroid Build Coastguard Worker SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0);
398*663afb9bSAndroid Build Coastguard Worker if (fd < 0)
399*663afb9bSAndroid Build Coastguard Worker goto freesock;
400*663afb9bSAndroid Build Coastguard Worker ownfd = 1;
401*663afb9bSAndroid Build Coastguard Worker }
402*663afb9bSAndroid Build Coastguard Worker if (sa) {
403*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
404*663afb9bSAndroid Build Coastguard Worker if (bufferevent_async_can_connect_(bev)) {
405*663afb9bSAndroid Build Coastguard Worker bufferevent_setfd(bev, fd);
406*663afb9bSAndroid Build Coastguard Worker r = bufferevent_async_connect_(bev, fd, sa, socklen);
407*663afb9bSAndroid Build Coastguard Worker if (r < 0)
408*663afb9bSAndroid Build Coastguard Worker goto freesock;
409*663afb9bSAndroid Build Coastguard Worker bufev_p->connecting = 1;
410*663afb9bSAndroid Build Coastguard Worker result = 0;
411*663afb9bSAndroid Build Coastguard Worker goto done;
412*663afb9bSAndroid Build Coastguard Worker } else
413*663afb9bSAndroid Build Coastguard Worker #endif
414*663afb9bSAndroid Build Coastguard Worker r = evutil_socket_connect_(&fd, sa, socklen);
415*663afb9bSAndroid Build Coastguard Worker if (r < 0)
416*663afb9bSAndroid Build Coastguard Worker goto freesock;
417*663afb9bSAndroid Build Coastguard Worker }
418*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
419*663afb9bSAndroid Build Coastguard Worker /* ConnectEx() isn't always around, even when IOCP is enabled.
420*663afb9bSAndroid Build Coastguard Worker * Here, we borrow the socket object's write handler to fall back
421*663afb9bSAndroid Build Coastguard Worker * on a non-blocking connect() when ConnectEx() is unavailable. */
422*663afb9bSAndroid Build Coastguard Worker if (BEV_IS_ASYNC(bev)) {
423*663afb9bSAndroid Build Coastguard Worker event_assign(&bev->ev_write, bev->ev_base, fd,
424*663afb9bSAndroid Build Coastguard Worker EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bev);
425*663afb9bSAndroid Build Coastguard Worker }
426*663afb9bSAndroid Build Coastguard Worker #endif
427*663afb9bSAndroid Build Coastguard Worker bufferevent_setfd(bev, fd);
428*663afb9bSAndroid Build Coastguard Worker if (r == 0) {
429*663afb9bSAndroid Build Coastguard Worker if (! be_socket_enable(bev, EV_WRITE)) {
430*663afb9bSAndroid Build Coastguard Worker bufev_p->connecting = 1;
431*663afb9bSAndroid Build Coastguard Worker result = 0;
432*663afb9bSAndroid Build Coastguard Worker goto done;
433*663afb9bSAndroid Build Coastguard Worker }
434*663afb9bSAndroid Build Coastguard Worker } else if (r == 1) {
435*663afb9bSAndroid Build Coastguard Worker /* The connect succeeded already. How very BSD of it. */
436*663afb9bSAndroid Build Coastguard Worker result = 0;
437*663afb9bSAndroid Build Coastguard Worker bufev_p->connecting = 1;
438*663afb9bSAndroid Build Coastguard Worker bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
439*663afb9bSAndroid Build Coastguard Worker } else {
440*663afb9bSAndroid Build Coastguard Worker /* The connect failed already. How very BSD of it. */
441*663afb9bSAndroid Build Coastguard Worker result = 0;
442*663afb9bSAndroid Build Coastguard Worker bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS);
443*663afb9bSAndroid Build Coastguard Worker bufferevent_disable(bev, EV_WRITE|EV_READ);
444*663afb9bSAndroid Build Coastguard Worker }
445*663afb9bSAndroid Build Coastguard Worker
446*663afb9bSAndroid Build Coastguard Worker goto done;
447*663afb9bSAndroid Build Coastguard Worker
448*663afb9bSAndroid Build Coastguard Worker freesock:
449*663afb9bSAndroid Build Coastguard Worker if (ownfd)
450*663afb9bSAndroid Build Coastguard Worker evutil_closesocket(fd);
451*663afb9bSAndroid Build Coastguard Worker done:
452*663afb9bSAndroid Build Coastguard Worker bufferevent_decref_and_unlock_(bev);
453*663afb9bSAndroid Build Coastguard Worker return result;
454*663afb9bSAndroid Build Coastguard Worker }
455*663afb9bSAndroid Build Coastguard Worker
456*663afb9bSAndroid Build Coastguard Worker static void
bufferevent_connect_getaddrinfo_cb(int result,struct evutil_addrinfo * ai,void * arg)457*663afb9bSAndroid Build Coastguard Worker bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
458*663afb9bSAndroid Build Coastguard Worker void *arg)
459*663afb9bSAndroid Build Coastguard Worker {
460*663afb9bSAndroid Build Coastguard Worker struct bufferevent *bev = arg;
461*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bev_p = BEV_UPCAST(bev);
462*663afb9bSAndroid Build Coastguard Worker int r;
463*663afb9bSAndroid Build Coastguard Worker BEV_LOCK(bev);
464*663afb9bSAndroid Build Coastguard Worker
465*663afb9bSAndroid Build Coastguard Worker bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP);
466*663afb9bSAndroid Build Coastguard Worker bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP);
467*663afb9bSAndroid Build Coastguard Worker
468*663afb9bSAndroid Build Coastguard Worker bev_p->dns_request = NULL;
469*663afb9bSAndroid Build Coastguard Worker
470*663afb9bSAndroid Build Coastguard Worker if (result == EVUTIL_EAI_CANCEL) {
471*663afb9bSAndroid Build Coastguard Worker bev_p->dns_error = result;
472*663afb9bSAndroid Build Coastguard Worker bufferevent_decref_and_unlock_(bev);
473*663afb9bSAndroid Build Coastguard Worker return;
474*663afb9bSAndroid Build Coastguard Worker }
475*663afb9bSAndroid Build Coastguard Worker if (result != 0) {
476*663afb9bSAndroid Build Coastguard Worker bev_p->dns_error = result;
477*663afb9bSAndroid Build Coastguard Worker bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
478*663afb9bSAndroid Build Coastguard Worker bufferevent_decref_and_unlock_(bev);
479*663afb9bSAndroid Build Coastguard Worker if (ai)
480*663afb9bSAndroid Build Coastguard Worker evutil_freeaddrinfo(ai);
481*663afb9bSAndroid Build Coastguard Worker return;
482*663afb9bSAndroid Build Coastguard Worker }
483*663afb9bSAndroid Build Coastguard Worker
484*663afb9bSAndroid Build Coastguard Worker /* XXX use the other addrinfos? */
485*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_set_conn_address_(bev, ai->ai_addr, (int)ai->ai_addrlen);
486*663afb9bSAndroid Build Coastguard Worker r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
487*663afb9bSAndroid Build Coastguard Worker if (r < 0)
488*663afb9bSAndroid Build Coastguard Worker bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
489*663afb9bSAndroid Build Coastguard Worker bufferevent_decref_and_unlock_(bev);
490*663afb9bSAndroid Build Coastguard Worker evutil_freeaddrinfo(ai);
491*663afb9bSAndroid Build Coastguard Worker }
492*663afb9bSAndroid Build Coastguard Worker
493*663afb9bSAndroid Build Coastguard Worker int
bufferevent_socket_connect_hostname(struct bufferevent * bev,struct evdns_base * evdns_base,int family,const char * hostname,int port)494*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_connect_hostname(struct bufferevent *bev,
495*663afb9bSAndroid Build Coastguard Worker struct evdns_base *evdns_base, int family, const char *hostname, int port)
496*663afb9bSAndroid Build Coastguard Worker {
497*663afb9bSAndroid Build Coastguard Worker char portbuf[10];
498*663afb9bSAndroid Build Coastguard Worker struct evutil_addrinfo hint;
499*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bev_p = BEV_UPCAST(bev);
500*663afb9bSAndroid Build Coastguard Worker
501*663afb9bSAndroid Build Coastguard Worker if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
502*663afb9bSAndroid Build Coastguard Worker return -1;
503*663afb9bSAndroid Build Coastguard Worker if (port < 1 || port > 65535)
504*663afb9bSAndroid Build Coastguard Worker return -1;
505*663afb9bSAndroid Build Coastguard Worker
506*663afb9bSAndroid Build Coastguard Worker memset(&hint, 0, sizeof(hint));
507*663afb9bSAndroid Build Coastguard Worker hint.ai_family = family;
508*663afb9bSAndroid Build Coastguard Worker hint.ai_protocol = IPPROTO_TCP;
509*663afb9bSAndroid Build Coastguard Worker hint.ai_socktype = SOCK_STREAM;
510*663afb9bSAndroid Build Coastguard Worker
511*663afb9bSAndroid Build Coastguard Worker evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
512*663afb9bSAndroid Build Coastguard Worker
513*663afb9bSAndroid Build Coastguard Worker BEV_LOCK(bev);
514*663afb9bSAndroid Build Coastguard Worker bev_p->dns_error = 0;
515*663afb9bSAndroid Build Coastguard Worker
516*663afb9bSAndroid Build Coastguard Worker bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP);
517*663afb9bSAndroid Build Coastguard Worker bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP);
518*663afb9bSAndroid Build Coastguard Worker
519*663afb9bSAndroid Build Coastguard Worker bufferevent_incref_(bev);
520*663afb9bSAndroid Build Coastguard Worker bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname,
521*663afb9bSAndroid Build Coastguard Worker portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev);
522*663afb9bSAndroid Build Coastguard Worker BEV_UNLOCK(bev);
523*663afb9bSAndroid Build Coastguard Worker
524*663afb9bSAndroid Build Coastguard Worker return 0;
525*663afb9bSAndroid Build Coastguard Worker }
526*663afb9bSAndroid Build Coastguard Worker
527*663afb9bSAndroid Build Coastguard Worker int
bufferevent_socket_get_dns_error(struct bufferevent * bev)528*663afb9bSAndroid Build Coastguard Worker bufferevent_socket_get_dns_error(struct bufferevent *bev)
529*663afb9bSAndroid Build Coastguard Worker {
530*663afb9bSAndroid Build Coastguard Worker int rv;
531*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bev_p = BEV_UPCAST(bev);
532*663afb9bSAndroid Build Coastguard Worker
533*663afb9bSAndroid Build Coastguard Worker BEV_LOCK(bev);
534*663afb9bSAndroid Build Coastguard Worker rv = bev_p->dns_error;
535*663afb9bSAndroid Build Coastguard Worker BEV_UNLOCK(bev);
536*663afb9bSAndroid Build Coastguard Worker
537*663afb9bSAndroid Build Coastguard Worker return rv;
538*663afb9bSAndroid Build Coastguard Worker }
539*663afb9bSAndroid Build Coastguard Worker
540*663afb9bSAndroid Build Coastguard Worker /*
541*663afb9bSAndroid Build Coastguard Worker * Create a new buffered event object.
542*663afb9bSAndroid Build Coastguard Worker *
543*663afb9bSAndroid Build Coastguard Worker * The read callback is invoked whenever we read new data.
544*663afb9bSAndroid Build Coastguard Worker * The write callback is invoked whenever the output buffer is drained.
545*663afb9bSAndroid Build Coastguard Worker * The error callback is invoked on a write/read error or on EOF.
546*663afb9bSAndroid Build Coastguard Worker *
547*663afb9bSAndroid Build Coastguard Worker * Both read and write callbacks maybe NULL. The error callback is not
548*663afb9bSAndroid Build Coastguard Worker * allowed to be NULL and have to be provided always.
549*663afb9bSAndroid Build Coastguard Worker */
550*663afb9bSAndroid Build Coastguard Worker
551*663afb9bSAndroid Build Coastguard Worker struct bufferevent *
bufferevent_new(evutil_socket_t fd,bufferevent_data_cb readcb,bufferevent_data_cb writecb,bufferevent_event_cb eventcb,void * cbarg)552*663afb9bSAndroid Build Coastguard Worker bufferevent_new(evutil_socket_t fd,
553*663afb9bSAndroid Build Coastguard Worker bufferevent_data_cb readcb, bufferevent_data_cb writecb,
554*663afb9bSAndroid Build Coastguard Worker bufferevent_event_cb eventcb, void *cbarg)
555*663afb9bSAndroid Build Coastguard Worker {
556*663afb9bSAndroid Build Coastguard Worker struct bufferevent *bufev;
557*663afb9bSAndroid Build Coastguard Worker
558*663afb9bSAndroid Build Coastguard Worker if (!(bufev = bufferevent_socket_new(NULL, fd, 0)))
559*663afb9bSAndroid Build Coastguard Worker return NULL;
560*663afb9bSAndroid Build Coastguard Worker
561*663afb9bSAndroid Build Coastguard Worker bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg);
562*663afb9bSAndroid Build Coastguard Worker
563*663afb9bSAndroid Build Coastguard Worker return bufev;
564*663afb9bSAndroid Build Coastguard Worker }
565*663afb9bSAndroid Build Coastguard Worker
566*663afb9bSAndroid Build Coastguard Worker
567*663afb9bSAndroid Build Coastguard Worker static int
be_socket_enable(struct bufferevent * bufev,short event)568*663afb9bSAndroid Build Coastguard Worker be_socket_enable(struct bufferevent *bufev, short event)
569*663afb9bSAndroid Build Coastguard Worker {
570*663afb9bSAndroid Build Coastguard Worker if (event & EV_READ &&
571*663afb9bSAndroid Build Coastguard Worker bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1)
572*663afb9bSAndroid Build Coastguard Worker return -1;
573*663afb9bSAndroid Build Coastguard Worker if (event & EV_WRITE &&
574*663afb9bSAndroid Build Coastguard Worker bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1)
575*663afb9bSAndroid Build Coastguard Worker return -1;
576*663afb9bSAndroid Build Coastguard Worker return 0;
577*663afb9bSAndroid Build Coastguard Worker }
578*663afb9bSAndroid Build Coastguard Worker
579*663afb9bSAndroid Build Coastguard Worker static int
be_socket_disable(struct bufferevent * bufev,short event)580*663afb9bSAndroid Build Coastguard Worker be_socket_disable(struct bufferevent *bufev, short event)
581*663afb9bSAndroid Build Coastguard Worker {
582*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
583*663afb9bSAndroid Build Coastguard Worker if (event & EV_READ) {
584*663afb9bSAndroid Build Coastguard Worker if (event_del(&bufev->ev_read) == -1)
585*663afb9bSAndroid Build Coastguard Worker return -1;
586*663afb9bSAndroid Build Coastguard Worker }
587*663afb9bSAndroid Build Coastguard Worker /* Don't actually disable the write if we are trying to connect. */
588*663afb9bSAndroid Build Coastguard Worker if ((event & EV_WRITE) && ! bufev_p->connecting) {
589*663afb9bSAndroid Build Coastguard Worker if (event_del(&bufev->ev_write) == -1)
590*663afb9bSAndroid Build Coastguard Worker return -1;
591*663afb9bSAndroid Build Coastguard Worker }
592*663afb9bSAndroid Build Coastguard Worker return 0;
593*663afb9bSAndroid Build Coastguard Worker }
594*663afb9bSAndroid Build Coastguard Worker
595*663afb9bSAndroid Build Coastguard Worker static void
be_socket_destruct(struct bufferevent * bufev)596*663afb9bSAndroid Build Coastguard Worker be_socket_destruct(struct bufferevent *bufev)
597*663afb9bSAndroid Build Coastguard Worker {
598*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
599*663afb9bSAndroid Build Coastguard Worker evutil_socket_t fd;
600*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(BEV_IS_SOCKET(bufev));
601*663afb9bSAndroid Build Coastguard Worker
602*663afb9bSAndroid Build Coastguard Worker fd = event_get_fd(&bufev->ev_read);
603*663afb9bSAndroid Build Coastguard Worker
604*663afb9bSAndroid Build Coastguard Worker if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0)
605*663afb9bSAndroid Build Coastguard Worker EVUTIL_CLOSESOCKET(fd);
606*663afb9bSAndroid Build Coastguard Worker
607*663afb9bSAndroid Build Coastguard Worker evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
608*663afb9bSAndroid Build Coastguard Worker }
609*663afb9bSAndroid Build Coastguard Worker
610*663afb9bSAndroid Build Coastguard Worker static int
be_socket_flush(struct bufferevent * bev,short iotype,enum bufferevent_flush_mode mode)611*663afb9bSAndroid Build Coastguard Worker be_socket_flush(struct bufferevent *bev, short iotype,
612*663afb9bSAndroid Build Coastguard Worker enum bufferevent_flush_mode mode)
613*663afb9bSAndroid Build Coastguard Worker {
614*663afb9bSAndroid Build Coastguard Worker return 0;
615*663afb9bSAndroid Build Coastguard Worker }
616*663afb9bSAndroid Build Coastguard Worker
617*663afb9bSAndroid Build Coastguard Worker
618*663afb9bSAndroid Build Coastguard Worker static void
be_socket_setfd(struct bufferevent * bufev,evutil_socket_t fd)619*663afb9bSAndroid Build Coastguard Worker be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd)
620*663afb9bSAndroid Build Coastguard Worker {
621*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
622*663afb9bSAndroid Build Coastguard Worker
623*663afb9bSAndroid Build Coastguard Worker BEV_LOCK(bufev);
624*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(BEV_IS_SOCKET(bufev));
625*663afb9bSAndroid Build Coastguard Worker
626*663afb9bSAndroid Build Coastguard Worker event_del(&bufev->ev_read);
627*663afb9bSAndroid Build Coastguard Worker event_del(&bufev->ev_write);
628*663afb9bSAndroid Build Coastguard Worker
629*663afb9bSAndroid Build Coastguard Worker evbuffer_unfreeze(bufev->input, 0);
630*663afb9bSAndroid Build Coastguard Worker evbuffer_unfreeze(bufev->output, 1);
631*663afb9bSAndroid Build Coastguard Worker
632*663afb9bSAndroid Build Coastguard Worker event_assign(&bufev->ev_read, bufev->ev_base, fd,
633*663afb9bSAndroid Build Coastguard Worker EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
634*663afb9bSAndroid Build Coastguard Worker event_assign(&bufev->ev_write, bufev->ev_base, fd,
635*663afb9bSAndroid Build Coastguard Worker EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
636*663afb9bSAndroid Build Coastguard Worker
637*663afb9bSAndroid Build Coastguard Worker if (fd >= 0)
638*663afb9bSAndroid Build Coastguard Worker bufferevent_enable(bufev, bufev->enabled);
639*663afb9bSAndroid Build Coastguard Worker
640*663afb9bSAndroid Build Coastguard Worker evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
641*663afb9bSAndroid Build Coastguard Worker
642*663afb9bSAndroid Build Coastguard Worker BEV_UNLOCK(bufev);
643*663afb9bSAndroid Build Coastguard Worker }
644*663afb9bSAndroid Build Coastguard Worker
645*663afb9bSAndroid Build Coastguard Worker /* XXXX Should non-socket bufferevents support this? */
646*663afb9bSAndroid Build Coastguard Worker int
bufferevent_priority_set(struct bufferevent * bufev,int priority)647*663afb9bSAndroid Build Coastguard Worker bufferevent_priority_set(struct bufferevent *bufev, int priority)
648*663afb9bSAndroid Build Coastguard Worker {
649*663afb9bSAndroid Build Coastguard Worker int r = -1;
650*663afb9bSAndroid Build Coastguard Worker struct bufferevent_private *bufev_p = BEV_UPCAST(bufev);
651*663afb9bSAndroid Build Coastguard Worker
652*663afb9bSAndroid Build Coastguard Worker BEV_LOCK(bufev);
653*663afb9bSAndroid Build Coastguard Worker if (BEV_IS_ASYNC(bufev) || BEV_IS_FILTER(bufev) || BEV_IS_PAIR(bufev))
654*663afb9bSAndroid Build Coastguard Worker goto done;
655*663afb9bSAndroid Build Coastguard Worker
656*663afb9bSAndroid Build Coastguard Worker if (event_priority_set(&bufev->ev_read, priority) == -1)
657*663afb9bSAndroid Build Coastguard Worker goto done;
658*663afb9bSAndroid Build Coastguard Worker if (event_priority_set(&bufev->ev_write, priority) == -1)
659*663afb9bSAndroid Build Coastguard Worker goto done;
660*663afb9bSAndroid Build Coastguard Worker
661*663afb9bSAndroid Build Coastguard Worker event_deferred_cb_set_priority_(&bufev_p->deferred, priority);
662*663afb9bSAndroid Build Coastguard Worker
663*663afb9bSAndroid Build Coastguard Worker r = 0;
664*663afb9bSAndroid Build Coastguard Worker done:
665*663afb9bSAndroid Build Coastguard Worker BEV_UNLOCK(bufev);
666*663afb9bSAndroid Build Coastguard Worker return r;
667*663afb9bSAndroid Build Coastguard Worker }
668*663afb9bSAndroid Build Coastguard Worker
669*663afb9bSAndroid Build Coastguard Worker /* XXXX Should non-socket bufferevents support this? */
670*663afb9bSAndroid Build Coastguard Worker int
bufferevent_base_set(struct event_base * base,struct bufferevent * bufev)671*663afb9bSAndroid Build Coastguard Worker bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
672*663afb9bSAndroid Build Coastguard Worker {
673*663afb9bSAndroid Build Coastguard Worker int res = -1;
674*663afb9bSAndroid Build Coastguard Worker
675*663afb9bSAndroid Build Coastguard Worker BEV_LOCK(bufev);
676*663afb9bSAndroid Build Coastguard Worker if (!BEV_IS_SOCKET(bufev))
677*663afb9bSAndroid Build Coastguard Worker goto done;
678*663afb9bSAndroid Build Coastguard Worker
679*663afb9bSAndroid Build Coastguard Worker bufev->ev_base = base;
680*663afb9bSAndroid Build Coastguard Worker
681*663afb9bSAndroid Build Coastguard Worker res = event_base_set(base, &bufev->ev_read);
682*663afb9bSAndroid Build Coastguard Worker if (res == -1)
683*663afb9bSAndroid Build Coastguard Worker goto done;
684*663afb9bSAndroid Build Coastguard Worker
685*663afb9bSAndroid Build Coastguard Worker res = event_base_set(base, &bufev->ev_write);
686*663afb9bSAndroid Build Coastguard Worker done:
687*663afb9bSAndroid Build Coastguard Worker BEV_UNLOCK(bufev);
688*663afb9bSAndroid Build Coastguard Worker return res;
689*663afb9bSAndroid Build Coastguard Worker }
690*663afb9bSAndroid Build Coastguard Worker
691*663afb9bSAndroid Build Coastguard Worker static int
be_socket_ctrl(struct bufferevent * bev,enum bufferevent_ctrl_op op,union bufferevent_ctrl_data * data)692*663afb9bSAndroid Build Coastguard Worker be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
693*663afb9bSAndroid Build Coastguard Worker union bufferevent_ctrl_data *data)
694*663afb9bSAndroid Build Coastguard Worker {
695*663afb9bSAndroid Build Coastguard Worker switch (op) {
696*663afb9bSAndroid Build Coastguard Worker case BEV_CTRL_SET_FD:
697*663afb9bSAndroid Build Coastguard Worker be_socket_setfd(bev, data->fd);
698*663afb9bSAndroid Build Coastguard Worker return 0;
699*663afb9bSAndroid Build Coastguard Worker case BEV_CTRL_GET_FD:
700*663afb9bSAndroid Build Coastguard Worker data->fd = event_get_fd(&bev->ev_read);
701*663afb9bSAndroid Build Coastguard Worker return 0;
702*663afb9bSAndroid Build Coastguard Worker case BEV_CTRL_GET_UNDERLYING:
703*663afb9bSAndroid Build Coastguard Worker case BEV_CTRL_CANCEL_ALL:
704*663afb9bSAndroid Build Coastguard Worker default:
705*663afb9bSAndroid Build Coastguard Worker return -1;
706*663afb9bSAndroid Build Coastguard Worker }
707*663afb9bSAndroid Build Coastguard Worker }
708