client: avoid FD leak on failed connect()
Async connect() can fail immediately in some cases.
This commit is contained in:
+8
-6
@@ -62,17 +62,19 @@ void Connection::startConnecting()
|
||||
{
|
||||
assert(!this->bev);
|
||||
|
||||
auto bev(bufferevent_socket_new(context->tcp_loop.base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS));
|
||||
decltype(this->bev) bev(__FILE__, __LINE__,
|
||||
bufferevent_socket_new(context->tcp_loop.base, -1,
|
||||
BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS));
|
||||
|
||||
bufferevent_setcb(bev, &bevReadS, nullptr, &bevEventS, this);
|
||||
bufferevent_setcb(bev.get(), &bevReadS, nullptr, &bevEventS, this);
|
||||
|
||||
timeval tmo(totv(context->effective.tcpTimeout));
|
||||
bufferevent_set_timeouts(bev, &tmo, &tmo);
|
||||
bufferevent_set_timeouts(bev.get(), &tmo, &tmo);
|
||||
|
||||
if(bufferevent_socket_connect(bev, const_cast<sockaddr*>(&peerAddr->sa), peerAddr.size()))
|
||||
if(bufferevent_socket_connect(bev.get(), const_cast<sockaddr*>(&peerAddr->sa), peerAddr.size()))
|
||||
throw std::runtime_error("Unable to begin connecting");
|
||||
{
|
||||
auto fd(bufferevent_getfd(bev));
|
||||
auto fd(bufferevent_getfd(bev.get()));
|
||||
int opt = 1;
|
||||
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt))<0) {
|
||||
auto err(SOCKERRNO);
|
||||
@@ -80,7 +82,7 @@ void Connection::startConnecting()
|
||||
}
|
||||
}
|
||||
|
||||
connect(bev);
|
||||
connect(std::move(bev));
|
||||
|
||||
log_debug_printf(io, "Connecting to %s, RX readahead %zu\n", peerName.c_str(), readahead);
|
||||
}
|
||||
|
||||
+10
-8
@@ -39,8 +39,10 @@ ConnBase::ConnBase(bool isClient, bool sendBE, bufferevent* bev, const SockAddr&
|
||||
,txBody(__FILE__, __LINE__, evbuffer_new())
|
||||
,state(Holdoff)
|
||||
{
|
||||
if(bev) // true for server connection. client will call connect() shortly
|
||||
connect(bev);
|
||||
if(bev) { // true for server connection. client will call connect() shortly
|
||||
decltype(this->bev) temp(__FILE__, __LINE__, bev);
|
||||
connect(std::move(temp));
|
||||
}
|
||||
}
|
||||
|
||||
ConnBase::~ConnBase() {}
|
||||
@@ -50,30 +52,30 @@ const char* ConnBase::peerLabel() const
|
||||
return isClient ? "Server" : "Client";
|
||||
}
|
||||
|
||||
void ConnBase::connect(bufferevent* bev)
|
||||
void ConnBase::connect(ev_owned_ptr<bufferevent> &&bev)
|
||||
{
|
||||
if(!bev)
|
||||
throw BAD_ALLOC();
|
||||
assert(!this->bev && state==Holdoff);
|
||||
|
||||
this->bev.reset(bev);
|
||||
|
||||
readahead = evsocket::get_buffer_size(bufferevent_getfd(bev), false);
|
||||
readahead = evsocket::get_buffer_size(bufferevent_getfd(bev.get()), false);
|
||||
|
||||
#if LIBEVENT_VERSION_NUMBER >= 0x02010000
|
||||
// allow to drain OS socket buffer in a single read
|
||||
(void)bufferevent_set_max_single_read(bev, readahead);
|
||||
(void)bufferevent_set_max_single_read(bev.get(), readahead);
|
||||
#endif
|
||||
|
||||
readahead *= tcp_readahead_mult;
|
||||
|
||||
#if LIBEVENT_VERSION_NUMBER >= 0x02010000
|
||||
// allow attempt to write as much as is available
|
||||
(void)bufferevent_set_max_single_write(bev, EV_SSIZE_MAX);
|
||||
(void)bufferevent_set_max_single_write(bev.get(), EV_SSIZE_MAX);
|
||||
#endif
|
||||
|
||||
state = isClient ? Connecting : Connected;
|
||||
|
||||
this->bev = std::move(bev);
|
||||
|
||||
// initially wait for at least a header
|
||||
bufferevent_setwatermark(this->bev.get(), EV_READ, 8, readahead);
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public:
|
||||
|
||||
bufferevent* connection() { return bev.get(); }
|
||||
|
||||
void connect(bufferevent* bev);
|
||||
void connect(ev_owned_ptr<bufferevent>&& bev);
|
||||
void disconnect();
|
||||
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user