Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
CuriousGeorgiy opened this issue Oct 11, 2023 · 0 comments
Labels
bug Something isn't working refactoring Code refactoring

Comments

@CuriousGeorgiy
Copy link
Member

CuriousGeorgiy commented Oct 11, 2023

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);
}
@CuriousGeorgiy CuriousGeorgiy added bug Something isn't working refactoring Code refactoring labels Oct 11, 2023
@CuriousGeorgiy CuriousGeorgiy changed the title Connector::WaitAny cannot handle scenario when all connections are dead Connector::waitAny cannot handle scenario when all connections are dead Oct 11, 2023
CuriousGeorgiy added a commit to CuriousGeorgiy/tntcxx that referenced this issue Oct 11, 2023
Currently, the `Connector::wait*` methods do not check the connection's
state, so if the connection has an error, they will either create a busy
loop for the duration of the timeout or simply hang if the timeout was not
set. In order to fix this, add a check for the connection state to all the
methods.

One problematic method is `Connection::waitAny`, which is not fixed in
scope of this patch (see tarantool#51 for details).

Closes tarantool#50
alyapunov pushed a commit that referenced this issue Oct 13, 2023
Currently, the `Connector::wait*` methods do not check the connection's
state, so if the connection has an error, they will either create a busy
loop for the duration of the timeout or simply hang if the timeout was not
set. In order to fix this, add a check for the connection state to all the
methods.

One problematic method is `Connection::waitAny`, which is not fixed in
scope of this patch (see #51 for details).

Closes #50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working refactoring Code refactoring
Projects
None yet
Development

No branches or pull requests

1 participant