void bson_add_string(mcon_str *str, char *fieldname, char *string) { mcon_str_addl(str, "\x02", 1, 0); mcon_str_addl(str, fieldname, strlen(fieldname) + 1, 0); mcon_serialize_int(str, strlen(string) + 1); mcon_str_add(str, string, 0); mcon_str_addl(str, "", 1, 0); /* Trailing 0x00 */ }
mcon_str *bson_create_authenticate_packet(mongo_connection *con, char *database, char *username, char *nonce, char *key) { struct mcon_str *str; char *ns; int hdr, length; /* We use the selected database to construct the namespace */ length = strlen(database) + 5 + 1; ns = malloc(length); snprintf(ns, length, "%s.$cmd", database); str = create_simple_header(con, ns); free(ns); hdr = str->l; mcon_serialize_int(str, 0); /* We need to fill this with the length */ bson_add_long(str, "authenticate", 1); bson_add_string(str, "user", username); bson_add_string(str, "nonce", nonce); bson_add_string(str, "key", key); mcon_str_addl(str, "", 1, 0); /* Trailing 0x00 */ /* Set length */ ((int*) (&(str->d[hdr])))[0] = str->l - hdr; ((int*) str->d)[0] = str->l; return str; }
char *mongo_read_preference_squash_tagset(mongo_read_preference_tagset *tagset) { int i; struct mcon_str str = { 0 }; for (i = 0; i < tagset->tag_count; i++) { if (i) { mcon_str_addl(&str, ", ", 2, 0); } mcon_str_add(&str, tagset->tags[i], 0); } return str.d; }
mcon_str *bson_create_rs_status_packet(mongo_connection *con) { struct mcon_str *str = create_simple_header(con, NULL); int hdr; hdr = str->l; mcon_serialize_int(str, 0); /* We need to fill this with the length */ bson_add_long(str, "replSetGetStatus", 1); mcon_str_addl(str, "", 1, 0); /* Trailing 0x00 */ /* Set length */ ((int*) (&(str->d[hdr])))[0] = str->l - hdr; ((int*) str->d)[0] = str->l; return str; }
/* Creates a simple query header. * * The ns argument selects which namespace to use. If it's not set, we use * "admin.$cmd". */ static mcon_str *create_simple_header(mongo_connection *con, char *ns) { struct mcon_str *str; mcon_str_ptr_init(str); mcon_serialize_int(str, 0); /* We need to fill this with the length */ mcon_serialize_int(str, mongo_connection_get_reqid(con)); mcon_serialize_int(str, 0); /* Reponse to */ mcon_serialize_int(str, 2004); /* OP_QUERY */ mcon_serialize_int(str, MONGO_QUERY_FLAG_SLAVE_OK); /* Flags */ mcon_str_addl(str, ns ? ns : "admin.$cmd", ns ? strlen(ns) + 1 : 11, 0); mcon_serialize_int(str, 0); /* Number to skip */ mcon_serialize_int(str, -1); /* Number to return, has to be -1 for admin commands */ return str; }
void mcon_serialize_int64(struct mcon_str *str, int64_t num) { int64_t i = MONGO_64(num); mcon_str_addl(str, (char*) &i, 8, 0); }
void mcon_serialize_int32(struct mcon_str *str, int num) { int i = MONGO_32(num); mcon_str_addl(str, (char*) &i, 4, 0); }
static mongo_connection *mongo_get_connection_multiple(mongo_con_manager *manager, mongo_servers *servers, int connection_flags, char **error_message) { mongo_connection *con = NULL; mongo_connection *tmp; mcon_collection *collection = NULL; mongo_read_preference tmp_rp; /* We only support NEAREST for MULTIPLE right now */ int i; int found_connected_server = 0; mcon_str *messages; int found_supported_wire_version = 1; mcon_str_ptr_init(messages); /* Create a connection to every of the servers in the seed list */ for (i = 0; i < servers->count; i++) { int ismaster_error = 0; char *con_error_message = NULL; tmp = mongo_get_connection_single(manager, servers->server[i], &servers->options, connection_flags, (char **) &con_error_message); if (tmp) { found_connected_server++; /* Run ismaster, if needed, to extract server flags */ ismaster_error = mongo_connection_ismaster(manager, tmp, &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 0: /* Some error */ case 3: /* Run just fine, but hostname didn't match what we expected */ case 4: /* Danger danger, reported wire version does not overlap what we support */ 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); /* If it failed because of wire version, we have to bail out completely * later on, but we should continue to aggregate the errors in case more * servers are unsupported */ if (ismaster_error == 4) { mongo_manager_connection_deregister(manager, tmp); found_supported_wire_version = 0; } else { mongo_connection_destroy(manager, tmp, MONGO_CLOSE_BROKEN); } tmp = NULL; found_connected_server--; } } if (!tmp) { if (!(connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "Couldn't connect to '%s:%d': %s", servers->server[i]->host, servers->server[i]->port, con_error_message); if (messages->l) { mcon_str_addl(messages, "; ", 2, 0); } mcon_str_add(messages, "Failed to connect to: ", 0); mcon_str_add(messages, servers->server[i]->host, 0); mcon_str_addl(messages, ":", 1, 0); mcon_str_add_int(messages, servers->server[i]->port); mcon_str_addl(messages, ": ", 2, 0); mcon_str_add(messages, con_error_message, 1); /* Also frees con_error_message */ } else { free(con_error_message); } } } if (!found_supported_wire_version) { *error_message = strdup("Found a server running unsupported wire version. Please upgrade the driver, or take the server out of rotation"); mcon_str_ptr_dtor(messages); return NULL; } /* If we don't have a connected server then there is no point in continueing */ if (!found_connected_server && (connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) { mcon_str_ptr_dtor(messages); return NULL; } /* When selecting a *mongos* node, readPreferences make no sense as we * don't have a "primary" or "secondary" mongos. The mongos nodes aren't * tagged either. To pick a mongos we therefore simply pick the "nearest" * mongos node. */ tmp_rp.type = MONGO_RP_NEAREST; tmp_rp.tagsets = NULL; tmp_rp.tagset_count = 0; collection = mongo_find_candidate_servers(manager, &tmp_rp, servers); if (!collection || collection->count == 0) { if (messages->l) { *error_message = strdup(messages->d); } else { *error_message = strdup("No candidate servers found"); } goto bailout; } collection = mongo_sort_servers(manager, collection, &servers->read_pref); collection = mongo_select_nearest_servers(manager, collection, &servers->options, &servers->read_pref); if (!collection) { *error_message = strdup("No server near us"); goto bailout; } con = mongo_pick_server_from_set(manager, collection, &servers->read_pref); bailout: /* Cleaning up */ mcon_str_ptr_dtor(messages); if (collection) { mcon_collection_free(collection); } return con; }
void mcon_str_add(mcon_str *xs, char *str, int f) { return mcon_str_addl(xs, str, strlen(str), f); }
static mongo_connection *mongo_get_connection_multiple(mongo_con_manager *manager, mongo_servers *servers, int connection_flags, char **error_message) { mongo_connection *con = NULL; mongo_connection *tmp; mcon_collection *collection = NULL; char *con_error_message = NULL; mongo_read_preference tmp_rp; /* We only support NEAREST for MULTIPLE right now */ int i; int found_connected_server = 0; mcon_str *messages; mcon_str_ptr_init(messages); /* Create a connection to every of the servers in the seed list */ for (i = 0; i < servers->count; i++) { tmp = mongo_get_connection_single(manager, servers->server[i], &servers->options, connection_flags, (char **) &con_error_message); if (tmp) { found_connected_server = 1; } else if (!(connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "Couldn't connect to '%s:%d': %s", servers->server[i]->host, servers->server[i]->port, con_error_message); if (messages->l) { mcon_str_addl(messages, "; ", 2, 0); } mcon_str_add(messages, "Failed to connect to: ", 0); mcon_str_add(messages, servers->server[i]->host, 0); mcon_str_addl(messages, ":", 1, 0); mcon_str_add_int(messages, servers->server[i]->port); mcon_str_addl(messages, ": ", 2, 0); mcon_str_add(messages, con_error_message, 1); /* Also frees con_error_message */ } } /* If we don't have a connected server then there is no point in continueing */ if (!found_connected_server && (connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) { return NULL; } /* When selecting a *mongos* node, readPreferences make no sense as we * don't have a "primary" or "secondary" mongos. The mongos nodes aren't * tagged either. To pick a mongos we therefore simply pick the "nearest" * mongos node. */ tmp_rp.type = MONGO_RP_NEAREST; tmp_rp.tagsets = NULL; tmp_rp.tagset_count = 0; collection = mongo_find_candidate_servers(manager, &tmp_rp, servers); if (!collection || collection->count == 0) { if (messages->l) { *error_message = strdup(messages->d); } else { *error_message = strdup("No candidate servers found"); } goto bailout; } collection = mongo_sort_servers(manager, collection, &servers->read_pref); collection = mongo_select_nearest_servers(manager, collection, &servers->read_pref); if (!collection) { *error_message = strdup("No server near us"); goto bailout; } con = mongo_pick_server_from_set(manager, collection, &servers->read_pref); bailout: /* Cleaning up */ mcon_str_ptr_dtor(messages); if (collection) { mcon_collection_free(collection); } return con; }
void bson_add_long(mcon_str *str, char *fieldname, int64_t v) { mcon_str_addl(str, "\x12", 1, 0); mcon_str_addl(str, fieldname, strlen(fieldname) + 1, 0); mcon_serialize_int64(str, v); }