void mcon_serialize_int(struct mcon_str *str, int num) { int i = MONGO_32(num); mcon_str_addl(str, (char*) &i, 4, 0); }
char *bson_next(char *data) { unsigned char type = data[0]; int32_t length; if (type == 0) { return NULL; } data = bson_skip_field_name(data + 1); /* Skip 1, because of the type in data[0] */ /* element ::= "\x01" e_name double Floating point | "\x02" e_name string UTF-8 string | "\x03" e_name document Embedded document | "\x04" e_name document Array | "\x05" e_name binary Binary data | "\x06" e_name Undefined — Deprecated | "\x07" e_name (byte*12) ObjectId | "\x08" e_name "\x00" Boolean "false" | "\x08" e_name "\x01" Boolean "true" | "\x09" e_name int64 UTC datetime | "\x0A" e_name Null value | "\x0B" e_name cstring cstring Regular expression | "\x0C" e_name string (byte*12) DBPointer — Deprecated | "\x0D" e_name string JavaScript code | "\x0E" e_name string Symbol | "\x0F" e_name code_w_s JavaScript code w/ scope | "\x10" e_name int32 32-bit Integer | "\x11" e_name int64 Timestamp | "\x12" e_name int64 64-bit integer | "\xFF" e_name Min key | "\x7F" e_name Max key */ switch (type) { case BSON_DOUBLE: return data + sizeof(double); case BSON_STRING: case BSON_JAVASCRIPT: case BSON_SYMBOL: length = MONGO_32(*(int*)data); return data + sizeof(int32_t) + length; case BSON_DOCUMENT: case BSON_ARRAY: length = MONGO_32(*(int*)data); return data + length; case BSON_BINARY: length = MONGO_32(*(int*)data); return data + sizeof(int32_t) + 1 + length; case BSON_UNDEFINED: case BSON_NULL: case BSON_MIN_KEY: case BSON_MAX_KEY: return data; case BSON_OBJECT_ID: return data + 12; case BSON_BOOLEAN: return data + 1; case BSON_DATETIME: case BSON_TIMESTAMP: case BSON_INT64: return data + sizeof(int64_t); case BSON_REGEXP: return strchr(data, '\0') + 1; case BSON_DBPOINTER: length = MONGO_32(*(int*)data); return data + sizeof(int32_t) + length + 12; case BSON_JAVASCRIPT_WITH_SCOPE: exit(-3); /* TODO */ case BSON_INT32: return data + sizeof(int32_t); } return NULL; }
/* Returns 1 if it worked, and 0 if it didn't. If 0 is returned, *error_message * is set and must be free()d. On success *data_buffer is set and must be free()d */ static int mongo_connect_send_packet(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mcon_str *packet, char **data_buffer, char **error_message) { int read; uint32_t data_size; char reply_buffer[MONGO_REPLY_HEADER_SIZE]; uint32_t flags; /* To check for query reply status */ /* Send and wait for reply */ if (manager->send(con, options, packet->d, packet->l, error_message) == -1) { mcon_str_ptr_dtor(packet); return 0; } mcon_str_ptr_dtor(packet); read = manager->recv_header(con, options, options->socketTimeoutMS, reply_buffer, MONGO_REPLY_HEADER_SIZE, error_message); if (read < 0) { /* Error already populated */ return 0; } mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "send_packet: read from header: %d", read); if (read < MONGO_REPLY_HEADER_SIZE) { *error_message = malloc(256); snprintf(*error_message, 256, "send_package: the amount of bytes read (%d) is less than the header size (%d)", read, MONGO_REPLY_HEADER_SIZE); return 0; } /* Read result flags */ flags = MONGO_32(*(int*)(reply_buffer + sizeof(int32_t) * 4)); /* Read the rest of the data */ data_size = MONGO_32(*(int*)(reply_buffer)) - MONGO_REPLY_HEADER_SIZE; mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "send_packet: data_size: %d", data_size); /* Check size limits */ if (con->max_bson_size && data_size > (uint32_t)con->max_bson_size) { *error_message = malloc(256); snprintf(*error_message, 256, "send_package: data corruption: the returned size of the reply (%d) is larger than the maximum allowed size (%d)", data_size, con->max_bson_size); return 0; } /* Read data */ *data_buffer = malloc(data_size + 1); if (manager->recv_data(con, options, options->socketTimeoutMS, *data_buffer, data_size, error_message) <= 0) { free(*data_buffer); return 0; } /* Check for a query error */ if (flags & MONGO_REPLY_FLAG_QUERY_FAILURE) { char *ptr = *data_buffer + sizeof(int32_t); /* Skip the length */ char *err; int32_t code; /* Find the error */ if (bson_find_field_as_string(ptr, "$err", &err)) { *error_message = malloc(256 + strlen(err)); if (bson_find_field_as_int32(ptr, "code", &code)) { snprintf(*error_message, 256 + strlen(err), "send_package: the query returned a failure: %s (code: %d)", err, code); } else { snprintf(*error_message, 256 + strlen(err), "send_package: the query returned a failure: %s", err); } } else { *error_message = strdup("send_package: the query returned an unknown error"); } free(*data_buffer); return 0; } return 1; }
/* * Gets a reply from the MongoDB server and * creates a cursor for it */ int mongo_link_hear(SV *cursor_sv) { int sock; int num_returned = 0; mongo_cursor *cursor = (mongo_cursor*)perl_mongo_get_ptr_from_instance(cursor_sv); SV *link_sv = perl_mongo_call_reader(cursor_sv, "_connection"); mongo_link *link = (mongo_link*)perl_mongo_get_ptr_from_instance(link_sv); if (!check_connection(link)) { SvREFCNT_dec(link_sv); croak("can't get db response, not connected"); return 0; } sock = perl_mongo_link_master(link_sv); // if this fails, we might be disconnected... but we're probably // just out of results if (recv(sock, (char*)&cursor->header.length, INT_32, 0) == -1) { SvREFCNT_dec(link_sv); return 0; } cursor->header.length = MONGO_32(cursor->header.length); // make sure we're not getting crazy data if (cursor->header.length > MAX_RESPONSE_LEN || cursor->header.length < REPLY_HEADER_SIZE) { set_disconnected(link); if (!check_connection(link)) { SvREFCNT_dec(link_sv); croak("bad response length: %d, max: %d, did the db assert?\n", cursor->header.length, MAX_RESPONSE_LEN); return 0; } } if (recv(sock, (char*)&cursor->header.request_id, INT_32, 0) == -1 || recv(sock, (char*)&cursor->header.response_to, INT_32, 0) == -1 || recv(sock, (char*)&cursor->header.op, INT_32, 0) == -1 || recv(sock, (char*)&cursor->flag, INT_32, 0) == -1 || recv(sock, (char*)&cursor->cursor_id, INT_64, 0) == -1 || recv(sock, (char*)&cursor->start, INT_32, 0) == -1 || recv(sock, (char*)&num_returned, INT_32, 0) == -1) { SvREFCNT_dec(link_sv); return 0; } cursor->header.request_id = MONGO_32(cursor->header.request_id); cursor->header.response_to = MONGO_32(cursor->header.response_to); cursor->header.op = MONGO_32(cursor->header.op); cursor->flag = MONGO_32(cursor->flag); cursor->cursor_id = MONGO_64(cursor->cursor_id); cursor->start = MONGO_32(cursor->start); num_returned = MONGO_32(num_returned); // create buf cursor->header.length -= INT_32*9; // point buf.start at buf's first char if (!cursor->buf.start) { New(0, cursor->buf.start, cursor->header.length, char); cursor->buf.end = cursor->buf.start + cursor->header.length; }