Esempio n. 1
0
as_status
as_event_command_execute(as_event_command* cmd, as_error* err)
{
    ck_pr_inc_32(&cmd->cluster->async_pending);

    // Only do this after the above increment to avoid a race with as_cluster_destroy().
    if (!cmd->cluster->valid) {
        as_event_command_free(cmd);
        return as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Client shutting down");
    }

    // Use pointer comparison for performance.
    // If portability becomes an issue, use "pthread_equal(event_loop->thread, pthread_self())"
    // instead.
    if (cmd->event_loop->thread == pthread_self()) {
        // We are already in event loop thread, so start processing.
        as_event_command_begin(cmd);
    }
    else {
        if (cmd->timeout_ms) {
            // Store current time in first 8 bytes which is not used yet.
            *(uint64_t*)cmd = cf_getms();
        }

        // Send command through queue so it can be executed in event loop thread.
        if (! as_event_send(cmd)) {
            as_event_command_free(cmd);
            return as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to queue command");
        }
    }
    return AEROSPIKE_OK;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
as_status
as_command_parse_success_failure_bins(uint8_t** pp, as_error* err, as_msg* msg, as_val** value)
{
    uint8_t* p = *pp;
    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, "SUCCESS") == 0) {
            if (value) {
                as_command_parse_value(p, type, value_size, value);
            }
            *pp = p + value_size;
            return AEROSPIKE_OK;
        }

        if (strcmp(name, "FAILURE") == 0) {
            as_val* val = 0;
            as_command_parse_value(p, type, value_size, &val);

            if (val == 0) {
                as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Received null FAILURE bin.");
            }
            else if (val->type == AS_STRING) {
                as_error_set_message(err, AEROSPIKE_ERR_CLIENT, ((as_string*)val)->value);
            }
            else {
                as_error_update(err, AEROSPIKE_ERR_CLIENT, "Expected string for FAILURE bin. Received %d", val->type);
            }
            as_val_destroy(val);
            return err->code;
        }
        p += value_size;
    }
    return as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to find SUCCESS or FAILURE bin.");
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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
aerospike_scan_async(
	aerospike* as, as_error* err, const as_policy_scan* policy, const as_scan* scan, uint64_t* scan_id,
	as_async_scan_listener listener, void* udata, as_event_loop* event_loop
	)
{
	as_error_reset(err);

	as_nodes* nodes = as_nodes_reserve(as->cluster);
	uint32_t n_nodes = nodes->size;
	
	if (n_nodes == 0) {
		as_nodes_release(nodes);
		return as_error_set_message(err, AEROSPIKE_ERR_SERVER, "Scan command failed because cluster is empty.");
	}

	// Reserve each node in cluster.
	for (uint32_t i = 0; i < n_nodes; i++) {
		as_node_reserve(nodes->array[i]);
	}

	as_status status = as_scan_async(as, err, policy, scan, scan_id, listener, udata, event_loop, nodes->array, n_nodes);
	as_nodes_release(nodes);
	return status;
}
static as_status
as_scan_parse_record_async(as_event_command* cmd, uint8_t** pp, as_msg* msg, as_error* err)
{
	as_record rec;
	as_record_inita(&rec, msg->n_ops);
	
	rec.gen = msg->generation;
	rec.ttl = cf_server_void_time_to_ttl(msg->record_ttl);
	*pp = as_command_parse_key(*pp, msg->n_fields, &rec.key);

	as_status status = as_command_parse_bins(pp, err, &rec, msg->n_ops,
											 cmd->flags2 & AS_ASYNC_FLAGS2_DESERIALIZE);

	if (status != AEROSPIKE_OK) {
		as_record_destroy(&rec);
		return status;
	}

	as_event_executor* executor = cmd->udata;  // udata is overloaded to contain executor.
	bool rv = ((as_async_scan_executor*)executor)->listener(0, &rec, executor->udata, executor->event_loop);
	as_record_destroy(&rec);

	if (! rv) {
		executor->notify = false;
		return as_error_set_message(err, AEROSPIKE_ERR_CLIENT_ABORT, "");
	}
	return AEROSPIKE_OK;
}
Esempio n. 8
0
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 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;
}
Esempio n. 10
0
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));
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}
/**
 * @return AEROSPIKE_OK if successful. Otherwise an error occurred.
 */
as_status aerospike_udf_put(
	aerospike * as, as_error * err, const as_policy_info * policy, 
	const char * filename, as_udf_type type, as_bytes * content)
{
	if (type != AS_UDF_TYPE_LUA) {
		return as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid udf type: %d", type);
	}
	
	as_error_reset(err);
	
	if (! policy) {
		policy = &as->config.policies.info;
	}
		
	char* command = NULL;
	
	as_string filename_string;
	const char* filebase = as_basename(&filename_string, filename);
		
	uint32_t encoded_len = cf_b64_encoded_len(content->size);
	char* content_base64 = malloc(encoded_len + 1);
	
	cf_b64_encode(content->value, content->size, content_base64);
	content_base64[encoded_len] = 0;
	
	if (! asprintf(&command, "udf-put:filename=%s;content=%s;content-len=%d;udf-type=%s;",
				   filebase, content_base64, encoded_len, as_udf_type_str[type])) {
		as_string_destroy(&filename_string);
		free(content_base64);
		return as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Udf put asprintf failed");
	}
	as_string_destroy(&filename_string);
	
	char* response = 0;
	as_status status = aerospike_info_any(as, err, policy, command, &response);
	free(command);
	free(content_base64);
	
	if (status) {
		return status;
	}
	
	free(response);
	return AEROSPIKE_OK;
}
Esempio n. 15
0
static as_status
as_admin_read_list(aerospike* as, as_error* err, const as_policy_admin* policy, uint8_t* command, uint8_t* end, as_admin_parse_fn parse_fn, as_vector* list)
{
    int 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, command, end, deadline_ms);

    if (status) {
        as_node_close_connection(node, fd);
        as_node_release(node);
        return status;
    }

    status = as_admin_read_blocks(err, fd, deadline_ms, parse_fn, list);

    if (status) {
        as_node_close_connection(node, fd);
        as_node_release(node);
        return status;
    }

    as_node_put_connection(node, fd);
    as_node_release(node);
    return status;
}
Esempio n. 16
0
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;
}
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;
}
Esempio n. 18
0
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;
}
Esempio n. 19
0
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);
}
Esempio n. 20
0
static as_status
as_admin_write_privileges(uint8_t** p, as_error* err, as_privilege** privileges, int privileges_size)
{
    uint8_t* q = *p + FIELD_HEADER_SIZE;
    *q++ = (uint8_t)privileges_size;

    for (int i = 0; i < privileges_size; i++) {
        as_privilege* priv = privileges[i];
        *q++ = (uint8_t)priv->code;

        if (priv->code >= AS_PRIVILEGE_READ) {
            q = as_admin_write_string(q, priv->ns);
            q = as_admin_write_string(q, priv->set);
        }
        else {
            if (priv->ns[0] || priv->set[0]) {
                return as_error_set_message(err, AEROSPIKE_ERR_PARAM, "Admin privilege has namespace/set scope which is invalid.");
            }
        }
    }
    as_admin_write_field_header(*p, PRIVILEGES, (int)(q - *p - FIELD_HEADER_SIZE));
    *p = q;
    return AEROSPIKE_OK;
}
Esempio n. 21
0
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;
}
static as_status
as_scan_generic(
	aerospike* as, as_error* err, const as_policy_scan* policy, const as_scan* scan,
	aerospike_scan_foreach_callback callback, void* udata, uint64_t* task_id_ptr)
{
	as_error_reset(err);
	
	if (! policy) {
		policy = &as->config.policies.scan;
	}
	
	as_cluster* cluster = as->cluster;
	as_nodes* nodes = as_nodes_reserve(cluster);
	uint32_t n_nodes = nodes->size;
	
	if (n_nodes == 0) {
		as_nodes_release(nodes);
		return as_error_set_message(err, AEROSPIKE_ERR_SERVER, "Scan command failed because cluster is empty.");
	}
	
	// Reserve each node in cluster.
	for (uint32_t i = 0; i < n_nodes; i++) {
		as_node_reserve(nodes->array[i]);
	}
	
	uint64_t task_id;
	if (task_id_ptr) {
		if (*task_id_ptr == 0) {
			*task_id_ptr = cf_get_rand64() / 2;
		}
		task_id = *task_id_ptr;
	}
	else {
		task_id = cf_get_rand64() / 2;
	}

	// Create scan command
	as_buffer argbuffer;
	uint16_t n_fields = 0;
	size_t size = as_scan_command_size(scan, &n_fields, &argbuffer);
	uint8_t* cmd = as_command_init(size);
	size = as_scan_command_init(cmd, policy, scan, task_id, n_fields, &argbuffer);
	
	// Initialize task.
	uint32_t error_mutex = 0;
	as_scan_task task;
	task.cluster = as->cluster;
	task.policy = policy;
	task.scan = scan;
	task.callback = callback;
	task.udata = udata;
	task.err = err;
	task.error_mutex = &error_mutex;
	task.task_id = task_id;
	task.cmd = cmd;
	task.cmd_size = size;
	
	as_status status = AEROSPIKE_OK;
	
	if (scan->concurrent) {
		uint32_t n_wait_nodes = n_nodes;
		task.complete_q = cf_queue_create(sizeof(as_scan_complete_task), true);

		// Run node scans in parallel.
		for (uint32_t i = 0; i < n_nodes; i++) {
			// Stack allocate task for each node.  It should be fine since the task
			// only needs to be valid within this function.
			as_scan_task* task_node = alloca(sizeof(as_scan_task));
			memcpy(task_node, &task, sizeof(as_scan_task));
			task_node->node = nodes->array[i];
			
			int rc = as_thread_pool_queue_task(&cluster->thread_pool, as_scan_worker, task_node);
			
			if (rc) {
				// Thread could not be added. Abort entire scan.
				if (ck_pr_fas_32(task.error_mutex, 1) == 0) {
					status = as_error_update(task.err, AEROSPIKE_ERR_CLIENT, "Failed to add scan thread: %d", rc);
				}
				
				// Reset node count to threads that were run.
				n_wait_nodes = i;
				break;
			}
		}

		// Wait for tasks to complete.
		for (uint32_t i = 0; i < n_wait_nodes; i++) {
			as_scan_complete_task complete;
			cf_queue_pop(task.complete_q, &complete, CF_QUEUE_FOREVER);
			
			if (complete.result != AEROSPIKE_OK && status == AEROSPIKE_OK) {
				status = complete.result;
			}
		}
		
		// Release temporary queue.
		cf_queue_destroy(task.complete_q);
	}
	else {
		task.complete_q = 0;
		
		// Run node scans in series.
		for (uint32_t i = 0; i < n_nodes && status == AEROSPIKE_OK; i++) {
			task.node = nodes->array[i];
			status = as_scan_command_execute(&task);
		}
	}
	
	// Release each node in cluster.
	for (uint32_t i = 0; i < n_nodes; i++) {
		as_node_release(nodes->array[i]);
	}
	
	// Release nodes array.
	as_nodes_release(nodes);

	// Free command memory.
	as_command_free(cmd, size);

	// If user aborts query, command is considered successful.
	if (status == AEROSPIKE_ERR_CLIENT_ABORT) {
		status = AEROSPIKE_OK;
	}

	// If completely successful, make the callback that signals completion.
	if (callback && status == AEROSPIKE_OK) {
		callback(NULL, udata);
	}
	return status;
}
Esempio n. 23
0
as_status
as_command_execute(as_cluster* cluster, as_error* err, as_command_node* cn, uint8_t* command, size_t command_len,
	uint32_t timeout_ms, uint32_t retry,
	as_parse_results_fn parse_results_fn, void* parse_results_data
)
{
	uint64_t deadline_ms = as_socket_deadline(timeout_ms);
	uint32_t sleep_between_retries_ms = 0;
	uint32_t failed_nodes = 0;
	uint32_t failed_conns = 0;
	uint32_t iterations = 0;
	bool release_node;

	// Execute command until successful, timed out or maximum iterations have been reached.
	while (true) {
		as_node* node;
		
		if (cn->node) {
			node = cn->node;
			release_node = false;
		}
		else {
			node = as_node_get(cluster, cn->ns, cn->digest, cn->write, cn->replica);
			release_node = true;
		}
		
		if (!node) {
			as_error_set_message(err, AEROSPIKE_ERR_INVALID_NODE, "Invalid node");
			failed_nodes++;
			sleep_between_retries_ms = 10;
			goto Retry;
		}
		
		int fd;
		as_status status = as_node_get_connection(err, node, deadline_ms, &fd);
		
		if (status) {
			if (release_node) {
				as_node_release(node);
			}
			failed_conns++;
			sleep_between_retries_ms = 1;
			goto Retry;
		}
		
		// Send command.
		status = as_socket_write_deadline(err, fd, command, command_len, deadline_ms);
		
		if (status) {
			// Socket errors are considered temporary anomalies.  Retry.
			// Close socket to flush out possible garbage.	Do not put back in pool.
			as_node_close_connection(node, fd);
			if (release_node) {
				as_node_release(node);
			}
			sleep_between_retries_ms = 0;
			goto Retry;
		}
		
		// Parse results returned by server.
		status = parse_results_fn(err, fd, deadline_ms, parse_results_data);
		
		if (status == AEROSPIKE_OK) {
			// Reset error code if retry had occurred.
			if (iterations > 0) {
				as_error_reset(err);
			}
		}
		else {
			switch (status) {
				case AEROSPIKE_ERR_TIMEOUT:
					as_node_close_connection(node, fd);
					if (release_node) {
						as_node_release(node);
					}
					return as_error_update(err, AEROSPIKE_ERR_TIMEOUT,
							"Timeout: timeout=%d iterations=%u failedNodes=%u failedConns=%u",
							timeout_ms, ++iterations, failed_nodes, failed_conns);
				
				// Close socket on errors that can leave unread data in socket.
				case AEROSPIKE_ERR_QUERY_ABORTED:
				case AEROSPIKE_ERR_SCAN_ABORTED:
				case AEROSPIKE_ERR_CLIENT_ABORT:
				case AEROSPIKE_ERR_CLIENT:
					as_node_close_connection(node, fd);
					if (release_node) {
						as_node_release(node);
					}
					err->code = status;
					return status;
				
				default:
					err->code = status;
					break;
			}
		}
		
		// Put connection back in pool.
		as_node_put_connection(node, fd);
		
		// Release resources.
		if (release_node) {
			as_node_release(node);
		}
		return status;

Retry:
		// Check if max retries reached.
		if (++iterations > retry) {
			break;
		}
		
		// Check for client timeout.
		if (deadline_ms > 0) {
			int remaining_ms = (int)(deadline_ms - cf_getms() - sleep_between_retries_ms);
			
			if (remaining_ms <= 0) {
				break;
			}
			
			// Reset timeout in send buffer (destined for server).
			*(uint32_t*)(command + 22) = cf_swap_to_be32(remaining_ms);
		}
		
		if (sleep_between_retries_ms > 0) {
			// Sleep before trying again.
			usleep(sleep_between_retries_ms * 1000);
		}
	}
	
	// Retries have been exhausted.  Return last error.
	// Fill in timeout stats if timeout occurred.
	if (err->code == AEROSPIKE_ERR_TIMEOUT) {
		as_error_update(err, AEROSPIKE_ERR_TIMEOUT,
		   "Timeout: timeout=%d iterations=%u failedNodes=%u failedConns=%u",
		   timeout_ms, iterations, failed_nodes, failed_conns);
	}
	return err->code;
}
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;
}
Esempio n. 25
0
static as_status
protocols_parse(as_config_tls* tlscfg, uint16_t* oprotocols, as_error* errp)
{
	// In case we don't make it all the way through ...
	*oprotocols = AS_TLS_PROTOCOL_NONE;
	
	// If no protocol_spec is provided, use a default value.
	if (! tlscfg->protocols) {
		*oprotocols = AS_TLS_PROTOCOL_DEFAULT;
		return AEROSPIKE_OK;
	}

	uint16_t protocols = AS_TLS_PROTOCOL_NONE;
	
	char const* delim = " \t";
	char* saveptr = NULL;
	for (char* tok = strtok_r(tlscfg->protocols, delim, &saveptr);
		 tok != NULL;
		 tok = strtok_r(NULL, delim, &saveptr)) {
		char act = '\0';
		uint16_t current;

		// Is there a +/- prefix?
		if ((*tok == '+') || (*tok == '-')) {
			act = *tok;
			++tok;
		}
		
		if (strcasecmp(tok, "SSLv2") == 0) {
			return as_error_set_message(errp, AEROSPIKE_ERR_TLS_ERROR,
										"SSLv2 not supported (RFC 6176)");
		}
		else if (strcasecmp(tok, "SSLv3") == 0) {
			return as_error_set_message(errp, AEROSPIKE_ERR_TLS_ERROR,
										"SSLv3 not supported");
		}
		else if (strcasecmp(tok, "TLSv1") == 0) {
			current = AS_TLS_PROTOCOL_TLSV1;
		}
		else if (strcasecmp(tok, "TLSv1.1") == 0) {
			current = AS_TLS_PROTOCOL_TLSV1_1;
		}
		else if (strcasecmp(tok, "TLSv1.2") == 0) {
			current = AS_TLS_PROTOCOL_TLSV1_2;
		}
		else if (strcasecmp(tok, "all") == 0) {
			current = AS_TLS_PROTOCOL_ALL;
		}
		else {
			return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
								   "unknown TLS protocol %s", tok);
		}

		if (act == '-') {
			protocols &= ~current;
        }
        else if (act == '+') {
            protocols |= current;
        }
		else {
			if (protocols != AS_TLS_PROTOCOL_NONE) {
				return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
						   "TLS protocol %s overrides already set parameters."
									   "Check if a +/- prefix is missing ...",
									   tok);
			}
			protocols = current;
		}
	}

	*oprotocols = protocols;
	return AEROSPIKE_OK;
}
Esempio n. 26
0
as_status
as_tls_context_setup(as_config_tls* tlscfg, as_tls_context* ctx, as_error* errp)
{
	// Clear the destination, in case we don't make it.
	ctx->ssl_ctx = NULL;
	ctx->pkey = NULL;
	ctx->cert_blacklist = NULL;
	ctx->log_session_info = tlscfg->log_session_info;
	ctx->for_login_only = tlscfg->for_login_only;

	as_tls_check_init();
	pthread_mutex_init(&ctx->lock, NULL);

	if (tlscfg->cert_blacklist) {
		ctx->cert_blacklist = cert_blacklist_read(tlscfg->cert_blacklist);

		if (! ctx->cert_blacklist) {
			as_tls_context_destroy(ctx);
			return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
								   "Failed to read certificate blacklist: %s",
								   tlscfg->cert_blacklist);
		}
	}
	
	uint16_t protocols = AS_TLS_PROTOCOL_NONE;
	as_status status = protocols_parse(tlscfg, &protocols, errp);

	if (status != AEROSPIKE_OK) {
		as_tls_context_destroy(ctx);
		return status;
	}

	const SSL_METHOD* method = NULL;

	// If the selected protocol set is a single protocol we can use a specific method.
	if (protocols == AS_TLS_PROTOCOL_TLSV1) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
		method = TLS_client_method();
