diff options
34 files changed, 2484 insertions, 1063 deletions
diff --git a/ctrl/facemgr/doc/interface.md b/ctrl/facemgr/doc/interface.md index 11c8da275..c7168ef23 100644 --- a/ctrl/facemgr/doc/interface.md +++ b/ctrl/facemgr/doc/interface.md @@ -281,7 +281,7 @@ The facelet event can then be defined and raised to the face maanger for further processing through the following code: ``` facelet_set_event(facelet, EVENT_TYPE_CREATE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); ``` Here the event is a facelet creation (`EVENT_TYPE_CREATE`). The full facelet API diff --git a/ctrl/facemgr/examples/run-bonjour.sh b/ctrl/facemgr/examples/run-bonjour.sh index c6c317b42..cc1c28e27 100755 --- a/ctrl/facemgr/examples/run-bonjour.sh +++ b/ctrl/facemgr/examples/run-bonjour.sh @@ -1,5 +1,21 @@ #!/bin/bash +# Notes for MacOS: +# +# - Browse all discoverable services +# dns-sd -B _services._dns-sd._udp local. +# +# - Browse all hICN services +# dns-sd -B _hicn._udp local. +# +# - Lookup for specific options +# dns-sd -L "hicn node" _hicn._udp local. +# +# - Lookup addresses +# dns-sd -G v4v6 adreena.local. +# +# NOTE: trailing dot '.' is optional + set -e PORT=9695 diff --git a/ctrl/facemgr/examples/updownsrv/updownsrv.c b/ctrl/facemgr/examples/updownsrv/updownsrv.c index e10247860..5d624583b 100644 --- a/ctrl/facemgr/examples/updownsrv/updownsrv.c +++ b/ctrl/facemgr/examples/updownsrv/updownsrv.c @@ -112,6 +112,12 @@ int main() { fd = create_unix_server(UNIX_PATH); if (fd < 0) exit(EXIT_FAILURE); + + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + perror("fcntl"); + exit(EXIT_FAILURE); + } + FD_SET (fd, &active_fd_set); /* Create timer */ @@ -121,7 +127,7 @@ int main() { exit(EXIT_FAILURE); } - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + if (fcntl(tfd, F_SETFL, O_NONBLOCK) < 0) { perror("fcntl"); exit(EXIT_FAILURE); } diff --git a/ctrl/facemgr/includes/CMakeLists.txt b/ctrl/facemgr/includes/CMakeLists.txt index 566424c67..e7265eebb 100644 --- a/ctrl/facemgr/includes/CMakeLists.txt +++ b/ctrl/facemgr/includes/CMakeLists.txt @@ -22,8 +22,10 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") set(TO_INSTALL_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/facemgr.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/api.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/cfg.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/loop.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/android_utility/android_utility.h PARENT_SCOPE diff --git a/ctrl/facemgr/includes/hicn/facemgr/api.h b/ctrl/facemgr/includes/hicn/facemgr/api.h index c5c29c219..e6151da11 100644 --- a/ctrl/facemgr/includes/hicn/facemgr/api.h +++ b/ctrl/facemgr/includes/hicn/facemgr/api.h @@ -26,6 +26,18 @@ #include <hicn/android_utility/android_utility.h> #endif +/* facemgr callbacks */ + +typedef enum { + FACEMGR_CB_TYPE_REGISTER_FD, + FACEMGR_CB_TYPE_UNREGISTER_FD, + FACEMGR_CB_TYPE_REGISTER_TIMER, + FACEMGR_CB_TYPE_UNREGISTER_TIMER, +} facemgr_cb_type_t; + +typedef int (*facemgr_cb_t)(void * loop, facemgr_cb_type_t type, void * data); + + /* * \brief Manual overlay settings (alternative to service discovery) */ @@ -64,11 +76,11 @@ facemgr_t * facemgr_create_with_config(facemgr_cfg_t * cfg); void facemgr_stop(facemgr_t *); void facemgr_free(facemgr_t *); + +void facemgr_set_callback(facemgr_t * facemgr, void * callback_owner, facemgr_cb_t callback); + int facemgr_set_config(facemgr_t * facemgr, facemgr_cfg_t * cfg); int facemgr_reset_config(facemgr_t * facemgr); -void facemgr_set_event_loop_handler(facemgr_t * facemgr, void * loop, - void * loop_register_fd, - void * loop_unregister_event); int facemgr_bootstrap(facemgr_t * facemgr); #ifdef __ANDROID__ void facemgr_set_jvm(facemgr_t * facemgr, JavaVM *jvm); diff --git a/ctrl/facemgr/includes/hicn/facemgr/cfg.h b/ctrl/facemgr/includes/hicn/facemgr/cfg.h index c121c687f..525e1a9e3 100644 --- a/ctrl/facemgr/includes/hicn/facemgr/cfg.h +++ b/ctrl/facemgr/includes/hicn/facemgr/cfg.h @@ -91,7 +91,7 @@ typedef struct { #define FACEMGR_CFG_DEFAULT_DISCOVERY true //#define DEFAULT_IGNORE "lo" #define FACEMGR_CFG_DEFAULT_IPV4 true -#define FACEMGR_CFG_DEFAULT_IPV6 true +#define FACEMGR_CFG_DEFAULT_IPV6 false @@ -140,6 +140,10 @@ int facemgr_cfg_set_face_type(facemgr_cfg_t * cfg, facemgr_face_type_t * face_ty int facemgr_cfg_unset_face_type(facemgr_cfg_t * cfg); int facemgr_cfg_set_discovery(facemgr_cfg_t * cfg, bool status); int facemgr_cfg_unset_discovery(facemgr_cfg_t * cfg); +int facemgr_cfg_set_ipv4(facemgr_cfg_t * cfg, bool status); +int facemgr_cfg_unset_ipv4(facemgr_cfg_t * cfg); +int facemgr_cfg_set_ipv6(facemgr_cfg_t * cfg, bool status); +int facemgr_cfg_unset_ipv6(facemgr_cfg_t * cfg); int facemgr_cfg_set_overlay(facemgr_cfg_t * cfg, int family, ip_address_t * local_addr, uint16_t local_port, diff --git a/ctrl/facemgr/includes/hicn/facemgr/loop.h b/ctrl/facemgr/includes/hicn/facemgr/loop.h new file mode 100644 index 000000000..77cbedb21 --- /dev/null +++ b/ctrl/facemgr/includes/hicn/facemgr/loop.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017-2019 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: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file loop.h + * \brief Face manager main loop + */ + +#ifndef FACEMGR_LOOP_H +#define FACEMGR_LOOP_H + +#include <hicn/facemgr/api.h> + +/* fd & timer callbacks */ + +typedef int (*fd_callback_t)(void * owner, int fd, void * data); + +typedef struct { + int fd; + void *owner; + fd_callback_t callback; + //int (*callback)(void * owner, int fd, void * data); + void *data; +} fd_callback_data_t; + +/* timer callbacks */ +typedef struct { + unsigned delay_ms; + void *owner; + fd_callback_t callback; + //int (*callback)(void * owner, int fd, void * data); + void *data; +} timer_callback_data_t; + +/* loop */ + +typedef struct loop_s loop_t; + +/** + * \brief Creates a main loop + * \return Pointer to the newly created loop, or NULL in case of error + */ +loop_t * loop_create(); + +/** + * \brief Releases a loop instance and frees all associated memory + * \param [in] loop - Pointer to the loop instance to free + */ +void loop_free(loop_t * loop); + +/** + * \brief Runs the loop instance to process events + * \param [in] loop - Pointer to the loop instance + */ +void loop_dispatch(loop_t * loop); + +/** + * \brief Terminates the dispatching of events + * \param [in] loop - Pointer to the loop instance + */ +void loop_undispatch(loop_t * loop); + +/** + * \brief Breaks out of the loop + * \param [in] loop - Pointer to the loop instance + */ +void loop_break(loop_t * loop); + + +/** + * \brief Callback for loop helpers + * \param [in] loop - Pointer to the loop instance + * \param [in] type - Type of service to be requested + * \param [in] data - Service specific data + */ +int loop_callback(loop_t * loop, facemgr_cb_type_t type, void * data); + +#endif /* FACEMGR_LOOP_H */ diff --git a/ctrl/facemgr/src/CMakeLists.txt b/ctrl/facemgr/src/CMakeLists.txt index f99e57e07..88f554c40 100644 --- a/ctrl/facemgr/src/CMakeLists.txt +++ b/ctrl/facemgr/src/CMakeLists.txt @@ -24,6 +24,7 @@ set(HEADER_FILES error.h facelet.h interface.h + loop.h util/hash.h util/map.h util/set.h @@ -32,12 +33,27 @@ set(HEADER_FILES set(SOURCE_FILES api.c cfg.c + cfg_file.c error.c facelet.c interface.c util/log.c ) +if(APPLE) +set(SOURCE_FILES + ${SOURCE_FILES} + loop_dispatcher.c +) +endif() + +if (LINUX) +set(SOURCE_FILES + ${SOURCE_FILES} + loop_libevent.c +) +endif() + set(INCLUDE_DIRS ./ ../includes/ diff --git a/ctrl/facemgr/src/api.c b/ctrl/facemgr/src/api.c index de0f062d3..a1507bd70 100644 --- a/ctrl/facemgr/src/api.c +++ b/ctrl/facemgr/src/api.c @@ -49,9 +49,12 @@ #define DEFAULT_PORT 9695 +#define MAX_FDS 10 + typedef struct { interface_t * interface; - void * event; + int fds[MAX_FDS]; + size_t num_fds; } interface_map_data_t; TYPEDEF_SET_H(facelet_cache, facelet_t *); @@ -60,8 +63,6 @@ TYPEDEF_SET(facelet_cache, facelet_t *, facelet_cmp, facelet_snprintf); TYPEDEF_MAP_H(interface_map, const char *, interface_map_data_t *); TYPEDEF_MAP(interface_map, const char *, interface_map_data_t *, strcmp, string_snprintf, generic_snprintf); -int int_cmp(int x, int y) { return x - y; } - TYPEDEF_MAP_H(bonjour_map, netdevice_t *, interface_t *); TYPEDEF_MAP(bonjour_map, netdevice_t *, interface_t *, netdevice_cmp, generic_snprintf, generic_snprintf); @@ -106,10 +107,9 @@ struct facemgr_s { JavaVM *jvm; #endif /* __ANDROID__ */ - /* Event loop support */ - void * loop; - void * (*loop_register_fd)(void * loop, int fd, void * cb, void * cb_args); - int (*loop_unregister_event)(void * loop, void * event); + /* Callback */ + facemgr_cb_t callback; + void * callback_owner; /****************************/ /* Internal data structures */ @@ -191,28 +191,42 @@ ERR_INTERFACE_MAP: int facemgr_finalize(facemgr_t * facemgr) { + int ret = 0; int rc; - /* TODO Free all interfaces: pass free to map */ - rc = interface_map_finalize(&facemgr->interface_map); - if (rc < 0) - goto ERR; + if (rc < 0) { + ERROR("[facemgr_finalize] Could not finalize interface_map"); + ret = -1; + } + + /* Free all facelets from cache */ + facelet_t ** facelet_array; + int n = facelet_cache_get_array(&facemgr->facelet_cache, &facelet_array); + if (n < 0) { + ERROR("[facemgr_finalize] Could not retrieve facelets in cache"); + } else { + for (unsigned i = 0; i < n; i++) { + facelet_t * facelet = facelet_array[i]; + if (facelet_cache_remove(&facemgr->facelet_cache, facelet, NULL)) { + ERROR("[facemgr_finalize] Could not purge facelet from cache"); + } + facelet_free(facelet); + } + free(facelet_array); + } rc = facelet_cache_finalize(&facemgr->facelet_cache); if (rc < 0) - goto ERR; + ret = -1; #ifdef __linux__ rc = bonjour_map_finalize(&facemgr->bonjour_map); if (rc < 0) - goto ERR; + ret = -1; #endif /* __linux__ */ - return 0; - -ERR: - return -1; + return ret; } AUTOGENERATE_CREATE_FREE(facemgr); @@ -251,13 +265,12 @@ facemgr_create_with_config(facemgr_cfg_t * cfg) return facemgr; } -int facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet); +int facemgr_callback(facemgr_t * facemgr, interface_cb_type_t type, void * data); int facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, void * cfg, interface_t ** pinterface) { - int fd, rc; - void * event = NULL; + int fd; char rand_name[RAND_NAME_LEN+1]; interface_t * interface; @@ -276,29 +289,23 @@ facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * ty ERROR("Error creating interface %s [%s]", name, type); goto ERR_CREATE; } - interface_set_callback(interface, facemgr_on_event, facemgr); + interface_set_callback(interface, facemgr, facemgr_callback); fd = interface_initialize(interface, cfg); if (fd < 0) goto ERR_INIT; - if (fd != 0) { - event = facemgr->loop_register_fd(facemgr->loop, fd, interface->ops->callback, interface); - if (event == NULL) - goto ERR_FD; - } interface_map_data_t * interface_map_data = malloc(sizeof(interface_map_data_t)); if (!interface_map_data) goto ERR_MAP_DATA; - *interface_map_data = (interface_map_data_t) { .interface = interface, - .event = event, + .fds = {0}, + .num_fds = 0, }; - rc = interface_map_add(&facemgr->interface_map, interface->name, interface_map_data); - if (rc < 0) + if (interface_map_add(&facemgr->interface_map, interface->name, interface_map_data) < 0) goto ERR_MAP_ADD; DEBUG("Interface %s created successfully.", name); @@ -309,9 +316,6 @@ facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * ty ERR_MAP_ADD: free(interface_map_data); ERR_MAP_DATA: - if (fd > 0) - facemgr->loop_unregister_event(facemgr->loop, interface_map_data->event); -ERR_FD: interface_finalize(interface); ERR_INIT: interface_free(interface); @@ -328,7 +332,7 @@ facemgr_delete_interface(facemgr_t * facemgr, interface_t * interface) interface_map_data_t * interface_map_data = NULL; - DEBUG("Removing interface %s\n", interface->name); + DEBUG("Removing interface %s", interface->name); rc = interface_map_remove(&facemgr->interface_map, interface->name, &interface_map_data); if (rc < 0) return -1; @@ -336,12 +340,14 @@ facemgr_delete_interface(facemgr_t * facemgr, interface_t * interface) if (!interface_map_data) return -1; - free(interface_map_data); - - rc = facemgr->loop_unregister_event(facemgr->loop, interface_map_data->event); - if (rc < 0) - return -1; + for (unsigned i = 0; i < interface_map_data->num_fds; i++) { + int fd = interface_map_data->fds[i]; + facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_UNREGISTER_FD, &fd); + if (rc < 0) + WARN("[facemgr_delete_interface] Error unregistering fd %d for interface", fd); + } + free(interface_map_data); interface_finalize(interface); interface_free(interface); @@ -445,26 +451,18 @@ facelet_cache_lookup(const facelet_cache_t * facelet_cache, facelet_t * facelet, } *cached_facelets = malloc(n * sizeof(facelet_t*)); - DEBUG("cache match n = %d", n); - int num_match = 0; for (unsigned i = 0; i < n; i++) { char buf[128]; facelet_snprintf(buf, 128, facelet_array[i]); - DEBUG("- facelet_array[%d] %s", i, buf); facelet_snprintf(buf, 128, facelet); - DEBUG(" facelet %s", buf); - DEBUG("match ?"); if (!facelet_match(facelet_array[i], facelet)) { - DEBUG("no match"); continue; } - DEBUG("match!"); (*cached_facelets)[num_match++] = facelet_array[i]; } free(facelet_array); - DEBUG("return nummatch=%d", num_match); return num_match; } @@ -519,24 +517,36 @@ facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet) return -3; } - /* IPv4 */ - bool ipv4; - if (facemgr_cfg_get_ipv4(facemgr->cfg, &netdevice, netdevice_type, - &ipv4) < 0) - return -1; - if (!ipv4) { - DEBUG("Ignored IPv4..."); - return -3; - } + switch(family) { + case AF_INET: + { + bool ipv4; + if (facemgr_cfg_get_ipv4(facemgr->cfg, &netdevice, netdevice_type, + &ipv4) < 0) + return -1; + if (!ipv4) { + DEBUG("Ignored IPv4 facelet..."); + return -3; + } + break; + } - /* IPv6 */ - bool ipv6; - if (facemgr_cfg_get_ipv6(facemgr->cfg, &netdevice, netdevice_type, - &ipv6) < 0) - return -1; - if (!ipv6) { - DEBUG("Ignored IPv6..."); - return -3; + case AF_INET6: + { + bool ipv6; + if (facemgr_cfg_get_ipv6(facemgr->cfg, &netdevice, netdevice_type, + &ipv6) < 0) + return -1; + if (!ipv6) { + DEBUG("Ignored IPv6 facelet..."); + return -3; + } + break; + } + + default: + DEBUG("Ignored facelet with unknown family"); + return -2; } return 0; @@ -839,6 +849,7 @@ facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet) */ rc = facemgr_facelet_satisfy_rules(facemgr, facelet); if (rc == -3) { + facelet_set_status(facelet, FACELET_STATUS_IGNORED); /* Does not satisfy rules */ return 0; } @@ -884,7 +895,7 @@ facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet) char facelet_s[MAXSZ_FACELET]; facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet); - DEBUG("---[ FACELET CREATE : %s ] ---", facelet_s); + //DEBUG("---[ FACELET CREATE : %s ] ---", facelet_s); /* Do we have enough information about the facelet ? */ if (!facelet_validate_face(facelet)) { @@ -921,6 +932,7 @@ facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet) * \param [in] facemgr - Pointer to the face manager instance * \param [in] facelet - Pointer to the facelet event to process * \return 0 if everything went correctly, or -1 in case of error. + * -2 means we ignored the face purposedly */ int facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet) @@ -931,10 +943,10 @@ facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet) if (facelet_get_netdevice(facelet, &netdevice) < 0) return -1; if (!IS_VALID_NETDEVICE(netdevice)) - return 0; + return -2; return facelet_cache_add(&facemgr->facelet_cache, facelet); } - return 0; + return -2; } /** @@ -959,7 +971,7 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) char facelet_s[MAXSZ_FACELET]; facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet); - DEBUG("---[ FACELET UPDATE : %s ] ---", facelet_s); + //DEBUG("---[ FACELET UPDATE : %s ] ---", facelet_s); /* Sets face type */ if (!facelet_has_face_type(facelet)) { @@ -1013,6 +1025,7 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) rc = facemgr_facelet_satisfy_rules(facemgr, facelet); if (rc == -3) { + facelet_set_status(facelet, FACELET_STATUS_IGNORED); /* Does not satisfy rules */ return 0; } @@ -1048,6 +1061,7 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) rc = facemgr_facelet_satisfy_rules(facemgr, facelet); if (rc == -3) { + facelet_set_status(facelet, FACELET_STATUS_IGNORED); /* Does not satisfy rules */ return 0; } @@ -1067,6 +1081,15 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) case FACELET_STATUS_CONFLICT: ERROR("[facemgr_process_update] Conflict resolution (not) yet implemented"); return -1; + + case FACELET_STATUS_ERROR: + ERROR("[facemgr_process_update] Case ERROR (not) yet implemented"); + break; + + case FACELET_STATUS_IGNORED: + ERROR("[facemgr_process_update] Case IGNORED (not) yet implemented"); + break; + case FACELET_STATUS_N: ERROR("[facemgr_process_update] Facelet in error"); return -1; @@ -1117,13 +1140,15 @@ facemgr_process_delete(facemgr_t * facemgr, facelet_t * facelet) int facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) { + bool remove_facelet = true; int ret = 0; + int rc; assert(facelet_in); char facelet_s[MAXSZ_FACELET]; facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet_in); - DEBUG("----------------------------------"); - DEBUG("EVENT %s\n", facelet_s); + //DEBUG("----------------------------------"); + DEBUG("EVENT %s", facelet_s); facelet_t ** cached_facelets = NULL; int n = facelet_cache_lookup(&facemgr->facelet_cache, facelet_in, &cached_facelets); @@ -1131,7 +1156,6 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) ERROR("[facemgr_on_event] Error during cache lookup"); goto ERR; } - DEBUG("num matches n=%d", n); if (n == 0) { /* This is a new facelet... we expect a CREATE event. */ switch(facelet_get_event(facelet_in)) { @@ -1141,7 +1165,9 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) ERROR("[facemgr_on_event] Error adding facelet to cache"); return -1; } - DEBUG("Facelet added to cache"); + //DEBUG("Facelet added to cache"); + + remove_facelet = false; if (facemgr_process_create(facemgr, facelet_in) < 0) { ERROR("[facemgr_on_event] Error processing CREATE event"); @@ -1151,7 +1177,10 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) case FACELET_EVENT_GET: /* Insert new facelet in cached */ - if (facemgr_process_get(facemgr, facelet_in) < 0) { + rc = facemgr_process_get(facemgr, facelet_in); + if (rc == 0) + remove_facelet = false; + if (rc == -1) { ERROR("[facemgr_on_event] Error processing GET event"); goto ERR; } @@ -1189,7 +1218,6 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) * reconciliation by sending appropriate updates to the forwarder */ facelet_t * facelet = cached_facelets[i]; - DEBUG("... match #%d", i); switch(facelet_get_event(facelet_in)) { case FACELET_EVENT_CREATE: // This case will occur when we try to re-create existing faces, @@ -1247,14 +1275,41 @@ ERR: ret = -1; DUMP_CACHE: +#if 1 DEBUG(" <CACHE>"); facelet_cache_dump(&facemgr->facelet_cache); DEBUG(" </CACHE>"); DEBUG("</EVENT ret=%d>", ret); DEBUG("----------------------------------"); +#endif + + if (remove_facelet) + facelet_free(facelet_in); + return ret; } +int facemgr_callback(facemgr_t * facemgr, interface_cb_type_t type, void * data) +{ + switch(type) { + case INTERFACE_CB_TYPE_RAISE_EVENT: + return facemgr_on_event(facemgr, data); + case INTERFACE_CB_TYPE_REGISTER_FD: + return facemgr->callback(facemgr->callback_owner, + FACEMGR_CB_TYPE_REGISTER_FD, data); + case INTERFACE_CB_TYPE_REGISTER_TIMER: + return facemgr->callback(facemgr->callback_owner, + FACEMGR_CB_TYPE_REGISTER_TIMER, data); + case INTERFACE_CB_TYPE_UNREGISTER_TIMER: + return facemgr->callback(facemgr->callback_owner, + FACEMGR_CB_TYPE_UNREGISTER_TIMER, data); + case INTERFACE_CB_TYPE_UNREGISTER_FD: + return facemgr->callback(facemgr->callback_owner, + FACEMGR_CB_TYPE_UNREGISTER_FD, data); + } + return -1; +} + int facemgr_bootstrap(facemgr_t * facemgr) { @@ -1395,15 +1450,15 @@ void facemgr_stop(facemgr_t * facemgr) facemgr_delete_interface(facemgr, facemgr->nl); /* Delete all bonjour interfaces */ - interface_t ** bonjour_array;// = NULL; // NOTE: would allow avoiding tests + interface_t ** bonjour_array = NULL; int n = bonjour_map_get_value_array(&facemgr->bonjour_map, &bonjour_array); - if (n > 0) { - netdevice_t ** netdevice_array; // = NULL; + if (n >= 0) { + netdevice_t ** netdevice_array = NULL; int m = bonjour_map_get_key_array(&facemgr->bonjour_map, &netdevice_array); - if (m > 0) { + if (m >= 0) { assert(m == n); for (int i = 0; i < n; i++) { /* Fail silently */ - DEBUG("Deleting bonjour interface associated to %s (%p)\n", + DEBUG("Deleting bonjour interface associated to %s (%p)", netdevice_array[i]->name, bonjour_array[i]); facemgr_delete_interface(facemgr, bonjour_array[i]); } @@ -1435,11 +1490,11 @@ void facemgr_set_jvm(facemgr_t * facemgr, JavaVM *jvm) } #endif /* __ANDROID__ */ -void facemgr_set_event_loop_handler(facemgr_t * facemgr, void * loop, void * loop_register_fd, void * loop_unregister_event) +void +facemgr_set_callback(facemgr_t * facemgr, void * callback_owner, facemgr_cb_t callback) { - facemgr->loop = loop; - facemgr->loop_register_fd = loop_register_fd; - facemgr->loop_unregister_event = loop_unregister_event; + facemgr->callback = callback; + facemgr->callback_owner = callback_owner; } void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data) diff --git a/ctrl/facemgr/src/cfg.c b/ctrl/facemgr/src/cfg.c index be7ea33bb..527da54e7 100644 --- a/ctrl/facemgr/src/cfg.c +++ b/ctrl/facemgr/src/cfg.c @@ -490,6 +490,20 @@ int facemgr_cfg_finalize(facemgr_cfg_t * cfg) { /* TODO Free all rules */ + facemgr_cfg_rule_t ** rule_array; + int n = facemgr_cfg_rule_set_get_array(cfg->rule_set, &rule_array); + if (n < 0) { + ERROR("[facemgr_cfg_finalize] Could not retrieve rule set array from configuration"); + } else { + for (unsigned i = 0; i < n; i++) { + facemgr_cfg_rule_t * rule = rule_array[i]; + if (facemgr_cfg_rule_set_remove(cfg->rule_set, rule, NULL) < 0) { + ERROR("[facemgr_cfg_finalize] Could not remove rule from set"); + } + facemgr_cfg_rule_free(rule); + } + free(rule_array); + } facemgr_cfg_rule_set_free(cfg->rule_set); return facemgr_cfg_override_finalize(&cfg->global); } @@ -531,6 +545,38 @@ facemgr_cfg_unset_discovery(facemgr_cfg_t * cfg) return 0; } +int facemgr_cfg_set_ipv4(facemgr_cfg_t * cfg, bool status) +{ + cfg->global.is_ipv4 = true; + cfg->global.ipv4 = status; + DEBUG("<global>"); + DEBUG(" <ipv4>%d</ipv4>", cfg->global.ipv4); + DEBUG("</global>"); + return 0; +} + +int facemgr_cfg_unset_ipv4(facemgr_cfg_t * cfg) +{ + cfg->global.is_ipv4 = false; + return 0; +} + +int facemgr_cfg_set_ipv6(facemgr_cfg_t * cfg, bool status) +{ + cfg->global.is_ipv6 = true; + cfg->global.ipv6 = status; + DEBUG("<global>"); + DEBUG(" <ipv6>%d</ipv6>", cfg->global.ipv6); + DEBUG("</global>"); + return 0; +} + +int facemgr_cfg_unset_ipv6(facemgr_cfg_t * cfg) +{ + cfg->global.is_ipv6 = false; + return 0; +} + int facemgr_cfg_set_overlay(facemgr_cfg_t * cfg, int family, ip_address_t * local_addr, uint16_t local_port, @@ -689,12 +735,10 @@ facemgr_cfg_get_override(const facemgr_cfg_t * cfg, #endif /* __ANDROID__ */ } /* Found match... do we have an override for face_type */ - DEBUG("override found nd=%s, ndt=%s", rule_array[i]->match.interface_name, netdevice_type_str[rule_array[i]->match.interface_type]); *override = &rule_array[i]->override; goto FOUND; } - DEBUG("override not found"); *override = NULL; FOUND: diff --git a/ctrl/facemgr/src/cfg_file.c b/ctrl/facemgr/src/cfg_file.c new file mode 100644 index 000000000..5c187e0a2 --- /dev/null +++ b/ctrl/facemgr/src/cfg_file.c @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2017-2019 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: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file cfg_file.c + * \brief Implementation of configuration file parsing + */ + +#include <unistd.h> // access +#include <libconfig.h> +#include "cfg_file.h" + +#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x)) + +static const char * DEFAULT_CFGFILES[] = { + "/etc/facemgr.conf", + "~/facemgr.conf", +}; + +int +probe_cfgfile(char * f) +{ + for (unsigned i = 0; i < ARRAYSIZE(DEFAULT_CFGFILES); i++) { + if (access(DEFAULT_CFGFILES[i], F_OK ) != -1) { + if (!realpath(DEFAULT_CFGFILES[i], f)) + continue; + return 0; + } + } + return -1; +} + +int +parse_config_global(facemgr_cfg_t * cfg, config_setting_t * setting) +{ + /* - face_type */ + + const char *face_type_str; + facemgr_face_type_t face_type; + if (config_setting_lookup_string(setting, "face_type", &face_type_str)) { + if (strcasecmp(face_type_str, "auto") == 0) { + face_type = FACEMGR_FACE_TYPE_DEFAULT; + } else + if (strcasecmp(face_type_str, "native-udp") == 0) { + face_type = FACEMGR_FACE_TYPE_NATIVE_UDP; + } else + if (strcasecmp(face_type_str, "native-tcp") == 0) { + face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; + } else + if (strcasecmp(face_type_str, "overlay-udp") == 0) { + face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; + } else + if (strcasecmp(face_type_str, "overlay-tcp") == 0) { + face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP; + } else { + ERROR("Invalid face type in section 'global'"); + return -1; + } + + int rc = facemgr_cfg_set_face_type(cfg, &face_type); + if (rc < 0) + goto ERR; + } + + /* - disable_discovery */ + + int disable_discovery; + if (config_setting_lookup_bool(setting, "disable_discovery", + &disable_discovery)) { + int rc = facemgr_cfg_set_discovery(cfg, !disable_discovery); + if (rc < 0) + goto ERR; + } + + /* - disable_ipv4 */ + + int disable_ipv4; + if (config_setting_lookup_bool(setting, "disable_ipv4", + &disable_ipv4)) { + int rc = facemgr_cfg_set_ipv4(cfg, !disable_ipv4); + if (rc < 0) + goto ERR; + } + + /* - disable ipv6 */ + + int disable_ipv6; + if (config_setting_lookup_bool(setting, "disable_ipv6", + &disable_ipv6)) { + int rc = facemgr_cfg_set_ipv6(cfg, !disable_ipv6); + if (rc < 0) + goto ERR; + } + + /* - overlay */ + config_setting_t *overlay = config_setting_get_member(setting, "overlay"); + if (overlay) { + + /* ipv4 */ + config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4"); + if (overlay_v4) { + const char * local_addr_str, * remote_addr_str; + ip_address_t local_addr = IP_ADDRESS_EMPTY; + ip_address_t remote_addr = IP_ADDRESS_EMPTY; + ip_address_t * local_addr_p = NULL; + ip_address_t * remote_addr_p = NULL; + int local_port = 0; + int remote_port = 0; + + if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) { + if (ip_address_pton(local_addr_str, &local_addr) < 0) { + ERROR("Error parsing v4 local addr"); + goto ERR; + } + local_addr_p = &local_addr; + } + + if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) { + if (!IS_VALID_PORT(local_port)) + goto ERR; + } + + if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) { + if (ip_address_pton(remote_addr_str, &remote_addr) < 0) { + ERROR("Error parsing v4 remote addr"); + goto ERR; + } + remote_addr_p = &remote_addr; + } + + if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) { + if (!IS_VALID_PORT(remote_port)) + goto ERR; + } + int rc = facemgr_cfg_set_overlay(cfg, AF_INET, + local_addr_p, local_port, + remote_addr_p, remote_port); + if (rc < 0) + goto ERR; + } + + /* ipv6 */ + config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6"); + if (overlay_v6) { + const char * local_addr_str, * remote_addr_str; + ip_address_t local_addr = IP_ADDRESS_EMPTY; + ip_address_t remote_addr = IP_ADDRESS_EMPTY; + ip_address_t * local_addr_p = NULL; + ip_address_t * remote_addr_p = NULL; + int local_port = 0; + int remote_port = 0; + + if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) { + if (ip_address_pton(local_addr_str, &local_addr) < 0) { + ERROR("Error parsing v6 local addr"); + goto ERR; + } + local_addr_p = &local_addr; + } + + if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) { + if (!IS_VALID_PORT(local_port)) + goto ERR; + } + + if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) { + if (ip_address_pton(remote_addr_str, &remote_addr) < 0) { + ERROR("Error parsing v6 remote addr"); + goto ERR; + } + remote_addr_p = &remote_addr; + } + + if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) { + if (!IS_VALID_PORT(remote_port)) + goto ERR; + } + int rc = facemgr_cfg_set_overlay(cfg, AF_INET6, + local_addr_p, local_port, + remote_addr_p, remote_port); + if (rc < 0) + goto ERR; + } + + } /* overlay */ + + return 0; + +ERR: + return -1; +} + +int +parse_config_rules(facemgr_cfg_t * cfg, config_setting_t * setting) +{ + /* List of match-override tuples */ + facemgr_cfg_rule_t * rule; + + int count = config_setting_length(setting); + for (unsigned i = 0; i < count; ++i) { + config_setting_t * rule_setting = config_setting_get_elem(setting, i); + + /* Sanity check */ + + config_setting_t * match_setting = config_setting_get_member(rule_setting, "match"); + if (!match_setting) { + ERROR("Missing match section in rule #%d", i); + goto ERR_CHECK; + } + + config_setting_t * override_setting = config_setting_get_member(rule_setting, "override"); + if (!override_setting) { + ERROR("Missing override section in rule #%d", i); + goto ERR_CHECK; + } + + rule = facemgr_cfg_rule_create(); + if (!rule) + goto ERR_RULE; + + /* Parse match */ + + const char * interface_name = NULL; + config_setting_lookup_string(match_setting, "interface_name", &interface_name); + + const char * interface_type_str; + netdevice_type_t interface_type = NETDEVICE_TYPE_UNDEFINED; + if (config_setting_lookup_string(match_setting, "interface_type", &interface_type_str)) { + if (strcasecmp(interface_type_str, "wired") == 0) { + interface_type = NETDEVICE_TYPE_WIRED; + } else + if (strcasecmp(interface_type_str, "wifi") == 0) { + interface_type = NETDEVICE_TYPE_WIFI; + } else + if (strcasecmp(interface_type_str, "cellular") == 0) { + interface_type = NETDEVICE_TYPE_CELLULAR; + } else { + ERROR("Unknown interface type in rule #%d", i); + goto ERR; + } + } + + if ((!interface_name) && (interface_type == NETDEVICE_TYPE_UNDEFINED)) { + ERROR("Empty match section in rule #%d", i); + goto ERR; + } + + /* Associate match to rule */ + + int rc = facemgr_cfg_rule_set_match(rule, interface_name, interface_type); + if (rc < 0) + goto ERR; + + /* Parse override */ + + /* - face_type */ + + const char *face_type_str; + facemgr_face_type_t face_type; + if (config_setting_lookup_string(override_setting, "face_type", &face_type_str)) { + if (strcasecmp(face_type_str, "auto")) { + /* We currently hardcode different behaviours based on the OS */ +#ifdef __ANDROID__ + face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; +#else + face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; +#endif + } else + if (strcasecmp(face_type_str, "native-udp") == 0) { + face_type = FACEMGR_FACE_TYPE_NATIVE_UDP; + } else + if (strcasecmp(face_type_str, "native-tcp") == 0) { + face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; + } else + if (strcasecmp(face_type_str, "overlay-udp") == 0) { + face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; + } else + if (strcasecmp(face_type_str, "overlay-tcp") == 0) { + face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP; + } else { + ERROR("Invalid face type in section 'global'"); + return -1; + } + + int rc = facemgr_cfg_rule_set_face_type(rule, &face_type); + if (rc < 0) + goto ERR; + } + + /* - disable_discovery */ + + int disable_discovery; + if (config_setting_lookup_bool(override_setting, "disable_discovery", + &disable_discovery)) { + int rc = facemgr_cfg_rule_set_discovery(rule, !disable_discovery); + if (rc < 0) + goto ERR; + } + + /* - disable_ipv4 */ + + int disable_ipv4; + if (config_setting_lookup_bool(override_setting, "disable_ipv4", + &disable_ipv4)) { + INFO("Ignored setting 'disable_ipv4' in rule #%d (not implemented).", i); +#if 0 + int rc = facemgr_cfg_rule_set_ipv4(rule, !disable_ipv4); + if (rc < 0) + goto ERR; +#endif + } + + /* - disable ipv6 */ + + int disable_ipv6; + if (config_setting_lookup_bool(override_setting, "disable_ipv6", + &disable_ipv6)) { + INFO("Ignored setting 'disable_ipv6' in rule #%d (not implemented).", i); +#if 0 + int rc = facemgr_cfg_rule_set_ipv6(rule, !disable_ipv6); + if (rc < 0) + goto ERR; +#endif + } + + /* - ignore */ + int ignore; + if (config_setting_lookup_bool(override_setting, "ignore", &ignore)) { + int rc = facemgr_cfg_rule_set_ignore(rule, !!ignore); + if (rc < 0) + goto ERR; + } + + /* - tags */ + config_setting_t *tag_settings = config_setting_get_member(override_setting, "tags"); + if (tag_settings) { + INFO("Ignored setting 'tags' in rule #%d (not implemented).", i); +#if 0 + policy_tags_t tags = POLICY_TAGS_EMPTY; + for (unsigned j = 0; j < config_setting_length(tag_settings); j++) { + const char * tag_str = config_setting_get_string_elem(tag_settings, j); + policy_tag_t tag = policy_tag_from_str(tag_str); + if (tag == POLICY_TAG_N) + goto ERR; + policy_tags_add(&tags, tag); + } + + int rc = facemgr_cfg_rule_set_tags(rule, tags); + if (rc < 0) + goto ERR; + +#if 0 + char tags_str[MAXSZ_POLICY_TAGS]; + policy_tags_snprintf(tags_str, MAXSZ_POLICY_TAGS, tags); + DEBUG("Added tags tags=%s", tags_str); +#endif +#endif + } + + /* - overlay */ + config_setting_t *overlay = config_setting_get_member(override_setting, "overlay"); + if (overlay) { + + /* ipv4 */ + config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4"); + if (overlay_v4) { + const char * local_addr_str, * remote_addr_str; + ip_address_t local_addr = IP_ADDRESS_EMPTY; + ip_address_t remote_addr = IP_ADDRESS_EMPTY; + ip_address_t * local_addr_p = NULL; + ip_address_t * remote_addr_p = NULL; + int local_port = 0; + int remote_port = 0; + + if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) { + ip_address_pton(local_addr_str, &local_addr); + local_addr_p = &local_addr; + } + + if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) { + if (!IS_VALID_PORT(local_port)) + goto ERR; + } + + if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) { + ip_address_pton(remote_addr_str, &remote_addr); + remote_addr_p = &remote_addr; + } + + if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) { + if (!IS_VALID_PORT(remote_port)) + goto ERR; + } + int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET, + local_addr_p, local_port, + remote_addr_p, remote_port); + if (rc < 0) + goto ERR; + } + + /* ipv6 */ + config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6"); + if (overlay_v6) { + const char * local_addr_str, * remote_addr_str; + ip_address_t local_addr = IP_ADDRESS_EMPTY; + ip_address_t remote_addr = IP_ADDRESS_EMPTY; + ip_address_t * local_addr_p = NULL; + ip_address_t * remote_addr_p = NULL; + int local_port = 0; + int remote_port = 0; + + if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) { + ip_address_pton(local_addr_str, &local_addr); + local_addr_p = &local_addr; + } + + if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) { + if (!IS_VALID_PORT(local_port)) + goto ERR; + } + + if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) { + ip_address_pton(remote_addr_str, &remote_addr); + remote_addr_p = &remote_addr; + } + + if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) { + if (!IS_VALID_PORT(remote_port)) + goto ERR; + } + int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET6, + local_addr_p, local_port, + remote_addr_p, remote_port); + if (rc < 0) + goto ERR; + } + + } /* overlay */ + + /* Add newly created rule */ + + rc = facemgr_cfg_add_rule(cfg, rule); + if (rc < 0) + goto ERR; + } + return 0; + +ERR: + facemgr_cfg_rule_free(rule); +ERR_RULE: +ERR_CHECK: + return -1; +} + +/* Currently not using facemgr_cfg_t */ +int +parse_config_log(facemgr_cfg_t * cfg, config_setting_t * setting) +{ + const char *log_level_str; + if (config_setting_lookup_string(setting, "log_level", &log_level_str)) { + if (strcasecmp(log_level_str, "FATAL") == 0) { + log_conf.log_level = LOG_FATAL; + } else + if (strcasecmp(log_level_str, "ERROR") == 0) { + log_conf.log_level = LOG_ERROR; + } else + if (strcasecmp(log_level_str, "WARN") == 0) { + log_conf.log_level = LOG_WARN; + } else + if (strcasecmp(log_level_str, "INFO") == 0) { + log_conf.log_level = LOG_INFO; + } else + if (strcasecmp(log_level_str, "DEBUG") == 0) { + log_conf.log_level = LOG_DEBUG; + } else + if (strcasecmp(log_level_str, "TRACE") == 0) { + log_conf.log_level = LOG_TRACE; + } else { + ERROR("Invalid log level in section 'log'"); + return -1; + } + } + return 0; +} + +int +parse_config_file(const char * cfgpath, facemgr_cfg_t * cfg) +{ + /* Reading configuration file */ + config_t cfgfile; + config_setting_t *setting; + + config_init(&cfgfile); + + /* Read the file. If there is an error, report it and exit. */ + if(!config_read_file(&cfgfile, cfgpath)) + goto ERR_FILE; + + setting = config_lookup(&cfgfile, "global"); + if (setting) { + int rc = parse_config_global(cfg, setting); + if (rc < 0) + goto ERR_PARSE; + } + + setting = config_lookup(&cfgfile, "rules"); + if (setting) { + int rc = parse_config_rules(cfg, setting); + if (rc < 0) + goto ERR_PARSE; + } + + setting = config_lookup(&cfgfile, "log"); + if (setting) { + int rc = parse_config_log(cfg, setting); + if (rc < 0) + goto ERR_PARSE; + } + + config_destroy(&cfgfile); + return 0; + +ERR_FILE: + ERROR("Could not read configuration file %s", cfgpath); + fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile), + config_error_line(&cfgfile), config_error_text(&cfgfile)); + config_destroy(&cfgfile); + exit(EXIT_FAILURE); + return -1; +ERR_PARSE: + fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile), + config_error_line(&cfgfile), config_error_text(&cfgfile)); + config_destroy(&cfgfile); + return -1; +} + diff --git a/ctrl/facemgr/src/cfg_file.h b/ctrl/facemgr/src/cfg_file.h new file mode 100644 index 000000000..dfce041d8 --- /dev/null +++ b/ctrl/facemgr/src/cfg_file.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019 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: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file cfg_file.h + * \brief Configuration file parsing + */ + +#ifndef FACEMGR_CFG_FILE_H +#define FACEMGR_CFG_FILE_H + +#include <hicn/facemgr/cfg.h> + +/** + * \brief Probe for the configuration file location + * \param [in] f - File name + * \return 0 in case of success, -1 otherwise. + */ +int probe_cfgfile(char * f); + +/** + * \brief Parses the provided configuration file into the facemgr configuration + * data structure. + * \param [in] cfgpath - Path to the configuration file + * \param [out] cfg - Pre-allocated configuration data structure + * \return 0 in case of success, -1 otherwise. + */ +int parse_config_file(const char * cfgpath, facemgr_cfg_t * cfg); + +#endif /* FACEMGR_CFG_FILE_H */ diff --git a/ctrl/facemgr/src/common.h b/ctrl/facemgr/src/common.h index 9d6e8ca87..56bd706f1 100644 --- a/ctrl/facemgr/src/common.h +++ b/ctrl/facemgr/src/common.h @@ -28,9 +28,6 @@ //#define DEBUG -/* Useful types and macros for comparisons */ -typedef int(*cmp_t)(const void * x, const void * y); - #define INT_CMP(x, y) x < y ? -1 : (x == y ? 0 : 1) /* Dump with indent */ diff --git a/ctrl/facemgr/src/facelet.c b/ctrl/facemgr/src/facelet.c index def901ff3..6d6d74c2b 100644 --- a/ctrl/facemgr/src/facelet.c +++ b/ctrl/facemgr/src/facelet.c @@ -80,7 +80,6 @@ struct facelet_s { /* Joins */ bool bj_done; bool au_done; - int num_pending; }; const char * facelet_event_str[] = { @@ -111,7 +110,6 @@ facelet_create() facelet->bj_done = false; facelet->au_done = false; - facelet->num_pending = 0; facelet->event = FACELET_EVENT_UNDEFINED; @@ -305,7 +303,6 @@ facelet_create_from_face(face_t * face) facelet->bj_done = false; facelet->au_done = false; - facelet->num_pending = 0; facelet->event = FACELET_EVENT_UNDEFINED; @@ -343,7 +340,6 @@ facelet_dup(const facelet_t * current_facelet) facelet->bj_done = current_facelet->bj_done; facelet->au_done = current_facelet->au_done; - facelet->num_pending = current_facelet->num_pending; return facelet; @@ -752,32 +748,6 @@ facelet_set_status(facelet_t * facelet, facelet_status_t status) facelet->status = status; } -int -facelet_add_pending(facelet_t * facelet) -{ - assert(facelet); - facelet->num_pending++; - return 0; -} - -int -facelet_remove_pending(facelet_t * facelet) -{ - assert(facelet); - if (facelet->num_pending == 0) - return -1; - facelet->num_pending--; - return 0; -} - -bool -facelet_has_pending(const facelet_t * facelet) -{ - assert(facelet); - DEBUG("num pending=%d\n", facelet->num_pending); - return (facelet->num_pending > 0); -} - void facelet_set_bj_done(facelet_t * facelet) { @@ -790,7 +760,6 @@ facelet_unset_bj_done(facelet_t * facelet) facelet->bj_done = false; } - bool facelet_is_bj_done(const facelet_t * facelet) { @@ -822,14 +791,6 @@ facelet_set_event(facelet_t * facelet, facelet_event_t event) } int -facelet_raise_event(facelet_t * facelet, const interface_t * interface) -{ - if (interface->callback) - interface->callback(interface->callback_data, facelet); - return 0; -} - -int facelet_snprintf(char * s, size_t size, facelet_t * facelet) { char * cur = s; @@ -838,14 +799,13 @@ facelet_snprintf(char * s, size_t size, facelet_t * facelet) assert(facelet); /* Header + key attributes (netdevice + family) */ - rc = snprintf(cur, s + size - cur, "<Facelet %s (%s) [%d]", + rc = snprintf(cur, s + size - cur, "<Facelet %s (%s)", // FIXME, better than the event would be the action to be performed next facelet_event_str[facelet->event], (facelet->family == AF_INET) ? "AF_INET" : (facelet->family == AF_INET6) ? "AF_INET6" : (facelet->family == AF_UNSPEC) ? "AF_UNSPEC" : - "unknown", - facelet->num_pending); + "unknown"); if (rc < 0) return rc; cur += rc; @@ -1000,7 +960,7 @@ HEURISTIC_END: } if (facelet_has_face_type(facelet)) { - rc = snprintf(cur, s + size - cur, " face_type=IP%s/%s", + rc = snprintf(cur, s + size - cur, " face_type=LAYER%s/%s", FACEMGR_FACE_TYPE_STR(facelet->face_type)); if (rc < 0) return rc; diff --git a/ctrl/facemgr/src/facelet.h b/ctrl/facemgr/src/facelet.h index e07572e23..16c23b12e 100644 --- a/ctrl/facemgr/src/facelet.h +++ b/ctrl/facemgr/src/facelet.h @@ -31,7 +31,7 @@ #include <hicn/ctrl/face.h> #include <hicn/facemgr.h> -#include "interface.h" +#define MAXSZ_FACELET 1024 /* NOTE: Any test should be sufficient */ #define IS_VALID_NETDEVICE(netdevice) ((netdevice.index != 0) && (netdevice.name[0] != '\0')) @@ -46,6 +46,8 @@ typedef struct facelet_s facelet_t; _(DIRTY) \ _(CONFLICT) \ _(DELETED) \ + _(IGNORED) \ + _(ERROR) \ _(N) typedef enum { @@ -170,10 +172,6 @@ int facelet_merge(facelet_t * facelet, const facelet_t * facelet_to_merge); facelet_status_t facelet_get_status(const facelet_t * facelet); void facelet_set_status(facelet_t * facelet, facelet_status_t status); -int facelet_add_pending(facelet_t * facelet); -int facelet_remove_pending(facelet_t * facelet); -bool facelet_has_pending(const facelet_t * facelet); - void facelet_set_bj_done(facelet_t * facelet); void facelet_unset_bj_done(facelet_t * facelet); bool facelet_is_bj_done(const facelet_t * facelet); @@ -183,17 +181,12 @@ bool facelet_is_au_done(const facelet_t * facelet); facelet_event_t facelet_get_event(const facelet_t * facelet); void facelet_set_event(facelet_t * facelet, facelet_event_t event); -/** - * \brief Create and raises an event to the face manager - * \param [in] event_type - Type of the event to create - * \param [in] facelet - Facelet to communicate with the event - * \param [in] interface - Interface that raised the event (or NULL if it was - * created but the face manager itself, or is a joined event) - */ -int facelet_raise_event(facelet_t * facelet, const interface_t * interface); - int facelet_snprintf(char * buf, size_t size, facelet_t * facelet); -#define MAXSZ_FACELET 1024 +#define DUMP_FACELET(msg, facelet) do { \ + char buf[MAXSZ_FACELET]; \ + facelet_snprintf(buf, MAXSZ_FACELET, facelet); \ + DEBUG("%s : %s", msg, buf); \ +} while(0) #endif /* FACEMGR_FACELET_H */ diff --git a/ctrl/facemgr/src/interface.c b/ctrl/facemgr/src/interface.c index 3e6bc0854..5cefcb98c 100644 --- a/ctrl/facemgr/src/interface.c +++ b/ctrl/facemgr/src/interface.c @@ -18,10 +18,12 @@ * \brief Implementation of interface base class. */ +#include <assert.h> #include <stdlib.h> #include <string.h> #include "facelet.h" #include "interface.h" +#include <hicn/facemgr/loop.h> /* *_callback_data_t */ #include "util/map.h" TYPEDEF_MAP_H(interface_ops_map, const char *, const interface_ops_t *); @@ -41,6 +43,28 @@ interface_register(const interface_ops_t * ops) return 0; } +int +interface_unregister_all() +{ + int ret = 0; + const char ** ops_name_array = NULL; + int n = interface_ops_map_get_key_array(interface_ops_map, &ops_name_array); + if (n < 0) { + ERROR("[interface_unregister_all] Could not get interface ops array"); + ret = -1; + } else { + for (unsigned i = 0; i < n; i++) { + const char * ops_name = ops_name_array[i]; + if (interface_ops_map_remove(interface_ops_map, ops_name, NULL) < 0) { + ERROR("[interface_unregister_all] Could not remove %s from interface ops map", ops_name); + ret = -1; + } + } + free(ops_name_array); + } + return ret; +} + interface_t * interface_create(const char * name, const char * type) { @@ -60,7 +84,7 @@ interface_create(const char * name, const char * type) /* this should use type */ interface->ops = ops; interface->callback = NULL; - interface->callback_data = NULL; + interface->callback_owner = NULL; interface->data = NULL; return interface; @@ -74,10 +98,11 @@ interface_free(interface_t * interface) } void -_interface_set_callback(interface_t * interface, callback_t callback, void * callback_data) +interface_set_callback(interface_t * interface, void * callback_owner, + interface_cb_t callback) { interface->callback = callback; - interface->callback_data = callback_data; + interface->callback_owner = callback_owner; } int @@ -103,3 +128,59 @@ interface_on_event(interface_t * interface, const facelet_t * facelet) return -1; return interface->ops->on_event(interface, facelet); } + +int +interface_raise_event(interface_t * interface, facelet_t * facelet) +{ + assert(interface->callback); + return interface->callback(interface->callback_owner, + INTERFACE_CB_TYPE_RAISE_EVENT, facelet); +} + +int +interface_register_fd(interface_t * interface, int fd, void * data) +{ + assert(interface->callback); + fd_callback_data_t fd_callback = { + .fd = fd, + .owner = interface, + .callback = (fd_callback_t)interface->ops->callback, + .data = data, + }; + return interface->callback(interface->callback_owner, + INTERFACE_CB_TYPE_REGISTER_FD, &fd_callback); +} + +int +interface_unregister_fd(interface_t * interface, int fd) +{ + assert(interface->callback); + return interface->callback(interface->callback_owner, + INTERFACE_CB_TYPE_UNREGISTER_FD, &fd); +} + +typedef int (*interface_fd_callback_t)(interface_t * interface, int fd, void * unused); + +int +interface_register_timer(interface_t * interface, unsigned delay_ms, + interface_fd_callback_t callback, void * data) +{ + assert(interface->callback); + timer_callback_data_t timer_callback = { + .delay_ms = delay_ms, + .owner = interface, + .callback = (fd_callback_t)callback, + .data = data, + }; + int rc = interface->callback(interface->callback_owner, + INTERFACE_CB_TYPE_REGISTER_TIMER, &timer_callback); + return rc; +} + +int +interface_unregister_timer(interface_t * interface, int fd) +{ + assert(interface->callback); + return interface->callback(interface->callback_owner, + INTERFACE_CB_TYPE_UNREGISTER_TIMER, &fd); +} diff --git a/ctrl/facemgr/src/interface.h b/ctrl/facemgr/src/interface.h index 331312bde..d99f4fc8e 100644 --- a/ctrl/facemgr/src/interface.h +++ b/ctrl/facemgr/src/interface.h @@ -29,15 +29,22 @@ #define FACEMGR_INTERFACE_H #include <stdbool.h> +#include <hicn/facemgr/loop.h> -struct facelet_s; -typedef int (*callback_t)(struct facelet_s * facelet, void * callback_data); +typedef enum { + INTERFACE_CB_TYPE_REGISTER_FD, + INTERFACE_CB_TYPE_UNREGISTER_FD, + INTERFACE_CB_TYPE_RAISE_EVENT, + INTERFACE_CB_TYPE_REGISTER_TIMER, + INTERFACE_CB_TYPE_UNREGISTER_TIMER, +} interface_cb_type_t; -struct interface_s; +typedef int (*interface_cb_t)(facemgr_t * facemgr, interface_cb_type_t type, void * data); /** * \brief Interface operations */ +struct interface_s; typedef struct { /** The type given to the interfaces */ char * type; @@ -46,7 +53,7 @@ typedef struct { /* Destructor */ int (*finalize)(struct interface_s * interface); /* Callback upon file descriptor event (iif previously registered) */ - int (*callback)(struct interface_s * interface); + int (*callback)(struct interface_s * interface, int fd, void * data); /* Callback upon face events coming from the face manager */ int (*on_event)(struct interface_s * interface, const struct facelet_s * facelet); } interface_ops_t; @@ -54,8 +61,10 @@ typedef struct { typedef struct interface_s { char * name; const interface_ops_t * ops; - callback_t callback; - void * callback_data; + + interface_cb_t callback; + void * callback_owner; + void * data; } interface_t; @@ -83,19 +92,51 @@ interface_t * interface_create(const char * name, const char * type); */ void interface_free(interface_t * interface); -/** - * This function is equivalent to interface_set_callback, which should be - * preferred. The difference is the lack of explicit type casts which should - * simplify the calling syntax. - */ -void _interface_set_callback(interface_t * interface, callback_t callback, void * callback_data); -#define interface_set_callback(interface, callback, callback_data) \ - _interface_set_callback(interface, (callback_t)callback, (void*)callback_data) +void interface_set_callback(interface_t * interface, void * callback_owner, interface_cb_t callback); int interface_initialize(interface_t * interface, void * cfg); + int interface_finalize(interface_t * interface); int interface_on_event(interface_t * interface, const struct facelet_s * facelet); +/** + * \brief Raises a facelet event to the face manager + * \param [in] interface - Interface that raised the event (or NULL if it was + * created but the face manager itself, or is a joined event) + * \param [in] facelet - Facelet to communicate with the event + * \return Error code + */ +int interface_callback(interface_t * interface, interface_cb_type_t type, void * data); + +int interface_raise_event(interface_t * interface, facelet_t * facelet); + +int interface_register_fd(interface_t * interface, int fd, void * data); + +int interface_unregister_fd(interface_t * interface, int fd); + +typedef int (*interface_fd_callback_t)(interface_t * interface, int fd, void * unused); + +/** + * \brief Registers a timer event + * \param [in] interface - Pointer to the interface responsible for the timer + * \param [in] delay_ms - Delay in milliseconds between timer events (first + * occurence happends after this delay) + * \param [in] callback - Callback function to be triggered + * \param [in] data - User data + * \return A positive value uniquely identifying the timer, or -1 in case of + * error + */ +int interface_register_timer(interface_t * interface, unsigned delay_ms, + interface_fd_callback_t callback, void * data); + +/** + * \brief Unregisters a timer event + * \param [in] interface - Pointer to the interface responsible for the timer + * \param [in] fd - Timer identifier + * \return 0 in case of success, -1 otherwise + */ +int interface_unregister_timer(interface_t * interface, int fd); + #endif /* FACEMGR_INTERFACE_H */ diff --git a/ctrl/facemgr/src/interfaces/android_utility/android_utility.c b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c index bb612507f..a4aa2cbfc 100644 --- a/ctrl/facemgr/src/interfaces/android_utility/android_utility.c +++ b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c @@ -124,7 +124,7 @@ int au_on_event(interface_t * interface, const facelet_t * facelet) DEBUG("sending AU udpate"); facelet_set_event(facelet_new, FACELET_EVENT_UPDATE); - facelet_raise_event(facelet_new, interface); + interface_raise_event(interface, facelet_new); return 0; } diff --git a/ctrl/facemgr/src/interfaces/bonjour/bonjour.c b/ctrl/facemgr/src/interfaces/bonjour/bonjour.c index d7b27b995..4d09d89bb 100644 --- a/ctrl/facemgr/src/interfaces/bonjour/bonjour.c +++ b/ctrl/facemgr/src/interfaces/bonjour/bonjour.c @@ -107,7 +107,9 @@ int bj_initialize(interface_t * interface, void * cfg) WSAStartup(versionWanted, &wsaData); #endif - return data->sock; + interface_register_fd(interface, data->sock, NULL); + + return 0; ERR_BUFFER: #ifndef __ANDROID__ @@ -268,7 +270,7 @@ callback(const struct sockaddr* from, mdns_entry_type_t entry, uint16_t type, //facelet_set_remote_port(facelet, ((struct sockaddr_in*)&addr)->sin_port); facelet_set_event(facelet, FACELET_EVENT_UPDATE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); break; } @@ -291,7 +293,7 @@ callback(const struct sockaddr* from, mdns_entry_type_t entry, uint16_t type, //facelet_set_remote_port(facelet, ((struct sockaddr_in6*)&addr)->sin6_port); facelet_set_event(facelet, FACELET_EVENT_UPDATE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); break; } @@ -317,7 +319,7 @@ callback(const struct sockaddr* from, mdns_entry_type_t entry, uint16_t type, facelet_set_remote_port(facelet, srv.port); facelet_set_event(facelet, FACELET_EVENT_UPDATE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); facelet = facelet_create(); facelet_set_netdevice(facelet, bj_data->cfg.netdevice); @@ -325,7 +327,7 @@ callback(const struct sockaddr* from, mdns_entry_type_t entry, uint16_t type, facelet_set_remote_port(facelet, srv.port); facelet_set_event(facelet, FACELET_EVENT_UPDATE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); break; } @@ -374,7 +376,7 @@ callback(const struct sockaddr* from, mdns_entry_type_t entry, uint16_t type, * The fact we use a single fd does not allow us to get user_data associated to * the query. */ -int bj_callback(interface_t * interface) +int bj_callback(interface_t * interface, int fd, void * unused) { bj_data_t * data = (bj_data_t*)interface->data; DEBUG("Got an mDNS reply"); diff --git a/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c b/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c index 2fdc3f7c3..1f20177c2 100644 --- a/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c +++ b/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c @@ -17,6 +17,7 @@ * \file interfaces/hicn_light/hicn_light.c * \brief hICN light interface */ +#include <assert.h> #include <stdbool.h> #include <stdio.h> // snprintf #include <time.h> // time @@ -32,34 +33,43 @@ #define DEFAULT_ROUTE_COST 0 +#define INTERVAL_MS 1000 + typedef enum { HL_STATE_UNDEFINED, + HL_STATE_CONNECTING, HL_STATE_FACES_SENT, HL_STATE_DONE, } hl_state_t; typedef struct { - hc_sock_t * s; + hc_sock_t * s; /* NULL means no active socket */ hl_state_t state; + int timer_fd; /* 0 means no active timer */ } hl_data_t; +/* Forward declarations */ +int hl_timeout(interface_t * interface, int fd, void * unused); + int hl_process_state(interface_t * interface) { hl_data_t * data = (hl_data_t *)interface->data; - hc_data_t * faces; #if 0 char buf[MAXSZ_FACE]; #endif switch(data->state) { - case HL_STATE_UNDEFINED: - if (hc_face_list(data->s, &faces) < 0) { + case HL_STATE_UNDEFINED: // FIXME + case HL_STATE_CONNECTING: // FIXME + if (hc_face_list_async(data->s) < 0) { /* Blocking call */ printf("Could not retrieve face list\n"); return -1; } + break; +#if 0 foreach_face(f, faces) { #if 0 hc_face_snprintf(buf, MAXSZ_FACE, f); @@ -67,9 +77,10 @@ int hl_process_state(interface_t * interface) #endif facelet_t * facelet = facelet_create_from_face(&f->face); facelet_set_event(facelet, FACELET_EVENT_GET); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); } break; +#endif case HL_STATE_FACES_SENT: break; @@ -81,36 +92,132 @@ int hl_process_state(interface_t * interface) return 0; } -int hl_initialize(interface_t * interface, void * cfg) + +int +hl_after_connect(interface_t * interface) { - hl_data_t * data = malloc(sizeof(hl_data_t)); - if (!data) { - ERROR("[hicn_light] Out of memory!"); - goto ERR_MALLOC; + hl_data_t * data = interface->data; + // XXX cancel timer + + /* File descriptor for control socket operations */ + if (interface_register_fd(interface, hc_sock_get_fd(data->s), NULL) < 0) { + ERROR("[hc_connect] Error registering fd"); + goto ERR_FD; + } + + data->state = HL_STATE_UNDEFINED; + + hl_process_state(interface); + + return 0; + + //interface_unregister_fd(interface, hc_sock_get_fd(data->s)); +ERR_FD: + return -1; +} + +int _hl_connect(interface_t * interface); + +int +hl_connect_timeout(interface_t * interface, int fd, void * unused) +{ + int rc = _hl_connect(interface); + if (rc < 0) { + ERROR("[hl_initialize] Error during connection reattempt; next attempt in %ds", INTERVAL_MS / 1000); + return -1; } + if (interface_unregister_timer(interface, fd) < 0) { + ERROR("[hl_connect_timeout] Could not cancel timer after successful connect"); + } + + /* Connect success */ + return hl_after_connect(interface); +} + + +int +_hl_connect(interface_t * interface) +{ + hl_data_t * data = interface->data; + assert(!data->s); + data->s = hc_sock_create(); if (data->s <= 0) { - ERROR("[hicn_light] Could not create control socket"); + ERROR("[hc_connect] Could not create control socket"); goto ERR_SOCK; } if (hc_sock_connect(data->s) < 0) { - ERROR("[hicn_light] Could not connect control socket"); + ERROR("[hc_connect] Could not connect control socket"); goto ERR_CONNECT; } - data->state = HL_STATE_UNDEFINED; + return hl_after_connect(interface); + +ERR_CONNECT: + hc_sock_free(data->s); + data->s = NULL; +ERR_SOCK: + return -1; + +} + +int hl_disconnect(interface_t * interface) +{ + hl_data_t * data = (hl_data_t *) interface->data; + if (data->timer_fd > 0) + interface_unregister_timer(interface, data->timer_fd); + + if (data->s) { + interface_unregister_fd(interface, hc_sock_get_fd(data->s)); + hc_sock_free(data->s); + } + + return 0; +} + +int +hl_connect(interface_t * interface) +{ + hl_data_t * data = interface->data; + + if (_hl_connect(interface) >= 0) + return 0; + + /* Timer for managing the connection to the forwarder */ + DEBUG("Connection to forwarder failed... next retry in %ds", INTERVAL_MS / 1000); + data->timer_fd = interface_register_timer(interface, INTERVAL_MS, hl_connect_timeout, NULL); + if (data->timer_fd < 0) { + ERROR("[hc_connect] Could not initialize reattempt timer"); + return -1; + } + + return 0; +} + +int +hl_initialize(interface_t * interface, void * cfg) +{ + hl_data_t * data = malloc(sizeof(hl_data_t)); + if (!data) { + ERROR("[hicn_light] Out of memory!"); + goto ERR_MALLOC; + } + + data->s = NULL; + data->timer_fd = 0; interface->data = data; - hl_process_state(interface); + if (hl_connect(interface) < 0) { + ERROR("[hl_initialize] Error during connection to forwarder"); + goto ERR_CONNECT; + } return 0; ERR_CONNECT: - hc_sock_free(data->s); -ERR_SOCK: free(data); ERR_MALLOC: return -1; @@ -118,8 +225,12 @@ ERR_MALLOC: int hl_finalize(interface_t * interface) { - //hc_data_t * data = interface->data; - //hc_sock_close(data->s); + hl_data_t * data = (hl_data_t *) interface->data; + + hl_disconnect(interface); + + free(data); + return 0; } @@ -131,9 +242,23 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) hl_data_t * data = (hl_data_t *)interface->data; face_t * face = NULL; - if (facelet_get_face(facelet, &face) < 0) + + /* NOTE + * - One example where this fails (and it is normal) is when we delete a + * face that was not completely created, because for instance bonjour did + * not give any data + */ + if (facelet_get_face(facelet, &face) < 0) { + ERROR("Could not retrieve face from facelet"); + return -1; + } + + if (!data->s) { + /* We are not connected to the forwarder */ return -1; + } + switch(facelet_get_event(facelet)) { case FACELET_EVENT_CREATE: @@ -147,10 +272,10 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) } INFO("Created face id=%d\n", hc_face.id); -#if 0 - /* Add default route v4 */ + /* Adding default routs e*/ +#if 1 route = (hc_route_t) { - .face_id = face.id, + .face_id = hc_face.id, .family = AF_INET, .remote_addr = IPV4_ANY, .len = 0, @@ -161,12 +286,9 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) ERROR("Failed to create default hICN/IPv4 route"); goto ERR; } - INFO("Successfully created default hICN/IPv4 route."); -#endif -#if 0 route = (hc_route_t) { - .face_id = face.id, + .face_id = hc_face.id, .family = AF_INET6, .remote_addr = IPV6_ANY, .len = 0, @@ -176,9 +298,8 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) ERROR("Failed to create default hICN/IPv6 route"); goto ERR; } -#endif - /* Adding default route */ +#else route = (hc_route_t) { .face_id = hc_face.id, .family = AF_INET6, @@ -193,6 +314,8 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) ERROR("Failed to create hICN/IPv6 route"); goto ERR; } +#endif + INFO("Successfully created default route(s)."); break; @@ -212,6 +335,8 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) if (facelet_get_admin_state_status(facelet) == FACELET_ATTR_STATUS_DIRTY) { hc_face.face = *face; hc_face_t * face_found; + + printf("hc_face_get\n"); rc = hc_face_get(data->s, &hc_face, &face_found); if (rc < 0) { ERROR("Failed to find face\n"); @@ -224,7 +349,6 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) char conn_id_or_name[SYMBOLIC_NAME_LEN]; snprintf(conn_id_or_name, SYMBOLIC_NAME_LEN, "%d", face_found->id); free(face_found); - printf("Face id = %d\n", face_found->id); face_state_t admin_state; if (facelet_get_admin_state(facelet, &admin_state) < 0) { @@ -233,6 +357,7 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) } printf("Setting admin state"); + printf("hc_connection_set_admin_state\n"); if (hc_connection_set_admin_state(data->s, conn_id_or_name, admin_state) < 0) { ERROR("Failed to update admin state"); goto ERR; @@ -247,15 +372,56 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) goto ERR; } + face_free(face); return 0; ERR: + face_free(face); return -1; } +int hl_callback(interface_t * interface, int fd, void * unused) +{ + hl_data_t * data = (hl_data_t*)interface->data; + + hc_data_t * faces; + if (hc_sock_callback(data->s, &faces) < 0){ + DEBUG("Closing socket... reconnecting..."); + if (interface_unregister_fd(interface, hc_sock_get_fd(data->s)) < 0) { + ERROR("[hl_initialize] Error registering fd"); + } + hc_sock_free(data->s); + data->s = NULL; + hl_connect(interface); + return 0; + } + + if (faces->complete) { + foreach_face(f, faces) { +#if 1 + char buf[MAXSZ_FACE]; + hc_face_snprintf(buf, MAXSZ_FACE, f); + printf("Face: %s\n", buf); +#else + facelet_t * facelet = facelet_create_from_face(&f->face); + facelet_set_event(facelet, FACELET_EVENT_GET); + interface_raise_event(interface, facelet); +#endif + } + } + hc_data_free(faces); + + /* XXX how do we know what object we get back */ + + /* We have a queue of pending data elements per active query */ + + return 0; +} + const interface_ops_t hicn_light_ops = { .type = "hicn_light", .initialize = hl_initialize, .finalize = hl_finalize, .on_event = hl_on_event, + .callback = hl_callback, }; diff --git a/ctrl/facemgr/src/interfaces/netlink/netlink.c b/ctrl/facemgr/src/interfaces/netlink/netlink.c index 08cbe4d3b..babf1c305 100644 --- a/ctrl/facemgr/src/interfaces/netlink/netlink.c +++ b/ctrl/facemgr/src/interfaces/netlink/netlink.c @@ -67,6 +67,7 @@ int nl_process_state(interface_t * interface) switch(data->state) { case NL_STATE_UNDEFINED: { + DEBUG("[nl_process_state] UNDEFINED->LINK_SENT"); struct { struct nlmsghdr header; struct rtgenmsg payload; @@ -93,6 +94,7 @@ int nl_process_state(interface_t * interface) case NL_STATE_LINK_SENT: { + DEBUG("[nl_process_state] LINK_SENT->ADDR_SENT"); /* Issue a first query to receive static state */ struct { struct nlmsghdr header; @@ -120,6 +122,7 @@ int nl_process_state(interface_t * interface) case NL_STATE_ADDR_SENT: { + DEBUG("[nl_process_state] ADDR_SENT->DONE"); data->state = NL_STATE_DONE; break; } @@ -167,9 +170,13 @@ int nl_initialize(interface_t * interface, void * cfg) interface->data = data; + interface_register_fd(interface, data->fd, NULL); + +#if 1 nl_process_state(interface); +#endif - return data->fd; // 0; + return 0; ERR_BIND: close(data->fd); @@ -205,7 +212,7 @@ int parse_link(struct nlmsghdr * h, facelet_t ** facelet, *facelet = facelet_create(); netdevice_t * netdevice = netdevice_create_from_name(interface_name); if (!netdevice) - goto ERROR; + goto ERROR_ND; int rc = facelet_set_netdevice(*facelet, *netdevice); if (rc < 0) goto ERROR; @@ -237,9 +244,12 @@ int parse_link(struct nlmsghdr * h, facelet_t ** facelet, // - ifi_change // - IFLA_PROTINFO + netdevice_free(netdevice); return 0; ERROR: + netdevice_free(netdevice); +ERROR_ND: facelet_free(*facelet); *facelet = NULL; @@ -303,7 +313,7 @@ int parse_addr(struct nlmsghdr * h, facelet_t ** facelet, netdevice_t * netdevice = netdevice_create_from_index(ifa->ifa_index); if (!netdevice) { ERROR("[netlink.parse_addr] error creating netdevice '%s'", interface_name); - goto ERROR; + goto ERROR_ND; } if (interface_name) { @@ -324,16 +334,19 @@ int parse_addr(struct nlmsghdr * h, facelet_t ** facelet, goto ERROR; } + netdevice_free(netdevice); return 0; ERROR: + netdevice_free(netdevice); +ERROR_ND: facelet_free(*facelet); *facelet = NULL; return -1; } -int nl_callback(interface_t * interface) +int nl_callback(interface_t * interface, int fd, void * unused) { nl_data_t * data = (nl_data_t*)interface->data; @@ -403,10 +416,10 @@ int nl_callback(interface_t * interface) break; } - DEBUG("Interface %s: address was removed", interface_name); + //DEBUG("Interface %s: address was removed", interface_name); if (facelet) { facelet_set_event(facelet, FACELET_EVENT_DELETE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); } break; } @@ -423,11 +436,11 @@ int nl_callback(interface_t * interface) break; } - DEBUG("Interface %s: new address was assigned: %s", interface_name, interface_address); + //DEBUG("Interface %s: new address was assigned: %s", interface_name, interface_address); if (facelet) { facelet_set_event(facelet, FACELET_EVENT_UPDATE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); } break; } @@ -441,12 +454,15 @@ int nl_callback(interface_t * interface) ERROR("Error parsing link message"); break; } - if (facelet) { - facelet_set_event(facelet, FACELET_EVENT_DELETE); - facelet_raise_event(facelet, interface); - } - DEBUG("Network interface %s was removed", interface_name); + //DEBUG("Network interface %s was removed", interface_name); + + if (!facelet) + break; + + facelet_set_event(facelet, FACELET_EVENT_DELETE); + interface_raise_event(interface, facelet); + break; } @@ -464,11 +480,15 @@ int nl_callback(interface_t * interface) // UP RUNNING // UP NOT RUNNING // DOWN NOT RUNNING +#if 0 DEBUG("New network interface %s, state: %s %s", interface_name, up ? "UP" : "DOWN", running ? "RUNNING" : "NOT_RUNNING"); +#endif - if (facelet && up && running) { + if (!facelet) + break; + if (up && running) { facelet_set_event(facelet, FACELET_EVENT_CREATE); facelet_t * facelet6 = facelet_dup(facelet); if (!facelet6) { @@ -477,10 +497,12 @@ int nl_callback(interface_t * interface) } facelet_set_family(facelet, AF_INET); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); facelet_set_family(facelet6, AF_INET6); - facelet_raise_event(facelet6, interface); + interface_raise_event(interface, facelet6); + } else { + facelet_free(facelet); } break; } @@ -507,6 +529,7 @@ int nl_finalize(interface_t * interface) { nl_data_t * data = (nl_data_t*)interface->data; close(data->fd); + free(interface->data); return 0; } diff --git a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c index ed2f88e9e..f438d34d5 100644 --- a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c +++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c @@ -18,6 +18,8 @@ * \brief Implementation of Network framework interface */ +#include "Availability.h" + #include <sys/socket.h> #include <arpa/inet.h> @@ -36,6 +38,11 @@ #include "network_framework.h" +#if !defined(MAC_OS_X_VERSION_10_14) +#error "Network frameork requires MacOSX 10.14+" +#endif /* !defined(MAC_OS_X_VERSION_10_14) */ + + /* * Bonjour service discovery for hICN forwarder * @@ -59,7 +66,7 @@ #define BONJOUR_PROTOCOL udp #define BONJOUR_SERVICE_DOMAIN "local" -#define BONJOUR_SERVICE_NAME "hicn" +#define BONJOUR_SERVICE_NAME "hicn node" /* Generated variables */ #define BONJOUR_SERVICE_TYPE "_hicn._" STRINGIZE(BONJOUR_PROTOCOL) @@ -80,7 +87,7 @@ const char * interface_type_str[] = { "OTHER", "WIFI", "CELLULAR", "WIRED", "LOOPBACK", }; -#if 0 +#if 1 typedef enum { PATH_STATUS_INVALID, PATH_STATUS_SATISTIED, @@ -212,6 +219,28 @@ dump_connection(nw_connection_t connection, int indent) nw_release(path); } +#if defined(MAC_OS_X_VERSION_10_15) +void +dump_browse_result(nw_browse_result_t result, int indent) +{ + /* Endpoint */ + nw_endpoint_t browse_endpoint = nw_browse_result_copy_endpoint(result); + if (!bendpoint) { + ERROR("[network_framework.dump_result] Failed to retrieve endpoint from Bonjour browse result"); + return; + } + printfi(indent + 1, "Endpoint:") + dump_endpoint(browse_endpoint, indent + 2); + + /* Interfaces */ + printfi(indent + 1, "Interfaces:") + nw_browse_result_enumerate_interfaces(result, ^(nw_interface_t interface) { + dump_interface(interface, index + 2); + return true; + }); +} +#endif /* defined(MAC_OS_X_VERSION_10_15) */ + facelet_t * facelet_create_from_connection(nw_connection_t connection) { @@ -302,7 +331,7 @@ void on_connection_state_event(interface_t * interface, nw_interface_t iface, nw_connection_t cnx, nw_connection_state_t state, nw_error_t error) { -#if 0 +#if 1 DEBUG("Connection [new state = %s]:\n", connection_state_str[state]); nw_path_t path = nw_connection_copy_current_path(cnx); nw_path_enumerate_interfaces(path, (nw_path_enumerate_interfaces_block_t)^(nw_interface_t interface) { @@ -331,7 +360,9 @@ on_connection_state_event(interface_t * interface, nw_interface_t iface, case nw_connection_state_ready: { -#if 0 + printf("info:\n"); + warn("connection ready"); +#if 1 WITH_DEBUG({ dump_connection(cnx, 1); }); @@ -340,7 +371,7 @@ on_connection_state_event(interface_t * interface, nw_interface_t iface, if (!facelet) return; facelet_set_event(facelet, FACELET_EVENT_CREATE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); break; } case nw_connection_state_failed: @@ -371,10 +402,10 @@ void on_connection_path_event(interface_t * interface, nw_interface_t iface, nw_connection_t cnx, nw_path_t path) { -#if 0 +#if 1 DEBUG("Connection [path changed]:\n"); WITH_DEBUG({ - //dump_connection(cnx, 1); + dump_connection(cnx, 1); }); #endif /* redundant *//* @@ -418,15 +449,7 @@ void on_interface_event(interface_t * interface, nw_interface_t iface) * time, if none is discovered, we cannot do any tunnel face. */ - nw_endpoint_t endpoint; - - endpoint = nw_endpoint_create_bonjour_service( - BONJOUR_SERVICE_NAME, - BONJOUR_SERVICE_TYPE, - BONJOUR_SERVICE_DOMAIN); - - if (!endpoint) - goto ERR; + // OLD CODE /* nw_parameters_create_secure_{udp,tcp} */ nw_parameters_t parameters = nw_parameters_create_fn( @@ -434,14 +457,93 @@ void on_interface_event(interface_t * interface, nw_interface_t iface) NW_PARAMETERS_DEFAULT_CONFIGURATION /* default udp/tcp */); if (!parameters) - goto ERR; + goto ERR_PARAMETERS; nw_parameters_require_interface(parameters, iface); nw_parameters_set_reuse_local_address(parameters, true); +#if defined(MAC_OS_X_VERSION_10_15) + /* + * Before being able to create a bonjour endpoint, we need to browse for + * available services on the local network using the parameters specified + * before. + */ + nw_browse_descriptor_t descriptor = nw_browse_descriptor_create_bonjour_service(BONJOUR_SERVICE_TYPE, BONJOUR_SERVICE_DOMAIN); + if (!descriptor) { + ERROR("[network_framework.on_interface_event] Failed to create a bonjour browse descriptor"); + goto ERR_DESCRIPTOR; + } + + nw_browser_t browser = nw_browser_create(descriptor, parameters); + nw_browser_set_queue(browser, dispatch_get_main_queue()); + nw_browser_set_browse_results_changed_handler(browser, ^(nw_browse_result_t result, nw_browse_result_t result2, bool flag) { + /* Dump result */ + printfi(0, "NEW BROWSE RESULT"); + printfi(1, "Result:"); + dump_browse_result(result, 2); + printfi(1, "Result2:"); + dump_browse_result(result2, 2); + printfi("Flag: %s\n", flag?"ON":"OFF"); + + /* Changes */ + nw_browse_result_change_t change = nw_browse_result_get_changes(result, result2); + switch(change) { + case nw_browse_result_change_identical: + printfi("The compared services are identical."); + break; + case nw_browse_result_change_result_added: + printfi(2, "A new service was discovered."); + break; + + case nw_browse_result_change_result_removed: + printfi(2, "A previously discovered service was removed."); + break; + + case nw_browse_result_change_txt_record_changed: + printfi(2, "The service's associated TXT record changed."); + break; + + case nw_browse_result_change_interface_added: + printfi(2, "The service was discovered over a new interface."); + break; + +nw_browse_result_change_interface_removed + printfi(2, "The service was no longer discovered over a certain interface."); + break; + } + }); + + browser.browseResultsChangedHandler = { browseResults, _ in + for browseResult in browseResults { + print("Discovered \(browseResult.endpoint) over \(browseResult.interfaces)") + } + } + nw_browser_start(browser); +//#else +//#warning "Bonjour discovery only available in MacOS 10.15+" +#endif /* defined(MAC_OS_X_VERSION_10_15) */ + + /* + * Now that we have resolve the name of a bonjour remote, we can create a + * connection to the corresponding endpoint identified by its name. + */ + nw_endpoint_t endpoint; + + DEBUG("Creating bonjour service towards NAME=%s TYPE=%s DOMAIN=%s", + BONJOUR_SERVICE_NAME, BONJOUR_SERVICE_TYPE, BONJOUR_SERVICE_DOMAIN); + endpoint = nw_endpoint_create_bonjour_service( + BONJOUR_SERVICE_NAME, + BONJOUR_SERVICE_TYPE, + BONJOUR_SERVICE_DOMAIN); + + if (!endpoint) { + ERROR("[network_framework.on_interface_event] Failed to create bound Bonjour connection"); + goto ERR_ENDPOINT; + } + nw_connection_t connection = nw_connection_create(endpoint, parameters); if (!connection) - goto ERR; + goto ERR_CONNECTION; nw_release(endpoint); nw_release(parameters); @@ -460,7 +562,7 @@ void on_interface_event(interface_t * interface, nw_interface_t iface) }); nw_connection_set_better_path_available_handler(connection, ^(bool value) { -#if 0 +#if 1 DEBUG("Connection [better path = %s]\n", (value ? "true" : "false")); WITH_DEBUG({ dump_connection(connection, 1); @@ -469,7 +571,7 @@ void on_interface_event(interface_t * interface, nw_interface_t iface) }); nw_connection_set_viability_changed_handler(connection, ^(bool value) { -#if 0 +#if 1 DEBUG("Connection [viable = %s]\n", (value ? "true" : "false")); WITH_DEBUG({ //dump_connection(connection, 1); @@ -484,7 +586,7 @@ void on_interface_event(interface_t * interface, nw_interface_t iface) if (!facelet) return; facelet_set_event(facelet, value ? FACELET_EVENT_CREATE : FACELET_EVENT_DELETE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); }); @@ -493,14 +595,26 @@ void on_interface_event(interface_t * interface, nw_interface_t iface) nw_connection_set_queue(connection, dispatch_get_main_queue()); nw_retain(connection); // Hold a reference until cancelled -#if 0 - DEBUG("Created Bonjour cnx on interface:\n"); +#if 1 + DEBUG("Created Bonjour cnx on interface:"); WITH_DEBUG({ dump_interface(iface, 1); }); #endif -ERR: + return; + + nw_release(connection); +ERR_CONNECTION: + nw_release(endpoint); +ERR_ENDPOINT: +#if defined(MAC_OS_X_VERSION_10_15) + nw_release(descriptor); +ERR_DESCRIPTOR: +#endif /* defined(MAC_OS_X_VERSION_10_15) */ + nw_release(parameters); + +ERR_PARAMETERS: return; } @@ -509,7 +623,7 @@ void on_path_event(interface_t * interface, nw_path_t path) /* Simplification: we handle path event only once. * Ideally, test whether we discover new interfaces or not */ -#if 0 +#if 1 DEBUG("Path [event]:\n"); WITH_DEBUG({ dump_path(path, 1); @@ -529,6 +643,9 @@ int nf_initialize(interface_t * interface, void * cfg) if (!data) goto ERR_MALLOC; + if (cfg) + data->cfg = * (network_framework_cfg_t *)cfg; + data->pm = nw_path_monitor_create(); if (!data->pm) goto ERR_PM; diff --git a/ctrl/facemgr/src/interfaces/updown/updown.c b/ctrl/facemgr/src/interfaces/updown/updown.c index f5a813cd4..c864c8c04 100644 --- a/ctrl/facemgr/src/interfaces/updown/updown.c +++ b/ctrl/facemgr/src/interfaces/updown/updown.c @@ -125,7 +125,7 @@ int updown_callback(interface_t * interface) facelet_set_event(facelet, FACELET_EVENT_UPDATE); - facelet_raise_event(facelet, interface); + interface_raise_event(interface, facelet); return 0; } diff --git a/ctrl/facemgr/src/loop_dispatcher.c b/ctrl/facemgr/src/loop_dispatcher.c new file mode 100644 index 000000000..7e7f9d667 --- /dev/null +++ b/ctrl/facemgr/src/loop_dispatcher.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017-2019 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: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file loop_dispatcher.c + * \brief Implementation of facemgr main loop using Apple Dispatcher framework + */ + +#ifndef __APPLE__ +#error "This implementation only supports Apple platforms" +#endif /* __APPLE__ */ + +#ifdef WITH_THREAD +#error "Multithreaded implementation is not (yet) supported on Apple platforms" +#endif /* WITH_THREAD */ + +#include <stdlib.h> + +#include <Dispatch/Dispatch.h> + +#include <hicn/facemgr/loop.h> +#include <hicn/util/log.h> + +struct loop_s { +}; + +loop_t * +loop_create() +{ + /* Nothing to do */ + return NULL; +} + +void +loop_free(loop_t * loop) +{ + /* Nothing to do */ +} + +void +loop_dispatch(loop_t * loop) +{ + dispatch_main(); +} + +void +loop_undispatch(loop_t * loop) +{ + /* Nothing to do */ +} + +void +loop_break(loop_t * loop) +{ + exit(0); +} + +int +loop_callback(loop_t * loop, facemgr_cb_type_t type, void * data) +{ + INFO("loop_callback not (yet) implemented"); + return 0; +} diff --git a/ctrl/facemgr/src/loop_libevent.c b/ctrl/facemgr/src/loop_libevent.c new file mode 100644 index 000000000..4042c717a --- /dev/null +++ b/ctrl/facemgr/src/loop_libevent.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2017-2019 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: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file loop_libevent.c + * \brief Implementation of facemgr main loop using libevent + */ + +#ifndef __linux__ +#error "Only linux is supported" +#endif /* __linux__ */ + +#include <assert.h> +#include <event2/event.h> +#include <event2/thread.h> +#include <fcntl.h> // fcntl +#ifdef WITH_THREAD +#include <pthread.h> +#endif /* WITH_THREAD */ +#include <stdlib.h> +#include <sys/timerfd.h> +#include <unistd.h> // fcntl + +#include <hicn/facemgr/api.h> +#include <hicn/util/log.h> + +#include <hicn/facemgr/loop.h> +#include "util/map.h" + +/** + * \brief Holds all callback parameters + */ +typedef struct { + void * owner; + fd_callback_t callback; + void * data; +} cb_wrapper_args_t; + +TYPEDEF_MAP_H(event_map, int, struct event *); +TYPEDEF_MAP(event_map, int, struct event *, int_cmp, int_snprintf, generic_snprintf); + +/* Map that associates timer fds with their associated cb_wrapper_args_t */ +TYPEDEF_MAP_H(timer_fd_map, int, cb_wrapper_args_t *); +TYPEDEF_MAP(timer_fd_map, int, cb_wrapper_args_t *, int_cmp, int_snprintf, generic_snprintf); + +struct loop_s { + struct event_base * event_base; + event_map_t * event_map; + timer_fd_map_t * timer_fd_map; +#ifdef WITH_THREAD + pthread_t thread; +#endif /* WITH_THREAD */ +}; + +/* Forward declarations */ +int _loop_unregister_fd(loop_t * loop, int fd); +int _loop_unregister_timer(loop_t * loop, int fd); + +loop_t * +loop_create() +{ + loop_t * loop = malloc(sizeof(loop_t)); + if (!loop) { + ERROR("[loop_create] Failed to allocate memory"); + goto ERR_MALLOC; + } + +#ifdef WITH_THREAD + evthread_use_pthreads(); +#endif /* WITH_THREAD */ + + loop->event_base = event_base_new(); + if (!loop) + goto ERR_EVENT; + + loop->event_map = event_map_create(); + if (!loop->event_map) { + ERROR("[loop_create] Failed to create event_map"); + goto ERR_EVENT_MAP; + } + + loop->timer_fd_map = timer_fd_map_create(); + if (!loop->timer_fd_map) { + ERROR("[loop_create] Failed to create timer_fd_map"); + goto ERR_TIMER_FD_MAP; + } + + event_set_log_callback(NULL); + + return loop; + + timer_fd_map_free(loop->timer_fd_map); +ERR_TIMER_FD_MAP: + event_map_free(loop->event_map); +ERR_EVENT_MAP: + event_base_free(loop->event_base); +ERR_EVENT: + free(loop); +ERR_MALLOC: + return NULL; +} + +void +loop_free(loop_t * loop) +{ + /* + * Release all timer cb_wrapper_args_t + * + * We need to stop all timers, this should release associated fd events at + * the same time... for that reason, this code has to be called before + * releasing events + */ + + int * timer_fd_map_array; + int n = timer_fd_map_get_key_array(loop->timer_fd_map, &timer_fd_map_array); + if (n < 0) { + ERROR("[loop_free] Could not get event map array"); + } else { + for (unsigned i = 0; i < n; i++) { + int fd = timer_fd_map_array[i]; + if (_loop_unregister_timer(loop, fd) < 0) { + ERROR("[loop_free] Could not unregister timer"); + } + } + free(timer_fd_map_array); + } + timer_fd_map_free(loop->timer_fd_map); + + /* Release all events */ + + int * event_map_array; + n = event_map_get_key_array(loop->event_map, &event_map_array); + if (n < 0) { + ERROR("[loop_free] Could not get event map array"); + } else { + for (unsigned i = 0; i < n; i++) { + int fd = event_map_array[i]; + if (_loop_unregister_fd(loop, fd) < 0) { + ERROR("[loop_free] Could not unregister fd"); + } + } + free(event_map_array); + } + event_map_free(loop->event_map); + + event_base_free(loop->event_base); + + free(loop); +} + +void +loop_dispatch(loop_t * loop) +{ +#ifdef WITH_THREAD + if (pthread_create(loop->thread, NULL, start_dispatch, loop)) { + fprintf(stderr, "Error creating thread\n"); + return EXIT_FAILURE; + } +#else + event_base_dispatch(loop->event_base); +#endif /* WITH_THREAD */ +} + +void +loop_undispatch(loop_t * loop) +{ +#ifdef WITH_THREAD + DEBUG("Waiting for loop to terminate..."); + if(pthread_join(loop->thread, NULL)) { + fprintf(stderr, "Error joining thread\n"); + return EXIT_FAILURE; + } + DEBUG("Loop terminated !"); +#endif /* WITH_THREAD */ +} + +void +loop_break(loop_t * loop) +{ + event_base_loopbreak(loop->event_base); +} + +void cb_wrapper(evutil_socket_t fd, short what, void * arg) { + cb_wrapper_args_t * cb_wrapper_args = arg; + cb_wrapper_args->callback(cb_wrapper_args->owner, fd, cb_wrapper_args->data); +} + +/** + * \brief Registers a new file descriptor to the event loop + * \param [in] fd - File descriptor to register + * \param [in] callback_owner - Pointer to the owner of the callack (first + * parameter of callback function) + * \param [in] callback - Callback function + * \param [in] callback_data - User data to pass alongside callback invocation + * \return 0 in case of success, -1 otherwise + */ +int +_loop_register_fd(loop_t * loop, int fd, void * callback_owner, + fd_callback_t callback, void * callback_data) +{ + /* This will be freed with the event */ + cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t)); + *cb_wrapper_args = (cb_wrapper_args_t) { + .owner = callback_owner, + .callback = callback, + .data = callback_data, + }; + + evutil_make_socket_nonblocking(fd); + struct event * event = event_new(loop->event_base, fd, EV_READ | EV_PERSIST, cb_wrapper, cb_wrapper_args); + if (!event) + goto ERR_EVENT_NEW; + + if (event_add(event, NULL) < 0) + goto ERR_EVENT_ADD; + + if (event_map_add(loop->event_map, fd, event) < 0) + goto ERR_EVENT_MAP; + + return 0; + +ERR_EVENT_MAP: +ERR_EVENT_ADD: + event_free(event); +ERR_EVENT_NEW: + return -1; +} + +/** + * \brief Unregisters a file descriptor from the event loop + * \param [in] fd - File descriptor to unregister + * \return 0 in case of success, -1 otherwise + */ +int +_loop_unregister_fd(loop_t * loop, int fd) +{ + struct event * event = NULL; + + if (event_map_remove(loop->event_map, fd, &event) < 0) { + ERROR("[loop_unregister_fd] Error removing event associated to fd"); + return -1; + } + + assert(event); + + cb_wrapper_args_t * cb_wrapper_args = event_get_callback_arg(event); + free(cb_wrapper_args); + + event_del(event); + event_free(event); + + return 0; +} + +int +loop_timer_callback(loop_t * loop, int fd, void * data) +{ + char buf[1024]; /* size is not important */ + cb_wrapper_args_t * cb_wrapper_args = data; + while (read(fd, &buf, sizeof(buf)) > 0) + ; + + int rc = cb_wrapper_args->callback(cb_wrapper_args->owner, fd, + cb_wrapper_args->data); + + return rc; +} + +int +_loop_register_timer(loop_t * loop, timer_callback_data_t * timer_callback_data) +{ + int fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd == -1) { + perror("timerfd_create"); + return -1; + } + + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + perror("fcntl"); + return -1; + } + + struct itimerspec ts = { + .it_interval = { + .tv_sec = 1, //timer_callback_data->delay_ms / 1000, + .tv_nsec = (timer_callback_data->delay_ms % 1000) * 1000000, + }, + .it_value = { + .tv_sec = 1, //timer_callback_data->delay_ms / 1000, + .tv_nsec = (timer_callback_data->delay_ms % 1000) * 1000000, + } + }; + + if (timerfd_settime(fd, 0, &ts, NULL) == -1) { + perror("timerfd_settime"); + return -1; + } + + /* This should be freed together with the timer release */ + cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t)); + *cb_wrapper_args = (cb_wrapper_args_t) { + .owner = timer_callback_data->owner, + .callback = timer_callback_data->callback, + .data = timer_callback_data->data, + }; + + if (timer_fd_map_add(loop->timer_fd_map, fd, cb_wrapper_args) < 0) { + ERROR("[loop_callback] Could not add cb_wrapper to timer map"); + return -1; + } + + if (_loop_register_fd(loop, fd, loop, + (fd_callback_t) loop_timer_callback, cb_wrapper_args) < 0) { + ERROR("[loop_callback] Error registering fd to event loop"); + return -1; + } + + return fd; +} + +int +_loop_unregister_timer(loop_t * loop, int fd) +{ + struct itimerspec ts = { + .it_interval = { + .tv_sec = 0, + .tv_nsec = 0, + }, + .it_value = { /* This value disables the timer */ + .tv_sec = 0, + .tv_nsec = 0, + } + }; + ts.it_value.tv_sec = 0; + + if (timerfd_settime(fd, 0, &ts, NULL) == -1) { + perror("timerfd_settime"); + return -1; + } + + cb_wrapper_args_t * cb_wrapper_args; + if (timer_fd_map_remove(loop->timer_fd_map, fd, &cb_wrapper_args) < 0) { + ERROR("[loop_callback] Could not remove cb_wrapper from timer map"); + return -1; + } + assert(cb_wrapper_args); + free(cb_wrapper_args); + + if (_loop_unregister_fd(loop, fd) < 0) { + ERROR("[loop_callback] Error unregistering fd from event loop"); + return -1; + } + + return 0; +} + +int +loop_callback(loop_t * loop, facemgr_cb_type_t type, void * data) +{ + switch(type) { + case FACEMGR_CB_TYPE_REGISTER_FD: + { + fd_callback_data_t * fd_callback_data = (fd_callback_data_t *)data; + if (_loop_register_fd(loop, fd_callback_data->fd, + fd_callback_data->owner, + fd_callback_data->callback, + fd_callback_data->data) < 0) { + + ERROR("[loop_callback] Error registering fd to event loop"); + return -1; + } + break; + } + + case FACEMGR_CB_TYPE_UNREGISTER_FD: + { + int fd = *(int*)data; + /* We need a map to associate fd and events */ + if (_loop_unregister_fd(loop, fd) < 0) { + ERROR("[loop_callback] Error registering fd to event loop"); + return -1; + } + break; + } + + case FACEMGR_CB_TYPE_REGISTER_TIMER: + { + timer_callback_data_t * timer_callback_data = (timer_callback_data_t *)data; + + int fd = _loop_register_timer(loop, timer_callback_data); + if (fd < 0) { + ERROR("[loop_callback] Error registering timer to event loop"); + return -1; + } + return fd; + + } + + case FACEMGR_CB_TYPE_UNREGISTER_TIMER: + { + int fd = *(int*)data; + + if (_loop_unregister_timer(loop, fd) < 0) { + ERROR("[loop_callback] Error unregistering timer from event loop"); + return -1; + } + return 0; + + } + } + return 0; +} + diff --git a/ctrl/facemgr/src/main.c b/ctrl/facemgr/src/main.c index 307d05236..be5ff3c68 100644 --- a/ctrl/facemgr/src/main.c +++ b/ctrl/facemgr/src/main.c @@ -18,33 +18,12 @@ * \brief Face manager daemon entry point */ -#ifdef WITH_THREAD -#ifndef __linux__ -#error "Not implemented" -#endif /* __linux__ */ -#include <pthread.h> -#endif /* WITH_THREAD */ - -#ifndef __APPLE__ -#include <event2/event.h> -#include <event2/thread.h> -#endif /* __APPLE__ */ - #include <getopt.h> #include <limits.h> #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <unistd.h> // faccess - -#include <libconfig.h> - -#ifdef __APPLE__ -#include <Dispatch/Dispatch.h> -#else -#include <event2/event.h> -#endif #include <hicn/facemgr.h> #include <hicn/policy.h> @@ -53,28 +32,17 @@ #include <hicn/util/log.h> #include <hicn/facemgr/cfg.h> +#include <hicn/facemgr/loop.h> -#define FACEMGR_TIMEOUT 3 +#include "cfg_file.h" +#include "util/map.h" -static struct event_base * loop; +#define FACEMGR_TIMEOUT 3 -void facemgr_signal_handler(int signal) { - fprintf(stderr, "Received ^C... quitting !\n"); - exit(0); #if 0 - return; - - // FIXME - - /* should be atomic */ - // FIXME Don't use loop in a static variable as we should not need it if all - // events are properly unregistered... +static struct event_base * loop; #endif -#ifdef __linux__ - event_base_loopbreak(loop); -#endif /* __linux__ */ - loop = NULL; -} +static loop_t * loop = NULL; static struct option long_options[] = { @@ -86,13 +54,6 @@ typedef struct { char * cfgfile; } facemgr_options_t; -static const char * DEFAULT_CFGFILES[] = { - "/etc/facemgr.conf", - "~/facemgr.conf", -}; - -#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x)) - void usage(const char * progname) { printf("%s: Face manager daemon\n", progname); @@ -104,16 +65,11 @@ void usage(const char * progname) printf("\n"); } -int probe_cfgfile(char * f) -{ - for (unsigned i = 0; i < ARRAYSIZE(DEFAULT_CFGFILES); i++) { - if (access(DEFAULT_CFGFILES[i], F_OK ) != -1) { - if (!realpath(DEFAULT_CFGFILES[i], f)) - continue; - return 0; - } +void facemgr_signal_handler(int signal) { + fprintf(stderr, "Received ^C... quitting !\n"); + if (loop) { + loop_break(loop); } - return -1; } int parse_cmdline(int argc, char ** argv, facemgr_options_t * opts) @@ -122,7 +78,7 @@ int parse_cmdline(int argc, char ** argv, facemgr_options_t * opts) while ((c = getopt_long(argc, argv, "c:", long_options, NULL)) != -1) { switch(c) { case 'c': - opts->cfgfile = strdup(optarg); + opts->cfgfile = optarg; break; case ':': case '?': @@ -135,596 +91,14 @@ int parse_cmdline(int argc, char ** argv, facemgr_options_t * opts) return 0; } -int -parse_config_global(facemgr_cfg_t * cfg, config_setting_t * setting) -{ - /* - face_type */ - - const char *face_type_str; - facemgr_face_type_t face_type; - if (config_setting_lookup_string(setting, "face_type", &face_type_str)) { - if (strcasecmp(face_type_str, "auto") == 0) { - face_type = FACEMGR_FACE_TYPE_DEFAULT; - } else - if (strcasecmp(face_type_str, "native-udp") == 0) { - face_type = FACEMGR_FACE_TYPE_NATIVE_UDP; - } else - if (strcasecmp(face_type_str, "native-tcp") == 0) { - face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; - } else - if (strcasecmp(face_type_str, "overlay-udp") == 0) { - face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; - } else - if (strcasecmp(face_type_str, "overlay-tcp") == 0) { - face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP; - } else { - ERROR("Invalid face type in section 'global'"); - return -1; - } - - int rc = facemgr_cfg_set_face_type(cfg, &face_type); - if (rc < 0) - goto ERR; - } - - /* - disable_discovery */ - - int disable_discovery; - if (config_setting_lookup_bool(setting, "disable_discovery", - &disable_discovery)) { - int rc = facemgr_cfg_set_discovery(cfg, !disable_discovery); - if (rc < 0) - goto ERR; - } - - /* - disable_ipv4 */ - - int disable_ipv4; - if (config_setting_lookup_bool(setting, "disable_ipv4", - &disable_ipv4)) { - INFO("Ignored setting 'disable_ipv4' in section 'global' (not implemented)."); -#if 0 - int rc = facemgr_cfg_set_ipv4(cfg, !disable_ipv4); - if (rc < 0) - goto ERR; -#endif - } - - /* - disable ipv6 */ - - int disable_ipv6; - if (config_setting_lookup_bool(setting, "disable_ipv6", - &disable_ipv6)) { - INFO("Ignored setting 'disable_ipv6' in section 'global': (not implemented)."); -#if 0 - int rc = facemgr_cfg_set_ipv6(cfg, !disable_ipv6); - if (rc < 0) - goto ERR; -#endif - } - - /* - overlay */ - config_setting_t *overlay = config_setting_get_member(setting, "overlay"); - if (overlay) { - - /* ipv4 */ - config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4"); - if (overlay_v4) { - const char * local_addr_str, * remote_addr_str; - ip_address_t local_addr = IP_ADDRESS_EMPTY; - ip_address_t remote_addr = IP_ADDRESS_EMPTY; - ip_address_t * local_addr_p = NULL; - ip_address_t * remote_addr_p = NULL; - int local_port = 0; - int remote_port = 0; - - if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) { - if (ip_address_pton(local_addr_str, &local_addr) < 0) { - ERROR("Error parsing v4 local addr"); - goto ERR; - } - local_addr_p = &local_addr; - } - - if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) { - if (!IS_VALID_PORT(local_port)) - goto ERR; - } - - if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) { - if (ip_address_pton(remote_addr_str, &remote_addr) < 0) { - ERROR("Error parsing v4 remote addr"); - goto ERR; - } - remote_addr_p = &remote_addr; - } - - if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) { - if (!IS_VALID_PORT(remote_port)) - goto ERR; - } - int rc = facemgr_cfg_set_overlay(cfg, AF_INET, - local_addr_p, local_port, - remote_addr_p, remote_port); - if (rc < 0) - goto ERR; - } - - /* ipv6 */ - config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6"); - if (overlay_v6) { - const char * local_addr_str, * remote_addr_str; - ip_address_t local_addr = IP_ADDRESS_EMPTY; - ip_address_t remote_addr = IP_ADDRESS_EMPTY; - ip_address_t * local_addr_p = NULL; - ip_address_t * remote_addr_p = NULL; - int local_port = 0; - int remote_port = 0; - - if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) { - if (ip_address_pton(local_addr_str, &local_addr) < 0) { - ERROR("Error parsing v6 local addr"); - goto ERR; - } - local_addr_p = &local_addr; - } - - if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) { - if (!IS_VALID_PORT(local_port)) - goto ERR; - } - - if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) { - if (ip_address_pton(remote_addr_str, &remote_addr) < 0) { - ERROR("Error parsing v6 remote addr"); - goto ERR; - } - remote_addr_p = &remote_addr; - } - - if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) { - if (!IS_VALID_PORT(remote_port)) - goto ERR; - } - int rc = facemgr_cfg_set_overlay(cfg, AF_INET6, - local_addr_p, local_port, - remote_addr_p, remote_port); - if (rc < 0) - goto ERR; - } - - } /* overlay */ - - return 0; - -ERR: - return -1; -} - -int -parse_config_rules(facemgr_cfg_t * cfg, config_setting_t * setting) -{ - /* List of match-override tuples */ - facemgr_cfg_rule_t * rule; - - int count = config_setting_length(setting); - for (unsigned i = 0; i < count; ++i) { - config_setting_t * rule_setting = config_setting_get_elem(setting, i); - - /* Sanity check */ - - config_setting_t * match_setting = config_setting_get_member(rule_setting, "match"); - if (!match_setting) { - ERROR("Missing match section in rule #%d", i); - goto ERR_CHECK; - } - - config_setting_t * override_setting = config_setting_get_member(rule_setting, "override"); - if (!override_setting) { - ERROR("Missing override section in rule #%d", i); - goto ERR_CHECK; - } - - rule = facemgr_cfg_rule_create(); - if (!rule) - goto ERR_RULE; - - /* Parse match */ - - const char * interface_name = NULL; - config_setting_lookup_string(match_setting, "interface_name", &interface_name); - - const char * interface_type_str; - netdevice_type_t interface_type = NETDEVICE_TYPE_UNDEFINED; - if (config_setting_lookup_string(match_setting, "interface_type", &interface_type_str)) { - if (strcasecmp(interface_type_str, "wired") == 0) { - interface_type = NETDEVICE_TYPE_WIRED; - } else - if (strcasecmp(interface_type_str, "wifi") == 0) { - interface_type = NETDEVICE_TYPE_WIFI; - } else - if (strcasecmp(interface_type_str, "cellular") == 0) { - interface_type = NETDEVICE_TYPE_CELLULAR; - } else { - ERROR("Unknown interface type in rule #%d", i); - goto ERR; - } - } - - if ((!interface_name) && (interface_type == NETDEVICE_TYPE_UNDEFINED)) { - ERROR("Empty match section in rule #%d", i); - goto ERR; - } - - /* Associate match to rule */ - - int rc = facemgr_cfg_rule_set_match(rule, interface_name, interface_type); - if (rc < 0) - goto ERR; - - /* Parse override */ - - /* - face_type */ - - const char *face_type_str; - facemgr_face_type_t face_type; - if (config_setting_lookup_string(override_setting, "face_type", &face_type_str)) { - if (strcasecmp(face_type_str, "auto")) { - /* We currently hardcode different behaviours based on the OS */ -#ifdef __ANDROID__ - face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; -#else - face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; -#endif - } else - if (strcasecmp(face_type_str, "native-udp") == 0) { - face_type = FACEMGR_FACE_TYPE_NATIVE_UDP; - } else - if (strcasecmp(face_type_str, "native-tcp") == 0) { - face_type = FACEMGR_FACE_TYPE_NATIVE_TCP; - } else - if (strcasecmp(face_type_str, "overlay-udp") == 0) { - face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP; - } else - if (strcasecmp(face_type_str, "overlay-tcp") == 0) { - face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP; - } else { - ERROR("Invalid face type in section 'global'"); - return -1; - } - - int rc = facemgr_cfg_rule_set_face_type(rule, &face_type); - if (rc < 0) - goto ERR; - } - - /* - disable_discovery */ - - int disable_discovery; - if (config_setting_lookup_bool(override_setting, "disable_discovery", - &disable_discovery)) { - int rc = facemgr_cfg_rule_set_discovery(rule, !disable_discovery); - if (rc < 0) - goto ERR; - } - - /* - disable_ipv4 */ - - int disable_ipv4; - if (config_setting_lookup_bool(override_setting, "disable_ipv4", - &disable_ipv4)) { - INFO("Ignored setting 'disable_ipv4' in rule #%d (not implemented).", i); -#if 0 - int rc = facemgr_cfg_rule_set_ipv4(rule, !disable_ipv4); - if (rc < 0) - goto ERR; -#endif - } - - /* - disable ipv6 */ - - int disable_ipv6; - if (config_setting_lookup_bool(override_setting, "disable_ipv6", - &disable_ipv6)) { - INFO("Ignored setting 'disable_ipv6' in rule #%d (not implemented).", i); -#if 0 - int rc = facemgr_cfg_rule_set_ipv6(rule, !disable_ipv6); - if (rc < 0) - goto ERR; -#endif - } - - /* - ignore */ - int ignore; - if (config_setting_lookup_bool(override_setting, "ignore", &ignore)) { - int rc = facemgr_cfg_rule_set_ignore(rule, !!ignore); - if (rc < 0) - goto ERR; - } - - /* - tags */ - config_setting_t *tag_settings = config_setting_get_member(override_setting, "tags"); - if (tag_settings) { - INFO("Ignored setting 'tags' in rule #%d (not implemented).", i); -#if 0 - policy_tags_t tags = POLICY_TAGS_EMPTY; - for (unsigned j = 0; j < config_setting_length(tag_settings); j++) { - const char * tag_str = config_setting_get_string_elem(tag_settings, j); - policy_tag_t tag = policy_tag_from_str(tag_str); - if (tag == POLICY_TAG_N) - goto ERR; - policy_tags_add(&tags, tag); - } - - int rc = facemgr_cfg_rule_set_tags(rule, tags); - if (rc < 0) - goto ERR; - -#if 0 - char tags_str[MAXSZ_POLICY_TAGS]; - policy_tags_snprintf(tags_str, MAXSZ_POLICY_TAGS, tags); - DEBUG("Added tags tags=%s", tags_str); -#endif -#endif - } - - /* - overlay */ - config_setting_t *overlay = config_setting_get_member(override_setting, "overlay"); - if (overlay) { - - /* ipv4 */ - config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4"); - if (overlay_v4) { - const char * local_addr_str, * remote_addr_str; - ip_address_t local_addr = IP_ADDRESS_EMPTY; - ip_address_t remote_addr = IP_ADDRESS_EMPTY; - ip_address_t * local_addr_p = NULL; - ip_address_t * remote_addr_p = NULL; - int local_port = 0; - int remote_port = 0; - - if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) { - if (ip_address_pton(local_addr_str, &local_addr) < 0) { - ERROR("Error parsing v4 local addr"); - goto ERR; - } - local_addr_p = &local_addr; - } - - if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) { - if (!IS_VALID_PORT(local_port)) - goto ERR; - } - - if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) { - if (ip_address_pton(remote_addr_str, &remote_addr) < 0) { - ERROR("Error parsing v4 remote addr"); - goto ERR; - } - remote_addr_p = &remote_addr; - } - - if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) { - if (!IS_VALID_PORT(remote_port)) - goto ERR; - } - int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET, - local_addr_p, local_port, - remote_addr_p, remote_port); - if (rc < 0) - goto ERR; - } - - /* ipv6 */ - config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6"); - if (overlay_v6) { - const char * local_addr_str, * remote_addr_str; - ip_address_t local_addr = IP_ADDRESS_EMPTY; - ip_address_t remote_addr = IP_ADDRESS_EMPTY; - ip_address_t * local_addr_p = NULL; - ip_address_t * remote_addr_p = NULL; - int local_port = 0; - int remote_port = 0; - - if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) { - if (ip_address_pton(local_addr_str, &local_addr) < 0) { - ERROR("Error parsing v6 local addr"); - goto ERR; - } - local_addr_p = &local_addr; - } - - if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) { - if (!IS_VALID_PORT(local_port)) - goto ERR; - } - - if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) { - if (ip_address_pton(remote_addr_str, &remote_addr) < 0) { - ERROR("Error parsing v6 remote addr"); - goto ERR; - } - remote_addr_p = &remote_addr; - } - - if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) { - if (!IS_VALID_PORT(remote_port)) - goto ERR; - } - int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET6, - local_addr_p, local_port, - remote_addr_p, remote_port); - if (rc < 0) - goto ERR; - } - - } /* overlay */ - - /* Add newly created rule */ - - rc = facemgr_cfg_add_rule(cfg, rule); - if (rc < 0) - goto ERR; - } - return 0; - -ERR: - facemgr_cfg_rule_free(rule); -ERR_RULE: -ERR_CHECK: - return -1; -} - -/* Currently not using facemgr_cfg_t */ -int -parse_config_log(facemgr_cfg_t * cfg, config_setting_t * setting) -{ - const char *log_level_str; - if (config_setting_lookup_string(setting, "log_level", &log_level_str)) { - if (strcasecmp(log_level_str, "FATAL") == 0) { - log_conf.log_level = LOG_FATAL; - } else - if (strcasecmp(log_level_str, "ERROR") == 0) { - log_conf.log_level = LOG_ERROR; - } else - if (strcasecmp(log_level_str, "WARN") == 0) { - log_conf.log_level = LOG_WARN; - } else - if (strcasecmp(log_level_str, "INFO") == 0) { - log_conf.log_level = LOG_INFO; - } else - if (strcasecmp(log_level_str, "DEBUG") == 0) { - log_conf.log_level = LOG_DEBUG; - } else - if (strcasecmp(log_level_str, "TRACE") == 0) { - log_conf.log_level = LOG_TRACE; - } else { - ERROR("Invalid log level in section 'log'"); - return -1; - } - } - return 0; -} - -int -parse_config_file(const char * cfgpath, facemgr_cfg_t * cfg) -{ - /* Reading configuration file */ - config_t cfgfile; - config_setting_t *setting; - - config_init(&cfgfile); - - /* Read the file. If there is an error, report it and exit. */ - if(!config_read_file(&cfgfile, cfgpath)) - goto ERR_FILE; - - setting = config_lookup(&cfgfile, "global"); - if (setting) { - int rc = parse_config_global(cfg, setting); - if (rc < 0) - goto ERR_PARSE; - } - - setting = config_lookup(&cfgfile, "rules"); - if (setting) { - int rc = parse_config_rules(cfg, setting); - if (rc < 0) - goto ERR_PARSE; - } - - setting = config_lookup(&cfgfile, "log"); - if (setting) { - int rc = parse_config_log(cfg, setting); - if (rc < 0) - goto ERR_PARSE; - } - - config_destroy(&cfgfile); - return 0; - -ERR_FILE: - ERROR("Could not read configuration file %s", cfgpath); - fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile), - config_error_line(&cfgfile), config_error_text(&cfgfile)); - config_destroy(&cfgfile); - exit(EXIT_FAILURE); - return -1; -ERR_PARSE: - fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile), - config_error_line(&cfgfile), config_error_text(&cfgfile)); - config_destroy(&cfgfile); - return -1; -} - #ifdef __linux__ -typedef struct { - void (*cb)(void *, ...); - void * args; -} cb_wrapper_args_t; - -void cb_wrapper(evutil_socket_t fd, short what, void * arg) { - cb_wrapper_args_t * cb_wrapper_args = arg; - cb_wrapper_args->cb(cb_wrapper_args->args); -} - -struct event * -loop_register_fd(struct event_base * loop, int fd, void * cb, void * cb_args) -{ - // TODO: not freed - cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t)); - *cb_wrapper_args = (cb_wrapper_args_t) { - .cb = cb, - .args = cb_args, - }; - - evutil_make_socket_nonblocking(fd); - struct event * event = event_new(loop, fd, EV_READ | EV_PERSIST, cb_wrapper, cb_wrapper_args); - if (!event) - goto ERR_EVENT_NEW; - - if (event_add(event, NULL) < 0) - goto ERR_EVENT_ADD; - - return event; - -ERR_EVENT_ADD: - event_free(event); -ERR_EVENT_NEW: - return NULL; -} - -int -loop_unregister_event(struct event_base * loop, struct event * event) -{ - if (!event) - return 0; - - event_del(event); - event_free(event); - - return 0; -} - - -void * start_dispatch(void * loop_ptr) -{ - struct event_base * loop = (struct event_base *) loop_ptr; - event_base_dispatch(loop); - - return NULL; -} - #endif /* __linux__ */ int main(int argc, char ** argv) { facemgr_cfg_t * cfg = NULL; facemgr_t * facemgr; -#ifdef WITH_THREAD - pthread_t facemgr_thread; -#endif /* WITH_THREAD */ struct sigaction sigIntHandler; sigIntHandler.sa_handler = facemgr_signal_handler; @@ -788,19 +162,9 @@ NO_CFGFILE: MAIN_LOOP: /* Main loop */ - - -#ifdef WITH_THREAD - evthread_use_pthreads(); -#endif /* WITH_THREAD */ - + loop = loop_create(); #ifdef __linux__ - /* Event loop */ - loop = event_base_new(); - if (!loop) - goto ERR_EVENT; - - facemgr_set_event_loop_handler(facemgr, loop, loop_register_fd, loop_unregister_event); + facemgr_set_callback(facemgr, loop, (void*)loop_callback); #endif /* __linux__ */ #ifdef __ANDROID__ @@ -812,24 +176,7 @@ MAIN_LOOP: if (facemgr_bootstrap(facemgr) < 0 ) goto ERR_BOOTSTRAP; -#ifdef __linux__ - event_set_log_callback(NULL); - -#ifdef WITH_THREAD - if (pthread_create(&facemgr_thread, NULL, start_dispatch, loop)) { - fprintf(stderr, "Error creating thread\n"); - return EXIT_FAILURE; - } -#else - event_base_dispatch(loop); -#endif /* WITH_THREAD */ - -#endif /* __linux__ */ - -#ifdef __APPLE__ - /* Main loop */ - dispatch_main(); -#endif /* __APPLE__ */ + loop_dispatch(loop); #ifdef __linux__ #ifdef WITH_THREAD @@ -842,34 +189,27 @@ MAIN_LOOP: facemgr_stop(facemgr); -#ifdef __linux__ -#ifdef WITH_THREAD - DEBUG("Waiting for loop to terminate..."); - if(pthread_join(facemgr_thread, NULL)) { - fprintf(stderr, "Error joining thread\n"); - return EXIT_FAILURE; - } - DEBUG("Loop terminated !"); -#endif /* WITH_THREAD */ -#endif /* __linux__ */ + loop_undispatch(loop); facemgr_free(facemgr); + if (cfg) + facemgr_cfg_free(cfg); + + loop_free(loop); + return EXIT_SUCCESS; ERR_BOOTSTRAP: -#ifdef __linux__ -ERR_EVENT: -#endif /* __linux__ */ facemgr_free(facemgr); ERR_FACEMGR_CONFIG: +ERR_FACEMGR: +ERR_PARSE: if (cfg) facemgr_cfg_free(cfg); -ERR_FACEMGR: ERR_FACEMGR_CFG: -ERR_PARSE: ERR_PATH: ERR_CMDLINE: return EXIT_FAILURE; diff --git a/ctrl/facemgr/src/util/map.h b/ctrl/facemgr/src/util/map.h index b6773f209..b113954a6 100644 --- a/ctrl/facemgr/src/util/map.h +++ b/ctrl/facemgr/src/util/map.h @@ -18,7 +18,6 @@ #include <stdlib.h> -#include "../common.h" #include "set.h" #define ERR_MAP_EXISTS -2 @@ -112,7 +111,30 @@ NAME ## _finalize(NAME ## _t * map) return NAME ## _pair_set_finalize(&map->pair_set); \ } \ \ -AUTOGENERATE_CREATE_FREE(NAME) \ +NAME ## _t * \ +NAME ## _create() \ +{ \ + NAME ## _t * map = malloc(sizeof(NAME ## _t)); \ + if (!map) \ + goto ERR_MALLOC; \ + \ + if (NAME ## _initialize(map) < 0) \ + goto ERR_INITIALIZE; \ + \ + return map; \ + \ +ERR_INITIALIZE: \ + free(map); \ +ERR_MALLOC: \ + return NULL; \ +} \ + \ +void \ +NAME ## _free(NAME ## _t * map) \ +{ \ + NAME ## _finalize(map); \ + free(map); \ +} \ \ int \ NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value) \ @@ -122,22 +144,22 @@ NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value) \ NAME ## _pair_t * pair = NAME ## _pair_create(key, value); \ if (!pair) \ - return -1; \ + return -1; \ \ rc = NAME ## _pair_set_get(&map->pair_set, pair, &found); \ - if (rc < 0) \ - return -1; \ + if (rc < 0) \ + return -1; \ if (found) { \ NAME ## _pair_free(pair); \ return ERR_MAP_EXISTS; \ } \ \ rc = NAME ## _pair_set_add(&map->pair_set, pair); \ - if (rc < 0) { \ + if (rc < 0) { \ NAME ## _pair_free(pair); \ - return -1; \ + return -1; \ } \ - return 0; \ + return 0; \ } \ \ int \ @@ -146,12 +168,12 @@ NAME ## _remove(NAME ## _t * map, KEY_T key, VAL_T * value) NAME ## _pair_t * found = NULL; \ NAME ## _pair_t search = { .key = key }; \ int rc = NAME ## _pair_set_remove(&map->pair_set, &search, &found); \ - if (rc < 0) \ + if (rc < 0) \ return ERR_MAP_NOT_FOUND; \ if (value) \ *value = found->value; \ NAME ## _pair_free(found); \ - return 0; \ + return 0; \ } \ \ int \ @@ -159,11 +181,11 @@ NAME ## _get(NAME ## _t * map, KEY_T key, VAL_T * value) { \ NAME ## _pair_t * found = NULL, search = { .key = key }; \ int rc = NAME ## _pair_set_get(&map->pair_set, &search, &found); \ - if (rc < 0) \ - return -1; \ + if (rc < 0) \ + return -1; \ if (found) \ *value = found->value; \ - return 0; \ + return 0; \ } \ \ void \ @@ -176,18 +198,18 @@ NAME ## _get_key_array(NAME ## _t * map, KEY_T **array) { NAME ## _pair_t ** pair_array; \ int n = NAME ## _pair_set_get_array(&map->pair_set, &pair_array); \ if (n < 0) \ - return -1; \ + return -1; \ /* Allocate result array */ \ - array = malloc(n * sizeof(KEY_T)); \ + *array = malloc(n * sizeof(KEY_T)); \ if (!array) { \ free(pair_array); \ - return -1; \ + return -1; \ } \ /* Copy keys */ \ for (int i = 0; i < n; i++) \ - array[i] = &pair_array[i]->key; \ + (*array)[i] = pair_array[i]->key; \ free(pair_array); \ - return 0; \ + return 0; \ } \ \ int \ @@ -195,18 +217,18 @@ NAME ## _get_value_array(NAME ## _t * map, VAL_T **array) { NAME ## _pair_t ** pair_array; \ int n = NAME ## _pair_set_get_array(&map->pair_set, &pair_array); \ if (n < 0) \ - return -1; \ + return -1; \ /* Allocate result array */ \ - array = malloc(n * sizeof(VAL_T)); \ + *array = malloc(n * sizeof(VAL_T)); \ if (!array) { \ free(pair_array); \ - return -1; \ + return -1; \ } \ /* Copy values */ \ for (int i = 0; i < n; i++) \ - array[i] = &pair_array[i]->value; \ + (*array)[i] = pair_array[i]->value; \ free(pair_array); \ - return 0; \ + return 0; \ } #endif /* UTIL_MAP_H */ diff --git a/ctrl/facemgr/src/util/set.h b/ctrl/facemgr/src/util/set.h index 61df209ab..0dad17423 100644 --- a/ctrl/facemgr/src/util/set.h +++ b/ctrl/facemgr/src/util/set.h @@ -24,7 +24,6 @@ //#else #define thread_local _Thread_local //#endif /* ! __ANDROID__ */ -#include "../common.h" #define ERR_SET_EXISTS -2 #define ERR_SET_NOT_FOUND -3 @@ -34,6 +33,13 @@ static inline int +int_cmp(const int x, const int y) +{ + return x - y; +} + +static inline +int int_snprintf(char * buf, size_t size, int value) { return snprintf(buf, size, "%d", value); } @@ -50,6 +56,8 @@ generic_snprintf(char * buf, size_t size, const void * value) { return snprintf(buf, BUFSIZE, "%p", value); } +typedef int(*cmp_t)(const void * x, const void * y); + #define TYPEDEF_SET_H(NAME, T) \ \ typedef struct { \ @@ -87,8 +95,33 @@ NAME ## _initialize(NAME ## _t * set) \ return 0; \ } \ \ -NO_FINALIZE(NAME); \ -AUTOGENERATE_CREATE_FREE(NAME); \ +int \ +NAME ## _finalize(NAME ## _t * set) { return 0; } \ + \ +NAME ## _t * \ +NAME ## _create() \ +{ \ + NAME ## _t * set = malloc(sizeof(NAME ## _t)); \ + if (!set) \ + goto ERR_MALLOC; \ + \ + if (NAME ## _initialize(set) < 0) \ + goto ERR_INITIALIZE; \ + \ + return set; \ + \ +ERR_INITIALIZE: \ + free(set); \ +ERR_MALLOC: \ + return NULL; \ +} \ + \ +void \ +NAME ## _free(NAME ## _t * set) \ +{ \ + NAME ## _finalize(set); \ + free(set); \ +} \ \ int \ NAME ## _add(NAME ## _t * set, const T element) \ diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index c1db751fb..62cf98927 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h @@ -43,7 +43,7 @@ * | MAP-Me | | | * +------------+---------------------+-----------------+--------------------------- * | connection | O O ! O O | O O O | state [-S] - * | listener | O O ! - O | O O O O | + * | listener | O O ! O O | O O O O | * +------------+---------------------+-----------------+--------------------------- * * LEGEND: [O] implemented, [!] in progress / TODO, [-] not supported @@ -571,7 +571,7 @@ int hc_face_list_async(hc_sock_t * s); //, hc_data_t ** pdata); #define MAX_FACE_ID 255 #define MAXSZ_FACE_ID_ 3 #define MAXSZ_FACE_ID MAXSZ_FACE_ID_ + NULLTERM -#define MAXSZ_FACE_NAME_ NAME_LEN +#define MAXSZ_FACE_NAME_ SYMBOLIC_NAME_LEN #define MAXSZ_FACE_NAME MAXSZ_FACE_NAME_ + NULLTERM #define MAXSZ_HC_FACE_ MAXSZ_FACE_ID_ + MAXSZ_FACE_NAME_ + MAXSZ_FACE_ + 5 diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h b/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h index 75f05988f..e69c93932 100755 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h @@ -168,8 +168,8 @@ typedef struct { uint32_t connid; uint8_t state; uint8_t admin_state; - char connectionName[16]; char interfaceName[16]; + char connectionName[16]; } list_connections_command; // SIZE=64 diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 983dd9b5e..0e5b529c5 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -514,6 +514,7 @@ hc_sock_free(hc_sock_t * s) } free(request_array); } + hc_sock_map_free(s->map); if (s->url) free(s->url); @@ -730,7 +731,6 @@ hc_sock_callback(hc_sock_t * s, hc_data_t ** data) for (;;) { int n = hc_sock_recv(s); if (n == 0) { - DEBUG("EOF"); goto ERR_EOF; } if (n < 0) { @@ -2048,13 +2048,64 @@ hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found) int hc_face_delete(hc_sock_t * s, hc_face_t * face) { - /* XXX We currently do not delete the listener */ hc_connection_t connection; if (hc_face_to_connection(face, &connection, false) < 0) { ERROR("[hc_face_delete] Could not convert face to connection."); return -1; } - return hc_connection_delete(s, &connection); + + if (hc_connection_delete(s, &connection) < 0) { + ERROR("[hc_face_delete] Error removing connection"); + return -1; + } + + /* If this is the last connection attached to the listener, remove it */ + + hc_data_t * connections; + hc_listener_t listener = {{0}}; + + /* + * Ensure we have a corresponding local listener + * NOTE: hc_face_to_listener is not appropriate + */ + if (hc_connection_to_local_listener(&connection, &listener) < 0) { + ERROR("[hc_face_create] Could not convert face to local listener."); + return -1; + } +#if 1 + /* + * The name is generated to prepare listener creation, we need it to be + * empty for deletion. The id should not need to be reset though. + */ + listener.id = 0; + memset(listener.name, 0, sizeof(listener.name)); +#endif + if (hc_connection_list(s, &connections) < 0) { + ERROR("[hc_face_delete] Error getting the list of listeners"); + return -1; + } + + bool delete = true; + foreach_connection(c, connections) { + if ((ip_address_cmp(&c->local_addr, &listener.local_addr, c->family) == 0) && + (c->local_port == listener.local_port) && + (strcmp(c->interface_name, listener.interface_name) == 0)) { + delete = false; + } + } + + if (delete) { + if (hc_listener_delete(s, &listener) < 0) { + ERROR("[hc_face_delete] Error removing listener"); + return -1; + } + } + + hc_data_free(connections); + + return 0; + + } /* FACE LIST */ diff --git a/ctrl/libhicnctrl/src/cli.c b/ctrl/libhicnctrl/src/cli.c index b8e90f40e..81400f8ee 100644 --- a/ctrl/libhicnctrl/src/cli.c +++ b/ctrl/libhicnctrl/src/cli.c @@ -17,6 +17,7 @@ * \file cli.c * \brief Command line interface */ +#include <ctype.h> // isalpha isalnum #include <stdlib.h> #include <stdio.h> #include <unistd.h> // getopt @@ -34,10 +35,11 @@ #define foreach_object \ _(UNDEFINED) \ - _(LISTENER) \ - _(CONNECTION) \ + _(FACE) \ _(ROUTE) \ _(STRATEGY) \ + _(LISTENER) \ + _(CONNECTION) \ _(N) typedef enum { @@ -48,7 +50,26 @@ foreach_object void usage(const char * prog) { - fprintf(stderr, "Usage: %s [ [-d] [-l|-c|-r] PARAMETERS | [-L|-C|-R] ]\n", prog); + fprintf(stderr, "Usage: %s [ [-d] [-f|-l|-c|-r] PARAMETERS | [-F|-L|-C|-R] ]\n", prog); + fprintf(stderr, "\n"); + fprintf(stderr, "High-level commands\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "%s -f <NAME> <TYPE> <LOCAL_ADDRESS> <LOCAL_PORT> <REMOTE_ADDRESS> <REMOTE_PORT>\n", prog); + fprintf(stderr, " Create a face on specified address and port.\n"); + fprintf(stderr, "%s -fc ...\n", prog); + fprintf(stderr, " Delete a face...\n"); + fprintf(stderr, "%s -F\n", prog); + fprintf(stderr, " List all faces.\n"); + fprintf(stderr, "%s -r ...>\n", prog); + fprintf(stderr, " Create a route...\n"); + fprintf(stderr, "%s -dr ...\n", prog); + fprintf(stderr, " Delete a route...\n"); + fprintf(stderr, "%s -R\n", prog); + fprintf(stderr, " List all routes.\n"); + fprintf(stderr, "%s -S\n", prog); + fprintf(stderr, " List all availble forwarding strategies.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Low level commands (hicn-light specific)\n"); fprintf(stderr, "\n"); fprintf(stderr, "%s -l <NAME> <TYPE> <ADDRESS> <PORT> <INTERFACE_NAME>\n", prog); fprintf(stderr, " Create a listener on specified address and port.\n"); @@ -56,73 +77,122 @@ void usage(const char * prog) fprintf(stderr, " Delete a listener...\n"); fprintf(stderr, "%s -L\n", prog); fprintf(stderr, " List all listeners.\n"); - fprintf(stderr, "%s -c <TYPE> <LOCAL_ADDRESS> <LOCAL_PORT> <REMOTE_ADDRESS> <REMOTE_PORT>\n", prog); + fprintf(stderr, "%s -c <NAME> <TYPE> <LOCAL_ADDRESS> <LOCAL_PORT> <REMOTE_ADDRESS> <REMOTE_PORT>\n", prog); fprintf(stderr, " Create a connection on specified address and port.\n"); fprintf(stderr, "%s -dc ...\n", prog); fprintf(stderr, " Delete a connection...\n"); fprintf(stderr, "%s -C\n", prog); fprintf(stderr, " List all connections.\n"); - fprintf(stderr, "%s -r ...>\n", prog); - fprintf(stderr, " Create a route...\n"); - fprintf(stderr, "%s -dr ...\n", prog); - fprintf(stderr, " Delete a route...\n"); - fprintf(stderr, "%s -R\n", prog); - fprintf(stderr, " List all routes.\n"); - fprintf(stderr, "%s -S\n", prog); - fprintf(stderr, " List all availble forwarding strategies.\n"); } typedef struct { hc_action_t action; hc_object_t object; union { + hc_face_t face; + hc_route_t route; hc_connection_t connection; hc_listener_t listener; - hc_route_t route; }; } hc_command_t; +/** + * Return true if string is purely an integer + */ +static inline +bool +is_number(const char *string) { + size_t len = strlen(string); + for (size_t i = 0; i < len; i++) + if (!isdigit(string[i])) + return false; + return true; +} + +/** + * A symbolic name must be at least 1 character and must begin with an alpha. + * The remainder must be an alphanum. + */ +static inline +bool +is_symbolic_name(const char *name) +{ + size_t len = strlen(name); + if (len <= 0) + return false; + if (!isalpha(name[0])) + return false; + for (size_t i = 1; i < len; i++) { + if (!isalnum(name[i])) + return false; + } + return true; +} + +face_type_t +face_type_from_str(const char * str) +{ +#define _(x) \ + if (strcasecmp(str, STRINGIZE(x)) == 0) \ + return FACE_TYPE_ ## x; \ + else +foreach_face_type +#undef _ + return FACE_TYPE_UNDEFINED; +} + + int parse_options(int argc, char *argv[], hc_command_t * command) { command->object = OBJECT_UNDEFINED; command->action = ACTION_CREATE; - int nargs = 0; /* default for list */ + int nargs = -1; /* unset */ int opt; int family; - while ((opt = getopt(argc, argv, "dlcrLCRSh")) != -1) { + while ((opt = getopt(argc, argv, "dflcrFLCRSh")) != -1) { switch (opt) { case 'd': command->action = ACTION_DELETE; break; + case 'f': + command->object = OBJECT_FACE; + break; case 'l': command->object = OBJECT_LISTENER; - nargs = 5; break; case 'c': command->object = OBJECT_CONNECTION; - nargs = 6; break; case 'r': command->object = OBJECT_ROUTE; nargs = 0; // XXX break; + case 'F': + command->action = ACTION_LIST; + command->object = OBJECT_FACE; + nargs = 0; + break; case 'L': command->action = ACTION_LIST; command->object = OBJECT_LISTENER; + nargs = 0; break; case 'C': command->action = ACTION_LIST; command->object = OBJECT_CONNECTION; + nargs = 0; break; case 'R': command->action = ACTION_LIST; command->object = OBJECT_ROUTE; + nargs = 0; break; case 'S': command->action = ACTION_LIST; command->object = OBJECT_STRATEGY; + nargs = 0; break; default: /* "h" */ usage(argv[0]); @@ -130,25 +200,126 @@ parse_options(int argc, char *argv[], hc_command_t * command) } } - if (command->action == ACTION_DELETE) - nargs = 1; - - /* Each option expects a different number of arguments */ - if ((command->object == OBJECT_UNDEFINED) || (optind != argc - nargs)) { - //printf("Object requires %d arguments [optind=%d != args=%d - nargs=%d\n", nargs, optind, argc, nargs); + if (command->object == OBJECT_UNDEFINED) { + fprintf(stderr, "Missing object specification: connection | listener | route\n"); return -1; } + if (nargs == 0) - return 0; + return 0; /* Parse and validate parameters for add/delete */ switch(command->object) { + case OBJECT_FACE: + switch(command->action) { + case ACTION_CREATE: + if ((argc - optind != 6) && (argc - optind != 7)) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "%s -f TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT [INTERFACE_NAME]\n", argv[0]); + goto ERR_PARAM; + } + /* NAME will be autogenerated (and currently not used) */ + //snprintf(command->face.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); + command->face.face.type = face_type_from_str(argv[optind++]); + if (command->face.face.type == FACE_TYPE_UNDEFINED) + goto ERR_PARAM; + command->face.face.family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->face.face.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], &command->face.face.local_addr) < 0) + goto ERR_PARAM; + command->face.face.local_port = atoi(argv[optind++]); + family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(family) || (command->face.face.family != family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], &command->face.face.remote_addr) < 0) + goto ERR_PARAM; + command->face.face.remote_port = atoi(argv[optind++]); + if (argc != optind) { + netdevice_set_name(&command->face.face.netdevice, argv[optind++]); + } + + break; + case ACTION_DELETE: + if ((argc - optind != 1) && (argc - optind != 5) && (argc - optind != 6)) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "%s -ld ID\n", argv[0]); + //fprintf(stderr, "%s -ld NAME\n", argv[0]); + fprintf(stderr, "%s -ld TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT [INTERFACE_NAME]\n", argv[0]); + goto ERR_PARAM; + } + + if (argc - optind == 1) { + /* Id or name */ + if (is_number(argv[optind])) { + command->face.id = atoi(argv[optind++]); + snprintf(command->face.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); + //} else if (is_symbolic_name(argv[optind])) { + // snprintf(command->face.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); + } else { + fprintf(stderr, "Invalid argument\n"); + goto ERR_PARAM; + } + } else { + command->face.face.type = face_type_from_str(argv[optind++]); + if (command->face.face.type == FACE_TYPE_UNDEFINED) + goto ERR_PARAM; + command->face.face.family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->face.face.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], &command->face.face.local_addr) < 0) + goto ERR_PARAM; + command->face.face.local_port = atoi(argv[optind++]); + family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(family) || (command->face.face.family != family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], &command->face.face.remote_addr) < 0) + goto ERR_PARAM; + command->face.face.remote_port = atoi(argv[optind++]); + if (argc != optind) { + netdevice_set_name(&command->face.face.netdevice, argv[optind++]); + } + } + break; + default: + goto ERR_COMMAND; + break; + } + break; + + case OBJECT_ROUTE: + switch(command->action) { + case ACTION_CREATE: + goto ERR_COMMAND; + break; + case ACTION_DELETE: + goto ERR_COMMAND; + break; + default: + goto ERR_COMMAND; + break; + } + break; + + case OBJECT_STRATEGY: + switch(command->action) { + case ACTION_LIST: + break; + default: + goto ERR_COMMAND; + break; + } + break; + case OBJECT_LISTENER: switch(command->action) { case ACTION_CREATE: - /* NAME TYPE LOCAL_ADDRESS LOCAL_PORT */ + if ((argc - optind != 4) && (argc - optind != 5)) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "%s -l NAME TYPE LOCAL_ADDRESS LOCAL_PORT [INTERFACE_NAME]\n", argv[0]); + goto ERR_PARAM; + } snprintf(command->listener.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - // conn type command->listener.type = connection_type_from_str(argv[optind++]); if (command->listener.type == CONNECTION_TYPE_UNDEFINED) goto ERR_PARAM; @@ -158,22 +329,62 @@ parse_options(int argc, char *argv[], hc_command_t * command) if (ip_address_pton(argv[optind++], &command->listener.local_addr) < 0) goto ERR_PARAM; command->listener.local_port = atoi(argv[optind++]); -#ifdef __linux__ - snprintf(command->listener.interface_name, INTERFACE_LEN, "%s", argv[optind++]); -#endif + if (argc != optind) { + snprintf(command->listener.interface_name, INTERFACE_LEN, "%s", argv[optind++]); + } break; + case ACTION_DELETE: - goto ERR_COMMAND; + if ((argc - optind != 1) && (argc - optind != 3) && (argc - optind != 4)) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "%s -ld ID\n", argv[0]); + fprintf(stderr, "%s -ld NAME\n", argv[0]); + fprintf(stderr, "%s -ld TYPE LOCAL_ADDRESS LOCAL_PORT [INTERFACE_NAME]\n", argv[0]); + goto ERR_PARAM; + } + + if (argc - optind == 1) { + /* Id or name */ + if (is_number(argv[optind])) { + command->listener.id = atoi(argv[optind++]); + snprintf(command->listener.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); + } else if (is_symbolic_name(argv[optind])) { + snprintf(command->listener.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); + } else { + fprintf(stderr, "Invalid argument\n"); + goto ERR_PARAM; + } + } else { + command->listener.type = connection_type_from_str(argv[optind++]); + if (command->listener.type == CONNECTION_TYPE_UNDEFINED) + goto ERR_PARAM; + command->listener.family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->listener.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], &command->listener.local_addr) < 0) + goto ERR_PARAM; + command->listener.local_port = atoi(argv[optind++]); + if (argc != optind) { + snprintf(command->listener.interface_name, INTERFACE_LEN, "%s", argv[optind++]); + } + } break; + default: goto ERR_COMMAND; break; } break; + case OBJECT_CONNECTION: switch(command->action) { case ACTION_CREATE: /* NAME TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT */ + if ((argc - optind != 6) && (argc - optind != 7)) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "%s -c NAME TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT [INTERFACE_NAME]\n", argv[0]); + goto ERR_PARAM; + } snprintf(command->connection.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); command->connection.type = connection_type_from_str(argv[optind++]); if (command->connection.type == CONNECTION_TYPE_UNDEFINED) @@ -191,45 +402,51 @@ parse_options(int argc, char *argv[], hc_command_t * command) goto ERR_PARAM; command->connection.remote_port = atoi(argv[optind++]); - { - char buf_connection[MAXSZ_HC_CONNECTION]; - if (hc_connection_snprintf(buf_connection, MAXSZ_HC_CONNECTION, &command->connection) >= MAXSZ_HC_CONNECTION) - printf("PARSED !!\n"); - else - printf("PARSED %s\n", buf_connection); - } - - break; - case ACTION_DELETE: - goto ERR_COMMAND; - break; - default: - goto ERR_COMMAND; - break; - } - break; - case OBJECT_ROUTE: - switch(command->action) { - case ACTION_CREATE: - goto ERR_COMMAND; break; case ACTION_DELETE: - goto ERR_COMMAND; - break; - default: - goto ERR_COMMAND; - break; - } - break; - case OBJECT_STRATEGY: - switch(command->action) { - case ACTION_LIST: + if ((argc - optind != 1) && (argc - optind != 5) && (argc - optind != 6)) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "%s -ld ID\n", argv[0]); + fprintf(stderr, "%s -ld NAME\n", argv[0]); + fprintf(stderr, "%s -ld TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT [INTERFACE_NAME]\n", argv[0]); + goto ERR_PARAM; + } + + if (argc - optind == 1) { + /* Id or name */ + if (is_number(argv[optind])) { + command->connection.id = atoi(argv[optind++]); + snprintf(command->connection.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); + } else if (is_symbolic_name(argv[optind])) { + snprintf(command->connection.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); + } else { + fprintf(stderr, "Invalid argument\n"); + goto ERR_PARAM; + } + } else { + command->connection.type = connection_type_from_str(argv[optind++]); + if (command->connection.type == CONNECTION_TYPE_UNDEFINED) + goto ERR_PARAM; + command->connection.family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->connection.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], &command->connection.local_addr) < 0) + goto ERR_PARAM; + command->connection.local_port = atoi(argv[optind++]); + family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(family) || (command->connection.family != family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], &command->connection.remote_addr) < 0) + goto ERR_PARAM; + command->connection.remote_port = atoi(argv[optind++]); + } break; default: goto ERR_COMMAND; break; } break; + default: goto ERR_COMMAND; break; @@ -246,7 +463,7 @@ int main(int argc, char *argv[]) { hc_data_t * data; int rc = 1; - hc_command_t command; + hc_command_t command = {0}; char buf_listener[MAXSZ_HC_LISTENER]; char buf_connection[MAXSZ_HC_CONNECTION]; char buf_route[MAXSZ_HC_ROUTE]; @@ -263,51 +480,29 @@ int main(int argc, char *argv[]) die(CONNECT, "Error connecting to the forwarder."); switch(command.object) { - case OBJECT_LISTENER: + case OBJECT_FACE: switch(command.action) { case ACTION_CREATE: - if (hc_listener_create(s, &command.listener) < 0) - die(COMMAND, "Error creating listener"); + if (hc_face_create(s, &command.face) < 0) + die(COMMAND, "Error creating face"); printf("OK\n"); break; - case ACTION_DELETE: - die(COMMAND, "Not implemented."); - break; - case ACTION_LIST: - if (hc_listener_list(s, &data) < 0) - die(COMMAND, "Error getting listeners."); - printf("Listeners:\n"); - foreach_listener(l, data) { - if (hc_listener_snprintf(buf_listener, MAXSZ_HC_LISTENER+17, l) >= MAXSZ_HC_LISTENER) - die(COMMAND, "Display error"); - printf("[%d] %s\n", l->id, buf_listener); - } - - hc_data_free(data); - break; - default: - die(COMMAND, "Unsupported command for listener"); - break; - } - break; - case OBJECT_CONNECTION: - switch(command.action) { - case ACTION_CREATE: - die(COMMAND, "Not implemented."); - break; case ACTION_DELETE: - die(COMMAND, "Not implemented."); + if (hc_face_delete(s, &command.face) < 0) + die(COMMAND, "Error creating face"); + printf("OK\n"); break; + case ACTION_LIST: - if (hc_connection_list(s, &data) < 0) + if (hc_face_list(s, &data) < 0) die(COMMAND, "Error getting connections."); - printf("Connections:\n"); - foreach_connection(c, data) { - if (hc_connection_snprintf(buf_connection, MAXSZ_HC_CONNECTION, c) >= MAXSZ_HC_CONNECTION) + printf("Faces:\n"); + foreach_face(f, data) { + if (hc_face_snprintf(buf_connection, MAXSZ_HC_FACE, f) >= MAXSZ_HC_FACE) die(COMMAND, "Display error"); - printf("[%s] %s\n", c->name, buf_connection); + printf("[%s] %s\n", f->name, buf_connection); } hc_data_free(data); @@ -317,6 +512,7 @@ int main(int argc, char *argv[]) break; } break; + case OBJECT_ROUTE: switch(command.action) { case ACTION_CREATE: @@ -343,6 +539,7 @@ int main(int argc, char *argv[]) break; } break; + case OBJECT_STRATEGY: switch(command.action) { case ACTION_LIST: @@ -363,6 +560,70 @@ int main(int argc, char *argv[]) break; } break; + + case OBJECT_LISTENER: + switch(command.action) { + case ACTION_CREATE: + if (hc_listener_create(s, &command.listener) < 0) + die(COMMAND, "Error creating listener"); + printf("OK\n"); + break; + case ACTION_DELETE: + if (hc_listener_delete(s, &command.listener) < 0) + die(COMMAND, "Error deleting listener"); + printf("OK\n"); + break; + break; + case ACTION_LIST: + if (hc_listener_list(s, &data) < 0) + die(COMMAND, "Error getting listeners."); + + printf("Listeners:\n"); + foreach_listener(l, data) { + if (hc_listener_snprintf(buf_listener, MAXSZ_HC_LISTENER+17, l) >= MAXSZ_HC_LISTENER) + die(COMMAND, "Display error"); + printf("[%d] %s\n", l->id, buf_listener); + } + + hc_data_free(data); + break; + default: + die(COMMAND, "Unsupported command for listener"); + break; + } + break; + + case OBJECT_CONNECTION: + switch(command.action) { + case ACTION_CREATE: + if (hc_connection_create(s, &command.connection) < 0) + die(COMMAND, "Error creating connection"); + printf("OK\n"); + break; + case ACTION_DELETE: + if (hc_connection_delete(s, &command.connection) < 0) + die(COMMAND, "Error creating connection"); + printf("OK\n"); + break; + case ACTION_LIST: + if (hc_connection_list(s, &data) < 0) + die(COMMAND, "Error getting connections."); + + printf("Connections:\n"); + foreach_connection(c, data) { + if (hc_connection_snprintf(buf_connection, MAXSZ_HC_CONNECTION, c) >= MAXSZ_HC_CONNECTION) + die(COMMAND, "Display error"); + printf("[%s] %s\n", c->name, buf_connection); + } + + hc_data_free(data); + break; + default: + die(COMMAND, "Unsupported command for connection"); + break; + } + break; + default: die(COMMAND, "Unsupported object"); break; diff --git a/hicn-plugin/README.md b/hicn-plugin/README.md index 664b9a446..3d332851b 100644 --- a/hicn-plugin/README.md +++ b/hicn-plugin/README.md @@ -66,10 +66,11 @@ Build dependencies: - VPP 19.08 - DEB packages (can be found https://packagecloud.io/fdio/release/install): + - vpp - libvppinfra-dev - vpp-dev -Running dependencies: +Runtime dependencies: - VPP 19.08 - DEB packages (can be found https://packagecloud.io/fdio/release/install): diff --git a/lib/src/util/ip_address.c b/lib/src/util/ip_address.c index 7afd3e2a4..c54b1fae6 100644 --- a/lib/src/util/ip_address.c +++ b/lib/src/util/ip_address.c @@ -98,19 +98,18 @@ int ip_address_pton (const char *ip_address_str, ip_address_t * ip_address) { int pton_fd; - char *addr = strdup (ip_address_str); int family; - family = ip_address_get_family (addr); + family = ip_address_get_family (ip_address_str); switch (family) { case AF_INET6: - pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer); + pton_fd = inet_pton (AF_INET6, ip_address_str, &ip_address->buffer); break; case AF_INET: - pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer); + pton_fd = inet_pton (AF_INET, ip_address_str, &ip_address->buffer); break; default: goto ERR; @@ -125,7 +124,6 @@ ip_address_pton (const char *ip_address_str, ip_address_t * ip_address) return 1; ERR: - free (addr); return -1; } |