static int _mongoc_stream_tls_bio_read (BIO *b, char *buf, int len) { mongoc_stream_tls_t *tls; int ret; BSON_ASSERT (b); BSON_ASSERT (buf); if (!(tls = b->ptr)) { return -1; } errno = 0; ret = (int)mongoc_stream_read (tls->base_stream, buf, len, 0, tls->timeout_msec); BIO_clear_retry_flags (b); if ((ret < 0) && MONGOC_ERRNO_IS_AGAIN (errno)) { BIO_set_retry_read (b); } return ret; }
static int _mongoc_stream_tls_bio_write (BIO *b, const char *buf, int len) { mongoc_stream_tls_t *tls; mongoc_iovec_t iov; int ret; BSON_ASSERT (b); BSON_ASSERT (buf); if (!(tls = b->ptr)) { return -1; } iov.iov_base = (void *)buf; iov.iov_len = len; errno = 0; ret = (int)mongoc_stream_writev (tls->base_stream, &iov, 1, tls->timeout_msec); BIO_clear_retry_flags (b); if ((ret < 0) && MONGOC_ERRNO_IS_AGAIN (errno)) { BIO_set_retry_write (b); } return ret; }
int mongoc_stream_tls_openssl_bio_read (BIO *b, char *buf, int len) { mongoc_stream_tls_t *tls; int ret; BSON_ASSERT (b); BSON_ASSERT (buf); ENTRY; tls = (mongoc_stream_tls_t *) BIO_get_data (b); if (!tls) { RETURN (-1); } errno = 0; ret = (int) mongoc_stream_read ( tls->base_stream, buf, len, 0, tls->timeout_msec); BIO_clear_retry_flags (b); if ((ret <= 0) && MONGOC_ERRNO_IS_AGAIN (errno)) { BIO_set_retry_read (b); } RETURN (ret); }
static bool _mongoc_stream_socket_should_retry (mongoc_stream_t *stream) /* IN */ { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; ENTRY; BSON_ASSERT (ss); BSON_ASSERT (ss->sock); RETURN (MONGOC_ERRNO_IS_AGAIN (ss->sock->errno_)); }
int mongoc_stream_tls_openssl_bio_write (BIO *b, const char *buf, int len) { mongoc_stream_tls_t *tls; mongoc_iovec_t iov; int ret; ENTRY; BSON_ASSERT (b); BSON_ASSERT (buf); tls = (mongoc_stream_tls_t *)b->ptr; if (!tls) { RETURN (-1); } iov.iov_base = (void *)buf; iov.iov_len = len; errno = 0; TRACE("mongoc_stream_writev is expected to write: %d", len); ret = (int)mongoc_stream_writev (tls->base_stream, &iov, 1, tls->timeout_msec); BIO_clear_retry_flags (b); if (len > ret) { TRACE("Returned short write: %d of %d", ret, len); } else { TRACE("Completed the %d", ret); } if (ret <= 0 && MONGOC_ERRNO_IS_AGAIN (errno)) { TRACE("%s", "Requesting a retry"); BIO_set_retry_write (b); } RETURN (ret); }
static bool _mongoc_socket_errno_is_again (mongoc_socket_t *sock) /* IN */ { TRACE ("errno is: %d", sock->errno_); return MONGOC_ERRNO_IS_AGAIN (sock->errno_); }
static bool _mongoc_socket_wait (mongoc_socket_t *sock, /* IN */ int events, /* IN */ int64_t expire_at) /* IN */ { #ifdef _WIN32 fd_set read_fds; fd_set write_fds; fd_set error_fds; struct timeval timeout_tv; #else struct pollfd pfd; #endif int ret; int timeout; int64_t now; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (events); #ifdef _WIN32 FD_ZERO (&read_fds); FD_ZERO (&write_fds); FD_ZERO (&error_fds); if (events & POLLIN) { FD_SET (sock->sd, &read_fds); } if (events & POLLOUT) { FD_SET (sock->sd, &write_fds); } FD_SET (sock->sd, &error_fds); #else pfd.fd = sock->sd; pfd.events = events | POLLERR | POLLHUP; pfd.revents = 0; #endif now = bson_get_monotonic_time (); for (;;) { if (expire_at < 0) { timeout = -1; } else if (expire_at == 0) { timeout = 0; } else { timeout = (int) ((expire_at - now) / 1000L); if (timeout < 0) { timeout = 0; } } #ifdef _WIN32 if (timeout == -1) { /* not WSAPoll: daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken */ ret = select (0 /*unused*/, &read_fds, &write_fds, &error_fds, NULL); } else { timeout_tv.tv_sec = timeout / 1000; timeout_tv.tv_usec = (timeout % 1000) * 1000; ret = select ( 0 /*unused*/, &read_fds, &write_fds, &error_fds, &timeout_tv); } if (ret == SOCKET_ERROR) { _mongoc_socket_capture_errno (sock); ret = -1; } else if (FD_ISSET (sock->sd, &error_fds)) { errno = WSAECONNRESET; ret = -1; } #else ret = poll (&pfd, 1, timeout); #endif if (ret > 0) { /* Something happened, so return that */ #ifdef _WIN32 return (FD_ISSET (sock->sd, &read_fds) || FD_ISSET (sock->sd, &write_fds)); #else RETURN (0 != (pfd.revents & events)); #endif } else if (ret < 0) { /* poll itself failed */ TRACE ("errno is: %d", errno); if (MONGOC_ERRNO_IS_AGAIN (errno)) { now = bson_get_monotonic_time (); if (expire_at < now) { _mongoc_socket_capture_errno (sock); RETURN (false); } else { continue; } } else { /* poll failed for some non-transient reason */ _mongoc_socket_capture_errno (sock); RETURN (false); } } else { /* ret == 0, poll timed out */ if (timeout) { mongoc_counter_streams_timeout_inc (); } #ifdef _WIN32 sock->errno_ = timeout ? WSAETIMEDOUT : EAGAIN; #else sock->errno_ = timeout ? ETIMEDOUT : EAGAIN; #endif RETURN (false); } } }
static void * sendv_test_client (void *data_) { socket_test_data_t *data = (socket_test_data_t *)data_; mongoc_socket_t *conn_sock; ssize_t r; int i; int amount = 0; struct sockaddr_in server_addr = { 0 }; mongoc_stream_t *stream; mongoc_iovec_t iov; bool done = false; char *buf = (char *)bson_malloc (gFourMB); memset (buf, 'a', (gFourMB)- 1); buf[gFourMB - 1] = '\0'; iov.iov_base = buf; iov.iov_len = gFourMB; conn_sock = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); assert (conn_sock); mongoc_mutex_lock(&data->cond_mutex); while (! data->server_port) { mongoc_cond_wait(&data->cond, &data->cond_mutex); } mongoc_mutex_unlock(&data->cond_mutex); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(data->server_port); server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = mongoc_socket_connect (conn_sock, (struct sockaddr *)&server_addr, sizeof(server_addr), -1); assert (r == 0); stream = mongoc_stream_socket_new (conn_sock); for (i = 0; i < 5; i++) { r = mongoc_stream_writev (stream, &iov, 1, WAIT); if (r > 0) { amount += r; } if (r != gFourMB) { if (MONGOC_ERRNO_IS_AGAIN(conn_sock->errno_)) { if (!done) { mongoc_mutex_lock(&data->cond_mutex); data->amount = amount; amount = 0; mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); done = true; } } else { assert (r == gFourMB); } } } assert(true == done); mongoc_mutex_lock(&data->cond_mutex); data->amount = amount; mongoc_cond_signal(&data->cond); mongoc_mutex_unlock(&data->cond_mutex); mongoc_stream_destroy (stream); 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; }