xref: /aosp_15_r20/external/libevent/bufferevent_sock.c (revision 663afb9b963571284e0f0a60f257164ab54f64bf)
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