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; } }
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; }
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); } }
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); } }
/* 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; }
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; }
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); } }