Skip to content

Connector allows double connects leading to socket leak #148

@CuriousGeorgiy

Description

@CuriousGeorgiy

Consider this trivial snippet with a Tarantool instance listening on port 3301:

#include "../src/Client/Connector.hpp"

using Buf_t = tnt::Buffer<16 * 1024>;
using Net_t = LibevNetProvider<Buf_t, DefaultStream>;

int
main()
{
	Connector<Buf_t, Net_t> client;
	Connection<Buf_t, Net_t> conn(client);
	struct ConnectOptions conn_opts{
		.address = "127.0.0.1",
		.service = "3301",		
	};
	printf("%d", client.connect(conn, conn_opts));
	conn.ping(); /* Tarantool server dies causing the connection to be set to dead state. */
	printf("%d", client.connect(conn, conn_opts);
}

Both connects succeed, because the Connector and NetProviders relies only on the stream status to determine whether a connection is established:

int
Connector<BUFFER, NetProvider>::connect(Connection<BUFFER, NetProvider> &conn,
const ConnectOptions &opts)
{
//Make sure that connection is not yet established.
assert(conn.get_strm().has_status(SS_DEAD));

inline int
UnixStream::connect(const ConnectOptions &opts_arg)
{
if (!has_status(SS_DEAD))
return US_DIE("Double connect");

This leads to leak of the previous socket, since it does not get closed by the connect code:

inline int
UnixStream::connect(const ConnectOptions &opts_arg)
{
if (!has_status(SS_DEAD))
return US_DIE("Double connect");
opts = opts_arg;
AddrInfo addr_info(opts.address, opts.service);
if (addr_info.last_rc() != 0)
return US_DIE("Network address resolve failed",
addr_info.last_error());
int socket_errno = 0, connect_errno = 0;
for (auto &inf: addr_info) {
fd = ::socket(inf.ai_family, inf.ai_socktype, inf.ai_protocol);

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions