Skip to content

Commit 06b4fa6

Browse files
committed
CDRIVER-3929 Include apiVersion in handshake commands
1 parent c69a70a commit 06b4fa6

File tree

7 files changed

+185
-26
lines changed

7 files changed

+185
-26
lines changed

src/libmongoc/src/mongoc/mongoc-client-pool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,5 +529,6 @@ mongoc_client_pool_set_server_api (mongoc_client_pool_t *pool,
529529
}
530530

531531
pool->api = mongoc_server_api_copy (api);
532+
_mongoc_topology_scanner_set_server_api (pool->topology->scanner, api);
532533
return true;
533534
}

src/libmongoc/src/mongoc/mongoc-client.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3114,5 +3114,6 @@ mongoc_client_set_server_api (mongoc_client_t *client,
31143114
}
31153115

31163116
client->api = mongoc_server_api_copy (api);
3117+
_mongoc_topology_scanner_set_server_api (client->topology->scanner, api);
31173118
return true;
31183119
}

src/libmongoc/src/mongoc/mongoc-cmd-private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ _is_retryable_read (const mongoc_cmd_parts_t *parts,
146146
void
147147
_mongoc_cmd_append_payload_as_array (const mongoc_cmd_t *cmd, bson_t *out);
148148

149+
void
150+
_mongoc_cmd_append_server_api (bson_t *command_body,
151+
const mongoc_server_api_t *api);
152+
149153
BSON_END_DECLS
150154

151155

src/libmongoc/src/mongoc/mongoc-cmd.c

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -827,14 +827,12 @@ mongoc_cmd_parts_assemble (mongoc_cmd_parts_t *parts,
827827
bson_error_t *error)
828828
{
829829
mongoc_server_description_type_t server_type;
830-
mongoc_server_api_t *api;
831830
mongoc_client_session_t *cs;
832831
const bson_t *cluster_time = NULL;
833832
mongoc_read_prefs_t *prefs = NULL;
834833
const char *cmd_name;
835834
bool is_get_more;
836835
const mongoc_read_prefs_t *prefs_ptr;
837-
const char *string_version;
838836
bool ret = false;
839837

840838
ENTRY;
@@ -994,23 +992,8 @@ mongoc_cmd_parts_assemble (mongoc_cmd_parts_t *parts,
994992
sending a getmore, or if we are in a transaction. */
995993
if (parts->client->api) {
996994
if (!is_get_more && !_txn_in_progress (parts)) {
997-
api = parts->client->api;
998-
string_version = mongoc_server_api_version_to_string (api->version);
999-
1000-
bson_append_utf8 (
1001-
&parts->assembled_body, "apiVersion", -1, string_version, -1);
1002-
1003-
if (api->strict_set) {
1004-
bson_append_bool (
1005-
&parts->assembled_body, "apiStrict", -1, api->strict);
1006-
}
1007-
1008-
if (api->deprecation_errors_set) {
1009-
bson_append_bool (&parts->assembled_body,
1010-
"apiDeprecationErrors",
1011-
-1,
1012-
api->deprecation_errors);
1013-
}
995+
_mongoc_cmd_append_server_api (&parts->assembled_body,
996+
parts->client->api);
1014997
}
1015998
}
1016999

@@ -1155,3 +1138,39 @@ _mongoc_cmd_append_payload_as_array (const mongoc_cmd_t *cmd, bson_t *out)
11551138

11561139
bson_append_array_end (out, &bson);
11571140
}
1141+
1142+
/*--------------------------------------------------------------------------
1143+
*
1144+
* _mongoc_cmd_append_server_api --
1145+
* Append versioned API fields to a mongoc_cmd_t
1146+
*
1147+
* Arguments:
1148+
* cmd The mongoc_cmd_t, which will have versioned API fields added
1149+
* api A mongoc_server_api_t holding server API information
1150+
*
1151+
* Pre-conditions:
1152+
* - @api is initialized.
1153+
*
1154+
*--------------------------------------------------------------------------
1155+
*/
1156+
void
1157+
_mongoc_cmd_append_server_api (bson_t *command_body,
1158+
const mongoc_server_api_t *api)
1159+
{
1160+
const char *string_version;
1161+
1162+
BSON_ASSERT (api);
1163+
1164+
string_version = mongoc_server_api_version_to_string (api->version);
1165+
1166+
bson_append_utf8 (command_body, "apiVersion", -1, string_version, -1);
1167+
1168+
if (api->strict_set) {
1169+
bson_append_bool (command_body, "apiStrict", -1, api->strict);
1170+
}
1171+
1172+
if (api->deprecation_errors_set) {
1173+
bson_append_bool (
1174+
command_body, "apiDeprecationErrors", -1, api->deprecation_errors);
1175+
}
1176+
}

src/libmongoc/src/mongoc/mongoc-topology-scanner-private.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ typedef struct mongoc_topology_scanner {
109109
bool negotiate_sasl_supported_mechs;
110110
bool bypass_cooldown;
111111
bool speculative_authentication;
112+
113+
mongoc_server_api_t *api;
112114
} mongoc_topology_scanner_t;
113115

114116
mongoc_topology_scanner_t *
@@ -223,6 +225,10 @@ bool
223225
mongoc_topology_scanner_node_in_cooldown (mongoc_topology_scanner_node_t *node,
224226
int64_t when);
225227

228+
void
229+
_mongoc_topology_scanner_set_server_api (mongoc_topology_scanner_t *ts,
230+
const mongoc_server_api_t *api);
231+
226232
/* for testing. */
227233
mongoc_stream_t *
228234
_mongoc_topology_scanner_tcp_initiate (mongoc_async_cmd_t *acmd);

src/libmongoc/src/mongoc/mongoc-topology-scanner.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,22 @@ _jumpstart_other_acmds (mongoc_topology_scanner_node_t *node,
104104
mongoc_async_cmd_t *acmd);
105105

106106
static void
107-
_add_ismaster (bson_t *cmd)
107+
_add_ismaster (bson_t *cmd, const mongoc_server_api_t *api)
108108
{
109109
BSON_APPEND_INT32 (cmd, "isMaster", 1);
110+
111+
if (api) {
112+
_mongoc_cmd_append_server_api (cmd, api);
113+
}
114+
}
115+
116+
static void
117+
_reset_ismaster (mongoc_topology_scanner_t *ts)
118+
{
119+
bson_init (&ts->ismaster_cmd);
120+
_add_ismaster (&ts->ismaster_cmd, ts->api);
121+
bson_init (&ts->ismaster_cmd_with_handshake);
122+
bson_init (&ts->cluster_time);
110123
}
111124

112125
const char *
@@ -226,7 +239,7 @@ _build_ismaster_with_handshake (mongoc_topology_scanner_t *ts)
226239
int count = 0;
227240
char buf[16];
228241

229-
_add_ismaster (doc);
242+
_add_ismaster (doc, ts->api);
230243

231244
BSON_APPEND_DOCUMENT_BEGIN (doc, HANDSHAKE_FIELD, &subdoc);
232245
res = _mongoc_handshake_build_doc_with_application (&subdoc, ts->appname);
@@ -346,21 +359,19 @@ mongoc_topology_scanner_new (
346359

347360
ts->async = mongoc_async_new ();
348361

349-
bson_init (&ts->ismaster_cmd);
350-
_add_ismaster (&ts->ismaster_cmd);
351-
bson_init (&ts->ismaster_cmd_with_handshake);
352-
bson_init (&ts->cluster_time);
353-
354362
ts->setup_err_cb = setup_err_cb;
355363
ts->cb = cb;
356364
ts->cb_data = data;
357365
ts->uri = uri;
358366
ts->appname = NULL;
367+
ts->api = NULL;
359368
ts->handshake_ok_to_send = false;
360369
ts->connect_timeout_msec = connect_timeout_msec;
361370
/* may be overridden for testing. */
362371
ts->dns_cache_timeout_ms = DNS_CACHE_TIMEOUT_MS;
363372

373+
_reset_ismaster (ts);
374+
364375
return ts;
365376
}
366377

@@ -399,6 +410,10 @@ mongoc_topology_scanner_destroy (mongoc_topology_scanner_t *ts)
399410
bson_destroy (&ts->ismaster_cmd_with_handshake);
400411
bson_destroy (&ts->cluster_time);
401412

413+
if (ts->api) {
414+
mongoc_server_api_destroy (ts->api);
415+
}
416+
402417
/* This field can be set by a mongoc_client */
403418
bson_free ((char *) ts->appname);
404419

@@ -1324,3 +1339,20 @@ _jumpstart_other_acmds (mongoc_topology_scanner_node_t *node,
13241339
}
13251340
}
13261341
}
1342+
1343+
void
1344+
_mongoc_topology_scanner_set_server_api (mongoc_topology_scanner_t *ts,
1345+
const mongoc_server_api_t *api)
1346+
{
1347+
mongoc_server_api_t *prev_api;
1348+
1349+
BSON_ASSERT (api);
1350+
1351+
prev_api = ts->api;
1352+
ts->api = mongoc_server_api_copy (api);
1353+
_reset_ismaster (ts);
1354+
1355+
if (prev_api) {
1356+
mongoc_server_api_destroy (prev_api);
1357+
}
1358+
}

