int main(void) { char *hash1, *hash2; char *host, *db, *username, *auth_hash; int port, pid; mongo_server_def def1 = { "whisky", 13000, NULL, NULL, NULL }; mongo_server_def def2 = { "whisky", 13000, "phpunit", "derick", "not!" }; hash1 = mongo_server_create_hash(&def1); mongo_server_split_hash(hash1, &host, &port, &db, &username, &auth_hash, &pid); printf("HASH: %s; host: %s, port: %d, db: %s, username: %s, auth_hash: %s, pid: %d\n", hash1, host, port, db, username, auth_hash, pid); free(host); free(hash1); hash2 = mongo_server_create_hash(&def2); mongo_server_split_hash(hash2, &host, &port, &db, &username, &auth_hash, &pid); printf("HASH: %s; host: %s, port: %d, db: %s, username: %s, auth_hash: %s, pid: %d\n", hash2, host, port, db, username, auth_hash, pid); free(host); free(db); free(username); free(auth_hash); host = db = username = auth_hash = NULL; port = pid = 0; mongo_server_split_hash(hash2, &host, &port, NULL, &username, &auth_hash, &pid); printf("HASH: %s; host: %s, port: %d, db: %s, username: %s, auth_hash: %s, pid: %d\n", hash2, host, port, db, username, auth_hash, pid); free(host); free(username); free(auth_hash); host = db = username = auth_hash = NULL; port = pid = 0; mongo_server_split_hash(hash2, &host, &port, &db, NULL, &auth_hash, &pid); printf("HASH: %s; host: %s, port: %d, db: %s, username: %s, auth_hash: %s, pid: %d\n", hash2, host, port, db, username, auth_hash, pid); free(host); free(db); free(auth_hash); host = db = username = auth_hash = NULL; port = pid = 0; mongo_server_split_hash(hash2, &host, &port, &db, NULL, NULL, &pid); printf("HASH: %s; host: %s, port: %d, db: %s, username: %s, auth_hash: %s, pid: %d\n", hash2, host, port, db, username, auth_hash, pid); free(host); free(db); host = db = username = auth_hash = NULL; port = pid = 0; mongo_server_split_hash(hash2, &host, &port, NULL, &username, NULL, &pid); printf("HASH: %s; host: %s, port: %d, db: %s, username: %s, auth_hash: %s, pid: %d\n", hash2, host, port, db, username, auth_hash, pid); free(host); free(username); free(hash2); return 0; }
mongo_connection *mongo_manager_connection_find_by_server_definition(mongo_con_manager *manager, mongo_server_def *definition) { char *hash = mongo_server_create_hash(definition); mongo_connection *con = mongo_manager_find_by_hash(manager, manager->connections, hash); free(hash); return con; }
static mcon_collection *mongo_filter_candidates_by_seed(mongo_con_manager *manager, mcon_collection *candidates, mongo_servers *servers) { int i, j; mcon_collection *filtered; char *server_hash; mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "limiting by seeded/discovered servers"); filtered = mcon_init_collection(sizeof(mongo_connection*)); for (j = 0; j < servers->count; j++) { server_hash = mongo_server_create_hash(servers->server[j]); for (i = 0; i < candidates->count; i++) { if (strcmp(((mongo_connection *) candidates->data[i])->hash, server_hash) == 0) { mongo_print_connection_info(manager, (mongo_connection *) candidates->data[i], MLOG_FINE); mcon_collection_add(filtered, (mongo_connection *) candidates->data[i]); } } free(server_hash); } mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "limiting by seeded/discovered servers: done"); return filtered; }
/* Helpers */ static mongo_connection *mongo_get_connection_single(mongo_con_manager *manager, mongo_server_def *server, mongo_server_options *options, int connection_flags, char **error_message) { char *hash; mongo_connection *con = NULL; mongo_connection_blacklist *blacklist = NULL; hash = mongo_server_create_hash(server); /* See if a connection is in our blacklist to short-circut trying to * connect to a node that is known to be down. This is done so we don't * waste precious time in connecting to unreachable nodes */ blacklist = mongo_manager_blacklist_find_by_hash(manager, hash); if (blacklist) { struct timeval start; /* It is blacklisted, but it may have been a long time again and * chances are we should give it another try */ if (mongo_connection_ping_check(manager, blacklist->last_ping, &start)) { /* The connection is blacklisted, but we've reached our ping * interval so lets remove the blacklisting and pretend we didn't * know about it */ mongo_manager_blacklist_deregister(manager, blacklist, hash); } else { /* Otherwise short-circut the connection attempt, and say we failed * right away */ free(hash); *error_message = strdup("Previous connection attempts failed, server blacklisted"); return NULL; } } con = mongo_manager_connection_find_by_hash(manager, hash); /* If we aren't about to (re-)connect then all we care about if it was a * known connection or not */ if (connection_flags & MONGO_CON_FLAG_DONT_CONNECT) { free(hash); return con; } /* If we found a valid connection check if we need to ping it */ if (con) { /* Do the ping, if needed */ if (!mongo_connection_ping(manager, con, options, error_message)) { /* If the ping failed, deregister the connection */ mongo_manager_connection_deregister(manager, con); /* Set the return value to NULL, as the connection is broken and * has been removed */ con = NULL; } free(hash); return con; } /* Since we didn't find an existing connection, lets make one! */ con = mongo_connection_create(manager, hash, server, options, error_message); if (con) { /* When we make a connection, we need to figure out the server version it is */ if (!mongo_connection_get_server_version(manager, con, options, error_message)) { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "server_version: error while getting the server version %s:%d: %s", server->host, server->port, *error_message); mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); free(hash); return NULL; } /* Do authentication if requested */ /* Note: Arbiters don't contain any data, including auth stuff, so you cannot authenticate on an arbiter */ if (con->connection_type != MONGO_NODE_ARBITER) { if (!manager->authenticate(manager, con, options, server, error_message)) { mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); free(hash); return NULL; } } /* Do the first-time ping to record the latency of the connection */ if (mongo_connection_ping(manager, con, options, error_message)) { /* Register the connection on successful pinging */ mongo_manager_connection_register(manager, con); } else { /* Or kill it and reset the return value if the ping somehow failed */ mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); con = NULL; } } free(hash); return con; }
/* 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; }
void* php_mongo_io_stream_connect(mongo_con_manager *manager, mongo_server_def *server, mongo_server_options *options, char **error_message) { char *errmsg; int errcode; php_stream *stream; char *hash = mongo_server_create_hash(server); struct timeval ctimeout = {0, 0}; char *dsn; int dsn_len; int tcp_socket = 1; ERROR_HANDLER_DECLARATION(error_handler) TSRMLS_FETCH(); if (server->host[0] == '/') { dsn_len = spprintf(&dsn, 0, "unix://%s", server->host); tcp_socket = 0; } else { dsn_len = spprintf(&dsn, 0, "tcp://%s:%d", server->host, server->port); } /* Connection timeout behavior varies based on the following: * - Negative => no timeout (i.e. block indefinitely) * - Zero => not specified (PHP will use default_socket_timeout) * - Positive => used specified timeout */ if (options->connectTimeoutMS) { /* Convert negative value to -1 second, which implies no timeout */ int connectTimeoutMS = options->connectTimeoutMS < 0 ? -1000 : options->connectTimeoutMS; ctimeout.tv_sec = connectTimeoutMS / 1000; ctimeout.tv_usec = (connectTimeoutMS % 1000) * 1000; mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "Connecting to %s (%s) with connection timeout: %d.%06d", dsn, hash, ctimeout.tv_sec, ctimeout.tv_usec); } else { mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "Connecting to %s (%s) without connection timeout (default_socket_timeout will be used)", dsn, hash); } ERROR_HANDLER_REPLACE(error_handler, mongo_ce_ConnectionException); stream = php_stream_xport_create(dsn, dsn_len, 0, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hash, options->connectTimeoutMS > 0 ? &ctimeout : NULL, (php_stream_context *)options->ctx, &errmsg, &errcode); ERROR_HANDLER_RESTORE(error_handler); efree(dsn); free(hash); if (!stream) { /* error_message will be free()d, but errmsg was allocated by PHP and needs efree() */ *error_message = strdup(errmsg); efree(errmsg); return NULL; } if (tcp_socket) { int socket = ((php_netstream_data_t*)stream->abstract)->socket; int flag = 1; setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); } if (options->ssl) { int crypto_enabled; ERROR_HANDLER_REPLACE(error_handler, mongo_ce_ConnectionException); if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0) { ERROR_HANDLER_RESTORE(error_handler); *error_message = strdup("Cannot setup SSL, is ext/openssl loaded?"); php_stream_close(stream); return NULL; } crypto_enabled = php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC); ERROR_HANDLER_RESTORE(error_handler); if (crypto_enabled < 0) { /* Setting up crypto failed. Thats only OK if we only preferred it */ if (options->ssl == MONGO_SSL_PREFER) { /* FIXME: We can't actually get here because we reject setting * this option to prefer in mcon/parse.c. This is however * probably what we need to do in the future when mongod starts * actually supporting this! :) */ mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "stream_connect: Failed establishing SSL for %s:%d", server->host, server->port); php_stream_xport_crypto_enable(stream, 0 TSRMLS_CC); } else { *error_message = strdup("Can't connect over SSL, is mongod running with SSL?"); php_stream_close(stream); return NULL; } } else { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "stream_connect: Establish SSL for %s:%d", server->host, server->port); } } else { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "stream_connect: Not establishing SSL for %s:%d", server->host, server->port); } /* Socket timeout behavior uses the same logic as connectTimeoutMS */ if (options->socketTimeoutMS) { struct timeval rtimeout = {0, 0}; /* Convert negative value to -1 second, which implies no timeout */ int socketTimeoutMS = options->socketTimeoutMS < 0 ? -1000 : options->socketTimeoutMS; rtimeout.tv_sec = socketTimeoutMS / 1000; rtimeout.tv_usec = (socketTimeoutMS % 1000) * 1000; php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &rtimeout); mongo_manager_log(MonGlo(manager), MLOG_CON, MLOG_FINE, "Setting stream timeout to %d.%06d", rtimeout.tv_sec, rtimeout.tv_usec); } /* Avoid a weird leak warning in debug mode when freeing the stream */ #if ZEND_DEBUG stream->__exposed = 1; #endif return stream; }
void* php_mongo_io_stream_connect(mongo_con_manager *manager, mongo_server_def *server, mongo_server_options *options, char **error_message) { char *errmsg; int errcode; php_stream *stream; char *hash = mongo_server_create_hash(server); struct timeval ctimeout = {0}; char *dsn; int dsn_len; TSRMLS_FETCH(); dsn_len = spprintf(&dsn, 0, "tcp://%s:%d", server->host, server->port); if (options->connectTimeoutMS) { ctimeout.tv_sec = options->connectTimeoutMS / 1000; ctimeout.tv_usec = (options->connectTimeoutMS % 1000) * 1000; } stream = php_stream_xport_create(dsn, dsn_len, 0, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hash, options->connectTimeoutMS ? &ctimeout : NULL, (php_stream_context *)options->ctx, &errmsg, &errcode); efree(dsn); free(hash); if (!stream) { /* error_message will be free()d, but errmsg was allocated by PHP and needs efree() */ *error_message = strdup(errmsg); efree(errmsg); return NULL; } if (options->ssl) { if ( (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL TSRMLS_CC) < 0) || (php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0)) { /* Setting up crypto failed. Thats only OK if we only preferred it */ if (options->ssl == MONGO_SSL_PREFER) { /* FIXME: We can't actually get here because we reject setting this optino to prefer in mcon/parse.c * This is however probably what we need to do in the future when mongod starts actually supporting this! :) */ mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "stream_connect: Failed establishing SSL for %s:%d", server->host, server->port); php_stream_xport_crypto_enable(stream, 0 TSRMLS_CC); } else { *error_message = strdup("Can't connect over SSL, is mongod running with SSL?"); php_stream_close(stream); return NULL; } } else { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "stream_connect: Establish SSL for %s:%d", server->host, server->port); } } else { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "stream_connect: Not establishing SSL for %s:%d", server->host, server->port); } php_stream_notify_progress_init(stream->context, 0, 0); if (options->socketTimeoutMS) { struct timeval rtimeout = {0}; rtimeout.tv_sec = options->socketTimeoutMS / 1000; rtimeout.tv_usec = (options->socketTimeoutMS % 1000) * 1000; php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &rtimeout); } /* Avoid a weird leak warning in debug mode when freeing the stream */ #if ZEND_DEBUG stream->__exposed = 1; #endif return stream; }
static mongo_connection *mongo_get_connection_single(mongo_con_manager *manager, mongo_server_def *server, mongo_server_options *options, int connection_flags, char **error_message) { char *hash; mongo_connection *con = NULL; mongo_connection_blacklist *blacklist = NULL; hash = mongo_server_create_hash(server); /* See if a connection is in our blacklist to short-circut trying to connect * to a node that is known to be down. This is done so we don't waste * precious time in connecting to unreachable nodes */ blacklist = mongo_manager_blacklist_find_by_hash(manager, hash); if (blacklist) { struct timeval start; /* It is blacklisted, but it may have been a long time again and chances are * we should give it another try */ if (mongo_connection_ping_check(manager, blacklist->last_ping, &start)) { /* The connection is blacklisted, but we've reached our ping interval * so lets remove the blacklisting and pretend we didn't know about it */ mongo_manager_blacklist_deregister(manager, blacklist, hash); con = NULL; } else { /* Otherwise short-circut the connection attempt, and say we failed right away */ free(hash); return NULL; } } con = mongo_manager_connection_find_by_hash(manager, hash); /* If we aren't about to (re-)connect then all we care about if it was a known connection or not */ if (connection_flags & MONGO_CON_FLAG_DONT_CONNECT) { free(hash); return con; } /* If we found a valid connection check if we need to ping it */ if (con) { /* Do the ping, if needed */ if (!mongo_connection_ping(manager, con, options, error_message)) { /* If the ping failed, deregister the connection */ mongo_manager_connection_deregister(manager, con); /* Set the return value to NULL, as the connection is broken and has been removed */ con = NULL; } free(hash); return con; } /* Since we didn't find an existing connection, lets make one! */ con = mongo_connection_create(manager, hash, server, options, error_message); if (con) { /* Do authentication if requested */ if (server->db && server->username && server->password) { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "get_connection_single: authenticating %s", hash); if (!authenticate_connection(manager, con, options, server->authdb ? server->authdb : server->db, server->username, server->password, error_message)) { mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); free(hash); return NULL; } } /* Do the first-time ping to record the latency of the connection */ if (mongo_connection_ping(manager, con, options, error_message)) { /* Register the connection on successful pinging */ mongo_manager_connection_register(manager, con); } else { /* Or kill it and reset the return value if the ping somehow failed */ mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); con = NULL; } } free(hash); return con; }
/* - 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); } }