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);
}
示例#6
0
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_);
}
示例#7
0
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;
}