diff options
Diffstat (limited to 'ctrl/libhicnctrl/src/api.c')
-rw-r--r-- | ctrl/libhicnctrl/src/api.c | 1161 |
1 files changed, 255 insertions, 906 deletions
diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index d68dc830e..c93853dd1 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Cisco and/or its affiliates. + * Copyright (c) 2021-2022 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -26,6 +26,13 @@ #include <math.h> // log2 #include "api_private.h" +#include "object_vft.h" +#include "request.h" + +#include <hicn/ctrl/socket.h> +#include "socket_private.h" + +#define ENOIMPL 42 #if 0 /* /!\ Please update constants in public header file upon changes */ @@ -60,685 +67,282 @@ connection_type_from_str(const char * str) * Control Data ******************************************************************************/ -hc_data_t *hc_data_create(size_t in_element_size, size_t out_element_size, - data_callback_t complete_cb) { - hc_data_t *data = malloc(sizeof(hc_data_t)); - if (!data) goto ERR_MALLOC; - - /* FIXME Could be NULL thanks to realloc provided size is 0 */ - data->max_size_log = DEFAULT_SIZE_LOG; - data->in_element_size = in_element_size; - data->out_element_size = out_element_size; - data->size = 0; - data->complete = false; - data->command_id = 0; // TODO this could also be a busy mark in the socket - /* No callback needed in blocking code for instance */ - data->complete_cb = complete_cb; - - data->buffer = malloc((1 << data->max_size_log) * data->out_element_size); - if (!data->buffer) goto ERR_BUFFER; - data->ret = 0; - data->current = 0; - - return data; - -ERR_BUFFER: - hc_data_free(data); -ERR_MALLOC: - return NULL; -} - -void hc_data_free(hc_data_t *data) { - if (data) free(data->buffer); - free(data); -} - -int hc_data_ensure_available(hc_data_t *data, size_t count) { - size_t new_size_log = - (data->size + count - 1 > 0) ? log2(data->size + count - 1) + 1 : 0; - if (new_size_log > data->max_size_log) { - data->max_size_log = new_size_log; - data->buffer = - realloc(data->buffer, (1 << new_size_log) * data->out_element_size); - if (!data->buffer) return -1; - } +/*----------------------------------------------------------------------------* + * Object model + *----------------------------------------------------------------------------*/ - return 0; -} +/*----------------------------------------------------------------------------* + * Entry point + *----------------------------------------------------------------------------*/ -int hc_data_push_many(hc_data_t *data, const void *elements, size_t count) { - if (hc_data_ensure_available(data, count) < 0) return -1; +int hc_sock_on_init(hc_sock_t *s, hc_request_t *request) { + int rc; + ssize_t size; - memcpy(data->buffer + data->size * data->out_element_size, elements, - count * data->out_element_size); - data->size += count; + uint8_t *buffer; - return 0; -} + size = s->ops.prepare(s, request, &buffer); + if (size < 0) goto ERR_PREPARE; -int hc_data_push(hc_data_t *data, const void *element) { - return hc_data_push_many(data, element, 1); -} + if (size == 0) return 1; /* Done */ -/** - * - * NOTE: This function make sure there is enough room available in the data - * structure. - */ -u8 *hc_data_get_next(hc_data_t *data) { - if (hc_data_ensure_available(data, 1) < 0) return NULL; + assert(hc_request_get_data(hc_request_get_current(request))); - return data->buffer + data->size * data->out_element_size; -} + rc = s->ops.send(s, buffer, size); + if (rc < 0) goto ERR_SEND; -int hc_data_set_callback(hc_data_t *data, data_callback_t cb, void *cb_data) { - data->complete_cb = cb; - data->complete_cb_data = cb_data; return 0; -} -int hc_data_set_complete(hc_data_t *data) { - data->complete = true; - data->ret = 0; - if (data->complete_cb) return data->complete_cb(data, data->complete_cb_data); - return 0; -} - -int hc_data_set_error(hc_data_t *data) { - data->ret = -1; - return 0; +ERR_PREPARE: +ERR_SEND: + return -1; } -int hc_data_reset(hc_data_t *data) { - data->size = 0; - return 0; -} +int hc_sock_on_receive(hc_sock_t *s, size_t count) { + int rc; -static hc_sock_t *_open_module(const char *name, const char *url) { - char complete_name[128]; -#ifdef __APPLE__ - snprintf(complete_name, 128, "%s.dylib", name); -#elif defined(__linux__) - snprintf(complete_name, 128, "%s.so", name); -#else -#error "System not supported for dynamic lynking" + DEBUG("hc_sock_on_receive: calling process with count=%ld", count); + rc = s->ops.process(s, count); + if (rc < 0) goto ERR_PROCESS; + + hc_request_t *request = hc_sock_get_request(s); + hc_request_t *current_request = hc_request_get_current(request); + hc_data_t *data = hc_request_get_data(current_request); + if (hc_data_is_complete(data)) { + /* + * We only notice a request is complete when trying to send the second + * time... either the state machine reaches the end, or in case of generic + * requests, we mark it as such. + */ +#if 0 + if (hc_request_is_complete(current_request)) { + if (!hc_request_pop(request)) { + /* Free request context */ + /* In case of error, data is NULL */ + // XXX bug if we free request XXX + // hc_sock_free_request(s, request); + if (!hc_request_is_subscription(request)) + hc_request_set_complete(request); + return 1; /* Done */ + } + } else { #endif - - void *handle = 0; - const char *error = 0; - hc_sock_t *(*creator)(const char *) = 0; - hc_sock_t *ret = 0; - - // open module - handle = dlopen(complete_name, RTLD_LAZY); - if (!handle) { - if ((error = dlerror()) != 0) { - ERROR("%s", error); + ON_INIT: + rc = hc_sock_on_init(s, request); + if (rc < 0) goto ERR_INIT; + if (rc == 1) { + if (!hc_request_pop(request)) { + /* Free request context */ + /* In case of error, data is NULL */ + // hc_sock_free_request(s, request); + if (!hc_request_is_subscription(request)) + hc_request_set_complete(request); + return 1; /* Done */ + } + goto ON_INIT; } - return 0; - } - - // get factory method - creator = - (hc_sock_t * (*)(const char *)) dlsym(handle, "_hc_sock_create_url"); - if (!creator) { - if ((error = dlerror()) != 0) { - ERROR("%s", error); +#if 0 } - return 0; - } - - ret = (*creator)(NULL); - ret->handle = handle; - - return ret; -} - -hc_sock_t *hc_sock_create_forwarder_url(forwarder_type_t forwarder, - const char *url) { - switch (forwarder) { - case HICNLIGHT: - return _open_module("hicnlightctrl_module", url); - case HICNLIGHT_NG: - return _open_module("hicnlightngctrl_module", url); - case VPP: - return _open_module("vppctrl_module", url); - default: - return NULL; - } -} - -#ifdef ANDROID -// In android we do not load a module at runtime -// but we link the hicnlight implmentation directly -// to the main library -extern hc_sock_t *_hc_sock_create_url(const char *url); #endif - -hc_sock_t *hc_sock_create_forwarder(forwarder_type_t forwarder) { -#ifdef ANDROID - assert(forwarder == HICNLIGHT_NG); - hc_sock_t *ret = _hc_sock_create_url(NULL); - ret->handle = NULL; - return ret; -#else - return hc_sock_create_forwarder_url(forwarder, NULL); -#endif -} - -hc_sock_t *hc_sock_create(void) { - return hc_sock_create_forwarder(HICNLIGHT_NG); -} - -void hc_sock_free(hc_sock_t *s) { - void *handle = s->handle; - s->hc_sock_free(s); - - if (handle) { - dlclose(handle); - } -} - -int hc_sock_get_next_seq(hc_sock_t *s) { return s->hc_sock_get_next_seq(s); } - -int hc_sock_set_nonblocking(hc_sock_t *s) { return s->hc_sock_get_next_seq(s); } - -int hc_sock_get_fd(hc_sock_t *s) { return s->hc_sock_get_fd(s); } - -int hc_sock_connect(hc_sock_t *s) { return s->hc_sock_connect(s); } - -int hc_sock_get_available(hc_sock_t *s, u8 **buffer, size_t *size) { - return s->hc_sock_get_available(s, buffer, size); -} - -int hc_sock_send(hc_sock_t *s, hc_msg_t *msg, size_t msglen, uint32_t seq) { - return s->hc_sock_send(s, msg, msglen, seq); -} - -int hc_sock_recv(hc_sock_t *s) { return s->hc_sock_recv(s); } - -int hc_sock_process(hc_sock_t *s, hc_data_t **data) { - return s->hc_sock_process(s, data); -} - -int hc_sock_callback(hc_sock_t *s, hc_data_t **data) { - return s->hc_sock_callback(s, data); -} - -int hc_sock_reset(hc_sock_t *s) { return s->hc_sock_reset(s); } - -void hc_sock_increment_woff(hc_sock_t *s, size_t bytes) { - s->hc_sock_increment_woff(s, bytes); -} - -int hc_sock_prepare_send(hc_sock_t *s, hc_result_t *result, - data_callback_t complete_cb, void *complete_cb_data) { - return s->hc_sock_prepare_send(s, result, complete_cb, complete_cb_data); -} - -int hc_sock_set_recv_timeout_ms(hc_sock_t *s, long timeout_ms) { - return s->hc_sock_set_recv_timeout_ms(s, timeout_ms); -} - -/*----------------------------------------------------------------------------* - * LISTENER - *----------------------------------------------------------------------------*/ - -int hc_listener_create(hc_sock_t *s, hc_listener_t *listener) { - return s->hc_listener_create(s, listener); -} - -hc_result_t *hc_listener_create_conf(hc_sock_t *s, hc_listener_t *listener) { - return s->hc_listener_create_conf(s, listener); -} - -int hc_listener_get(hc_sock_t *s, hc_listener_t *listener, - hc_listener_t **listener_found) { - return s->hc_listener_get(s, listener, listener_found); -} - -int hc_listener_delete(hc_sock_t *s, hc_listener_t *listener) { - return s->hc_listener_delete(s, listener); -} - -int hc_listener_list(hc_sock_t *s, hc_data_t **pdata) { - return s->hc_listener_list(s, pdata); -} - -GENERATE_FIND(listener); - -/* LISTENER VALIDATE */ - -int hc_listener_validate(const hc_listener_t *listener) { - if (!IS_VALID_NAME(listener->name)) { - ERROR("[hc_listener_validate] Invalid name specified"); - return -1; - } - if (!IS_VALID_INTERFACE_NAME(listener->interface_name)) { - ERROR("[hc_listener_validate] Invalid interface_name specified"); - return -1; - } - if (!IS_VALID_TYPE(listener->type)) { - ERROR("[hc_listener_validate] Invalid type specified"); - return -1; - } - if (!IS_VALID_FAMILY(listener->family)) { - ERROR("[hc_listener_validate] Invalid family specified"); - return -1; - } - if (!IS_VALID_ADDRESS(&listener->local_addr, listener->family)) { - ERROR("[hc_listener_validate] Invalid local_addr specified"); - return -1; - } - if (!IS_VALID_PORT(listener->local_port)) { - ERROR("[hc_listener_validate] Invalid local_port specified"); - return -1; } + return 0; /* Continue processing */ - return 0; +ERR_INIT: +ERR_PROCESS: + return -1; } -/* LISTENER CMP */ - -int hc_listener_cmp(const hc_listener_t *l1, const hc_listener_t *l2) { +// -1 error +// 0 = request is not yet complete +// 1 request is complete +int hc_sock_receive(hc_sock_t *s, hc_data_t **pdata) { int rc; + DEBUG("Waiting for data..."); + rc = s->ops.recv(s); + if (rc < 0) return -1; - rc = INT_CMP(l1->type, l2->type); - if (rc != 0) return rc; - - rc = INT_CMP(l1->family, l2->family); - if (rc != 0) return rc; - - rc = strncmp(l1->interface_name, l2->interface_name, INTERFACE_LEN); - if (rc != 0) return rc; - - rc = ip_address_cmp(&l1->local_addr, &l2->local_addr, l1->family); - if (rc != 0) return rc; - - rc = INT_CMP(l1->local_port, l2->local_port); - if (rc != 0) return rc; - - return rc; -} - -/* LISTENER SNPRINTF */ - -/* /!\ Please update constants in header file upon changes */ -int hc_listener_snprintf(char *s, size_t size, hc_listener_t *listener) { - char local[MAXSZ_URL]; - int rc; - rc = url_snprintf(local, MAXSZ_URL, listener->family, &listener->local_addr, - listener->local_port); - if (rc >= MAXSZ_URL) - WARN("[hc_listener_snprintf] Unexpected truncation of URL string"); - if (rc < 0) return rc; - - return snprintf(s, size, "%s %s %s interface=%s", listener->name, local, - face_type_str(listener->type), listener->interface_name); -} + rc = hc_sock_on_receive(s, 0); + if (rc < 0) return -1; -/*----------------------------------------------------------------------------* - * CONNECTION - *----------------------------------------------------------------------------*/ - -int hc_connection_create(hc_sock_t *s, hc_connection_t *connection) { - return s->hc_connection_create(s, connection); -} - -hc_result_t *hc_connection_create_conf(hc_sock_t *s, - hc_connection_t *connection) { - return s->hc_connection_create_conf(s, connection); -} - -int hc_connection_get(hc_sock_t *s, hc_connection_t *connection, - hc_connection_t **connection_found) { - return s->hc_connection_get(s, connection, connection_found); -} - -int hc_connection_update_by_id(hc_sock_t *s, int hc_connection_id, - hc_connection_t *connection) { - return s->hc_connection_update_by_id(s, hc_connection_id, connection); -} - -int hc_connection_update(hc_sock_t *s, hc_connection_t *connection_current, - hc_connection_t *connection_updated) { - return s->hc_connection_update(s, connection_current, connection_updated); -} - -int hc_connection_delete(hc_sock_t *s, hc_connection_t *connection) { - return s->hc_connection_delete(s, connection); -} - -hc_result_t *hc_connection_delete_conf(hc_sock_t *s, - hc_connection_t *connection) { - return s->hc_connection_delete_conf(s, connection); -} - -int hc_connection_list(hc_sock_t *s, hc_data_t **pdata) { - return s->hc_connection_list(s, pdata); -} - -int hc_connection_set_admin_state(hc_sock_t *s, const char *conn_id_or_name, - face_state_t state) { - return s->hc_connection_set_admin_state(s, conn_id_or_name, state); -} + hc_request_t *request = hc_sock_get_request(s); + /* + * If notification, display it, ideally callback. What to do with + * allocated data ? + */ + // XXX problem we display object on ACK... but not subsequent + // notifications + // XXX we should rely on callback here in addition, even for a synchronous + // request + if (hc_request_is_subscription(request)) { + hc_data_t *data = hc_request_get_data(request); + assert(data); + hc_object_t *obj = (hc_object_t *)hc_data_get_buffer(data); + char buf[MAXSZ_HC_OBJECT]; + hc_object_type_t object_type = hc_data_get_object_type(data); + if (hc_object_snprintf(buf, sizeof(buf), object_type, obj) > 0) { + ; + INFO("%s %s", object_type_str(object_type), buf); + } + } -#ifdef WITH_POLICY -int hc_connection_set_priority(hc_sock_t *s, const char *conn_id_or_name, - uint32_t priority) { - return s->hc_connection_set_priority(s, conn_id_or_name, priority); -} + // XXX need same for async + if (rc != 1) return 0; -int hc_connection_set_tags(hc_sock_t *s, const char *conn_id_or_name, - policy_tags_t tags) { - return s->hc_connection_set_tags(s, conn_id_or_name, tags); + hc_request_t *current_request = hc_request_get_current(request); + if (hc_request_is_complete(current_request)) { + /* We either return the (last) allocated data, or free it */ + if (pdata) { + *pdata = hc_request_get_data(request); + } else { + hc_request_reset_data(request); + } + hc_request_on_complete(request); + // hc_sock_free_request(s, request); + } + return 1; } -#endif // WITH_POLICY - -GENERATE_FIND(connection); -/* CONNECTION VALIDATE */ +int hc_sock_receive_all(hc_sock_t *s, hc_data_t **pdata) { + for (;;) { + int rc = hc_sock_receive(s, pdata); + if (rc < 0) return -1; -int hc_connection_validate(const hc_connection_t *connection) { - if (connection->name[0] != '\0' && !IS_VALID_NAME(connection->name)) { - ERROR("[hc_connection_validate] Invalid name specified"); - return -1; - } - if (!IS_VALID_INTERFACE_NAME(connection->interface_name)) { - ERROR("[hc_connection_validate] Invalid interface_name specified"); - return -1; - } - if (!IS_VALID_TYPE(connection->type)) { - ERROR("[hc_connection_validate] Invalid type specified"); - return -1; - } - if (!IS_VALID_FAMILY(connection->family)) { - ERROR("[hc_connection_validate] Invalid family specified"); - return -1; + /* If request is complete, stop */ + if (rc == 1) break; } - if (!IS_VALID_ADDRESS(&connection->local_addr, connection->family)) { - ERROR("[hc_connection_validate] Invalid local_addr specified"); - return -1; - } - if (!IS_VALID_PORT(connection->local_port)) { - ERROR("[hc_connection_validate] Invalid local_port specified"); - return -1; - } - if (!IS_VALID_ADDRESS(&connection->remote_addr, connection->family)) { - ERROR("[hc_connection_validate] Invalid remote_addr specified"); - return -1; - } - if (!IS_VALID_PORT(connection->remote_port)) { - ERROR("[hc_connection_validate] Invalid remote_port specified"); - return -1; - } - return 0; } -/* CONNECTION CMP */ - -/* - * hICN light uses ports even for hICN connections, but their value is ignored. - * As connections are specific to hicn-light, we can safely use IP and ports for - * comparison independently of the face type. +/** + * @return <0 in case of error + * -1 : validation error + * -2 : error during send + * -3 : error receiving or parsing + * + * If the caller provider a non-NULL hc_data_t pointer to receive results + * back, it is responsible for freeing it. */ -int hc_connection_cmp(const hc_connection_t *c1, const hc_connection_t *c2) { - int rc; - - rc = INT_CMP(c1->type, c2->type); - if (rc != 0) return rc; - - rc = INT_CMP(c1->family, c2->family); - if (rc != 0) return rc; - - rc = strncmp(c1->interface_name, c2->interface_name, INTERFACE_LEN); - if (rc != 0) return rc; - - rc = ip_address_cmp(&c1->local_addr, &c2->local_addr, c1->family); - if (rc != 0) return rc; - - rc = INT_CMP(c1->local_port, c2->local_port); - if (rc != 0) return rc; - - rc = ip_address_cmp(&c1->remote_addr, &c2->remote_addr, c1->family); - if (rc != 0) return rc; +int _hc_execute(hc_sock_t *s, hc_action_t action, hc_object_type_t object_type, + hc_object_t *object, hc_result_callback_t callback, + void *callback_data, hc_data_t **pdata) { + assert(!(hc_sock_is_async(s) && pdata)); - rc = INT_CMP(c1->remote_port, c2->remote_port); - if (rc != 0) return rc; - - return rc; -} - -/* CONNECTION SNPRINTF */ - -/* /!\ Please update constants in header file upon changes */ -int hc_connection_snprintf(char *s, size_t size, - const hc_connection_t *connection) { - char local[MAXSZ_URL]; - char remote[MAXSZ_URL]; - int rc; - - // assert(connection->connection_state) - if (strcmp(connection->name, "SELF") == 0) { - return snprintf(s, size, "%s", connection->name); + if (hc_sock_is_async(s) && !s->ops.get_fd) { + return -1; /* No async support */ } - rc = url_snprintf(local, MAXSZ_URL, connection->family, - &connection->local_addr, connection->local_port); - if (rc >= MAXSZ_URL) - WARN("[hc_connection_snprintf] Unexpected truncation of URL string"); - if (rc < 0) return rc; - rc = url_snprintf(remote, MAXSZ_URL, connection->family, - &connection->remote_addr, connection->remote_port); - if (rc >= MAXSZ_URL) - WARN("[hc_connection_snprintf] Unexpected truncation of URL string"); - if (rc < 0) return rc; - - return snprintf(s, size, "%s %s %s %s", connection->name, local, remote, - face_type_str(connection->type)); -} - -int hc_face_create(hc_sock_t *s, hc_face_t *face) { - return s->hc_face_create(s, face); -} - -int hc_face_get(hc_sock_t *s, hc_face_t *face, hc_face_t **face_found) { - return s->hc_face_get(s, face, face_found); -} - -int hc_face_delete(hc_sock_t *s, hc_face_t *face, uint8_t delete_listener) { - return s->hc_face_delete(s, face, delete_listener); -} - -int hc_face_list(hc_sock_t *s, hc_data_t **pdata) { - return s->hc_face_list(s, pdata); -} - -int hc_face_list_async(hc_sock_t *s) { return s->hc_face_list_async(s); } + // XXX no need to pass pdata to the request + // XXX sync socket, no multiplexed requests, no notifications + /* + * The request will contain all state needed to identify and demultiplex + * replies and notifications arriving on the socket. We assume there is at + * most a single request/reply in progress for a given request, and that + * requests involving multiple queries will run them sequentially. The use + * of a sequence number that is transported by the requests and reply is + * thus sufficient to disambiguate them. + */ + hc_request_t *request = hc_sock_create_request(s, action, object_type, object, + callback, callback_data); + if (!request) { + goto ERR_REQUEST; + } -int hc_face_set_admin_state(hc_sock_t *s, const char *conn_id_or_name, - face_state_t state) { - return s->hc_face_set_admin_state(s, conn_id_or_name, state); -} + if (hc_request_requires_object(request)) { + if (hc_object_is_empty(object) || + hc_object_validate(object_type, object, true) < 0) { + goto ERR_VALIDATE; + } + } else { + if (object && !hc_object_is_empty(object)) { + goto ERR_CHECK; + } + } -#ifdef WITH_POLICY -int hc_face_set_priority(hc_sock_t *s, const char *conn_id_or_name, - uint32_t priority) { - return s->hc_face_set_priority(s, conn_id_or_name, priority); -} + /* Workaround for non-fd based modules */ + if (s->ops.prepare && s->ops.send && s->ops.recv && s->ops.process) { + if (hc_sock_on_init(s, request) < 0) goto ERR_INIT; -int hc_face_set_tags(hc_sock_t *s, const char *conn_id_or_name, - policy_tags_t tags) { - return s->hc_face_set_tags(s, conn_id_or_name, tags); -} -#endif /* WITH_POLICY */ + if (hc_sock_is_async(s)) return 0; -/* /!\ Please update constants in header file upon changes */ -int hc_face_snprintf(char *s, size_t size, hc_face_t *face) { - /* URLs are also big enough to contain IP addresses in the hICN case */ - char local[MAXSZ_URL]; - char remote[MAXSZ_URL]; -#ifdef WITH_POLICY - char tags[MAXSZ_POLICY_TAGS]; -#endif /* WITH_POLICY */ - int rc; + /* Case in which no reply is expected */ + if (!pdata) return 0; - switch (face->face.type) { - case FACE_TYPE_HICN: - case FACE_TYPE_HICN_LISTENER: - rc = ip_address_snprintf(local, MAXSZ_URL, &face->face.local_addr, - face->face.family); - if (rc >= MAXSZ_URL) - WARN("[hc_face_snprintf] Unexpected truncation of URL string"); - if (rc < 0) return rc; - rc = ip_address_snprintf(remote, MAXSZ_URL, &face->face.remote_addr, - face->face.family); - if (rc >= MAXSZ_URL) - WARN("[hc_face_snprintf] Unexpected truncation of URL string"); - if (rc < 0) return rc; - break; - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - case FACE_TYPE_TCP_LISTENER: - case FACE_TYPE_UDP_LISTENER: - rc = url_snprintf(local, MAXSZ_URL, face->face.family, - &face->face.local_addr, face->face.local_port); - if (rc >= MAXSZ_URL) - WARN("[hc_face_snprintf] Unexpected truncation of URL string"); - if (rc < 0) return rc; - rc = url_snprintf(remote, MAXSZ_URL, face->face.family, - &face->face.remote_addr, face->face.remote_port); - if (rc >= MAXSZ_URL) - WARN("[hc_face_snprintf] Unexpected truncation of URL string"); - if (rc < 0) return rc; - break; - default: - return -1; + if (hc_sock_receive_all(s, pdata) < 0) goto ERR_RECV; + } else if (s->ops.prepare) { + // hc_data_t *data = hc_data_create(OBJECT_TYPE_LISTENER); + // hc_data_push(data, NULL); + // No nested requests for now... + ssize_t size = s->ops.prepare(s, request, NULL); + _ASSERT(size == 0); /* Done */ + if (hc_request_is_complete(request)) { + if (pdata) { + *pdata = hc_request_get_data(request); + } else { + hc_request_reset_data(request); + } + hc_request_on_complete(request); + } } - // [#ID NAME] TYPE LOCAL_URL REMOTE_URL STATE/ADMIN_STATE (TAGS) -#ifdef WITH_POLICY - rc = policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->face.tags); - if (rc >= MAXSZ_POLICY_TAGS) - WARN("[hc_face_snprintf] Unexpected truncation of policy tags string"); - if (rc < 0) return rc; - - return snprintf( - s, size, "[#%d %s] %s %s %s %s %s/%s [%d] (%s)", face->id, face->name, - face->face.netdevice.index != NETDEVICE_UNDEFINED_INDEX - ? face->face.netdevice.name - : "*", - face_type_str(face->face.type), local, remote, - face_state_str(face->face.state), face_state_str(face->face.admin_state), - face->face.priority, tags); -#else - return snprintf(s, size, "[#%d %s] %s %s %s %s %s/%s", face->id, face->name, - face->face.netdevice.index != NETDEVICE_UNDEFINED_INDEX - ? face->face.netdevice.name - : "*", - face_type_str(face->face.type), local, remote, - face_state_str(face->face.state), - face_state_str(face->face.admin_state)); -#endif /* WITH_POLICY */ -} - -/*----------------------------------------------------------------------------* - * ROUTE - *----------------------------------------------------------------------------*/ - -int hc_route_create(hc_sock_t *s, hc_route_t *route) { - return s->hc_route_create(s, route); -} + return 0; -hc_result_t *hc_route_create_conf(hc_sock_t *s, hc_route_t *route) { - return s->hc_route_create_conf(s, route); +ERR_RECV: + hc_request_reset_data(request); +ERR_INIT: + hc_sock_free_request(s, request, true); +ERR_CHECK: +ERR_REQUEST: +ERR_VALIDATE: + if (pdata) *pdata = NULL; + return -1; } -int hc_route_delete(hc_sock_t *s, hc_route_t *route) { - return s->hc_route_delete(s, route); +int hc_execute(hc_sock_t *s, hc_action_t action, hc_object_type_t object_type, + hc_object_t *object, hc_data_t **pdata) { + return _hc_execute(s, action, object_type, object, NULL, NULL, pdata); } -int hc_route_list(hc_sock_t *s, hc_data_t **pdata) { - return s->hc_route_list(s, pdata); +int hc_execute_async(hc_sock_t *s, hc_action_t action, + hc_object_type_t object_type, hc_object_t *object, + hc_result_callback_t callback, void *callback_data) { + return _hc_execute(s, action, object_type, object, callback, callback_data, + NULL); } -int hc_route_list_async(hc_sock_t *s) { return s->hc_route_list_async(s); } - -/* ROUTE SNPRINTF */ - -/* /!\ Please update constants in header file upon changes */ -int hc_route_snprintf(char *s, size_t size, hc_route_t *route) { - /* interface cost prefix length */ - - char prefix[MAXSZ_IP_ADDRESS]; - int rc; - - rc = ip_address_snprintf(prefix, MAXSZ_IP_ADDRESS, &route->remote_addr, - route->family); - if (rc >= MAXSZ_IP_ADDRESS) - ; - if (rc < 0) return rc; - - return snprintf(s, size, "%s %*d %s %*d conn_id=%d", route->name, MAXSZ_COST, - route->cost, prefix, MAXSZ_LEN, route->len, route->face_id); -} +/* This function has to be called after the first execute until data and + * request are complete */ +// execute is just setting things up so that we can keep on calling this +// function repeatedly until completion. +// +// in the caller, we don't know how much we will receive in advance... so in +// asio for instance, we will use async_receive rather than async_read. +// XXX the question remains about the buffers... -int hc_route_validate(const hc_route_t *route) { - if (!IS_VALID_ID(route->connection_id)) { - ERROR("[hc_route_validate] Invalid connection id"); - return -1; - } - if (route->name[0] == '\0') { - if (!IS_VALID_FACE_ID(route->face_id)) { - ERROR("[hc_route_validate] Invalid face_id"); - return -1; - } - } else if (!IS_VALID_NAME(route->name) && !IS_VALID_STR_ID(route->name)) { - ERROR("[hc_route_validate] Invalid name specified"); - return -1; - } - if (!IS_VALID_FAMILY(route->family)) { - ERROR("[hc_route_validate] Invalid family specified"); - return -1; - } - if (!IS_VALID_ADDRESS(&route->remote_addr, route->family)) { - ERROR("[hc_route_validate] Invalid remote_addr specified"); - return -1; - } - if (!IS_VALID_ROUTE_COST(route->cost)) { - ERROR("[hc_route_validate] Invalid cost"); - return -1; - } - if (!IS_VALID_PREFIX_LEN(route->len)) { - ERROR("[hc_route_validate] Invalid len"); - return -1; - } +/* + * request -> write command + * + * SYNC : hc_data_t + * ASYNC : provide socket-level callback + * + * socket available -> read -> parse -> populate data + * data complete -> + */ - return 0; -} +/****************************************************************************** + * OBJECT-SPECIFIC FUNCTIONS (backwards compatibility) + ******************************************************************************/ /*----------------------------------------------------------------------------* * FACE + * + * This is an abstraction provided for when the module does not implement + *it. Alternative is to move it to hicn light *----------------------------------------------------------------------------*/ +#if 0 + /* FACE -> LISTENER */ -int hc_face_to_listener(const hc_face_t *face, hc_listener_t *listener) { - const face_t *f = &face->face; - - switch (f->type) { - case FACE_TYPE_HICN_LISTENER: - break; - case FACE_TYPE_TCP_LISTENER: - break; - case FACE_TYPE_UDP_LISTENER: - break; - default: - return -1; - } - return -1; /* XXX Not implemented */ -} /* LISTENER -> FACE */ @@ -748,225 +352,10 @@ int hc_listener_to_face(const hc_listener_t *listener, hc_face_t *face) { /* FACE -> CONNECTION */ -int hc_face_to_connection(const hc_face_t *face, hc_connection_t *connection, - bool generate_name) { - int rc; - - const face_t *f = &face->face; - switch (f->type) { - case FACE_TYPE_HICN: - *connection = (hc_connection_t){ - .type = FACE_TYPE_HICN, - .family = f->family, - .local_addr = f->local_addr, - .local_port = 0, - .remote_addr = f->remote_addr, - .remote_port = 0, - .admin_state = f->admin_state, - .state = f->state, -#ifdef WITH_POLICY - .priority = f->priority, - .tags = f->tags, -#endif /* WITH_POLICY */ - }; - rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", - f->netdevice.name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN( - "[hc_face_to_connection] Unexpected truncation of symbolic " - "name string"); - break; - case FACE_TYPE_TCP: - *connection = (hc_connection_t){ - .type = FACE_TYPE_TCP, - .family = f->family, - .local_addr = f->local_addr, - .local_port = f->local_port, - .remote_addr = f->remote_addr, - .remote_port = f->remote_port, - .admin_state = f->admin_state, - .state = f->state, -#ifdef WITH_POLICY - .priority = f->priority, - .tags = f->tags, -#endif /* WITH_POLICY */ - }; - if (generate_name) { - rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "tcp%u", RANDBYTE()); - if (rc >= SYMBOLIC_NAME_LEN) - WARN( - "[hc_face_to_connection] Unexpected truncation of " - "symbolic name string"); - } else { - memset(connection->name, 0, SYMBOLIC_NAME_LEN); - } - break; - case FACE_TYPE_UDP: - *connection = (hc_connection_t){ - .type = FACE_TYPE_UDP, - .family = f->family, - .local_addr = f->local_addr, - .local_port = f->local_port, - .remote_addr = f->remote_addr, - .remote_port = f->remote_port, - .admin_state = f->admin_state, - .state = f->state, -#ifdef WITH_POLICY - .priority = f->priority, - .tags = f->tags, -#endif /* WITH_POLICY */ - }; - if (generate_name) { - rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "udp%u", RANDBYTE()); - if (rc >= SYMBOLIC_NAME_LEN) - WARN( - "[hc_face_to_connection] Unexpected truncation of " - "symbolic name string"); - } else { - memset(connection->name, 0, SYMBOLIC_NAME_LEN); - } - snprintf(connection->interface_name, INTERFACE_LEN, "%s", - f->netdevice.name); - break; - default: - return -1; - } - - connection->id = face->id; - rc = snprintf(connection->interface_name, INTERFACE_LEN, "%s", - f->netdevice.name); - if (rc >= INTERFACE_LEN) - WARN( - "hc_face_to_connection] Unexpected truncation of interface name " - "string"); - - return 0; -} /* CONNECTION -> FACE */ - -int hc_connection_to_face(const hc_connection_t *connection, hc_face_t *face) { - int rc; - switch (connection->type) { - case FACE_TYPE_TCP: - *face = (hc_face_t){ - .id = connection->id, - .face = - { - .type = FACE_TYPE_TCP, - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - .admin_state = connection->admin_state, - .state = connection->state, -#ifdef WITH_POLICY - .priority = connection->priority, - .tags = connection->tags, -#endif /* WITH_POLICY */ - }, - }; - break; - case FACE_TYPE_UDP: - *face = (hc_face_t){ - .id = connection->id, - .face = - { - .type = FACE_TYPE_UDP, - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - .admin_state = connection->admin_state, - .state = connection->state, -#ifdef WITH_POLICY - .priority = connection->priority, - .tags = connection->tags, -#endif /* WITH_POLICY */ - }, - }; - break; - case FACE_TYPE_HICN: - *face = (hc_face_t){ - .id = connection->id, - .face = - { - .type = FACE_TYPE_HICN, - .family = connection->family, - .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX - .local_addr = connection->local_addr, - .remote_addr = connection->remote_addr, - .admin_state = connection->admin_state, - .state = connection->state, -#ifdef WITH_POLICY - .priority = connection->priority, - .tags = connection->tags, -#endif /* WITH_POLICY */ - }, - }; - break; - default: - return -1; - } - face->face.netdevice.name[0] = '\0'; - face->face.netdevice.index = 0; - rc = snprintf(face->name, SYMBOLIC_NAME_LEN, "%s", connection->name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN( - "[hc_connection_to_face] Unexpected truncation of symbolic name " - "string"); - rc = snprintf(face->face.netdevice.name, INTERFACE_LEN, "%s", - connection->interface_name); - if (rc >= INTERFACE_LEN) - WARN( - "[hc_connection_to_face] Unexpected truncation of interface name " - "string"); - netdevice_update_index(&face->face.netdevice); - return 0; -} - /* CONNECTION -> LISTENER */ -int hc_connection_to_local_listener(const hc_connection_t *connection, - hc_listener_t *listener) { - int rc; - - face_type_t listener_type; - switch (connection->type) { - case FACE_TYPE_UDP: - listener_type = FACE_TYPE_UDP_LISTENER; - break; - case FACE_TYPE_TCP: - listener_type = FACE_TYPE_TCP_LISTENER; - break; - default: - return -1; - } - - *listener = (hc_listener_t){ - .id = ~0, - .type = listener_type, - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - }; - rc = snprintf(listener->name, SYMBOLIC_NAME_LEN, "lst%u", - RANDBYTE()); // generate name - if (rc >= SYMBOLIC_NAME_LEN) - WARN( - "[hc_connection_to_local_listener] Unexpected truncation of " - "symbolic name string"); - rc = snprintf(listener->interface_name, INTERFACE_LEN, "%s", - connection->interface_name); - if (rc >= INTERFACE_LEN) - WARN( - "[hc_connection_to_local_listener] Unexpected truncation of " - "interface name string"); - - return 0; -} /*----------------------------------------------------------------------------* * Punting @@ -1013,7 +402,7 @@ int hc_punting_cmp(const hc_punting_t *p1, const hc_punting_t *p2) { rc = INT_CMP(p1->family, p2->family); if (rc != 0) return rc; - rc = ip_address_cmp(&p1->prefix, &p2->prefix, p1->family); + rc = ip_address_cmp(&p1->prefix, &p2->prefix); if (rc != 0) return rc; rc = INT_CMP(p1->prefix_len, p2->prefix_len); @@ -1022,10 +411,12 @@ int hc_punting_cmp(const hc_punting_t *p1, const hc_punting_t *p2) { return rc; } +#if 0 int hc_punting_parse(void *in, hc_punting_t *punting) { ERROR("hc_punting_parse not (yet) implemented."); return -1; } +#endif int hc_punting_snprintf(char *s, size_t size, hc_punting_t *punting) { ERROR("hc_punting_snprintf not (yet) implemented."); @@ -1083,36 +474,6 @@ int hc_stats_snprintf(char *s, size_t size, const hicn_light_stats_t *stats) { } /*----------------------------------------------------------------------------* - * Strategy - *----------------------------------------------------------------------------*/ - -int hc_strategy_list(hc_sock_t *s, hc_data_t **data) { - return s->hc_strategy_list(s, data); -} - -int hc_strategy_set(hc_sock_t *s, hc_strategy_t *strategy) { - return s->hc_strategy_set(s, strategy); -} - -int hc_strategy_add_local_prefix(hc_sock_t *s, hc_strategy_t *strategy) { - return s->hc_strategy_add_local_prefix(s, strategy); -} - -hc_result_t *hc_strategy_set_conf(hc_sock_t *s, hc_strategy_t *strategy) { - return s->hc_strategy_set_conf(s, strategy); -} - -hc_result_t *hc_strategy_add_local_prefix_conf(hc_sock_t *s, - hc_strategy_t *strategy) { - return s->hc_strategy_add_local_prefix_conf(s, strategy); -} - -/* /!\ Please update constants in header file upon changes */ -int hc_strategy_snprintf(char *s, size_t size, hc_strategy_t *strategy) { - return snprintf(s, size, "%s", strategy->name); -} - -/*----------------------------------------------------------------------------* * WLDR *----------------------------------------------------------------------------*/ @@ -1146,67 +507,55 @@ int hc_mapme_send_update(hc_sock_t *s, hc_mapme_t *mapme) { * Policy *----------------------------------------------------------------------------*/ -#ifdef WITH_POLICY /* POLICY SNPRINTF */ /* /!\ Please update constants in header file upon changes */ int hc_policy_snprintf(char *s, size_t size, hc_policy_t *policy) { return 0; } -int hc_policy_validate(const hc_policy_t *policy) { +int hc_policy_validate(const hc_policy_t *policy, bool allow_partial) { if (!IS_VALID_FAMILY(policy->family)) return -1; return 0; } -#endif /* WITH_POLICY */ +#endif /*----------------------------------------------------------------------------* - * SUBSCRIPTION + * VFT *----------------------------------------------------------------------------*/ -int hc_subscription_create(hc_sock_t *s, hc_subscription_t *subscription) { - return s->hc_subscription_create(s, subscription); -} - -int hc_subscription_delete(hc_sock_t *s, hc_subscription_t *subscription) { - return s->hc_subscription_delete(s, subscription); -} -hc_result_t *hc_subscription_create_conf(hc_sock_t *s, - hc_subscription_t *subscription) { - return s->hc_subscription_create_conf(s, subscription); -} - -hc_result_t *hc_subscription_delete_conf(hc_sock_t *s, - hc_subscription_t *subscription) { - return s->hc_subscription_delete_conf(s, subscription); -} - -/*----------------------------------------------------------------------------* - * STATISTICS - *----------------------------------------------------------------------------*/ -int hc_stats_get(hc_sock_t *s, hc_data_t **pdata) { - return s->hc_stats_get(s, pdata); +int hc_object_create(hc_sock_t *s, hc_object_type_t object_type, + hc_object_t *object) { + return hc_execute(s, ACTION_CREATE, object_type, object, NULL); } -int hc_stats_list(hc_sock_t *s, hc_data_t **pdata) { - return s->hc_stats_list(s, pdata); +int hc_object_get(hc_sock_t *s, hc_object_type_t object_type, + hc_object_t *object, hc_object_t **found) { + return hc_execute(s, ACTION_GET, object_type, object, NULL); } -/*----------------------------------------------------------------------------* - * Result - *----------------------------------------------------------------------------*/ - -hc_msg_t *hc_result_get_msg(hc_sock_t *s, hc_result_t *result) { - return s->hc_result_get_msg(result); +int hc_object_find(hc_sock_t *s, hc_object_type_t object_type, hc_data_t *data, + const hc_object_t *element, hc_object_t **found) { +// XXX NOT IMPLEMENTED +#if 0 + foreach_type(hc_object_t, x, data) { + if (hc_object_cmp(x, element) == 0) { + *found = x; + return 0; + } + }; +#endif + *found = NULL; /* this is optional */ + return 0; } -int hc_result_get_cmd_id(hc_sock_t *s, hc_result_t *result) { - return s->hc_result_get_cmd_id(result); +int hc_object_delete(hc_sock_t *s, hc_object_type_t object_type, + hc_object_t *object) { + return hc_execute(s, ACTION_DELETE, object_type, object, NULL); } -bool hc_result_get_success(hc_sock_t *s, hc_result_t *result) { - return s->hc_result_get_success(result); +int hc_object_list(hc_sock_t *s, hc_object_type_t object_type, + hc_data_t **pdata) { + return hc_execute(s, ACTION_LIST, object_type, NULL, pdata); } - -void hc_result_free(hc_result_t *result) { free(result); } |