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

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions