Skip to content

CDRIVER-4207 handshake on new stream in scanner #915

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

Merged
merged 5 commits into from
Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/libmongoc/src/mongoc/mongoc-topology-scanner-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ typedef struct mongoc_topology_scanner_node {
mongoc_stream_t *stream;

int64_t last_used;
/* last_failed is set upon a network error trying to check a server.
* last_failed is used to enforce cooldownMS.
* last_failed is not set upon a network error during an application operation on @stream. */
int64_t last_failed;
bool has_auth;
bool hello_ok;
Expand Down
36 changes: 29 additions & 7 deletions src/libmongoc/src/mongoc/mongoc-topology-scanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,12 +374,13 @@ _begin_hello_cmd (mongoc_topology_scanner_node_t *node,
mongoc_stream_t *stream,
bool is_setup_done,
struct addrinfo *dns_result,
int64_t initiate_delay_ms)
int64_t initiate_delay_ms,
bool use_handshake)
{
mongoc_topology_scanner_t *ts = node->ts;
bson_t cmd;

if (node->last_used != -1 && node->last_failed == -1) {
if (node->last_used != -1 && node->last_failed == -1 && !use_handshake) {
/* The node's been used before and not failed recently */
bson_copy_to (
_mongoc_topology_scanner_get_monitoring_cmd (ts, node->hello_ok),
Expand Down Expand Up @@ -946,11 +947,21 @@ mongoc_topology_scanner_node_setup_tcp (mongoc_topology_scanner_node_t *node,
}

if (node->successful_dns_result) {
_begin_hello_cmd (node, NULL, false, node->successful_dns_result, 0);
_begin_hello_cmd (node,
NULL /* stream */,
false /* is_setup_done */,
node->successful_dns_result,
0 /* initiate_delay_ms */,
true /* use_handshake */);
} else {
LL_FOREACH2 (node->dns_results, iter, ai_next)
{
_begin_hello_cmd (node, NULL, false, iter, delay);
_begin_hello_cmd (node,
NULL /* stream */,
false /* is_setup_done */,
iter,
delay,
true /* use_handshake */);
/* each subsequent DNS result will have an additional 250ms delay. */
delay += HAPPY_EYEBALLS_DELAY_MS;
}
Expand Down Expand Up @@ -1017,7 +1028,8 @@ mongoc_topology_scanner_node_connect_unix (mongoc_topology_scanner_node_t *node,
stream,
false /* is_setup_done */,
NULL /* dns result */,
0 /* delay */);
0 /* delay */,
true /* use_handshake */);
RETURN (true);
}
bson_set_error (error,
Expand Down Expand Up @@ -1055,7 +1067,12 @@ mongoc_topology_scanner_node_setup (mongoc_topology_scanner_node_t *node,

/* if there is already a working stream, push it back to be re-scanned. */
if (node->stream) {
_begin_hello_cmd (node, node->stream, true /* is_setup_done */, NULL, 0);
_begin_hello_cmd (node,
node->stream,
true /* is_setup_done */,
NULL /* dns_result */,
0 /* initiate_delay_ms */,
false /* use_handshake */);
node->stream = NULL;
return;
}
Expand All @@ -1067,7 +1084,12 @@ mongoc_topology_scanner_node_setup (mongoc_topology_scanner_node_t *node,
node->ts->uri, &node->host, node->ts->initiator_context, error);
if (stream) {
success = true;
_begin_hello_cmd (node, stream, false, NULL, 0);
_begin_hello_cmd (node,
stream,
false /* is_setup_done */,
NULL /* dns_result */,
0 /* initiate_delay_ms */,
true /* use_handshake */);
}
} else {
if (node->host.family == AF_UNIX) {
Expand Down
63 changes: 63 additions & 0 deletions src/libmongoc/tests/test-mongoc-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -4145,6 +4145,65 @@ test_mongoc_client_get_handshake_establishes_connection_pooled (void)
mongoc_client_pool_destroy (pool);
}

/* Regression test for CDRIVER-4207. */
void
test_mongoc_client_resends_handshake_on_network_error (void)
{
mongoc_client_t *client;
mock_server_t *server;
future_t *future;
request_t *request;
bson_error_t error;
bson_t *ping = tmp_bson ("{'ping': 1}");

server = mock_server_new ();
mock_server_run (server);
client = mongoc_client_new_from_uri (mock_server_get_uri (server));
mongoc_client_set_appname (client, "foo");

/* Send a "ping" command. */
future = future_client_command_simple (
client, "db", ping, NULL /* read_prefs */, NULL /* reply */, &error);
/* The first command on the new connection is handshake. It uses the legacy
* hello and includes the client.application.name. */
request = mock_server_receives_legacy_hello (
server,
"{'" HANDSHAKE_CMD_LEGACY_HELLO
"': 1, 'client': {'application': {'name': 'foo'}}}");
mock_server_replies_simple (request, "{'ok': 1, 'maxWireVersion': 14 }");
request_destroy (request);
request = mock_server_receives_msg (
server, MONGOC_QUERY_NONE, tmp_bson ("{'ping': 1}"));
mock_server_hangs_up (request);
future_wait (future);
future_destroy (future);
ASSERT_ERROR_CONTAINS (error,
MONGOC_ERROR_STREAM,
MONGOC_ERROR_STREAM_SOCKET,
"socket error or timeout");
request_destroy (request);

/* Send another "ping" command. */
future = future_client_command_simple (
client, "db", ping, NULL /* read_prefs */, NULL /* reply */, &error);
/* Expect the new connection to send the full handshake. */
request = mock_server_receives_legacy_hello (
server,
"{'" HANDSHAKE_CMD_LEGACY_HELLO
"': 1, 'client': {'application': {'name': 'foo'}}}");
mock_server_replies_simple (request, "{'ok': 1, 'maxWireVersion': 14 }");
request_destroy (request);

request = mock_server_receives_msg (
server, MONGOC_QUERY_NONE, tmp_bson ("{'ping': 1}"));
mock_server_replies_ok_and_destroys (request);
ASSERT (future_get_bool (future));
future_destroy (future);

mongoc_client_destroy (client);
mock_server_destroy (server);
}

void
test_client_install (TestSuite *suite)
{
Expand Down Expand Up @@ -4452,4 +4511,8 @@ test_client_install (TestSuite *suite)
suite,
"/Client/get_handshake_establishes_connection/pooled",
test_mongoc_client_get_handshake_establishes_connection_pooled);
TestSuite_AddMockServerTest (
suite,
"/Client/resends_handshake_on_network_error",
test_mongoc_client_resends_handshake_on_network_error);
}