summaryrefslogtreecommitdiffstats
path: root/ctrl/libhicnctrl/src/api.c
diff options
context:
space:
mode:
Diffstat (limited to 'ctrl/libhicnctrl/src/api.c')
-rw-r--r--ctrl/libhicnctrl/src/api.c1161
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); }