Ejemplo n.º 1
0
int
bufferevent_socket_connect_hostname(struct bufferevent *bev,
    struct evdns_base *evdns_base, int family, const char *hostname, int port)
{
	char portbuf[10];
	struct evutil_addrinfo hint;
	int err;

	if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
		return -1;
	if (port < 1 || port > 65535)
		return -1;

	evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);

	memset(&hint, 0, sizeof(hint));
	hint.ai_family = family;
	hint.ai_protocol = IPPROTO_TCP;
	hint.ai_socktype = SOCK_STREAM;

	bufferevent_suspend_write(bev, BEV_SUSPEND_LOOKUP);
	bufferevent_suspend_read(bev, BEV_SUSPEND_LOOKUP);

	bufferevent_incref(bev);
	err = evutil_getaddrinfo_async(evdns_base, hostname, portbuf,
	    &hint, bufferevent_connect_getaddrinfo_cb, bev);

	if (err == 0) {
		return 0;
	} else {
		bufferevent_unsuspend_write(bev, BEV_SUSPEND_LOOKUP);
		bufferevent_unsuspend_read(bev, BEV_SUSPEND_LOOKUP);
		return -1;
	}
}
Ejemplo n.º 2
0
static void
bev_async_consider_reading(struct bufferevent_async *beva)
{
	size_t cur_size;
	size_t read_high;
	size_t at_most;
	int limit;
	struct bufferevent *bev = &beva->bev.bev;

	/* Don't read if there is a read in progress, or we do not
	 * want to read. */
	if (beva->read_in_progress || beva->bev.connecting)
		return;
	if (!beva->ok || !(bev->enabled&EV_READ)) {
		bev_async_del_read(beva);
		return;
	}

	/* Don't read if we're full */
	cur_size = evbuffer_get_length(bev->input);
	read_high = bev->wm_read.high;
	if (read_high) {
		if (cur_size >= read_high) {
			bev_async_del_read(beva);
			return;
		}
		at_most = read_high - cur_size;
	} else {
		at_most = 16384; /* FIXME totally magic. */
	}

	/* XXXX This over-commits. */
	/* XXXX see also not above on cast on _bufferevent_get_write_max() */
	limit = (int)_bufferevent_get_read_max(&beva->bev);
	if (at_most >= (size_t)limit && limit >= 0)
		at_most = limit;

	if (beva->bev.read_suspended) {
		bev_async_del_read(beva);
		return;
	}

	bufferevent_incref(bev);
	if (evbuffer_launch_read(bev->input, at_most, &beva->read_overlapped)) {
		beva->ok = 0;
		_bufferevent_run_eventcb(bev, BEV_EVENT_ERROR);
		bufferevent_decref(bev);
	} else {
		beva->read_in_progress = at_most;
		_bufferevent_decrement_read_buckets(&beva->bev, at_most);
		bev_async_add_read(beva);
	}

	return;
}
Ejemplo n.º 3
0
void
_bufferevent_run_writecb(struct bufferevent *bufev)
{
	/* Requires that we hold the lock and a reference */
	struct bufferevent_private *p =
	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
	if (p->options & BEV_OPT_DEFER_CALLBACKS) {
		p->writecb_pending = 1;
		if (!p->deferred.queued) {
			bufferevent_incref(bufev);
			SCHEDULE_DEFERRED(p);
		}
	} else {
		bufev->writecb(bufev, bufev->cbarg);
	}
}
Ejemplo n.º 4
0
void
_bufferevent_run_eventcb(struct bufferevent *bufev, short what)
{
	/* Requires that we hold the lock and a reference */
	struct bufferevent_private *p =
	    EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
	if (p->options & BEV_OPT_DEFER_CALLBACKS) {
		p->eventcb_pending |= what;
		p->errno_pending = EVUTIL_SOCKET_ERROR();
		if (!p->deferred.queued) {
			bufferevent_incref(bufev);
			SCHEDULE_DEFERRED(p);
		}
	} else {
		bufev->errorcb(bufev, what, bufev->cbarg);
	}
}
Ejemplo n.º 5
0
/* Implements the asynchronous-resolve side of
 * bufferevent_socket_connect_hostname(). */
int
_bufferevent_socket_connect_hostname_evdns(
    struct bufferevent *bufev,
    struct evdns_base *evdns_base,
    int family,
    const char *hostname,
    int port)
{
    struct evdns_request *r;
    struct resolveinfo *resolveinfo;

    if (family == AF_UNSPEC)
        family = AF_INET; /* XXXX handle "unspec" correctly */
    if (family != AF_INET && family != AF_INET6)
        return -1;
    if (!bufev || !evdns_base || !hostname)
        return -1;
    if (port < 1 || port > 65535)
        return -1;

    resolveinfo = mm_calloc(1, sizeof(resolveinfo));
    if (!resolveinfo)
        return -1;
    resolveinfo->family = family;
    resolveinfo->port = htons(port);
    resolveinfo->bev = bufev;

    if (family == AF_INET) {
        r = evdns_base_resolve_ipv4(evdns_base, hostname, 0,
                                    dns_reply_callback, resolveinfo);
    } else {
        r = evdns_base_resolve_ipv6(evdns_base, hostname, 0,
                                    dns_reply_callback, resolveinfo);
    }

    if (!r) {
        mm_free(resolveinfo);
        return -1;
    }

    /* We either need to incref the bufferevent here, or have some code to
     * cancel the resolve if the bufferevent gets freed.  Let's take the
     * first approach. */
    bufferevent_incref(bufev);
    return 0;
}
Ejemplo n.º 6
0
int
bufferevent_async_connect(struct bufferevent *bev, evutil_socket_t fd,
	const struct sockaddr *sa, int socklen)
{
	BOOL rc;
	struct bufferevent_async *bev_async = upcast(bev);
	struct sockaddr_storage ss;
	const struct win32_extension_fns *ext =
	    event_get_win32_extension_fns();

	EVUTIL_ASSERT(ext && ext->ConnectEx && fd >= 0 && sa != NULL);

	/* ConnectEx() requires that the socket be bound to an address
	 * with bind() before using, otherwise it will fail. We attempt
	 * to issue a bind() here, taking into account that the error
	 * code is set to WSAEINVAL when the socket is already bound. */
	memset(&ss, 0, sizeof(ss));
	if (sa->sa_family == AF_INET) {
		struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
		sin->sin_family = AF_INET;
		sin->sin_addr.s_addr = INADDR_ANY;
	} else if (sa->sa_family == AF_INET6) {
		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
		sin6->sin6_family = AF_INET6;
		sin6->sin6_addr = in6addr_any;
	} else {
		/* Well, the user will have to bind() */
		return -1;
	}
	if (bind(fd, (struct sockaddr *)&ss, sizeof(ss)) < 0 &&
	    WSAGetLastError() != WSAEINVAL)
		return -1;

	event_base_add_virtual(bev->ev_base);
	bufferevent_incref(bev);
	rc = ext->ConnectEx(fd, sa, socklen, NULL, 0, NULL,
			    &bev_async->connect_overlapped.overlapped);
	if (rc || WSAGetLastError() == ERROR_IO_PENDING)
		return 0;

	event_base_del_virtual(bev->ev_base);
	bufferevent_decref(bev);

	return -1;
}
Ejemplo n.º 7
0
static void
bev_async_consider_writing(struct bufferevent_async *beva)
{
	size_t at_most;
	int limit;
	struct bufferevent *bev = &beva->bev.bev;

	/* Don't write if there's a write in progress, or we do not
	 * want to write, or when there's nothing left to write. */
	if (beva->write_in_progress || beva->bev.connecting)
		return;
	if (!beva->ok || !(bev->enabled&EV_WRITE) ||
	    !evbuffer_get_length(bev->output)) {
		bev_async_del_write(beva);
		return;
	}

	at_most = evbuffer_get_length(bev->output);

	/* This is safe so long as bufferevent_get_write_max never returns
	 * more than INT_MAX.  That's true for now. XXXX */
	limit = (int)_bufferevent_get_write_max(&beva->bev);
	if (at_most >= (size_t)limit && limit >= 0)
		at_most = limit;

	if (beva->bev.write_suspended) {
		bev_async_del_write(beva);
		return;
	}

	/*  XXXX doesn't respect low-water mark very well. */
	bufferevent_incref(bev);
	if (evbuffer_launch_write(bev->output, at_most,
	    &beva->write_overlapped)) {
		bufferevent_decref(bev);
		beva->ok = 0;
		_bufferevent_run_eventcb(bev, BEV_EVENT_ERROR);
	} else {
		beva->write_in_progress = at_most;
		_bufferevent_decrement_write_buckets(&beva->bev, at_most);
		bev_async_add_write(beva);
	}
}