void mongo_servers_dtor(mongo_servers *servers) { int i; for (i = 0; i < servers->count; i++) { mongo_server_def_dtor(servers->server[i]); } if (servers->options.repl_set_name) { free(servers->options.repl_set_name); } if (servers->options.default_wstring) { free(servers->options.default_wstring); } for (i = 0; i < servers->read_pref.tagset_count; i++) { mongo_read_preference_tagset_dtor(servers->read_pref.tagsets[i]); } if (servers->read_pref.tagsets) { free(servers->read_pref.tagsets); } free(servers); }
/* Returns: * 1 on success * 0 on total failure (e.g. unsupported wire version) */ static int mongo_discover_topology(mongo_con_manager *manager, mongo_servers *servers) { int i, j; char *hash; mongo_connection *con; char *error_message; char *repl_set_name = servers->options.repl_set_name ? strdup(servers->options.repl_set_name) : NULL; int nr_hosts; char **found_hosts = NULL; char *tmp_hash; int res; int found_supported_wire_version = 1; /* Innocent unless proven guilty */ for (i = 0; i < servers->count; i++) { hash = mongo_server_create_hash(servers->server[i]); mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "discover_topology: checking ismaster for %s", hash); con = mongo_manager_connection_find_by_hash(manager, hash); if (!con) { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "discover_topology: couldn't create a connection for %s", hash); free(hash); continue; } /* Run ismaster, if needed, to extract server flags - and fetch the other known hosts */ res = mongo_connection_ismaster(manager, con, &servers->options, (char**) &repl_set_name, (int*) &nr_hosts, (char***) &found_hosts, (char**) &error_message, servers->server[i]); switch (res) { case 4: /* The server is running unsupported wire versions */ found_supported_wire_version = 0; /* break omitted intentionally */ case 0: /* Something is wrong with the connection, we need to remove * this from our list */ mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "discover_topology: ismaster return with an error for %s:%d: [%s]", servers->server[i]->host, servers->server[i]->port, error_message); free(error_message); mongo_manager_connection_deregister(manager, con); break; case 3: mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "discover_topology: ismaster worked, but we need to remove the seed host's connection"); mongo_manager_connection_deregister(manager, con); /* Break intentionally missing */ case 1: mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "discover_topology: ismaster worked"); /* Update the replica set name in the parsed "servers" struct * so that we can consistently compare it to the information * that is stored in the connection hashes. */ if (!servers->options.repl_set_name && repl_set_name) { servers->options.repl_set_name = strdup(repl_set_name); } /* Now loop over all the hosts that were found */ for (j = 0; j < nr_hosts; j++) { mongo_server_def *tmp_def; mongo_connection *new_con; char *con_error_message = NULL; /* Create a temp server definition to create a new * connection on-demand if we didn't have one already */ tmp_def = calloc(1, sizeof(mongo_server_def)); tmp_def->username = servers->server[i]->username ? strdup(servers->server[i]->username) : NULL; tmp_def->password = servers->server[i]->password ? strdup(servers->server[i]->password) : NULL; tmp_def->repl_set_name = servers->server[i]->repl_set_name ? strdup(servers->server[i]->repl_set_name) : NULL; tmp_def->db = servers->server[i]->db ? strdup(servers->server[i]->db) : NULL; tmp_def->authdb = servers->server[i]->authdb ? strdup(servers->server[i]->authdb) : NULL; tmp_def->host = mcon_strndup(found_hosts[j], strchr(found_hosts[j], ':') - found_hosts[j]); tmp_def->port = atoi(strchr(found_hosts[j], ':') + 1); tmp_def->mechanism = servers->server[i]->mechanism; /* Create a hash so that we can check whether we already have a * connection for this server definition. If we don't create * the connection, register it (done in * mongo_get_connection_single) and add it to the list of * servers that we're processing so we might use this host to * find more servers. */ tmp_hash = mongo_server_create_hash(tmp_def); if (!mongo_manager_connection_find_by_hash(manager, tmp_hash)) { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "discover_topology: found new host: %s:%d", tmp_def->host, tmp_def->port); new_con = mongo_get_connection_single(manager, tmp_def, &servers->options, MONGO_CON_FLAG_WRITE, (char **) &con_error_message); if (new_con) { int ismaster_error = mongo_connection_ismaster(manager, new_con, &servers->options, NULL, NULL, NULL, &con_error_message, NULL); switch (ismaster_error) { case 1: /* Run just fine */ case 2: /* ismaster() skipped due to interval */ break; case 4: /* Danger danger, reported wire version does not overlap what we support */ found_supported_wire_version = 0; /* break omitted intentionally */ case 0: /* Some error */ case 3: /* Run just fine, but hostname didn't match what we expected */ default: mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "server_flags: error while getting the server configuration %s:%d: %s", servers->server[i]->host, servers->server[i]->port, con_error_message); mongo_manager_connection_deregister(manager, new_con); new_con = NULL; } } if (new_con) { servers->server[servers->count] = tmp_def; servers->count++; } else { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "discover_topology: could not connect to new host: %s:%d: %s", tmp_def->host, tmp_def->port, con_error_message); free(con_error_message); } } else { mongo_server_def_dtor(tmp_def); } free(tmp_hash); /* Cleanup */ free(found_hosts[j]); } free(found_hosts); found_hosts = NULL; break; case 2: mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "discover_topology: ismaster got skipped"); break; } free(hash); } if (repl_set_name) { free(repl_set_name); } return found_supported_wire_version; }
/* - Helpers */ static void mongo_discover_topology(mongo_con_manager *manager, mongo_servers *servers) { int i, j; char *hash; mongo_connection *con; char *error_message; char *repl_set_name = servers->options.repl_set_name ? strdup(servers->options.repl_set_name) : NULL; int nr_hosts; char **found_hosts = NULL; char *tmp_hash; int res; for (i = 0; i < servers->count; i++) { hash = mongo_server_create_hash(servers->server[i]); mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "discover_topology: checking ismaster for %s", hash); con = mongo_manager_connection_find_by_hash(manager, hash); if (!con) { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "discover_topology: couldn't create a connection for %s", hash); free(hash); continue; } res = mongo_connection_ismaster(manager, con, &servers->options, (char**) &repl_set_name, (int*) &nr_hosts, (char***) &found_hosts, (char**) &error_message, servers->server[i]); switch (res) { case 0: /* Something is wrong with the connection, we need to remove * this from our list */ mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "discover_topology: ismaster return with an error for %s:%d: [%s]", servers->server[i]->host, servers->server[i]->port, error_message); free(error_message); mongo_manager_connection_deregister(manager, con); break; case 3: mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "discover_topology: ismaster worked, but we need to remove the seed host's connection"); mongo_manager_connection_deregister(manager, con); /* Break intentionally missing */ case 1: mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "discover_topology: ismaster worked"); /* Update the replica set name in the parsed "servers" struct * so that we can consistently compare it to the information * that is stored in the connection hashes. */ if (!servers->options.repl_set_name && repl_set_name) { servers->options.repl_set_name = strdup(repl_set_name); } /* Now loop over all the hosts that were found */ for (j = 0; j < nr_hosts; j++) { mongo_server_def *tmp_def; mongo_connection *new_con; char *con_error_message = NULL; /* Create a temp server definition to create a new connection on-demand if we didn't have one already */ tmp_def = calloc(1, sizeof(mongo_server_def)); tmp_def->username = servers->server[i]->username ? strdup(servers->server[i]->username) : NULL; tmp_def->password = servers->server[i]->password ? strdup(servers->server[i]->password) : NULL; tmp_def->repl_set_name = servers->server[i]->repl_set_name ? strdup(servers->server[i]->repl_set_name) : NULL; tmp_def->db = servers->server[i]->db ? strdup(servers->server[i]->db) : NULL; tmp_def->authdb = servers->server[i]->authdb ? strdup(servers->server[i]->authdb) : NULL; tmp_def->host = mcon_strndup(found_hosts[j], strchr(found_hosts[j], ':') - found_hosts[j]); tmp_def->port = atoi(strchr(found_hosts[j], ':') + 1); /* Create a hash so that we can check whether we already have a * connection for this server definition. If we don't create * the connection, register it (done in * mongo_get_connection_single) and add it to the list of * servers that we're processing so we might use this host to * find more servers. */ tmp_hash = mongo_server_create_hash(tmp_def); if (!mongo_manager_connection_find_by_hash(manager, tmp_hash)) { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "discover_topology: found new host: %s:%d", tmp_def->host, tmp_def->port); new_con = mongo_get_connection_single(manager, tmp_def, &servers->options, MONGO_CON_FLAG_WRITE, (char **) &con_error_message); if (new_con) { servers->server[servers->count] = tmp_def; servers->count++; } else { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "discover_topology: could not connect to new host: %s:%d: %s", tmp_def->host, tmp_def->port, con_error_message); free(con_error_message); } } else { mongo_server_def_dtor(tmp_def); } free(tmp_hash); /* Cleanup */ free(found_hosts[j]); } free(found_hosts); found_hosts = NULL; break; case 2: mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "discover_topology: ismaster got skipped"); break; } free(hash); } if (repl_set_name) { free(repl_set_name); } }