Example #1
0
void Connection::on_connect(Connector* connector) {
  Connection* connection = static_cast<Connection*>(connector->data());

  if (connection->connect_timer_ == NULL) {
    return; // Timed out
  }

  if (connector->status() == 0) {
    LOG_DEBUG("Connected to host %s", connection->addr_string_.c_str());

    if (connection->ssl_session_) {
      uv_read_start(copy_cast<uv_tcp_t*, uv_stream_t*>(&connection->socket_),
                    Connection::alloc_buffer_ssl, Connection::on_read_ssl);
    } else {
      uv_read_start(copy_cast<uv_tcp_t*, uv_stream_t*>(&connection->socket_),
                    Connection::alloc_buffer, Connection::on_read);
    }

    connection->state_ = CONNECTION_STATE_CONNECTED;

    if (connection->ssl_session_) {
      connection->ssl_handshake();
    } else {
      connection->on_connected();
    }
  } else {
    LOG_ERROR("Connect error '%s' on host %s",
              UV_ERRSTR(connector->status()),
              connection->addr_string_.c_str() );
    connection->notify_error("Unable to connect");
  }
}
Example #2
0
void Connection::SslHandshakeWriter::on_write(uv_write_t* req, int status) {
  SslHandshakeWriter* writer = static_cast<SslHandshakeWriter*>(req->data);
  if (status != 0) {
    writer->connection_->notify_error("Write error '" +
                                      std::string(UV_ERRSTR(status, writer->connection_->loop_)) +
                                      "'");
  }
  delete writer;
}
Example #3
0
void Connection::on_read_ssl(uv_stream_t* client, ssize_t nread, uv_buf_t buf) {
#else
void Connection::on_read_ssl(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) {
#endif
  Connection* connection = static_cast<Connection*>(client->data);

  SslSession* ssl_session = connection->ssl_session_.get();
  assert(ssl_session != NULL);

  if (nread < 0) {
#if UV_VERSION_MAJOR == 0
    if (uv_last_error(connection->loop_).code != UV_EOF) {
#else
    if (nread != UV_EOF) {
#endif
      connection->notify_error("Read error '" +
                               std::string(UV_ERRSTR(nread, connection->loop_)) +
                               "'");
    } else {
      connection->defunct();
    }
    return;
  }

  ssl_session->incoming().commit(nread);

  if (ssl_session->is_handshake_done()) {
    char buf[SSL_READ_SIZE];
    int rc =  0;
    while ((rc = ssl_session->decrypt(buf, sizeof(buf))) > 0) {
      connection->consume(buf, rc);
    }
    if (rc <= 0 && ssl_session->has_error()) {
      connection->notify_error("Unable to decrypt data: " + ssl_session->error_message(),
                               CONNECTION_ERROR_SSL);
    }
  } else {
    connection->ssl_handshake();
  }
}

void Connection::on_timeout(Timer* timer) {
  Handler* handler = static_cast<Handler*>(timer->data());
  Connection* connection = handler->connection();
  LOG_INFO("Request timed out to host %s on connection(%p)",
           connection->host_->address_string().c_str(),
           static_cast<void*>(connection));
  // TODO (mpenick): We need to handle the case where we have too many
  // timeout requests and we run out of stream ids. The java-driver
  // uses a threshold to defunct the connection.
  handler->set_state(Handler::REQUEST_STATE_TIMEOUT);
  handler->on_timeout();

  connection->metrics_->request_timeouts.inc();
}
Example #4
0
void Connection::on_connect(Connector* connector) {
  Connection* connection = static_cast<Connection*>(connector->data());

  if (!connection->connect_timer_.is_running()) {
    return; // Timed out
  }

  if (connector->status() == 0) {
    LOG_DEBUG("Connected to host %s on connection(%p)",
              connection->host_->address_string().c_str(),
              static_cast<void*>(connection));

#ifdef HAVE_NOSIGPIPE
    // This must be done after connection for the socket file descriptor to be
    // valid.
    uv_os_fd_t fd = 0;
    int enabled = 1;
    if (uv_fileno(copy_cast<uv_tcp_t*, uv_handle_t*>(&connection->socket_), &fd) != 0 ||
        setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&enabled, sizeof(int)) != 0) {
      LOG_WARN("Unable to set socket option SO_NOSIGPIPE for host %s",
               connection->host_->address_string().c_str());
    }
#endif

    if (connection->ssl_session_) {
      uv_read_start(copy_cast<uv_tcp_t*, uv_stream_t*>(&connection->socket_),
                    Connection::alloc_buffer_ssl, Connection::on_read_ssl);
    } else {
      uv_read_start(copy_cast<uv_tcp_t*, uv_stream_t*>(&connection->socket_),
                    Connection::alloc_buffer, Connection::on_read);
    }

    connection->set_state(CONNECTION_STATE_CONNECTED);

    if (connection->ssl_session_) {
      connection->ssl_handshake();
    } else {
      connection->on_connected();
    }
  } else {
    connection->notify_error("Connect error '" +
                             std::string(UV_ERRSTR(connector->status(), connection->loop_)) +
                             "'");
  }
}
Example #5
0
void Connection::on_read(uv_stream_t* client, ssize_t nread, uv_buf_t buf) {
#else
void Connection::on_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) {
#endif
  Connection* connection = static_cast<Connection*>(client->data);

  if (nread < 0) {
#if UV_VERSION_MAJOR == 0
    if (uv_last_error(connection->loop_).code != UV_EOF) {
#else
    if (nread != UV_EOF) {
#endif
      connection->notify_error("Read error '" +
                               std::string(UV_ERRSTR(nread, connection->loop_)) +
                               "'");
    } else {
      connection->defunct();
    }

#if UV_VERSION_MAJOR == 0
    connection->internal_reuse_buffer(buf);
#else
    connection->internal_reuse_buffer(*buf);
#endif
    return;
  }

#if UV_VERSION_MAJOR == 0
  connection->consume(buf.base, nread);
  connection->internal_reuse_buffer(buf);
#else
  connection->consume(buf->base, nread);
  connection->internal_reuse_buffer(*buf);
#endif
}

#if UV_VERSION_MAJOR == 0
uv_buf_t Connection::alloc_buffer_ssl(uv_handle_t* handle, size_t suggested_size) {
  Connection* connection = static_cast<Connection*>(handle->data);
  char* base = connection->ssl_session_->incoming().peek_writable(&suggested_size);
  return uv_buf_init(base, suggested_size);
}
Example #6
0
void Connection::PendingWriteBase::on_write(uv_write_t* req, int status) {
  PendingWrite* pending_write = static_cast<PendingWrite*>(req->data);

  Connection* connection = static_cast<Connection*>(pending_write->connection_);

  while (!pending_write->handlers_.is_empty()) {
    Handler* handler = pending_write->handlers_.front();

    pending_write->handlers_.remove(handler);

    switch (handler->state()) {
      case Handler::REQUEST_STATE_WRITING:
        if (status == 0) {
          handler->set_state(Handler::REQUEST_STATE_READING);
          connection->pending_reads_.add_to_back(handler);
        } else {
          if (!connection->is_closing()) {
            connection->notify_error("Write error '" +
                                     std::string(UV_ERRSTR(status, connection->loop_)) +
                                     "'");
            connection->defunct();
          }

          connection->stream_manager_.release(handler->stream());
          handler->stop_timer();
          handler->set_state(Handler::REQUEST_STATE_DONE);
          handler->on_error(CASS_ERROR_LIB_WRITE_ERROR,
                            "Unable to write to socket");
          handler->dec_ref();
        }
        break;

      case Handler::REQUEST_STATE_TIMEOUT_WRITE_OUTSTANDING:
        // The read may still come back, handle cleanup there
        handler->set_state(Handler::REQUEST_STATE_TIMEOUT);
        connection->pending_reads_.add_to_back(handler);
        break;

      case Handler::REQUEST_STATE_READ_BEFORE_WRITE:
        // The read callback happened before the write callback
        // returned. This is now responsible for cleanup.
        handler->stop_timer();
        handler->set_state(Handler::REQUEST_STATE_DONE);
        handler->dec_ref();
        break;

      case Handler::REQUEST_STATE_RETRY_WRITE_OUTSTANDING:
        handler->stop_timer();
        handler->retry();
        handler->dec_ref();
        break;

      default:
        assert(false && "Invalid request state after write finished");
        break;
    }
  }

  connection->pending_writes_size_ -= pending_write->size();
  if (connection->pending_writes_size_ <
      connection->config_.write_bytes_low_water_mark() &&
      connection->state_ == CONNECTION_STATE_OVERWHELMED) {
    connection->set_state(CONNECTION_STATE_READY);
  }

  connection->pending_writes_.remove(pending_write);
  delete pending_write;

  connection->flush();
}