src/libmongoc/tests/test-mongoc-topology.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <mongoc/mongoc-client-pool-private.h>
44

55
#include "mongoc/mongoc-client-private.h"
6+
#include "mongoc/mongoc-server-api-private.h"
67
#include "mongoc/mongoc-util-private.h"
78
#include "mongoc/mongoc-topology-background-monitoring-private.h"
89
#include "TestSuite.h"
@@ -2202,6 +2203,94 @@ test_slow_server_pooled (void)
22022203
mock_server_destroy (primary);
22032204
checks_cleanup (&checks);
22042205
}
2206+
2207+
static void
2208+
_test_ismaster_versioned_api (bool pooled)
2209+
{
2210+
mock_server_t *server;
2211+
mongoc_uri_t *uri;
2212+
mongoc_client_pool_t *pool;
2213+
mongoc_client_t *client;
2214+
char *ismaster;
2215+
future_t *future;
2216+
request_t *request;
2217+
bson_error_t error;
2218+
mongoc_server_api_version_t version;
2219+
mongoc_server_api_t *api;
2220+
2221+
server = mock_server_new ();
2222+
mock_server_run (server);
2223+
uri = mongoc_uri_copy (mock_server_get_uri (server));
2224+
2225+
mongoc_server_api_version_from_string ("1", &version);
2226+
api = mongoc_server_api_new (version);
2227+
2228+
if (pooled) {
2229+
pool = mongoc_client_pool_new (uri);
2230+
ASSERT_OR_PRINT (mongoc_client_pool_set_server_api (pool, api, &error),
2231+
error);
2232+
2233+
client = mongoc_client_pool_pop (pool);
2234+
} else {
2235+
client = mongoc_client_new_from_uri (uri);
2236+
ASSERT_OR_PRINT (mongoc_client_set_server_api (client, api, &error),
2237+
error);
2238+
}
2239+
2240+
ismaster = bson_strdup_printf ("{'ok': 1,"
2241+
" 'ismaster': true,"
2242+
" 'setName': 'rs',"
2243+
" 'minWireVersion': 2,"
2244+
" 'maxWireVersion': 5,"
2245+
" 'hosts': ['%s']}",
2246+
mock_server_get_host_and_port (server));
2247+
2248+
/* For client pools, the first handshake happens when the client is popped.
2249+
* For non-pooled clients, send a ping command to trigger a handshake. */
2250+
if (!pooled) {
2251+
future = future_client_command_simple (
2252+
client, "admin", tmp_bson ("{'ping': 1}"), NULL, NULL, &error);
2253+
}
2254+
2255+
request = mock_server_receives_ismaster (server);
2256+
BSON_ASSERT (request);
2257+
BSON_ASSERT (bson_has_field (request_get_doc (request, 0), "apiVersion"));
2258+
mock_server_replies_simple (request, ismaster);
2259+
request_destroy (request);
2260+
2261+
if (!pooled) {
2262+
request = mock_server_receives_command (
2263+
server, "admin", MONGOC_QUERY_SLAVE_OK, "{'ping': 1}");
2264+
mock_server_replies_ok_and_destroys (request);
2265+
BSON_ASSERT (future_get_bool (future));
2266+
future_destroy (future);
2267+
}
2268+
2269+
if (pooled) {
2270+
mongoc_client_pool_push (pool, client);
2271+
mongoc_client_pool_destroy (pool);
2272+
} else {
2273+
mongoc_client_destroy (client);
2274+
}
2275+
2276+
mongoc_server_api_destroy (api);
2277+
mongoc_uri_destroy (uri);
2278+
mock_server_destroy (server);
2279+
bson_free (ismaster);
2280+
}
2281+
2282+
static void
2283+
test_ismaster_versioned_api_single ()
2284+
{
2285+
_test_ismaster_versioned_api (false);
2286+
}
2287+
2288+
static void
2289+
test_ismaster_versioned_api_pooled ()
2290+
{
2291+
_test_ismaster_versioned_api (true);
2292+
}
2293+
22052294
void
22062295
test_topology_install (TestSuite *suite)
22072296
{
@@ -2356,4 +2445,11 @@ test_topology_install (TestSuite *suite)
23562445
test_last_server_removed_warning);
23572446
TestSuite_AddMockServerTest (
23582447
suite, "/Topology/slow_server/pooled", test_slow_server_pooled);
2448+
2449+
TestSuite_AddMockServerTest (suite,
2450+
"/Topology/ismaster/versioned_api/single",
2451+
test_ismaster_versioned_api_single);
2452+
TestSuite_AddMockServerTest (suite,
2453+
"/Topology/ismaster/versioned_api/pooled",
2454+
test_ismaster_versioned_api_pooled);
23592455
}

0 commit comments

Comments
 (0)