int as_event_create_socket(as_event_command* cmd) { // Create a non-blocking socket. int fd = as_socket_create_nb(); if (fd < 0) { as_error err; as_error_set_message(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Failed to create non-blocking socket"); as_event_connect_error(cmd, &err, fd); return -1; } if (cmd->pipe_listener != NULL) { if (as_event_send_buffer_size) { if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &as_event_send_buffer_size, sizeof(as_event_send_buffer_size)) < 0) { as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Failed to configure pipeline send buffer. size %d error %d (%s)", as_event_send_buffer_size, errno, strerror(errno)); as_event_connect_error(cmd, &err, fd); return -1; } } if (as_event_recv_buffer_size) { if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &as_event_recv_buffer_size, sizeof(as_event_recv_buffer_size)) < 0) { as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Failed to configure pipeline receive buffer. size %d error %d (%s)", as_event_recv_buffer_size, errno, strerror(errno)); as_event_connect_error(cmd, &err, fd); return -1; } } #if defined(__linux__) if (as_event_recv_buffer_size) { if (setsockopt(fd, SOL_TCP, TCP_WINDOW_CLAMP, &as_event_recv_buffer_size, sizeof(as_event_recv_buffer_size)) < 0) { as_error err; as_error_set_message(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Failed to configure pipeline TCP window."); as_event_connect_error(cmd, &err, fd); return -1; } } #endif int arg = 0; if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &arg, sizeof(arg)) < 0) { as_error err; as_error_set_message(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Failed to configure pipeline Nagle algorithm."); as_event_connect_error(cmd, &err, fd); return -1; } } return fd; }
static void as_uv_connect(as_event_command* cmd) { int fd = as_event_create_socket(cmd); if (fd < 0) { return; } as_event_connection* conn = cmd->conn; uv_tcp_t* socket = &conn->socket; int status = uv_tcp_init(cmd->event_loop->loop, socket); if (status) { as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "uv_tcp_init failed: %s", uv_strerror(status)); // Call standard event connection error handler because as_uv_connect_error() requires that // uv_tcp_init() has already succeeded. as_event_connect_error(cmd, &err, fd); return; } // Define externally created fd to uv_tcp_t. status = uv_tcp_open(socket, fd); if (status) { as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "uv_tcp_open failed: %s", uv_strerror(status)); // Close fd directly because we created it outside of libuv and uv_tcp_t does not know about it here. close(fd); as_uv_connect_error(cmd, &err); return; } socket->data = conn; conn->req.connect.data = cmd; as_node* node = cmd->node; as_address* primary = as_vector_get(&node->addresses, node->address_index); status = uv_tcp_connect(&conn->req.connect, socket, (struct sockaddr*)&primary->addr, as_uv_connected); if (status) { as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "uv_tcp_connect failed: %s", uv_strerror(status)); as_uv_connect_error(cmd, &err); } }
static void as_ev_connect(as_event_command* cmd) { int fd = as_event_create_socket(cmd); if (fd < 0) { return; } // Try primary address. as_node* node = cmd->node; as_address* primary = as_vector_get(&node->addresses, node->address_index); // Attempt non-blocking connection. if (connect(fd, (struct sockaddr*)&primary->addr, sizeof(struct sockaddr)) == 0) { as_ev_watcher_init(cmd, fd); return; } // Check if connection is in progress. if (errno == EINPROGRESS) { as_ev_watcher_init(cmd, fd); return; } // Try other addresses. as_vector* addresses = &node->addresses; for (uint32_t i = 0; i < addresses->size; i++) { as_address* address = as_vector_get(addresses, i); // Address points into alias array, so pointer comparison is sufficient. if (address != primary) { if (connect(fd, (struct sockaddr*)&address->addr, sizeof(struct sockaddr)) == 0) { // Replace invalid primary address with valid alias. // Other threads may not see this change immediately. // It's just a hint, not a requirement to try this new address first. as_log_debug("Change node address %s %s:%d", node->name, address->name, (int)cf_swap_from_be16(address->addr.sin_port)); ck_pr_store_32(&node->address_index, i); as_ev_watcher_init(cmd, fd); return; } // Check if connection is in progress. if (errno == EINPROGRESS) { // Replace invalid primary address with valid alias. // Other threads may not see this change immediately. // It's just a hint, not a requirement to try this new address first. as_log_debug("Change node address %s %s:%d", node->name, address->name, (int)cf_swap_from_be16(address->addr.sin_port)); ck_pr_store_32(&node->address_index, i); // Connection hasn't finished. as_ev_watcher_init(cmd, fd); return; } } } // Failed to start a connection on any socket address. as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Failed to connect: %s %s:%d", node->name, primary->name, (int)cf_swap_from_be16(primary->addr.sin_port)); as_event_connect_error(cmd, &err, fd); }