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