int mock_server_run (mock_server_t *server) { struct sockaddr_in saddr; mongoc_stream_t *stream; mongoc_thread_t thread; mongoc_socket_t *ssock; mongoc_socket_t *csock; void **closure; int optval; bson_return_val_if_fail (server, -1); bson_return_val_if_fail (!server->sock, -1); MONGOC_INFO ("Starting mock server on port %d.", server->port); ssock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); if (!ssock) { perror("Failed to create socket."); return -1; } optval = 1; mongoc_socket_setsockopt (ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); memset (&saddr, 0, sizeof saddr); saddr.sin_family = AF_INET; saddr.sin_port = htons(server->port); /* * TODO: Parse server->address. */ saddr.sin_addr.s_addr = htonl (INADDR_ANY); if (-1 == mongoc_socket_bind (ssock, (struct sockaddr *)&saddr, sizeof saddr)) { perror("Failed to bind socket"); return -1; } if (-1 == mongoc_socket_listen (ssock, 10)) { perror("Failed to put socket into listen mode"); return 3; } server->sock = ssock; mongoc_mutex_lock (&server->mutex); mongoc_cond_signal (&server->cond); mongoc_mutex_unlock (&server->mutex); for (;;) { csock = mongoc_socket_accept (server->sock, -1); if (!csock) { perror ("Failed to accept client socket"); break; } stream = mongoc_stream_socket_new (csock); closure = bson_malloc0 (sizeof(void*) * 2); closure[0] = server; closure[1] = stream; mongoc_thread_create (&thread, mock_server_worker, closure); } mongoc_socket_close (server->sock); server->sock = NULL; return 0; }
/** this function is meant to be run from ssl_test as a child thread * * It: * 1. spins up * 2. binds and listens to a random port * 3. notifies the client of its port through a condvar * 4. accepts a request * 5. reads a 32 bit length * 6. reads a string of that length * 7. echoes it back to the client * 8. shuts down */ static void * ssl_test_server (void *ptr) { ssl_test_data_t *data = (ssl_test_data_t *) ptr; mongoc_stream_t *sock_stream; mongoc_stream_t *ssl_stream; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; mongoc_socklen_t sock_len; char buf[4 * NUM_IOVECS]; ssize_t r; bson_error_t error; mongoc_iovec_t iov; struct sockaddr_in server_addr = {0}; int len; iov.iov_base = buf; iov.iov_len = sizeof buf; listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); BSON_ASSERT (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); server_addr.sin_port = htons (0); r = mongoc_socket_bind ( listen_sock, (struct sockaddr *) &server_addr, sizeof server_addr); BSON_ASSERT (r == 0); sock_len = sizeof (server_addr); r = mongoc_socket_getsockname ( listen_sock, (struct sockaddr *) &server_addr, &sock_len); BSON_ASSERT (r == 0); r = mongoc_socket_listen (listen_sock, 10); BSON_ASSERT (r == 0); mongoc_mutex_lock (&data->cond_mutex); data->server_port = ntohs (server_addr.sin_port); mongoc_cond_signal (&data->cond); mongoc_mutex_unlock (&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); BSON_ASSERT (conn_sock); sock_stream = mongoc_stream_socket_new (conn_sock); BSON_ASSERT (sock_stream); ssl_stream = mongoc_stream_tls_new_with_hostname (sock_stream, NULL, data->server, 0); if (!ssl_stream) { #ifdef MONGOC_ENABLE_SSL_OPENSSL unsigned long err = ERR_get_error (); #else unsigned long err = 42; #endif BSON_ASSERT (err); data->server_result->ssl_err = err; data->server_result->result = SSL_TEST_SSL_INIT; #ifdef MONGOC_ENABLE_SSL_OPENSSL MONGOC_ERROR ("ERRORED (line: %d): %s\n", __LINE__, ERR_error_string (ERR_get_error (), NULL)); #endif mongoc_stream_destroy (sock_stream); mongoc_socket_destroy (listen_sock); return NULL; } BSON_ASSERT (ssl_stream); r = mongoc_stream_tls_handshake_block ( ssl_stream, data->host, TIMEOUT, &error); if (!r) { unsigned long err = 43; MONGOC_ERROR ("ERRORED (line: %d): %s\n", __LINE__, error.message); #ifdef MONGOC_ENABLE_SSL_OPENSSL MONGOC_ERROR ("msg: %s\n", ERR_error_string (ERR_get_error (), NULL)); #endif data->server_result->ssl_err = err; data->server_result->result = SSL_TEST_SSL_HANDSHAKE; mongoc_socket_destroy (listen_sock); mongoc_stream_destroy (ssl_stream); return NULL; } r = mongoc_stream_readv (ssl_stream, &iov, 1, 4, TIMEOUT); if (r < 0) { data->server_result->err = errno; data->server_result->result = SSL_TEST_TIMEOUT; MONGOC_ERROR ( "ERRORED (line: %d): %s\n", __LINE__, "mongoc_stream_readv failed."); mongoc_stream_destroy (ssl_stream); mongoc_socket_destroy (listen_sock); return NULL; } BSON_ASSERT (r == 4); memcpy (&len, iov.iov_base, r); r = mongoc_stream_readv (ssl_stream, &iov, 1, len, TIMEOUT); BSON_ASSERT (r == len); iov.iov_len = r; mongoc_stream_writev (ssl_stream, &iov, 1, TIMEOUT); mongoc_stream_destroy (ssl_stream); mongoc_socket_destroy (listen_sock); data->server_result->result = SSL_TEST_SUCCESS; return NULL; }
/** this function is meant to be run from ssl_test as a child thread * * It: * 1. spins up * 2. binds and listens to a random port * 3. notifies the client of it's port through a condvar * 4. accepts a request * 5. reads a 32 bit length * 6. reads a string of that length * 7. echos it back to the client * 8. shuts down */ static void * ssl_test_server (void * ptr) { ssl_test_data_t *data = (ssl_test_data_t *)ptr; mongoc_stream_t *sock_stream; mongoc_stream_t *ssl_stream; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; socklen_t sock_len; char buf[1024]; ssize_t r; mongoc_iovec_t iov; struct sockaddr_in server_addr = { 0 }; int len; iov.iov_base = buf; iov.iov_len = sizeof buf; listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_ANY); server_addr.sin_port = htons (0); r = mongoc_socket_bind (listen_sock, (struct sockaddr *)&server_addr, sizeof server_addr); assert (r == 0); sock_len = sizeof(server_addr); r = mongoc_socket_getsockname (listen_sock, (struct sockaddr *)&server_addr, &sock_len); assert(r == 0); r = mongoc_socket_listen (listen_sock, 10); assert(r == 0); mongoc_mutex_lock(&data->cond_mutex); data->server_port = ntohs(server_addr.sin_port); mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); assert (conn_sock); sock_stream = mongoc_stream_socket_new (conn_sock); assert (sock_stream); ssl_stream = mongoc_stream_tls_new(sock_stream, data->server, 0); if (!ssl_stream) { unsigned long err = ERR_get_error(); assert(err); data->server_result->ssl_err = err; data->server_result->result = SSL_TEST_SSL_INIT; mongoc_stream_destroy (sock_stream); mongoc_socket_destroy (listen_sock); return NULL; } assert(ssl_stream); r = mongoc_stream_tls_do_handshake (ssl_stream, TIMEOUT); if (!r) { unsigned long err = ERR_get_error(); assert(err); data->server_result->ssl_err = err; data->server_result->result = SSL_TEST_SSL_HANDSHAKE; mongoc_socket_destroy (listen_sock); mongoc_stream_destroy(ssl_stream); return NULL; } r = mongoc_stream_readv(ssl_stream, &iov, 1, 4, TIMEOUT); if (r < 0) { #ifdef _WIN32 assert(errno == WSAETIMEDOUT); #else assert(errno == ETIMEDOUT); #endif data->server_result->err = errno; data->server_result->result = SSL_TEST_TIMEOUT; mongoc_stream_destroy(ssl_stream); mongoc_socket_destroy (listen_sock); return NULL; } assert(r == 4); memcpy(&len, iov.iov_base, r); r = mongoc_stream_readv(ssl_stream, &iov, 1, len, TIMEOUT); assert(r == len); iov.iov_len = r; mongoc_stream_writev(ssl_stream, &iov, 1, TIMEOUT); mongoc_stream_destroy(ssl_stream); mongoc_socket_destroy (listen_sock); data->server_result->result = SSL_TEST_SUCCESS; return NULL; }
/** run as a child thread by test_mongoc_tls_hangup * * It: * 1. spins up * 2. binds and listens to a random port * 3. notifies the client of its port through a condvar * 4. accepts a request * 5. reads a byte * 7. hangs up */ static void * ssl_error_server (void *ptr) { ssl_test_data_t *data = (ssl_test_data_t *)ptr; mongoc_stream_t *sock_stream; mongoc_stream_t *ssl_stream; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; socklen_t sock_len; char buf; ssize_t r; mongoc_iovec_t iov; struct sockaddr_in server_addr = { 0 }; iov.iov_base = &buf; iov.iov_len = 1; listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); server_addr.sin_port = htons (0); r = mongoc_socket_bind (listen_sock, (struct sockaddr *)&server_addr, sizeof server_addr); assert (r == 0); sock_len = sizeof (server_addr); r = mongoc_socket_getsockname (listen_sock, (struct sockaddr *)&server_addr, &sock_len); assert (r == 0); r = mongoc_socket_listen (listen_sock, 10); assert (r == 0); mongoc_mutex_lock (&data->cond_mutex); data->server_port = ntohs (server_addr.sin_port); mongoc_cond_signal (&data->cond); mongoc_mutex_unlock (&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); assert (conn_sock); sock_stream = mongoc_stream_socket_new (conn_sock); assert (sock_stream); ssl_stream = mongoc_stream_tls_new (sock_stream, data->server, 0); assert (ssl_stream); switch (data->behavior) { case SSL_TEST_BEHAVIOR_STALL_BEFORE_HANDSHAKE: _mongoc_usleep (data->handshake_stall_ms * 1000); break; case SSL_TEST_BEHAVIOR_HANGUP_AFTER_HANDSHAKE: r = mongoc_stream_tls_do_handshake (ssl_stream, TIMEOUT); assert (r); r = mongoc_stream_readv (ssl_stream, &iov, 1, 1, TIMEOUT); assert (r == 1); break; case SSL_TEST_BEHAVIOR_NORMAL: default: fprintf (stderr, "unimplemented ssl_test_behavior_t\n"); abort (); } data->server_result->result = SSL_TEST_SUCCESS; mongoc_stream_close (ssl_stream); mongoc_stream_destroy (ssl_stream); mongoc_socket_destroy (listen_sock); return NULL; }
static void * socket_test_server (void *data_) { socket_test_data_t *data = (socket_test_data_t *)data_; struct sockaddr_in server_addr = { 0 }; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; mongoc_stream_t *stream; mongoc_iovec_t iov; socklen_t sock_len; ssize_t r; char buf[5]; iov.iov_base = buf; iov.iov_len = sizeof (buf); listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); server_addr.sin_port = htons (0); r = mongoc_socket_bind (listen_sock, (struct sockaddr *)&server_addr, sizeof server_addr); assert (r == 0); sock_len = sizeof(server_addr); r = mongoc_socket_getsockname (listen_sock, (struct sockaddr *)&server_addr, &sock_len); assert(r == 0); r = mongoc_socket_listen (listen_sock, 10); assert(r == 0); mongoc_mutex_lock(&data->cond_mutex); data->server_port = ntohs(server_addr.sin_port); mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); assert (conn_sock); stream = mongoc_stream_socket_new (conn_sock); assert (stream); r = mongoc_stream_readv (stream, &iov, 1, 5, TIMEOUT); assert (r == 5); assert (strcmp (buf, "ping") == 0); strcpy (buf, "pong"); r = mongoc_stream_writev (stream, &iov, 1, TIMEOUT); assert (r == 5); mongoc_stream_destroy (stream); mongoc_mutex_lock(&data->cond_mutex); data->closed_socket = true; mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); mongoc_socket_destroy (listen_sock); return NULL; }
static void * sendv_test_server (void *data_) { socket_test_data_t *data = (socket_test_data_t *)data_; struct sockaddr_in server_addr = { 0 }; mongoc_socket_t *listen_sock; mongoc_socket_t *conn_sock; mongoc_stream_t *stream; mongoc_iovec_t iov; socklen_t sock_len; int amount = 0; ssize_t r; char *buf = (char *)bson_malloc (gFourMB); iov.iov_base = buf; iov.iov_len = gFourMB; listen_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (listen_sock); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); server_addr.sin_port = htons (0); r = mongoc_socket_bind (listen_sock, (struct sockaddr *)&server_addr, sizeof server_addr); assert (r == 0); sock_len = sizeof(server_addr); r = mongoc_socket_getsockname (listen_sock, (struct sockaddr *)&server_addr, &sock_len); assert(r == 0); r = mongoc_socket_listen (listen_sock, 10); assert(r == 0); mongoc_mutex_lock(&data->cond_mutex); data->server_port = ntohs(server_addr.sin_port); mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); conn_sock = mongoc_socket_accept (listen_sock, -1); assert (conn_sock); stream = mongoc_stream_socket_new (conn_sock); assert (stream); /* Wait until the client has pushed so much data he can't write more */ mongoc_mutex_lock(&data->cond_mutex); while (! data->amount) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } amount = data->amount; data->amount = 0; mongoc_mutex_unlock(&data->cond_mutex); /* Start reading everything off the socket to unblock the client */ do { r = mongoc_stream_readv (stream, &iov, 1, amount, WAIT); if (r > 0) { amount -= r; } else if (MONGOC_ERRNO_IS_AGAIN(errno)) { continue; } else { fprintf(stderr, "r: %"PRIu64" , errno: %d", (uint64_t)r, conn_sock->errno_); assert (r == amount); } } while (amount > 0); /* Allow the client to finish all its writes */ mongoc_mutex_lock(&data->cond_mutex); while (! data->amount) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } /* amount is likely negative value now, we've read more then caused the original blocker */ amount += data->amount; data->amount = 0; mongoc_mutex_unlock(&data->cond_mutex); do { r = mongoc_stream_readv (stream, &iov, 1, amount, WAIT); if (r > 0) { amount -= r; } else if (MONGOC_ERRNO_IS_AGAIN(errno)) { continue; } else { fprintf(stderr, "r: %"PRIu64" , errno: %d", (uint64_t)r, errno); assert (r == amount); } } while (amount > 0); ASSERT_CMPINT(0, ==, amount); mongoc_stream_destroy (stream); mongoc_socket_destroy (listen_sock); return NULL; }