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"); } }
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; }
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(); }
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_)) + "'"); } }
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); }
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(); }