Skip to content

Connector::waitAny cannot handle scenario when all connections are dead #51

@CuriousGeorgiy

Description

@CuriousGeorgiy

The Connector does not have access to the connections it is associated with, so it is impossible to detect a scenario when all connections are dead and a timeout is not specified, hence the Connector will simply hang in this loop:

while (m_ReadyToDecode.empty() && !timer.isExpired())
m_NetProvider.wait(timeout - timer.elapsed());

Simple reproducer:

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

const char *inet_address = "127.0.0.1";
int port = 3301;

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

int
main()
{
	pid_t pid = fork();
	if (pid < 0) {
		perror("fork failed");
		return EXIT_FAILURE;
	} else if (pid == 0) {
		int sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (sock < 0) {
			perror("socket failed");
			return EXIT_FAILURE;
		}

		struct sockaddr_in sock_address = {
			.sin_family = AF_INET,
			.sin_port = htons(port),
		};
		if (::inet_aton(inet_address, &sock_address.sin_addr) != 1) {
			perror("inet_aton failed");
			return EXIT_FAILURE;
		}

		if (::bind(sock, reinterpret_cast<const struct sockaddr *>(&sock_address),
			sizeof(sockaddr)) != 0) {
			perror("bind failed");
			return EXIT_FAILURE;
		}

		if (::listen(sock, 1) != 0) {
			perror("listen failed");
			return EXIT_FAILURE;
		}

		int accepted_sock = ::accept(sock, nullptr, nullptr);
		if (accepted_sock < 0) {
			perror("accept failed");
			return EXIT_FAILURE;
		}

		char buf[1];
		if (::read(accepted_sock, buf, sizeof(buf)) < 0) {
			perror("read failed");
			return EXIT_FAILURE;
		}

		close(accepted_sock);
		return EXIT_SUCCESS;
	}

	Connector<Buf_t, Net_t> client;
	Connection<Buf_t, Net_t> conn(client);

	int rc = client.connect(conn, {
		.address = inet_address,
		.service = std::to_string(port),
	});
	if (rc != 0) {
		std::cerr << conn.getError().msg << std::endl;
		return EXIT_FAILURE;
	}

	rid_t ping = conn.ping();
	assert(client.waitAny() == std::nullopt);
	assert(!conn.futureIsReady(ping));

	client.close(conn);
}

Metadata

Metadata

Labels

bugSomething isn't workingrefactoringCode refactoring

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions