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