static as_status as_command_parse_udf_failure(uint8_t* p, as_error* err, as_msg* msg, as_status status) { p = as_command_ignore_fields(p, msg->n_fields); as_bin_name name; for (uint32_t i = 0; i < msg->n_ops; i++) { uint32_t op_size = cf_swap_from_be32(*(uint32_t*)p); p += 5; uint8_t type = *p; p += 2; uint8_t name_size = *p++; uint8_t name_len = (name_size <= AS_BIN_NAME_MAX_LEN)? name_size : AS_BIN_NAME_MAX_LEN; memcpy(name, p, name_len); name[name_len] = 0; p += name_size; uint32_t value_size = (op_size - (name_size + 4)); if (strcmp(name, "FAILURE") == 0) { as_val* val = 0; as_command_parse_value(p, type, value_size, &val); status = as_command_parse_udf_error(err, status, val); as_val_destroy(val); return status; } p += value_size; } return as_error_set_message(err, status, as_error_string(status)); }
as_status as_authenticate(as_error* err, int fd, const char* user, const char* credential, uint64_t deadline_ms) { uint8_t buffer[AS_STACK_BUF_SIZE]; uint8_t* p = buffer + 8; p = as_admin_write_header(p, AUTHENTICATE, 2); p = as_admin_write_field_string(p, USER, user); p = as_admin_write_field_string(p, CREDENTIAL, credential); as_status status = as_admin_send(err, fd, buffer, p, deadline_ms); if (status) { return status; } status = as_socket_read_deadline(err, fd, buffer, HEADER_SIZE, deadline_ms); if (status) { return status; } status = buffer[RESULT_CODE]; if (status) { as_error_set_message(err, status, as_error_string(status)); } return status; }
static void as_uv_auth_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { if (uv_is_closing((uv_handle_t*)stream)) { return; } as_event_command* cmd = as_uv_auth_get_command(stream->data); if (nread < 0) { uv_read_stop(stream); as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Authenticate socket read failed: %zd", nread); as_event_socket_error(cmd, &err); return; } cmd->pos += nread; if (cmd->pos < cmd->len) { // Read not finished. return; } if (cmd->state == AS_ASYNC_STATE_AUTH_READ_HEADER) { as_event_set_auth_parse_header(cmd); if (cmd->len > cmd->capacity) { uv_read_stop(stream); as_error err; as_error_update(&err, AEROSPIKE_ERR_CLIENT, "Authenticate response size is corrupt: %u", cmd->auth_len); as_event_socket_error(cmd, &err); return; } return; } // Done reading authentication data. uv_read_stop(stream); // Parse authentication response. cmd->len -= cmd->auth_len; uint8_t code = cmd->buf[cmd->len + AS_ASYNC_AUTH_RETURN_CODE]; if (code) { // Can't authenticate socket, so must close it. as_error err; as_error_update(&err, code, "Authentication failed: %s", as_error_string(code)); as_event_socket_error(cmd, &err); return; } cmd->pos = 0; as_uv_command_write_start(cmd, stream); }
static void as_cluster_find_nodes_to_add(as_cluster* cluster, as_vector* /* <as_host> */ friends, as_vector* /* <as_node*> */ nodes_to_add) { as_error err; as_error_init(&err); as_vector addresses; as_vector_inita(&addresses, sizeof(struct sockaddr_in), 5); as_node_info node_info; for (uint32_t i = 0; i < friends->size; i++) { as_host* friend = as_vector_get(friends, i); as_vector_clear(&addresses); as_status status = as_lookup(&err, friend->name, friend->port, &addresses); if (status != AEROSPIKE_OK) { as_log_warn("%s %s", as_error_string(status), err.message); continue; } for (uint32_t i = 0; i < addresses.size; i++) { struct sockaddr_in* addr = as_vector_get(&addresses, i); status = as_lookup_node(cluster, &err, addr, &node_info); if (status == AEROSPIKE_OK) { as_node* node = as_cluster_find_node(cluster->nodes, nodes_to_add, node_info.name); if (node) { // Duplicate node name found. This usually occurs when the server // services list contains both internal and external IP addresses // for the same node. Add new host to list of alias filters // and do not add new node. as_close(node_info.fd); as_address* a = as_node_get_address_full(node); as_log_info("Node %s:%d already exists with nodeid %s and address %s:%d", friend->name, friend->port, node->name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); node->friends++; as_node_add_address(node, friend, addr); continue; } node = as_node_create(cluster, friend, addr, &node_info); as_address* a = as_node_get_address_full(node); as_log_info("Add node %s %s:%d", node_info.name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); as_vector_append(nodes_to_add, &node); } else { as_log_warn("Failed to connect to friend %s:%d. %s %s", friend->name, friend->port, as_error_string(status), err.message); } }
static as_status as_admin_read_blocks(as_error* err, int fd, uint64_t deadline_ms, as_admin_parse_fn parse_fn, as_vector* list) { as_status status = AEROSPIKE_OK; uint8_t* buf = 0; size_t capacity = 0; while (true) { // Read header as_proto proto; status = as_socket_read_deadline(err, fd, (uint8_t*)&proto, sizeof(as_proto), deadline_ms); if (status) { break; } as_proto_swap_from_be(&proto); size_t size = proto.sz; if (size > 0) { // Prepare buffer if (size > capacity) { as_command_free(buf, capacity); capacity = size; buf = as_command_init(capacity); } // Read remaining message bytes in group status = as_socket_read_deadline(err, fd, buf, size, deadline_ms); if (status) { break; } status = parse_fn(err, buf, size, list); if (status != AEROSPIKE_OK) { if (status == AEROSPIKE_QUERY_END) { status = AEROSPIKE_OK; } else { as_error_set_message(err, status, as_error_string(status)); } break; } } } as_command_free(buf, capacity); return status; }
static as_status as_admin_execute(aerospike* as, as_error* err, const as_policy_admin* policy, uint8_t* buffer, uint8_t* end) { uint32_t timeout_ms = (policy)? policy->timeout : as->config.policies.admin.timeout; if (timeout_ms <= 0) { timeout_ms = DEFAULT_TIMEOUT; } uint64_t deadline_ms = as_socket_deadline(timeout_ms); as_cluster* cluster = as->cluster; as_node* node = as_node_get_random(cluster); if (! node) { return as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to find server node."); } int fd; as_status status = as_node_get_connection(err, node, deadline_ms, &fd); if (status) { as_node_release(node); return status; } status = as_admin_send(err, fd, buffer, end, deadline_ms); if (status) { as_node_close_connection(node, fd); as_node_release(node); return status; } status = as_socket_read_deadline(err, fd, buffer, HEADER_SIZE, deadline_ms); if (status) { as_node_close_connection(node, fd); as_node_release(node); return status; } as_node_put_connection(node, fd); as_node_release(node); status = buffer[RESULT_CODE]; if (status) { return as_error_set_message(err, status, as_error_string(status)); } return status; }
bool as_event_command_parse_result(as_event_command* cmd) { as_msg* msg = (as_msg*)cmd->buf; as_msg_swap_header_from_be(msg); uint8_t* p = cmd->buf + sizeof(as_msg); as_status status = msg->result_code; switch (status) { case AEROSPIKE_OK: { as_record rec; if (msg->n_ops < 1000) { as_record_inita(&rec, msg->n_ops); } else { as_record_init(&rec, msg->n_ops); } rec.gen = msg->generation; rec.ttl = cf_server_void_time_to_ttl(msg->record_ttl); p = as_command_ignore_fields(p, msg->n_fields); as_command_parse_bins(&rec, p, msg->n_ops, cmd->deserialize); as_event_response_complete(cmd); ((as_async_record_command*)cmd)->listener(0, &rec, cmd->udata, cmd->event_loop); as_event_command_release(cmd); as_record_destroy(&rec); break; } case AEROSPIKE_ERR_UDF: { as_error err; as_command_parse_udf_failure(p, &err, msg, status); as_event_response_error(cmd, &err); break; } default: { as_error err; as_error_set_message(&err, status, as_error_string(status)); as_event_response_error(cmd, &err); break; } } return true; }
bool as_event_command_parse_header(as_event_command* cmd) { as_msg* msg = (as_msg*)cmd->buf; if (msg->result_code == AEROSPIKE_OK) { as_event_response_complete(cmd); ((as_async_write_command*)cmd)->listener(0, cmd->udata, cmd->event_loop); as_event_command_release(cmd); } else { as_error err; as_error_set_message(&err, msg->result_code, as_error_string(msg->result_code)); as_event_response_error(cmd, &err); } return true; }
static bool as_scan_parse_records_async(as_event_command* cmd) { as_error err; as_event_executor* executor = cmd->udata; // udata is overloaded to contain executor. uint8_t* p = cmd->buf; uint8_t* end = p + cmd->len; while (p < end) { as_msg* msg = (as_msg*)p; as_msg_swap_header_from_be(msg); if (msg->result_code) { // Special case - if we scan a set name that doesn't exist on a // node, it will return "not found". if (msg->result_code == AEROSPIKE_ERR_RECORD_NOT_FOUND) { as_event_query_complete(cmd); return true; } as_error_set_message(&err, msg->result_code, as_error_string(msg->result_code)); as_event_response_error(cmd, &err); return true; } p += sizeof(as_msg); if (msg->info3 & AS_MSG_INFO3_LAST) { as_event_query_complete(cmd); return true; } if (! executor->valid) { as_error_set_message(&err, AEROSPIKE_ERR_CLIENT_ABORT, ""); as_event_response_error(cmd, &err); return true; } if (as_scan_parse_record_async(cmd, &p, msg, &err) != AEROSPIKE_OK) { as_event_response_error(cmd, &err); return true; } } return false; }
bool as_event_command_parse_success_failure(as_event_command* cmd) { as_msg* msg = (as_msg*)cmd->buf; as_msg_swap_header_from_be(msg); uint8_t* p = cmd->buf + sizeof(as_msg); as_status status = msg->result_code; switch (status) { case AEROSPIKE_OK: { as_error err; as_val* val = 0; status = as_command_parse_success_failure_bins(&p, &err, msg, &val); if (status == AEROSPIKE_OK) { as_event_response_complete(cmd); ((as_async_value_command*)cmd)->listener(0, val, cmd->udata, cmd->event_loop); as_event_command_release(cmd); as_val_destroy(val); } else { as_event_response_error(cmd, &err); } break; } case AEROSPIKE_ERR_UDF: { as_error err; as_command_parse_udf_failure(p, &err, msg, status); as_event_response_error(cmd, &err); break; } default: { as_error err; as_error_set_message(&err, status, as_error_string(status)); as_event_response_error(cmd, &err); break; } } return true; }
as_status as_command_parse_header(as_error* err, int fd, uint64_t deadline_ms, void* user_data) { // Read header as_proto_msg* msg = user_data; as_status status = as_socket_read_deadline(err, fd, (uint8_t*)msg, sizeof(as_proto_msg), deadline_ms); if (status) { return status; } // Ensure that there is no data left to read. as_proto_swap_from_be(&msg->proto); as_msg_swap_header_from_be(&msg->m); size_t size = msg->proto.sz - msg->m.header_sz; if (size > 0) { as_log_warn("Unexpected data received from socket after a write: fd=%d size=%zu", fd, size); // Verify size is not corrupted. if (size > 100000) { // The socket will be closed on this error, so we don't have to worry about emptying it. return as_error_update(err, AEROSPIKE_ERR_CLIENT, "Unexpected data received from socket after a write: fd=%d size=%zu", fd, size); } // Empty socket. uint8_t* buf = cf_malloc(size); status = as_socket_read_deadline(err, fd, buf, size, deadline_ms); cf_free(buf); if (status) { return status; } } if (msg->m.result_code) { return as_error_set_message(err, msg->m.result_code, as_error_string(msg->m.result_code)); } return msg->m.result_code; }
static as_status as_scan_parse_records(uint8_t* buf, size_t size, as_scan_task* task, as_error* err) { uint8_t* p = buf; uint8_t* end = buf + size; as_status status; while (p < end) { as_msg* msg = (as_msg*)p; as_msg_swap_header_from_be(msg); if (msg->result_code) { // Special case - if we scan a set name that doesn't exist on a // node, it will return "not found" - we unify this with the // case where OK is returned and no callbacks were made. [AKG] // We are sending "no more records back" to the caller which will // send OK to the main worker thread. if (msg->result_code == AEROSPIKE_ERR_RECORD_NOT_FOUND) { return AEROSPIKE_NO_MORE_RECORDS; } return as_error_set_message(err, msg->result_code, as_error_string(msg->result_code)); } p += sizeof(as_msg); if (msg->info3 & AS_MSG_INFO3_LAST) { return AEROSPIKE_NO_MORE_RECORDS; } status = as_scan_parse_record(&p, msg, task); if (status != AEROSPIKE_OK) { return status; } if (ck_pr_load_32(task->error_mutex)) { err->code = AEROSPIKE_ERR_SCAN_ABORTED; return err->code; } } return AEROSPIKE_OK; }
static as_status as_command_parse_udf_error(as_error* err, as_status status, as_val* val) { if (val && val->type == AS_STRING) { char* begin = ((as_string*)val)->value; char* p = strrchr(begin, ':'); if (p) { p = strrchr(++p, ':'); if (p) { int code = atoi(++p); if (code > 0) { return as_error_set_message(err, code, begin); } } } return as_error_set_message(err, status, begin); } return as_error_set_message(err, status, as_error_string(status)); }
void as_event_timeout(as_event_command* cmd) { if (cmd->pipe_listener != NULL) { as_pipe_timeout(cmd); return; } as_error err; as_error_set_message(&err, AEROSPIKE_ERR_TIMEOUT, as_error_string(AEROSPIKE_ERR_TIMEOUT)); // Command has timed out. // Stop watcher if it has been initialized. if (cmd->state > AS_ASYNC_STATE_UNREGISTERED) { as_event_stop_watcher(cmd, cmd->conn); } // Assume timer has already been stopped. // Do not put connection back in pool. as_event_release_async_connection(cmd); as_event_error_callback(cmd, &err); }
static void as_ev_parse_authentication(as_event_command* cmd) { if (cmd->state == AS_ASYNC_STATE_AUTH_READ_HEADER) { // Read response length if (! as_ev_read(cmd)) { return; } as_event_set_auth_parse_header(cmd); if (cmd->len > cmd->capacity) { as_error err; as_error_update(&err, AEROSPIKE_ERR_CLIENT, "Authenticate response size is corrupt: %u", cmd->auth_len); as_event_socket_error(cmd, &err); return; } } if (! as_ev_read(cmd)) { return; } // Parse authentication response. cmd->len -= cmd->auth_len; uint8_t code = cmd->buf[cmd->len + AS_ASYNC_AUTH_RETURN_CODE]; if (code) { // Can't authenticate socket, so must close it. as_error err; as_error_update(&err, code, "Authentication failed: %s", as_error_string(code)); as_event_socket_error(cmd, &err); return; } cmd->pos = 0; as_ev_command_write_start(cmd); }
static as_status as_cluster_seed_nodes(as_cluster* cluster, as_error* err, bool enable_warnings) { // Add all nodes at once to avoid copying entire array multiple times. as_vector nodes_to_add; as_vector_inita(&nodes_to_add, sizeof(as_node*), 64); as_vector addresses; as_vector_inita(&addresses, sizeof(struct sockaddr_in), 5); as_node_info node_info; as_error error_local; as_error_init(&error_local); // AEROSPIKE_ERR_TIMEOUT doesn't come with a message; make sure it's initialized. as_status status = AEROSPIKE_OK; as_seeds* seeds = as_seeds_reserve(cluster); for (uint32_t i = 0; i < seeds->size; i++) { as_seed* seed = &seeds->array[i]; as_vector_clear(&addresses); status = as_lookup(&error_local, seed->name, seed->port, &addresses); if (status != AEROSPIKE_OK) { if (enable_warnings) { as_log_warn("Failed to lookup %s:%d. %s %s", seed->name, seed->port, as_error_string(status), error_local.message); } continue; } for (uint32_t i = 0; i < addresses.size; i++) { struct sockaddr_in* addr = as_vector_get(&addresses, i); status = as_lookup_node(cluster, &error_local, addr, &node_info); if (status == AEROSPIKE_OK) { as_host host; if (as_strncpy(host.name, seed->name, sizeof(host.name))) { as_log_warn("Hostname has been truncated: %s", host.name); } host.port = seed->port; as_node* node = as_cluster_find_node_in_vector(&nodes_to_add, node_info.name); if (node) { as_close(node_info.fd); as_node_add_address(node, &host, addr); } else { node = as_node_create(cluster, &host, addr, &node_info); as_address* a = as_node_get_address_full(node); as_log_info("Add node %s %s:%d", node->name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); as_vector_append(&nodes_to_add, &node); } } else { if (enable_warnings) { as_log_warn("Failed to connect to seed %s:%d. %s %s", seed->name, seed->port, as_error_string(status), error_local.message); } } } } as_seeds_release(seeds); if (nodes_to_add.size > 0) { as_cluster_add_nodes(cluster, &nodes_to_add); status = AEROSPIKE_OK; } else { status = as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to seed cluster"); } as_vector_destroy(&nodes_to_add); as_vector_destroy(&addresses); return status; }
as_status as_command_parse_success_failure(as_error* err, int fd, uint64_t deadline_ms, void* user_data) { // Read header as_proto_msg msg; as_status status = as_socket_read_deadline(err, fd, (uint8_t*)&msg, sizeof(as_proto_msg), deadline_ms); if (status) { return status; } as_proto_swap_from_be(&msg.proto); as_msg_swap_header_from_be(&msg.m); size_t size = msg.proto.sz - msg.m.header_sz; uint8_t* buf = 0; if (size > 0) { // Read remaining message bytes. buf = as_command_init(size); status = as_socket_read_deadline(err, fd, buf, size, deadline_ms); if (status) { as_command_free(buf, size); return status; } } as_val** val = user_data; // Parse result code and record. status = msg.m.result_code; switch (status) { case AEROSPIKE_OK: { uint8_t* p = buf; status = as_command_parse_success_failure_bins(&p, err, &msg.m, val); if (status != AEROSPIKE_OK) { if (val) { *val = 0; } } break; } case AEROSPIKE_ERR_UDF: { status = as_command_parse_udf_failure(buf, err, &msg.m, status); if (val) { *val = 0; } break; } default: as_error_set_message(err, status, as_error_string(status)); if (val) { *val = 0; } break; } as_command_free(buf, size); return status; }
as_status as_command_parse_result(as_error* err, int fd, uint64_t deadline_ms, void* user_data) { // Read header as_proto_msg msg; as_status status = as_socket_read_deadline(err, fd, (uint8_t*)&msg, sizeof(as_proto_msg), deadline_ms); if (status) { return status; } as_proto_swap_from_be(&msg.proto); as_msg_swap_header_from_be(&msg.m); size_t size = msg.proto.sz - msg.m.header_sz; uint8_t* buf = 0; if (size > 0) { // Read remaining message bytes. buf = as_command_init(size); status = as_socket_read_deadline(err, fd, buf, size, deadline_ms); if (status) { as_command_free(buf, size); return status; } } // Parse result code and record. status = msg.m.result_code; as_command_parse_result_data* data = user_data; switch (status) { case AEROSPIKE_OK: { if (data->record) { as_record* rec = *data->record; if (rec) { if (msg.m.n_ops > rec->bins.capacity) { if (rec->bins._free) { free(rec->bins.entries); } rec->bins.capacity = msg.m.n_ops; rec->bins.size = 0; rec->bins.entries = malloc(sizeof(as_bin) * msg.m.n_ops); rec->bins._free = true; } } else { rec = as_record_new(msg.m.n_ops); *data->record = rec; } rec->gen = msg.m.generation; rec->ttl = cf_server_void_time_to_ttl(msg.m.record_ttl); uint8_t* p = as_command_ignore_fields(buf, msg.m.n_fields); as_command_parse_bins(rec, p, msg.m.n_ops, data->deserialize); } break; } case AEROSPIKE_ERR_UDF: { status = as_command_parse_udf_failure(buf, err, &msg.m, status); break; } default: as_error_set_message(err, status, as_error_string(status)); break; } as_command_free(buf, size); return status; }