static void test_mongoc_buffer_basic (void) { mongoc_stream_t *stream; mongoc_buffer_t buf; uint8_t *data = bson_malloc0(1024); bson_error_t error = { 0 }; ssize_t r; mongoc_fd_t fd; fd = mongoc_open("tests/binary/reply1.dat", O_RDONLY); ASSERT(mongoc_fd_is_valid(fd)); stream = mongoc_stream_unix_new(fd); ASSERT(stream); _mongoc_buffer_init(&buf, data, 1024, bson_realloc); r = _mongoc_buffer_fill(&buf, stream, 537, 0, &error); ASSERT_CMPINT((int)r, ==, -1); r = _mongoc_buffer_fill(&buf, stream, 536, 0, &error); ASSERT_CMPINT((int)r, ==, 536); ASSERT(buf.len == 536); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); mongoc_stream_destroy(stream); }
static void test_mongoc_buffer_basic (void) { mongoc_stream_t *stream; mongoc_buffer_t buf; bson_uint8_t *data = bson_malloc0(1024); bson_error_t error = { 0 }; bson_bool_t r; int fd; fd = open("tests/binary/reply1.dat", O_RDONLY); assert(fd >= 0); stream = mongoc_stream_unix_new(fd); assert(stream); _mongoc_buffer_init(&buf, data, 1024, bson_realloc); r = _mongoc_buffer_fill(&buf, stream, 537, 0, &error); assert_cmpint(r, ==, -1); r = _mongoc_buffer_fill(&buf, stream, 536, 0, &error); assert_cmpint(r, ==, 536); assert(buf.len == 536); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); _mongoc_buffer_destroy(&buf); mongoc_stream_destroy(stream); }
void _mongoc_write_command_destroy (mongoc_write_command_t *command) { ENTRY; if (command) { bson_destroy (&command->cmd_opts); _mongoc_buffer_destroy (&command->payload); } EXIT; }
static void mongoc_stream_buffered_destroy (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *)stream; bson_return_if_fail(stream); mongoc_stream_destroy(buffered->base_stream); buffered->base_stream = NULL; _mongoc_buffer_destroy (&buffered->buffer); bson_free(stream); mongoc_counter_streams_active_dec(); mongoc_counter_streams_disposed_inc(); }
void mongoc_async_cmd_destroy (mongoc_async_cmd_t *acmd) { BSON_ASSERT (acmd); DL_DELETE (acmd->async->cmds, acmd); acmd->async->ncmds--; bson_destroy (&acmd->cmd); if (acmd->reply_needs_cleanup) { bson_destroy (&acmd->reply); } _mongoc_array_destroy (&acmd->array); _mongoc_buffer_destroy (&acmd->buffer); bson_free (acmd); }
void _mongoc_cursor_destroy (mongoc_cursor_t *cursor) { ENTRY; bson_return_if_fail(cursor); if (cursor->in_exhaust) { cursor->client->in_exhaust = FALSE; if (!cursor->done) { _mongoc_cluster_disconnect_node ( &cursor->client->cluster, &cursor->client->cluster.nodes[cursor->hint - 1]); } } else if (cursor->rpc.reply.cursor_id) { _mongoc_cursor_kill_cursor(cursor, cursor->rpc.reply.cursor_id); } if (cursor->reader) { bson_reader_destroy(cursor->reader); cursor->reader = NULL; } bson_destroy(&cursor->query); bson_destroy(&cursor->fields); _mongoc_buffer_destroy(&cursor->buffer); mongoc_read_prefs_destroy(cursor->read_prefs); bson_free(cursor); mongoc_counter_cursors_active_dec(); mongoc_counter_cursors_disposed_inc(); EXIT; }
static void * mock_server_worker (void *data) { mongoc_buffer_t buffer; mongoc_stream_t *stream; mock_server_t *server; mongoc_rpc_t rpc; bson_error_t error; int32_t msg_len; void **closure = data; ENTRY; BSON_ASSERT(closure); server = closure[0]; stream = closure[1]; _mongoc_buffer_init(&buffer, NULL, 0, NULL, NULL); again: if (_mongoc_buffer_fill (&buffer, stream, 4, -1, &error) == -1) { MONGOC_WARNING ("%s():%d: %s", __FUNCTION__, __LINE__, error.message); GOTO (failure); } assert (buffer.len >= 4); memcpy (&msg_len, buffer.data + buffer.off, 4); msg_len = BSON_UINT32_FROM_LE (msg_len); if (msg_len < 16) { MONGOC_WARNING ("No data"); GOTO (failure); } if (_mongoc_buffer_fill (&buffer, stream, msg_len, -1, &error) == -1) { MONGOC_WARNING ("%s():%d: %s", __FUNCTION__, __LINE__, error.message); GOTO (failure); } assert (buffer.len >= (unsigned)msg_len); DUMP_BYTES (buffer, buffer.data + buffer.off, buffer.len); if (!_mongoc_rpc_scatter(&rpc, buffer.data + buffer.off, msg_len)) { MONGOC_WARNING ("%s():%d: %s", __FUNCTION__, __LINE__, "Failed to scatter"); GOTO (failure); } _mongoc_rpc_swab_from_le(&rpc); if (!handle_command(server, stream, &rpc)) { server->handler(server, stream, &rpc, server->handler_data); } memmove (buffer.data, buffer.data + buffer.off + msg_len, buffer.len - msg_len); buffer.off = 0; buffer.len -= msg_len; GOTO (again); failure: mongoc_stream_close (stream); mongoc_stream_destroy (stream); bson_free(closure); _mongoc_buffer_destroy (&buffer); RETURN (NULL); }
bool _mongoc_client_recv_gle (mongoc_client_t *client, uint32_t hint, bson_t **gle_doc, bson_error_t *error) { mongoc_buffer_t buffer; mongoc_rpc_t rpc; bson_iter_t iter; bool ret = false; bson_t b; ENTRY; bson_return_val_if_fail (client, false); bson_return_val_if_fail (hint, false); if (gle_doc) { *gle_doc = NULL; } _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); if (!_mongoc_cluster_try_recv (&client->cluster, &rpc, &buffer, hint, error)) { GOTO (cleanup); } if (rpc.header.opcode != MONGOC_OPCODE_REPLY) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Received message other than OP_REPLY."); GOTO (cleanup); } if (_mongoc_rpc_reply_get_first (&rpc.reply, &b)) { if (gle_doc) { *gle_doc = bson_copy (&b); } if ((rpc.reply.flags & MONGOC_REPLY_QUERY_FAILURE)) { _bson_to_error (&b, error); bson_destroy (&b); GOTO (cleanup); } if (!bson_iter_init_find (&iter, &b, "ok") || BSON_ITER_HOLDS_DOUBLE (&iter)) { if (bson_iter_double (&iter) == 0.0) { _bson_to_error (&b, error); } } bson_destroy (&b); } ret = true; cleanup: _mongoc_buffer_destroy (&buffer); RETURN (ret); }
/* TODO: factor */ static void * worker_thread (void *data) { worker_closure_t *closure = (worker_closure_t *) data; mock_server_t *server = closure->server; mongoc_stream_t *client_stream = closure->client_stream; mongoc_buffer_t buffer; mongoc_rpc_t *rpc = NULL; bool handled; bson_error_t error; int32_t msg_len; bool stopped; sync_queue_t *q; request_t *request; mongoc_array_t autoresponders; ssize_t i; autoresponder_handle_t handle; #ifdef MONGOC_ENABLE_SSL bool ssl; #endif ENTRY; BSON_ASSERT(closure); #ifdef MONGOC_ENABLE_SSL mongoc_mutex_lock (&server->mutex); ssl = server->ssl; mongoc_mutex_unlock (&server->mutex); if (ssl) { if (!mongoc_stream_tls_handshake_block (client_stream, "localhost", TIMEOUT, &error)) { MONGOC_ERROR("Blocking TLS handshake failed"); mongoc_stream_close (client_stream); mongoc_stream_destroy (client_stream); RETURN (NULL); } } #endif _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); _mongoc_array_init (&autoresponders, sizeof (autoresponder_handle_t)); again: bson_free (rpc); rpc = NULL; handled = false; mongoc_mutex_lock (&server->mutex); stopped = server->stopped; mongoc_mutex_unlock (&server->mutex); if (stopped) { GOTO(failure); } if (_mongoc_buffer_fill (&buffer, client_stream, 4, TIMEOUT, &error) == -1) { GOTO (again); } assert (buffer.len >= 4); memcpy (&msg_len, buffer.data + buffer.off, 4); msg_len = BSON_UINT32_FROM_LE (msg_len); if (msg_len < 16) { MONGOC_WARNING ("No data"); GOTO (failure); } if (_mongoc_buffer_fill (&buffer, client_stream, (size_t) msg_len, -1, &error) == -1) { MONGOC_WARNING ("%s():%d: %s", BSON_FUNC, __LINE__, error.message); GOTO (failure); } assert (buffer.len >= (unsigned) msg_len); /* copies message from buffer */ request = request_new (&buffer, msg_len, server, client_stream, closure->port); mongoc_mutex_lock (&server->mutex); _mongoc_array_copy (&autoresponders, &server->autoresponders); mongoc_mutex_unlock (&server->mutex); if (mock_server_get_verbose (server)) { printf ("%5.2f %hu -> %hu %s\n", mock_server_get_uptime_sec (server), closure->port, server->port, request->as_str); fflush (stdout); } /* run responders most-recently-added-first */ for (i = server->autoresponders.len - 1; i >= 0; i--) { handle = _mongoc_array_index (&server->autoresponders, autoresponder_handle_t, i); if (handle.responder (request, handle.data)) { handled = true; /* responder should destroy the request */ request = NULL; break; } } if (!handled) { q = mock_server_get_queue (server); q_put (q, (void *) request); request = NULL; } memmove (buffer.data, buffer.data + buffer.off + msg_len, buffer.len - msg_len); buffer.off = 0; buffer.len -= msg_len; GOTO (again); failure: _mongoc_array_destroy (&autoresponders); _mongoc_buffer_destroy (&buffer); mongoc_stream_close (client_stream); mongoc_stream_destroy (client_stream); bson_free (rpc); bson_free (closure); _mongoc_buffer_destroy (&buffer); RETURN (NULL); }
bool _mongoc_client_recv_gle (mongoc_client_t *client, mongoc_server_stream_t *server_stream, bson_t **gle_doc, bson_error_t *error) { mongoc_buffer_t buffer; mongoc_rpc_t rpc; bson_iter_t iter; bool ret = false; bson_t b; ENTRY; BSON_ASSERT (client); BSON_ASSERT (server_stream); if (gle_doc) { *gle_doc = NULL; } _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); if (!mongoc_cluster_try_recv (&client->cluster, &rpc, &buffer, server_stream, error)) { mongoc_topology_invalidate_server (client->topology, server_stream->sd->id); GOTO (cleanup); } if (rpc.header.opcode != MONGOC_OPCODE_REPLY) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Received message other than OP_REPLY."); GOTO (cleanup); } if (_mongoc_rpc_reply_get_first (&rpc.reply, &b)) { if ((rpc.reply.flags & MONGOC_REPLY_QUERY_FAILURE)) { _bson_to_error (&b, error); bson_destroy (&b); GOTO (cleanup); } if (gle_doc) { *gle_doc = bson_copy (&b); } if (!bson_iter_init_find (&iter, &b, "ok") || BSON_ITER_HOLDS_DOUBLE (&iter)) { if (bson_iter_double (&iter) == 0.0) { _bson_to_error (&b, error); } } bson_destroy (&b); ret = true; } cleanup: _mongoc_buffer_destroy (&buffer); RETURN (ret); }
static void * worker_thread (void *data) { worker_closure_t *closure = (worker_closure_t *) data; mock_server_t *server = closure->server; mongoc_stream_t *client_stream = closure->client_stream; mongoc_buffer_t buffer; mongoc_rpc_t *rpc = NULL; bool handled; bson_error_t error; int32_t msg_len; sync_queue_t *requests; sync_queue_t *replies; request_t *request; mongoc_array_t autoresponders; ssize_t i; autoresponder_handle_t handle; reply_t *reply; #ifdef MONGOC_ENABLE_SSL bool ssl; #endif ENTRY; /* queue of client replies sent over this worker's connection */ replies = q_new (); #ifdef MONGOC_ENABLE_SSL mongoc_mutex_lock (&server->mutex); ssl = server->ssl; mongoc_mutex_unlock (&server->mutex); if (ssl) { if (!mongoc_stream_tls_handshake_block (client_stream, "localhost", TIMEOUT, &error)) { mongoc_stream_close (client_stream); mongoc_stream_destroy (client_stream); RETURN (NULL); } } #endif _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); _mongoc_array_init (&autoresponders, sizeof (autoresponder_handle_t)); again: /* loop, checking for requests to receive or replies to send */ bson_free (rpc); rpc = NULL; if (_mongoc_buffer_fill (&buffer, client_stream, 4, 10, &error) > 0) { assert (buffer.len >= 4); memcpy (&msg_len, buffer.data + buffer.off, 4); msg_len = BSON_UINT32_FROM_LE (msg_len); if (msg_len < 16) { MONGOC_WARNING ("No data"); GOTO (failure); } if (_mongoc_buffer_fill (&buffer, client_stream, (size_t) msg_len, -1, &error) == -1) { MONGOC_WARNING ("%s():%d: %s", BSON_FUNC, __LINE__, error.message); GOTO (failure); } assert (buffer.len >= (unsigned) msg_len); /* copies message from buffer */ request = request_new (&buffer, msg_len, server, client_stream, closure->port, replies); memmove (buffer.data, buffer.data + buffer.off + msg_len, buffer.len - msg_len); buffer.off = 0; buffer.len -= msg_len; mongoc_mutex_lock (&server->mutex); _mongoc_array_copy (&autoresponders, &server->autoresponders); mongoc_mutex_unlock (&server->mutex); test_suite_mock_server_log ("%5.2f %hu -> %hu %s", mock_server_get_uptime_sec (server), closure->port, server->port, request->as_str); /* run responders most-recently-added-first */ handled = false; for (i = server->autoresponders.len - 1; i >= 0; i--) { handle = _mongoc_array_index (&server->autoresponders, autoresponder_handle_t, i); if (handle.responder (request, handle.data)) { /* responder destroyed request and enqueued a reply in "replies" */ handled = true; request = NULL; break; } } if (!handled) { /* pass to the main thread via the queue */ requests = mock_server_get_queue (server); q_put (requests, (void *) request); } } if (_mock_server_stopping (server)) { GOTO (failure); } reply = q_get (replies, 10); if (reply) { _mock_server_reply_with_stream (server, reply, client_stream); _reply_destroy (reply); } if (_mock_server_stopping (server)) { GOTO (failure); } GOTO (again); failure: _mongoc_array_destroy (&autoresponders); _mongoc_buffer_destroy (&buffer); mongoc_stream_close (client_stream); mongoc_stream_destroy (client_stream); bson_free (rpc); bson_free (closure); _mongoc_buffer_destroy (&buffer); while ((reply = q_get_nowait (replies))) { _reply_destroy (reply); } q_destroy (replies); RETURN (NULL); }
mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_rpc (mongoc_async_cmd_t *acmd) { ssize_t bytes = _mongoc_buffer_try_append_from_stream ( &acmd->buffer, acmd->stream, acmd->bytes_to_read, 0); if (bytes <= 0 && mongoc_stream_should_retry (acmd->stream)) { return MONGOC_ASYNC_CMD_IN_PROGRESS; } if (bytes < 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to receive rpc bytes from server."); return MONGOC_ASYNC_CMD_ERROR; } if (bytes == 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Server closed connection."); return MONGOC_ASYNC_CMD_ERROR; } acmd->bytes_to_read = (size_t) (acmd->bytes_to_read - bytes); if (!acmd->bytes_to_read) { if (!_mongoc_rpc_scatter ( &acmd->rpc, acmd->buffer.data, acmd->buffer.len)) { bson_set_error (&acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server."); return MONGOC_ASYNC_CMD_ERROR; } if (BSON_UINT32_FROM_LE (acmd->rpc.header.opcode) == MONGOC_OPCODE_COMPRESSED) { uint8_t *buf = NULL; size_t len = BSON_UINT32_FROM_LE (acmd->rpc.compressed.uncompressed_size) + sizeof (mongoc_rpc_header_t); buf = bson_malloc0 (len); if (!_mongoc_rpc_decompress (&acmd->rpc, buf, len)) { bson_free (buf); bson_set_error (&acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Could not decompress server reply"); return MONGOC_ASYNC_CMD_ERROR; } _mongoc_buffer_destroy (&acmd->buffer); _mongoc_buffer_init (&acmd->buffer, buf, len, NULL, NULL); } _mongoc_rpc_swab_from_le (&acmd->rpc); if (!_mongoc_rpc_get_first_document (&acmd->rpc, &acmd->reply)) { bson_set_error (&acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server"); return MONGOC_ASYNC_CMD_ERROR; } acmd->reply_needs_cleanup = true; return MONGOC_ASYNC_CMD_SUCCESS; } return MONGOC_ASYNC_CMD_IN_PROGRESS; }