#else
		method = TLSv1_client_method();
#endif
	}
	else if (protocols == AS_TLS_PROTOCOL_TLSV1_1) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
		method = TLS_client_method();
#else
		method = TLSv1_1_client_method();
#endif
	}
	else if (protocols == AS_TLS_PROTOCOL_TLSV1_2) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
		method = TLS_client_method();
#else
		method = TLSv1_2_client_method();
#endif
	}
	else {
		// Multiple protocols are enabled, use a flexible method.
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
		method = TLS_client_method();
#else
		method = SSLv23_client_method();
#endif
	}

	ctx->ssl_ctx = SSL_CTX_new(method);

	if (ctx->ssl_ctx == NULL) {
		as_tls_context_destroy(ctx);

		unsigned long errcode = ERR_get_error();
		char errbuf[1024];
		ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
		return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
							   "Failed to create new TLS context: %s", errbuf);
	}

	/* always disable SSLv2, as per RFC 6176 */
    SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
	SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);

	// Turn off non-enabled protocols.
	if (! (protocols & AS_TLS_PROTOCOL_TLSV1)) {
        SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
    }
	if (! (protocols & AS_TLS_PROTOCOL_TLSV1_1)) {
        SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1);
    }
	if (! (protocols & AS_TLS_PROTOCOL_TLSV1_2)) {
        SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);
    }
	
	if (tlscfg->cafile || tlscfg->capath) {
		int rv = SSL_CTX_load_verify_locations(ctx->ssl_ctx, tlscfg->cafile, tlscfg->capath);

		if (rv != 1) {
			as_tls_context_destroy(ctx);

			char errbuf[1024];
			unsigned long errcode = ERR_get_error();

			if (errcode != 0) {
				ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
				return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
									   "Failed to load CAFile: %s", errbuf);
			}
			return as_error_set_message(errp, AEROSPIKE_ERR_TLS_ERROR,
										"Unknown failure loading CAFile");
		}
	}

	if (tlscfg->certfile) {
		int rv = SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, tlscfg->certfile);

		if (rv != 1) {
			// We seem to be seeing this bug:
			// https://groups.google.com/
			//          forum/#!topic/mailing.openssl.users/nRvRzmKnEQA
			// If the rv is not 1 check the error stack; if it doesn't have an
			// error assume we are OK.
			//
			unsigned long errcode = ERR_peek_error();

			if (errcode != SSL_ERROR_NONE) {
				// There *was* an error after all.
				as_tls_context_destroy(ctx);

				unsigned long errcode = ERR_get_error();
				char errbuf[1024];
				ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
				return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
									   "SSL_CTX_use_certificate_chain_file failed: %s",
									   errbuf);
			}
		}
	}

	if (tlscfg->keyfile) {
		bool ok = false;
		FILE *fh = fopen(tlscfg->keyfile, "r");

		if (fh == NULL) {
			as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
					"failed to open key file %s: %s", tlscfg->keyfile,
					strerror(errno));
		}
		else {
			EVP_PKEY *pkey = PEM_read_PrivateKey(fh, NULL, password_cb,
					tlscfg->keyfile_pw);

			if (pkey == NULL) {
				unsigned long errcode = ERR_get_error();

				if (ERR_GET_REASON(errcode) == PEM_R_BAD_PASSWORD_READ) {
					if (tlscfg->keyfile_pw == NULL) {
						as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
								"key file %s requires a password",
								tlscfg->keyfile);
					}
					else {
						as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
								"password for key file %s too long",
								tlscfg->keyfile);
					}
				}
				else if (ERR_GET_REASON(errcode) == EVP_R_BAD_DECRYPT) {
					as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
							"invalid password for key file %s",
							tlscfg->keyfile);
				}
				else {
					char errbuf[1024];
					ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
					as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR,
							"PEM_read_PrivateKey failed: %s", errbuf);
				}
			}
			else {
				ctx->pkey = pkey;
				SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey);
				ok = true;
			}

			fclose(fh);
		}

		if (!ok) {
			as_tls_context_destroy(ctx);
			return AEROSPIKE_ERR_TLS_ERROR;
		}
	}

	if (tlscfg->cipher_suite) {
		int rv = SSL_CTX_set_cipher_list(ctx->ssl_ctx, tlscfg->cipher_suite);

		if (rv != 1) {
			as_tls_context_destroy(ctx);
			return as_error_set_message(errp, AEROSPIKE_ERR_TLS_ERROR,
										"no compatible cipher found");
		}
		// It's bogus that we have to create an SSL just to get the
		// cipher list, but SSL_CTX_get_ciphers doesn't appear to
		// exist ...
		SSL* ssl = SSL_new(ctx->ssl_ctx);

		for (int prio = 0; true; ++prio) {
			char const * cipherstr = SSL_get_cipher_list(ssl, prio);
			if (!cipherstr) {
				break;
			}
			as_log_info("cipher %d: %s", prio+1, cipherstr);
		}
		SSL_free(ssl);
	}

	if (tlscfg->crl_check || tlscfg->crl_check_all) {
		X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new();
		unsigned long flags = X509_V_FLAG_CRL_CHECK;

		if (tlscfg->crl_check_all) {
			flags |= X509_V_FLAG_CRL_CHECK_ALL;
		}

		X509_VERIFY_PARAM_set_flags(param, flags);
		SSL_CTX_set1_param(ctx->ssl_ctx, param);
		X509_VERIFY_PARAM_free(param);
	}

	SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, verify_callback);
	manage_sigpipe();
	return AEROSPIKE_OK;
}
Esempio n. 27
0
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;
}