diff options
50 files changed, 3811 insertions, 1419 deletions
diff --git a/cmake/Modules/Packager.cmake b/cmake/Modules/Packager.cmake index 6f77fd3a8..e5e3fa731 100644 --- a/cmake/Modules/Packager.cmake +++ b/cmake/Modules/Packager.cmake @@ -136,7 +136,7 @@ macro(make_packages) set(CPACK_${type}_${uc}_PACKAGE_NAME "${lc}") set(CPACK_COMPONENT_${uc}_DESCRIPTION "${${lc}_DESCRIPTION}") - if (NOT ${${lc}_DEB_PACKAGE_CONTROL_EXTRA} STREQUAL "") + if (${lc}_DEB_PACKAGE_CONTROL_EXTRA) set(CPACK_DEBIAN_${uc}_PACKAGE_CONTROL_EXTRA "${${lc}_DEB_PACKAGE_CONTROL_EXTRA}") endif() endforeach() @@ -183,6 +183,10 @@ macro(make_packages) if (NOT ${${lc}_RPM_POST_UNINSTALL_SCRIPT_FILE} STREQUAL "") set(CPACK_RPM_${uc}_POST_UNINSTALL_SCRIPT_FILE "${${lc}_RPM_POST_UNINSTALL_SCRIPT_FILE}") endif() + + if (NOT ${${lc}_RPM_PRE_UNINSTALL_SCRIPT_FILE} STREQUAL "") + set(CPACK_RPM_${uc}_PRE_UNINSTALL_SCRIPT_FILE "${${lc}_RPM_PRE_UNINSTALL_SCRIPT_FILE}") + endif() endforeach() endif() 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 88595a9bc..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; @@ -833,18 +843,13 @@ facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet) */ int rc; - if (facelet_cache_add(&facemgr->facelet_cache, facelet) < 0) { - ERROR("[facemgr_process_create] Error adding facelet to cache"); - return -1; - } - DEBUG("Facelet added to cache"); - /* * If the facelet does not satisfy filters, we do not lose any information * but do not take any action to complement the face */ rc = facemgr_facelet_satisfy_rules(facemgr, facelet); if (rc == -3) { + facelet_set_status(facelet, FACELET_STATUS_IGNORED); /* Does not satisfy rules */ return 0; } @@ -890,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)) { @@ -927,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) @@ -937,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; } /** @@ -965,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)) { @@ -998,6 +1004,7 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) } /* Process GET/UDPATE... */ + int rc; switch(facelet_get_status(facelet)) { case FACELET_STATUS_UNDEFINED: ERROR("[facemgr_process_update] Unexpected facelet status"); @@ -1015,6 +1022,14 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) return -1; } } + + rc = facemgr_facelet_satisfy_rules(facemgr, facelet); + if (rc == -3) { + facelet_set_status(facelet, FACELET_STATUS_IGNORED); + /* Does not satisfy rules */ + return 0; + } + if (!facelet_validate_face(facelet)) return 0; @@ -1044,6 +1059,13 @@ 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; + } + if (!facelet_validate_face(facelet)) return 0; @@ -1059,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; @@ -1075,15 +1106,30 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) int facemgr_process_delete(facemgr_t * facemgr, facelet_t * facelet) { + + DEBUG("[facemgr_process_delete] Deleting facelet on hicn-light"); if (interface_on_event(facemgr->hl, facelet) < 0) return -1; + /* + * It might be tempting to cache old information, but for now we reset the + * facelet state that might change (such as IP addresses etc). + * netdevice, netdevice_type and admin_state should not be affected. + */ + DEBUG("[facemgr_process_delete] Cleaning cached data"); + facelet_unset_local_addr(facelet); + facelet_unset_local_port(facelet); + facelet_unset_remote_addr(facelet); + facelet_unset_remote_port(facelet); + facelet_set_status(facelet, FACELET_STATUS_DELETED); - //facelet_set_bj_done(facelet, false); + + facelet_unset_bj_done(facelet); return 0; } + /** * \brief Process incoming events from interfaces * @@ -1094,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); @@ -1108,21 +1156,32 @@ 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)) { case FACELET_EVENT_CREATE: + + if (facelet_cache_add(&facemgr->facelet_cache, facelet_in) < 0) { + ERROR("[facemgr_on_event] Error adding facelet to cache"); + return -1; + } + //DEBUG("Facelet added to cache"); + + remove_facelet = false; + if (facemgr_process_create(facemgr, facelet_in) < 0) { - ERROR("[facemgr_process_cached_facelet] Error processing CREATE event"); + ERROR("[facemgr_on_event] Error processing CREATE event"); goto ERR; } break; case FACELET_EVENT_GET: /* Insert new facelet in cached */ - if (facemgr_process_get(facemgr, facelet_in) < 0) { - ERROR("[facemgr_process_cached_facelet] Error processing GET event"); + 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; } break; @@ -1159,13 +1218,19 @@ 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: - // FIXME, this might occur if the facemgr restarts and we try to - // re-create existing faces - ERROR("[facemgr_on_event] CREATE event for a face that already exists..."); - ret = -1; + // This case will occur when we try to re-create existing faces, + // eg. in the situation of a forwarder restarting. + // likely this occurs when the interface receives a (potentially new) address + if (facelet_merge(facelet, facelet_in) < 0) { + ERROR("[facemgr_on_event] Error merging facelets"); + continue; + } + if (facemgr_process_create(facemgr, facelet) < 0) { + ERROR("[facemgr_on_event] Error processing CREATE event"); + ret = -1; + } continue; case FACELET_EVENT_GET: /* should be an INFORM message */ @@ -1176,14 +1241,6 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) continue; case FACELET_EVENT_UPDATE: - { - DEBUG("FACELET_EVENT_UPDATE"); - char buf[128]; - facelet_snprintf(buf, 128, facelet_in); - DEBUG("MERGE %s", buf); - facelet_snprintf(buf, 128, facelet); - DEBUG(" ON %s", buf); - } if (facelet_merge(facelet, facelet_in) < 0) { ERROR("[facemgr_on_event] Error merging facelets"); continue; @@ -1218,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) { @@ -1366,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]); } @@ -1406,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 6b04208bb..527da54e7 100644 --- a/ctrl/facemgr/src/cfg.c +++ b/ctrl/facemgr/src/cfg.c @@ -112,6 +112,11 @@ facemgr_cfg_override_initialize(facemgr_cfg_override_t * override) override->is_discovery = false; override->discovery = false; + override->is_ipv4 = false; + override->ipv6 = false; + override->is_ipv6 = false; + override->ipv6 = false; + override->overlays.v4 = NULL; override->overlays.v6 = NULL; @@ -485,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); } @@ -526,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, @@ -684,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 8a3074d2a..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; @@ -518,6 +514,11 @@ facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME) return facelet_set_local_ ## NAME(facelet, NAME); \ } \ \ +int \ +facelet_unset_ ## NAME(facelet_t * facelet) \ +{ \ + return facelet->NAME ## _status = FACELET_ATTR_STATUS_UNSET; \ +} #define _(TYPE, NAME) FACELET_ACCESSORS(TYPE, NAME) foreach_facelet_attr @@ -747,36 +748,16 @@ 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) +void +facelet_set_bj_done(facelet_t * facelet) { - assert(facelet); - DEBUG("num pending=%d\n", facelet->num_pending); - return (facelet->num_pending > 0); + facelet->bj_done = true; } void -facelet_set_bj_done(facelet_t * facelet) +facelet_unset_bj_done(facelet_t * facelet) { - facelet->bj_done = true; + facelet->bj_done = false; } bool @@ -810,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; @@ -826,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; @@ -988,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 fecee8641..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 { @@ -152,12 +154,12 @@ bool facelet_match(const facelet_t * facelet, const facelet_t * facelet_match); */ bool facelet_has_key(const facelet_t * facelet); - #define FACELET_ACCESSORS_H(TYPE, NAME) \ bool facelet_has_ ## NAME(const facelet_t * facelet); \ facelet_attr_status_t facelet_get_ ## NAME ## _status(const facelet_t * facelet);\ int facelet_get_ ## NAME(const facelet_t * facelet, TYPE * NAME); \ -int facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME); +int facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME); \ +int facelet_unset_ ## NAME(facelet_t * facelet); #define _(TYPE, NAME) FACELET_ACCESSORS_H(TYPE, NAME) foreach_facelet_attr @@ -170,11 +172,8 @@ 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); void facelet_set_au_done(facelet_t * facelet); bool facelet_is_au_done(const facelet_t * facelet); @@ -182,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 e42c6c6ae..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; @@ -205,7 +328,6 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) ERROR("Failed to delete face\n"); goto ERR; } - INFO("Deleted face id=%d\n", hc_face.id); break; case FACELET_EVENT_UPDATE: @@ -213,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"); @@ -222,10 +346,9 @@ int hl_on_event(interface_t * interface, const facelet_t * facelet) ERROR("Face to update has not been found"); goto ERR; } - char conn_id_or_name[NAME_LEN]; - snprintf(conn_id_or_name, NAME_LEN, "%d", face_found->id); + 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) { @@ -234,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; @@ -248,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 2a336db8f..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,568 +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, remote_addr; - 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_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, remote_addr; - 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_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, remote_addr; - 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, remote_addr; - 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; -} - #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; @@ -760,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__ @@ -784,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 @@ -814,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 a0ee828b9..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 @@ -73,11 +73,6 @@ #define HICN_DEFAULT_PORT 9695 -#define LIBHICNCTRL_SUCCESS 0 -#define LIBHICNCTRL_FAILURE -1 -#define LIBHICNCTRL_NOT_IMPLEMENTED -99 -#define LIBHICNCTRL_IS_ERROR(x) (x < 0) - /* Helper for avoiding warnings about type-punning */ #define UNION_CAST(x, destType) \ (((union {__typeof__(x) a; destType b;})x).b) @@ -219,11 +214,11 @@ hc_ ## TYPE ## _find(hc_data_t * data, const hc_ ## TYPE ## _t * element, \ foreach_type(hc_ ## TYPE ## _t, x, data) { \ if (hc_ ## TYPE ## _cmp(x, element) >= 0) { \ *found = x; \ - return LIBHICNCTRL_SUCCESS; \ + return 0; \ } \ }; \ *found = NULL; /* this is optional */ \ - return LIBHICNCTRL_SUCCESS; \ + return 0; \ } /****************************************************************************** @@ -236,113 +231,103 @@ hc_ ## TYPE ## _find(hc_data_t * data, const hc_ ## TYPE ## _t * element, \ /** * \brief Holds the state of an hICN control socket */ -typedef struct { - char * url; - int fd; - u32 seq; - - /* Partial receive buffer */ - u8 buf[RECV_BUFLEN]; - size_t roff; /**< Read offset */ - size_t woff; /**< Write offset */ - - /* - * Because received messages are potentially unbounded in size, we might not - * guarantee that we can store a full packet before processing it. We must - * implement a very simple state machine remembering the current parsing - * status in order to partially process the packet. - */ - size_t remaining; - u32 send_id; - u32 send_seq; - u32 recv_seq; -} hc_sock_t; +typedef struct hc_sock_s hc_sock_t; /** * \brief Create an hICN control socket using the specified URL. * \param [in] url - The URL to connect to. * \return an hICN control socket */ -hc_sock_t * -hc_sock_create_url(const char * url); +hc_sock_t * hc_sock_create_url(const char * url); /** * \brief Create an hICN control socket using the default connection type. * \return an hICN control socket */ -hc_sock_t * -hc_sock_create(void); +hc_sock_t * hc_sock_create(void); /** * \brief Frees an hICN control socket + * \param [in] s - hICN control socket */ -void -hc_sock_free(hc_sock_t *s); +void hc_sock_free(hc_sock_t * s); + +/** + * \brief Returns the next available sequence number to use for requests to the + * API. + * \param [in] s - hICN control socket + */ +int hc_sock_get_next_seq(hc_sock_t * s); /** * \brief Sets the socket as non-blocking + * \param [in] s - hICN control socket * \return Error code */ -int -hc_sock_set_nonblocking(hc_sock_t *s); +int hc_sock_set_nonblocking(hc_sock_t * s); + +/** + * \brief Return the file descriptor associated to the hICN contorl sock + * \param [in] s - hICN control socket + * \return The file descriptor (positive value), or a negative integer in case + * of error + */ +int hc_sock_get_fd(hc_sock_t * s); /** * \brief Connect the socket * \return Error code */ int -hc_sock_connect(hc_sock_t *s); +hc_sock_connect(hc_sock_t * s); /** * \brief Return the offset and size of available buffer space - * \param [in] sock - hICN control socket + * \param [in] s - hICN control socket * \param [out] buffer - Offset in buffer * \param [out] size - Remaining size * \return Error code */ -int -hc_sock_get_available(hc_sock_t * s, u8 ** buffer, size_t * size); +int hc_sock_get_available(hc_sock_t * s, u8 ** buffer, size_t * size); /** * \brief Write/read iexchance on the control socket (internal helper function) - * \param [in] sock - hICN control socket + * \param [in] s - hICN control socket * \param [in] msg - Message to send * \param [in] msglen - Length of the message to send * \return Error code */ -int -hc_sock_send(hc_sock_t * s, hc_msg_t * msg, size_t msglen); +int hc_sock_send(hc_sock_t * s, hc_msg_t * msg, size_t msglen, int seq); /** * \brief Helper for reading socket contents - * \param [in] sock - hICN control socket - * \param [in] data - Result data buffer - * \param [in] parse - Parse function to convert remote types into lib native - * types, or NULL not to perform any translation. + * \param [in] s - hICN control socket * \return Error code */ -int -hc_sock_recv(hc_sock_t * s, hc_data_t * data); +int hc_sock_recv(hc_sock_t * s); /** * \brief Processing data received by socket - * \param [in] sock - hICN control socket - * \param [in] data - Result data buffer + * \param [in] s - hICN control socket * \param [in] parse - Parse function to convert remote types into lib native * types, or NULL not to perform any translation. * \return Error code */ -int -hc_sock_process(hc_sock_t * s, hc_data_t * data, - int (*parse)(const u8 * src, u8 * dst)); +int hc_sock_process(hc_sock_t * s, hc_data_t ** data); + +/** + * \brief Callback used in async mode when data is available on the socket + * \param [in] s - hICN control socket + * \return Error code + */ +int hc_sock_callback(hc_sock_t * s, hc_data_t ** data); /** * \brief Reset the state of the sock (eg. to handle a reconnecton) - * \param [in] sock - hICN control socket + * \param [in] s - hICN control socket * \return Error code */ -int -hc_sock_reset(hc_sock_t * s); +int hc_sock_reset(hc_sock_t * s); /****************************************************************************** * Command-specific structures and functions @@ -395,9 +380,9 @@ hc_sock_reset(hc_sock_t * s); #define NULLTERM 1 #endif -#define NAME_LEN 16 /* NULL-terminated right ? */ +#define SYMBOLIC_NAME_LEN 16 /* NULL-terminated right ? */ #define INTERFACE_LEN 16 -#define MAXSZ_HC_NAME_ NAME_LEN +#define MAXSZ_HC_NAME_ SYMBOLIC_NAME_LEN #define MAXSZ_HC_NAME MAXSZ_HC_NAME_ + NULLTERM #define MAXSZ_HC_ID_ 10 /* Number of digits for MAX_INT */ @@ -460,7 +445,7 @@ typedef int (*HC_PARSE)(const u8 *, u8 *); // FIXME the listener should not require any port for hICN... typedef struct { - char name[NAME_LEN]; /* K.w */ // XXX clarify what used for + char name[SYMBOLIC_NAME_LEN]; /* K.w */ // XXX clarify what used for char interface_name[INTERFACE_LEN]; /* Kr. */ u32 id; hc_connection_type_t type; /* .rw */ @@ -471,7 +456,7 @@ typedef struct { int hc_listener_create(hc_sock_t * s, hc_listener_t * listener); /* listener_found might eventually be allocated, and needs to be freed */ -int hc_listener_get(hc_sock_t *s, hc_listener_t * listener, +int hc_listener_get(hc_sock_t * s, hc_listener_t * listener, hc_listener_t ** listener_found); int hc_listener_delete(hc_sock_t * s, hc_listener_t * listener); int hc_listener_list(hc_sock_t * s, hc_data_t ** pdata); @@ -500,7 +485,7 @@ int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener); */ typedef struct { u32 id; /* Kr. */ - char name[NAME_LEN]; /* K.w */ + char name[SYMBOLIC_NAME_LEN]; /* K.w */ char interface_name[INTERFACE_LEN]; /* Kr. */ hc_connection_type_t type; /* .rw */ int family; /* .rw */ @@ -518,7 +503,7 @@ typedef struct { int hc_connection_create(hc_sock_t * s, hc_connection_t * connection); /* connection_found will be allocated, and must be freed */ -int hc_connection_get(hc_sock_t *s, hc_connection_t * connection, +int hc_connection_get(hc_sock_t * s, hc_connection_t * connection, hc_connection_t ** connection_found); int hc_connection_update_by_id(hc_sock_t * s, int hc_connection_id, hc_connection_t * connection); @@ -562,7 +547,7 @@ int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connec typedef struct { u8 id; - char name[NAME_LEN]; + char name[SYMBOLIC_NAME_LEN]; face_t face; // or embed ? //face_id_t parent; /* Pointer from connection to listener */ } hc_face_t; @@ -579,13 +564,14 @@ int hc_face_create(hc_sock_t * s, hc_face_t * face); int 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); int hc_face_list(hc_sock_t * s, hc_data_t ** pdata); +int hc_face_list_async(hc_sock_t * s); //, hc_data_t ** pdata); #define foreach_face(VAR, data) foreach_type(hc_face_t, VAR, data) #define MAX_FACE_ID 255 #define MAXSZ_FACE_ID_ 3 #define MAXSZ_FACE_ID MAXSZ_FACE_ID_ + NULLTERM -#define MAXSZ_FACE_NAME_ NAMELEN +#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/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index 7b4413d55..4708595e0 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -24,6 +24,7 @@ set(HEADER_FILES set(UTIL_HEADER_FILES face.h util/log.h + util/map.h ) set(SOURCE_FILES diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 769c96076..0e5b529c5 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -20,6 +20,7 @@ #include <assert.h> // assert #include <math.h> // log2 +#include <stdbool.h> #include <stdio.h> // snprintf #include <string.h> // memmove, strcasecmp #include <sys/socket.h> // socket @@ -30,10 +31,83 @@ #include <hicn/ctrl/commands.h> #include <hicn/util/token.h> #include "util/log.h" +#include "util/map.h" #include <strings.h> #define PORT 9695 +/* + * Internal state associated to a pending request + */ +typedef struct { + int seq; + hc_data_t * data; + /* Information used to process results */ + int size_in; + int (*parse)(const u8 * src, u8 * dst); +} hc_sock_request_t; + +/** + * Messages to the forwarder might be multiplexed thanks to the seqNum fields in + * the header_control_message structure. The forwarder simply answers back the + * original sequence number. We maintain a map of such sequence number to + * outgoing queries so that replied can be demultiplexed and treated + * appropriately. + */ +TYPEDEF_MAP_H(hc_sock_map, int, hc_sock_request_t *); +TYPEDEF_MAP(hc_sock_map, int, hc_sock_request_t *, int_cmp, int_snprintf, generic_snprintf); + +struct hc_sock_s { + char * url; + int fd; + + /* Partial receive buffer */ + u8 buf[RECV_BUFLEN]; + size_t roff; /**< Read offset */ + size_t woff; /**< Write offset */ + + /* + * Because received messages are potentially unbounded in size, we might not + * guarantee that we can store a full packet before processing it. We must + * implement a very simple state machine remembering the current parsing + * status in order to partially process the packet. + */ + size_t remaining; + u32 send_id; + + /* Next sequence number to be used for requests */ + int seq; + + /* Request being parsed (NULL if none) */ + hc_sock_request_t * cur_request; + + bool async; + hc_sock_map_t * map; +}; + + +hc_sock_request_t * +hc_sock_request_create(int seq, hc_data_t * data, HC_PARSE parse) +{ + assert(seq >= 0); + assert(data); + + hc_sock_request_t * request = malloc(sizeof(hc_sock_request_t)); + if (!request) + return NULL; + request->seq = seq; + request->data = data; + request->parse = parse; + return request; +} + +void +hc_sock_request_free(hc_sock_request_t * request) +{ + free(request); +} + + #if 0 #ifdef __APPLE__ #define RANDBYTE() (u8)(arc4random() & 0xFF) @@ -239,7 +313,7 @@ hc_data_create(size_t in_element_size, size_t out_element_size) data->in_element_size = in_element_size; data->out_element_size = out_element_size; data->size = 0; - data->complete = 0; + data->complete = false; data->command_id = 0; // TODO this could also be a busy mark in the socket /* No callback needed in blocking code for instance */ data->complete_cb = NULL; @@ -274,21 +348,21 @@ hc_data_ensure_available(hc_data_t * data, size_t count) data->max_size_log = new_size_log; data->buffer = realloc(data->buffer, (1 << new_size_log) * data->out_element_size); if (!data->buffer) - return LIBHICNCTRL_FAILURE; + return -1; } - return LIBHICNCTRL_SUCCESS; + return 0; } int hc_data_push_many(hc_data_t * data, const void * elements, size_t count) { if (hc_data_ensure_available(data, count) < 0) - return LIBHICNCTRL_FAILURE; + return -1; memcpy(data->buffer + data->size * data->out_element_size, elements, count * data->out_element_size); data->size += count; - return LIBHICNCTRL_SUCCESS; + return 0; } int @@ -316,7 +390,7 @@ hc_data_set_callback(hc_data_t * data, data_callback_t cb, void * cb_data) { data->complete_cb = cb; data->complete_cb_data = cb_data; - return LIBHICNCTRL_SUCCESS; + return 0; } int @@ -325,14 +399,14 @@ hc_data_set_complete(hc_data_t * data) data->complete = true; if (data->complete_cb) return data->complete_cb(data, data->complete_cb_data); - return LIBHICNCTRL_SUCCESS; + return 0; } int hc_data_reset(hc_data_t * data) { data->size = 0; - return LIBHICNCTRL_SUCCESS; + return 0; } /****************************************************************************** @@ -377,10 +451,10 @@ hc_sock_parse_url(const char * url, struct sockaddr * sa) break; } default: - return LIBHICNCTRL_FAILURE; + return -1; } - return LIBHICNCTRL_SUCCESS; + return 0; } hc_sock_t * @@ -399,9 +473,20 @@ hc_sock_create_url(const char * url) if (hc_sock_reset(s) < 0) goto ERR_RESET; + s->seq = 0; + s->cur_request = NULL; + + s->map = hc_sock_map_create(); + if (!s->map) + goto ERR_MAP; + return s; + //hc_sock_map_free(s->map); +ERR_MAP: ERR_RESET: + if (s->url) + free(s->url); close(s->fd); ERR_SOCKET: free(s); @@ -418,6 +503,19 @@ hc_sock_create(void) void hc_sock_free(hc_sock_t * s) { + hc_sock_request_t ** request_array = NULL; + int n = hc_sock_map_get_value_array(s->map, &request_array); + if (n < 0) { + ERROR("Could not retrieve pending request array for freeing up resources"); + } else { + for (unsigned i = 0; i < n; i++) { + hc_sock_request_t * request = request_array[i]; + hc_sock_request_free(request); + } + free(request_array); + } + + hc_sock_map_free(s->map); if (s->url) free(s->url); close(s->fd); @@ -425,13 +523,25 @@ hc_sock_free(hc_sock_t * s) } int -hc_sock_set_nonblocking(hc_sock_t *s) +hc_sock_get_next_seq(hc_sock_t * s) +{ + return s->seq++; +} + +int +hc_sock_set_nonblocking(hc_sock_t * s) { return (fcntl(s->fd, F_SETFL, fcntl(s->fd, F_GETFL) | O_NONBLOCK) < 0); } int -hc_sock_connect(hc_sock_t *s) +hc_sock_get_fd(hc_sock_t * s) +{ + return s->fd; +} + +int +hc_sock_connect(hc_sock_t * s) { struct sockaddr_storage ss = { 0 }; @@ -444,17 +554,18 @@ hc_sock_connect(hc_sock_t *s) if (connect(s->fd, (struct sockaddr *)&ss, size) < 0) //sizeof(struct sockaddr)) < 0) goto ERR_CONNECT; - return LIBHICNCTRL_SUCCESS; + return 0; ERR_CONNECT: ERR_PARSE: - return LIBHICNCTRL_FAILURE; + return -1; } int -hc_sock_send(hc_sock_t * s, hc_msg_t * msg, size_t msglen) +hc_sock_send(hc_sock_t * s, hc_msg_t * msg, size_t msglen, int seq) { int rc; + msg->hdr.seqNum = seq; rc = send(s->fd, msg, msglen, 0); if (rc < 0) { perror("hc_sock_send"); @@ -469,11 +580,11 @@ hc_sock_get_available(hc_sock_t * s, u8 ** buffer, size_t * size) *buffer = s->buf + s->woff; *size = RECV_BUFLEN - s->woff; - return LIBHICNCTRL_SUCCESS; + return 0; } int -hc_sock_recv(hc_sock_t * s, hc_data_t * data) +hc_sock_recv(hc_sock_t * s) { int rc; @@ -485,24 +596,24 @@ hc_sock_recv(hc_sock_t * s, hc_data_t * data) rc = recv(s->fd, s->buf + s->woff, RECV_BUFLEN - s->woff, 0); if (rc == 0) { - return LIBHICNCTRL_FAILURE; /* Connection has been closed */ - // XXX + return 0; } if (rc < 0) { + /* + * Let's not return 0 which currently means the socket has been closed + */ + if (errno == EWOULDBLOCK) + return -1; perror("hc_sock_recv"); - /* Error occurred */ - // XXX check for EWOULDBLOCK; - // XXX - return LIBHICNCTRL_FAILURE; + return -1; } s->woff += rc; - return LIBHICNCTRL_SUCCESS; + return rc; } int -hc_sock_process(hc_sock_t * s, hc_data_t * data, - int (*parse)(const u8 * src, u8 * dst)) +hc_sock_process(hc_sock_t * s, hc_data_t ** data) { int err = 0; @@ -511,7 +622,7 @@ hc_sock_process(hc_sock_t * s, hc_data_t * data, while(available > 0) { - if (s->remaining == 0) { + if (!s->cur_request) { // No message being parsed, alternatively (remaining == 0) hc_msg_t * msg = (hc_msg_t*)(s->buf + s->roff); /* We expect a message header */ @@ -519,74 +630,82 @@ hc_sock_process(hc_sock_t * s, hc_data_t * data, break; /* Sanity checks (might instead raise warnings) */ - // TODO: sync check ? assert((msg->hdr.messageType == RESPONSE_LIGHT) || (msg->hdr.messageType == ACK_LIGHT) || (msg->hdr.messageType == NACK_LIGHT)); - //assert(msg->hdr.commandID == data->command_id); // FIXME - assert(msg->hdr.seqNum == s->recv_seq++); + hc_sock_request_t * request = NULL; + if (hc_sock_map_get(s->map, msg->hdr.seqNum, &request) < 0) { + ERROR("[hc_sock_process] Error searching for matching request"); + return -1; + } + if (!request) { + ERROR("[hc_sock_process] No request matching received sequence number"); + return -1; + } s->remaining = msg->hdr.length; if (s->remaining == 0) { - /* - * The protocol expects all sequence number to be reset after - * each transaction. We reset before running the callback in - * case it triggers new exchanges. - */ - s->send_seq = HICN_CTRL_SEND_SEQ_INIT; - s->recv_seq = HICN_CTRL_RECV_SEQ_INIT; - - // TODO : check before even sending ? - /* Complete message without payload */ - // TODO : is this correct ? no error code ? - hc_data_set_complete(data); + if (data) { + *data = request->data; +// } else { +// free(request->data); + } + hc_data_set_complete(request->data); + hc_sock_request_free(request); + } else { + /* We only remember it if there is still data to parse */ + s->cur_request = request; } available -= sizeof(hc_msg_header_t); s->roff += sizeof(hc_msg_header_t); } else { /* We expect the complete payload, or at least a chunk of it */ - size_t num_chunks = available / data->in_element_size; + size_t num_chunks = available / s->cur_request->data->in_element_size; if (num_chunks == 0) break; if (num_chunks > s->remaining) num_chunks = s->remaining; - if (!parse) { - hc_data_push_many(data, s->buf + s->roff, num_chunks); + if (!s->cur_request->parse) { + /* If we don't need to parse results, then we can directly push + * all of them into the result data structure */ + hc_data_push_many(s->cur_request->data, s->buf + s->roff, num_chunks); } else { int rc; - rc = hc_data_ensure_available(data, num_chunks); + rc = hc_data_ensure_available(s->cur_request->data, num_chunks); if (rc < 0) - return LIBHICNCTRL_FAILURE; + return -1; for (int i = 0; i < num_chunks; i++) { - u8 * dst = hc_data_get_next(data); + u8 * dst = hc_data_get_next(s->cur_request->data); if (!dst) - return LIBHICNCTRL_FAILURE; + return -1; - rc = parse(s->buf + s->roff + i * data->in_element_size, dst); + rc = s->cur_request->parse(s->buf + s->roff + i * s->cur_request->data->in_element_size, dst); if (rc < 0) err = -1; /* FIXME we let the loop complete (?) */ - data->size++; + s->cur_request->data->size++; } } - s->remaining -= num_chunks; + available -= num_chunks * s->cur_request->data->in_element_size; + s->roff += num_chunks * s->cur_request->data->in_element_size; if (s->remaining == 0) { - /* - * The protocol expects all sequence number to be reset after - * each transaction. We reset before running the callback in - * case it triggers new exchanges. - */ - s->send_seq = HICN_CTRL_SEND_SEQ_INIT; - s->recv_seq = HICN_CTRL_RECV_SEQ_INIT; - - hc_data_set_complete(data); + if (hc_sock_map_remove(s->map, s->cur_request->seq, NULL) < 0) { + ERROR("[hc_sock_process] Error removing request from map"); + return -1; + } + if (data) { + *data = s->cur_request->data; +// } else { +// free(s->cur_request->data); + } + hc_data_set_complete(s->cur_request->data); + hc_sock_request_free(s->cur_request); + s->cur_request = NULL; } - available -= num_chunks * data->in_element_size; - s->roff += num_chunks * data->in_element_size; } } @@ -605,13 +724,47 @@ hc_sock_process(hc_sock_t * s, hc_data_t * data, } int +hc_sock_callback(hc_sock_t * s, hc_data_t ** data) +{ + *data = NULL; + + for (;;) { + int n = hc_sock_recv(s); + if (n == 0) { + goto ERR_EOF; + } + if (n < 0) { + switch(errno) { + case ECONNRESET: + case ENODEV: + /* Forwarder restarted */ + WARN("Forwarder likely restarted: not (yet) implemented"); + goto ERR_EOF; + case EWOULDBLOCK: + //DEBUG("Would block... stop reading from socket"); + goto END; + default: + perror("hc_sock_recv"); + goto ERR_EOF; + } + } + if (hc_sock_process(s, data) < 0) { + return -1; + } + } +END: + return 0; + +ERR_EOF: + return -1; +} + +int hc_sock_reset(hc_sock_t * s) { s->roff = s->woff = 0; - s->send_seq = HICN_CTRL_SEND_SEQ_INIT; - s->recv_seq = HICN_CTRL_RECV_SEQ_INIT; s->remaining = 0; - return LIBHICNCTRL_SUCCESS; + return 0; } /****************************************************************************** @@ -630,8 +783,11 @@ typedef struct { int hc_execute_command(hc_sock_t * s, hc_msg_t * msg, size_t msg_len, - hc_command_params_t * params, hc_data_t ** pdata) + hc_command_params_t * params, hc_data_t ** pdata, bool async) { + if (async) + assert(!pdata); + /* Sanity check */ switch(params->cmd) { case ACTION_CREATE: @@ -655,35 +811,70 @@ hc_execute_command(hc_sock_t * s, hc_msg_t * msg, size_t msg_len, assert(params->parse == NULL); break; default: - return LIBHICNCTRL_FAILURE; + return -1; } - hc_sock_reset(s); + //hc_sock_reset(s); /* XXX data will at least store the result (complete) */ hc_data_t * data = hc_data_create(params->size_in, params->size_out); - if (!data) + if (!data) { + ERROR("[hc_execute_command] Could not create data storage"); goto ERR_DATA; + } + + int seq = hc_sock_get_next_seq(s); + if (seq < 0) { + ERROR("[hc_execute_command] Could not get next sequence number"); + goto ERR_SEQ; + } + + /* Create state used to process the request */ + hc_sock_request_t * request = NULL; + request = hc_sock_request_create(seq, data, params->parse); + if (!request) { + ERROR("[hc_execute_command] Could not create request state"); + goto ERR_REQUEST; + } + + /* Add state to map */ + if (hc_sock_map_add(s->map, seq, request) < 0) { + ERROR("[hc_execute_command] Error adding request state to map"); + goto ERR_MAP; + } - if (hc_sock_send(s, msg, msg_len) < 0) + if (hc_sock_send(s, msg, msg_len, seq) < 0) { + ERROR("[hc_execute_command] Error sending message"); goto ERR_PROCESS; + } + + if (async) + return 0; + while(!data->complete) { - if (hc_sock_recv(s, data) < 0) - break; - if (hc_sock_process(s, data, params->parse) < 0) { + /* + * As the socket is non blocking it might happen that we need to read + * several times before success... shall we alternate between blocking + * and non-blocking mode ? + */ + if (hc_sock_recv(s) < 0) + continue; //break; + if (hc_sock_process(s, pdata) < 0) { + ERROR("[hc_execute_command] Error processing socket results"); goto ERR_PROCESS; } } - if (pdata) - *pdata = data; - - return LIBHICNCTRL_SUCCESS; + return 0; ERR_PROCESS: +ERR_MAP: + hc_sock_request_free(request); +ERR_REQUEST: +ERR_SEQ: free(data); ERR_DATA: - return LIBHICNCTRL_FAILURE; + return -1; } /*----------------------------------------------------------------------------* @@ -693,13 +884,13 @@ ERR_DATA: /* LISTENER CREATE */ int -hc_listener_create(hc_sock_t * s, hc_listener_t * listener) +_hc_listener_create(hc_sock_t * s, hc_listener_t * listener, bool async) { if (!IS_VALID_FAMILY(listener->family)) - return LIBHICNCTRL_FAILURE; + return -1; if (!IS_VALID_CONNECTION_TYPE(listener->type)) - return LIBHICNCTRL_FAILURE; + return -1; struct { header_control_message hdr; @@ -709,7 +900,7 @@ hc_listener_create(hc_sock_t * s, hc_listener_t * listener) .messageType = REQUEST_LIGHT, .commandID = ADD_LISTENER, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { .address = { @@ -722,7 +913,7 @@ hc_listener_create(hc_sock_t * s, hc_listener_t * listener) } }; - snprintf(msg.payload.symbolic, NAME_LEN, "%s", listener->name); + snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", listener->name); snprintf(msg.payload.interfaceName, INTERFACE_LEN, "%s", listener->interface_name); hc_command_params_t params = { @@ -733,31 +924,43 @@ hc_listener_create(hc_sock_t * s, hc_listener_t * listener) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_listener_create(hc_sock_t * s, hc_listener_t * listener) +{ + return _hc_listener_create(s, listener, false); +} + +int +hc_listener_create_async(hc_sock_t * s, hc_listener_t * listener) +{ + return _hc_listener_create(s, listener, true); } /* LISTENER GET */ int -hc_listener_get(hc_sock_t *s, hc_listener_t * listener, +hc_listener_get(hc_sock_t * s, hc_listener_t * listener, hc_listener_t ** listener_found) { hc_data_t * listeners; hc_listener_t * found; if (hc_listener_list(s, &listeners) < 0) - return LIBHICNCTRL_FAILURE; + return -1; /* Test */ if (hc_listener_find(listeners, listener, &found) < 0) { hc_data_free(listeners); - return LIBHICNCTRL_FAILURE; + return -1; } if (found) { *listener_found = malloc(sizeof(hc_listener_t)); if (!*listener_found) - return LIBHICNCTRL_FAILURE; + return -1; **listener_found = *found; } else { *listener_found = NULL; @@ -765,14 +968,14 @@ hc_listener_get(hc_sock_t *s, hc_listener_t * listener, hc_data_free(listeners); - return LIBHICNCTRL_SUCCESS; + return 0; } /* LISTENER DELETE */ int -hc_listener_delete(hc_sock_t * s, hc_listener_t * listener) +_hc_listener_delete(hc_sock_t * s, hc_listener_t * listener, bool async) { struct { header_control_message hdr; @@ -782,25 +985,21 @@ hc_listener_delete(hc_sock_t * s, hc_listener_t * listener) .messageType = REQUEST_LIGHT, .commandID = REMOVE_LISTENER, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, }; if (listener->id) { - printf("Delete by ID\n"); - snprintf(msg.payload.symbolicOrListenerid, NAME_LEN, "%d", listener->id); + snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d", listener->id); } else if (*listener->name) { - printf("Delete by name %s\n", listener->name); - snprintf(msg.payload.symbolicOrListenerid, NAME_LEN, "%s", listener->name); + snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%s", listener->name); } else { - printf("Delete after search\n"); hc_listener_t * listener_found; if (hc_listener_get(s, listener, &listener_found) < 0) - return LIBHICNCTRL_FAILURE; + return -1; if (!listener_found) - return LIBHICNCTRL_FAILURE; - printf("Delete listener ID=%d\n", listener_found->id); - snprintf(msg.payload.symbolicOrListenerid, NAME_LEN, "%d", listener_found->id); + return -1; + snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d", listener_found->id); free(listener_found); } @@ -812,13 +1011,26 @@ hc_listener_delete(hc_sock_t * s, hc_listener_t * listener) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_listener_delete(hc_sock_t * s, hc_listener_t * listener) +{ + return _hc_listener_delete(s, listener, false); +} + +int +hc_listener_delete_async(hc_sock_t * s, hc_listener_t * listener) +{ + return _hc_listener_delete(s, listener, true); } + /* LISTENER LIST */ int -hc_listener_list(hc_sock_t * s, hc_data_t ** pdata) +_hc_listener_list(hc_sock_t * s, hc_data_t ** pdata, bool async) { struct { header_control_message hdr; @@ -827,7 +1039,7 @@ hc_listener_list(hc_sock_t * s, hc_data_t ** pdata) .messageType = REQUEST_LIGHT, .commandID = LIST_LISTENERS, .length = 0, - .seqNum = s->send_seq, + .seqNum = 0, }, }; @@ -839,7 +1051,19 @@ hc_listener_list(hc_sock_t * s, hc_data_t ** pdata) .parse = (HC_PARSE)hc_listener_parse, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata, async); +} + +int +hc_listener_list(hc_sock_t * s, hc_data_t ** pdata) +{ + return _hc_listener_list(s, pdata, false); +} + +int +hc_listener_list_async(hc_sock_t * s, hc_data_t ** pdata) +{ + return _hc_listener_list(s, pdata, true); } /* LISTENER VALIDATE */ @@ -848,12 +1072,12 @@ int hc_listener_validate(const hc_listener_t * listener) { if (!IS_VALID_FAMILY(listener->family)) - return LIBHICNCTRL_FAILURE; + return -1; if (!IS_VALID_CONNECTION_TYPE(listener->type)) - return LIBHICNCTRL_FAILURE; + return -1; - return LIBHICNCTRL_SUCCESS; + return 0; } /* LISTENER CMP */ @@ -866,8 +1090,8 @@ hc_listener_cmp(const hc_listener_t * l1, const hc_listener_t * l2) (strncmp(l1->interface_name, l2->interface_name, INTERFACE_LEN) == 0) && (ip_address_cmp(&l1->local_addr, &l2->local_addr, l1->family) == 0) && (l1->local_port == l2->local_port)) - ? LIBHICNCTRL_SUCCESS - : LIBHICNCTRL_FAILURE; + ? 0 + : -1; } /* LISTENER PARSE */ @@ -878,18 +1102,18 @@ hc_listener_parse(void * in, hc_listener_t * listener) list_listeners_command * cmd = (list_listeners_command *)in; if (!IS_VALID_LIST_LISTENERS_TYPE(cmd->encapType)) - return LIBHICNCTRL_FAILURE; + return -1; hc_connection_type_t type = map_from_encap_type[cmd->encapType]; if (type == CONNECTION_TYPE_UNDEFINED) - return LIBHICNCTRL_FAILURE; + return -1; if (!IS_VALID_ADDR_TYPE(cmd->addressType)) - return LIBHICNCTRL_FAILURE; + return -1; int family = map_from_addr_type[cmd->addressType]; if (!IS_VALID_FAMILY(family)) - return LIBHICNCTRL_FAILURE; + return -1; *listener = (hc_listener_t) { .id = cmd->connid, @@ -898,9 +1122,9 @@ hc_listener_parse(void * in, hc_listener_t * listener) .local_addr = UNION_CAST(cmd->address, ip_address_t), .local_port = ntohs(cmd->port), }; - snprintf(listener->name, NAME_LEN, "%s", cmd->listenerName); + snprintf(listener->name, SYMBOLIC_NAME_LEN, "%s", cmd->listenerName); snprintf(listener->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); - return LIBHICNCTRL_SUCCESS; + return 0; } GENERATE_FIND(listener) @@ -931,10 +1155,10 @@ hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener) /* CONNECTION CREATE */ int -hc_connection_create(hc_sock_t * s, hc_connection_t * connection) +_hc_connection_create(hc_sock_t * s, hc_connection_t * connection, bool async) { if (hc_connection_validate(connection) < 0) - return LIBHICNCTRL_FAILURE; + return -1; struct { header_control_message hdr; @@ -944,7 +1168,7 @@ hc_connection_create(hc_sock_t * s, hc_connection_t * connection) .messageType = REQUEST_LIGHT, .commandID = ADD_CONNECTION, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { /* we use IPv6 which is the longest address */ @@ -960,7 +1184,7 @@ hc_connection_create(hc_sock_t * s, hc_connection_t * connection) .connectionType = (u8)map_to_connection_type[connection->type], } }; - snprintf(msg.payload.symbolic, NAME_LEN, "%s", connection->name); + snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", connection->name); hc_command_params_t params = { .cmd = ACTION_CREATE, @@ -970,31 +1194,43 @@ hc_connection_create(hc_sock_t * s, hc_connection_t * connection) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_connection_create(hc_sock_t * s, hc_connection_t * connection) +{ + return _hc_connection_create(s, connection, false); +} + +int +hc_connection_create_async(hc_sock_t * s, hc_connection_t * connection) +{ + return _hc_connection_create(s, connection, true); } /* CONNECTION GET */ int -hc_connection_get(hc_sock_t *s, hc_connection_t * connection, +hc_connection_get(hc_sock_t * s, hc_connection_t * connection, hc_connection_t ** connection_found) { hc_data_t * connections; hc_connection_t * found; if (hc_connection_list(s, &connections) < 0) - return LIBHICNCTRL_FAILURE; + return -1; /* Test */ if (hc_connection_find(connections, connection, &found) < 0) { hc_data_free(connections); - return LIBHICNCTRL_FAILURE; + return -1; } if (found) { *connection_found = malloc(sizeof(hc_connection_t)); if (!*connection_found) - return LIBHICNCTRL_FAILURE; + return -1; **connection_found = *found; } else { *connection_found = NULL; @@ -1002,14 +1238,14 @@ hc_connection_get(hc_sock_t *s, hc_connection_t * connection, hc_data_free(connections); - return LIBHICNCTRL_SUCCESS; + return 0; } /* CONNECTION DELETE */ int -hc_connection_delete(hc_sock_t * s, hc_connection_t * connection) +_hc_connection_delete(hc_sock_t * s, hc_connection_t * connection, bool async) { struct { header_control_message hdr; @@ -1019,25 +1255,21 @@ hc_connection_delete(hc_sock_t * s, hc_connection_t * connection) .messageType = REQUEST_LIGHT, .commandID = REMOVE_CONNECTION, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, }; if (connection->id) { - printf("Delete by ID\n"); - snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%d", connection->id); + snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", connection->id); } else if (*connection->name) { - printf("Delete by name %s\n", connection->name); - snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%s", connection->name); + snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%s", connection->name); } else { - printf("Delete after search\n"); hc_connection_t * connection_found; if (hc_connection_get(s, connection, &connection_found) < 0) - return LIBHICNCTRL_FAILURE; + return -1; if (!connection_found) - return LIBHICNCTRL_FAILURE; - printf("Delete connection ID=%d\n", connection_found->id); - snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%d", connection_found->id); + return -1; + snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", connection_found->id); free(connection_found); } @@ -1049,14 +1281,25 @@ hc_connection_delete(hc_sock_t * s, hc_connection_t * connection) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); } +int +hc_connection_delete(hc_sock_t * s, hc_connection_t * connection) +{ + return _hc_connection_delete(s, connection, false); +} + +int +hc_connection_delete_async(hc_sock_t * s, hc_connection_t * connection) +{ + return _hc_connection_delete(s, connection, true); +} /* CONNECTION LIST */ int -hc_connection_list(hc_sock_t * s, hc_data_t ** pdata) +_hc_connection_list(hc_sock_t * s, hc_data_t ** pdata, bool async) { struct { header_control_message hdr; @@ -1065,7 +1308,7 @@ hc_connection_list(hc_sock_t * s, hc_data_t ** pdata) .messageType = REQUEST_LIGHT, .commandID = LIST_CONNECTIONS, .length = 0, - .seqNum = s->send_seq, + .seqNum = 0, }, }; @@ -1077,7 +1320,19 @@ hc_connection_list(hc_sock_t * s, hc_data_t ** pdata) .parse = (HC_PARSE)hc_connection_parse, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata, async); +} + +int +hc_connection_list(hc_sock_t * s, hc_data_t ** pdata) +{ + return _hc_connection_list(s, pdata, false); +} + +int +hc_connection_list_async(hc_sock_t * s, hc_data_t ** pdata) +{ + return _hc_connection_list(s, pdata, true); } /* CONNECTION VALIDATE */ @@ -1086,14 +1341,14 @@ int hc_connection_validate(const hc_connection_t * connection) { if (!IS_VALID_FAMILY(connection->family)) - return LIBHICNCTRL_FAILURE; + return -1; if (!IS_VALID_CONNECTION_TYPE(connection->type)) - return LIBHICNCTRL_FAILURE; + return -1; /* TODO assert both local and remote have the right family */ - return LIBHICNCTRL_SUCCESS; + return 0; } /* CONNECTION CMP */ @@ -1111,8 +1366,8 @@ int hc_connection_cmp(const hc_connection_t * c1, const hc_connection_t * c2) (c1->local_port == c2->local_port) && (ip_address_cmp(&c1->remote_addr, &c2->remote_addr, c1->family) == 0) && (c1->remote_port == c2->remote_port)) - ? LIBHICNCTRL_SUCCESS - : LIBHICNCTRL_FAILURE; + ? 0 + : -1; } /* CONNECTION PARSE */ @@ -1123,25 +1378,25 @@ hc_connection_parse(void * in, hc_connection_t * connection) list_connections_command * cmd = (list_connections_command *)in; if (!IS_VALID_LIST_CONNECTIONS_TYPE(cmd->connectionData.connectionType)) - return LIBHICNCTRL_FAILURE; + return -1; hc_connection_type_t type = map_from_list_connections_type[cmd->connectionData.connectionType]; if (type == CONNECTION_TYPE_UNDEFINED) - return LIBHICNCTRL_FAILURE; + return -1; if (!IS_VALID_LIST_CONNECTIONS_STATE(cmd->state)) - return LIBHICNCTRL_FAILURE; + return -1; hc_connection_state_t state = map_from_list_connections_state[cmd->state]; if (state == HC_CONNECTION_STATE_UNDEFINED) - return LIBHICNCTRL_FAILURE; + return -1; if (!IS_VALID_ADDR_TYPE(cmd->connectionData.ipType)) - return LIBHICNCTRL_FAILURE; + return -1; int family = map_from_addr_type[cmd->connectionData.ipType]; if (!IS_VALID_FAMILY(family)) - return LIBHICNCTRL_FAILURE; + return -1; *connection = (hc_connection_t) { .id = cmd->connid, @@ -1157,9 +1412,9 @@ hc_connection_parse(void * in, hc_connection_t * connection) #endif /* WITH_POLICY */ .state = state, }; - snprintf(connection->name, NAME_LEN, "%s", cmd->connectionData.symbolic); + snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", cmd->connectionData.symbolic); snprintf(connection->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); - return LIBHICNCTRL_SUCCESS; + return 0; } GENERATE_FIND(connection) @@ -1196,8 +1451,8 @@ hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection /* CONNECTION SET ADMIN STATE */ int -hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, - face_state_t state) +_hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, + face_state_t state, bool async) { struct { header_control_message hdr; @@ -1207,13 +1462,13 @@ hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, .messageType = REQUEST_LIGHT, .commandID = CONNECTION_SET_ADMIN_STATE, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { .admin_state = state, }, }; - snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%s", conn_id_or_name); + snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%s", conn_id_or_name); hc_command_params_t params = { .cmd = ACTION_SET, @@ -1223,7 +1478,21 @@ hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, + face_state_t state) +{ + return _hc_connection_set_admin_state(s, conn_id_or_name, state, false); +} + +int +hc_connection_set_admin_state_async(hc_sock_t * s, const char * conn_id_or_name, + face_state_t state) +{ + return _hc_connection_set_admin_state(s, conn_id_or_name, state, true); } /*----------------------------------------------------------------------------* @@ -1233,10 +1502,10 @@ hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, /* ROUTE CREATE */ int -hc_route_create(hc_sock_t * s, hc_route_t * route) +_hc_route_create(hc_sock_t * s, hc_route_t * route, bool async) { if (!IS_VALID_FAMILY(route->family)) - return LIBHICNCTRL_FAILURE; + return -1; struct { header_control_message hdr; @@ -1246,7 +1515,7 @@ hc_route_create(hc_sock_t * s, hc_route_t * route) .messageType = REQUEST_LIGHT, .commandID = ADD_ROUTE, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { /* we use IPv6 which is the longest address */ @@ -1261,7 +1530,7 @@ hc_route_create(hc_sock_t * s, hc_route_t * route) * The route commands expects the ID (or name that we don't use) as part of * the symbolicOrConnid attribute. */ - snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%d", route->face_id); + snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", route->face_id); hc_command_params_t params = { .cmd = ACTION_CREATE, @@ -1271,16 +1540,28 @@ hc_route_create(hc_sock_t * s, hc_route_t * route) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_route_create(hc_sock_t * s, hc_route_t * route) +{ + return _hc_route_create(s, route, false); +} + +int +hc_route_create_async(hc_sock_t * s, hc_route_t * route) +{ + return _hc_route_create(s, route, true); } /* ROUTE DELETE */ int -hc_route_delete(hc_sock_t * s, hc_route_t * route) +_hc_route_delete(hc_sock_t * s, hc_route_t * route, bool async) { if (!IS_VALID_FAMILY(route->family)) - return LIBHICNCTRL_FAILURE; + return -1; struct { header_control_message hdr; @@ -1290,7 +1571,7 @@ hc_route_delete(hc_sock_t * s, hc_route_t * route) .messageType = REQUEST_LIGHT, .commandID = REMOVE_ROUTE, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { /* we use IPv6 which is the longest address */ @@ -1308,13 +1589,25 @@ hc_route_delete(hc_sock_t * s, hc_route_t * route) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_route_delete(hc_sock_t * s, hc_route_t * route) +{ + return _hc_route_delete(s, route, false); +} + +int +hc_route_delete_async(hc_sock_t * s, hc_route_t * route) +{ + return _hc_route_delete(s, route, true); } /* ROUTE LIST */ int -hc_route_list(hc_sock_t * s, hc_data_t ** pdata) +_hc_route_list(hc_sock_t * s, hc_data_t ** pdata, bool async) { struct { header_control_message hdr; @@ -1323,7 +1616,7 @@ hc_route_list(hc_sock_t * s, hc_data_t ** pdata) .messageType = REQUEST_LIGHT, .commandID = LIST_ROUTES, .length = 0, - .seqNum = s->send_seq, + .seqNum = 0, }, }; @@ -1335,7 +1628,19 @@ hc_route_list(hc_sock_t * s, hc_data_t ** pdata) .parse = (HC_PARSE)hc_route_parse, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata, async); +} + +int +hc_route_list(hc_sock_t * s, hc_data_t ** pdata) +{ + return _hc_route_list(s, pdata, false); +} + +int +hc_route_list_async(hc_sock_t * s, hc_data_t ** pdata) +{ + return _hc_route_list(s, pdata, true); } /* ROUTE PARSE */ @@ -1346,11 +1651,11 @@ hc_route_parse(void * in, hc_route_t * route) list_routes_command * cmd = (list_routes_command *) in; if (!IS_VALID_ADDR_TYPE(cmd->addressType)) - return LIBHICNCTRL_FAILURE; + return -1; int family = map_from_addr_type[cmd->addressType]; if (!IS_VALID_FAMILY(family)) - return LIBHICNCTRL_FAILURE; + return -1; *route = (hc_route_t) { .face_id = cmd->connid, @@ -1359,7 +1664,7 @@ hc_route_parse(void * in, hc_route_t * route) .len = cmd->len, .cost = cmd->cost, }; - return LIBHICNCTRL_SUCCESS; + return 0; } /* ROUTE SNPRINTF */ @@ -1416,9 +1721,9 @@ hc_face_to_listener(const hc_face_t * face, hc_listener_t * listener) case FACE_TYPE_UDP_LISTENER: break; default: - return LIBHICNCTRL_FAILURE; + return -1; } - return LIBHICNCTRL_FAILURE; /* XXX Not implemented */ + return -1; /* XXX Not implemented */ } /* LISTENER -> FACE */ @@ -1426,7 +1731,7 @@ hc_face_to_listener(const hc_face_t * face, hc_listener_t * listener) int hc_listener_to_face(const hc_listener_t * listener, hc_face_t * face) { - return LIBHICNCTRL_FAILURE; /* XXX Not implemented */ + return -1; /* XXX Not implemented */ } /* FACE -> CONNECTION */ @@ -1451,7 +1756,7 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool .tags = f->tags, #endif /* WITH_POLICY */ }; - snprintf(connection->name, NAME_LEN, "%s", + snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", f->netdevice.name); snprintf(connection->interface_name, INTERFACE_LEN, "%s", f->netdevice.name); @@ -1471,9 +1776,9 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; if (generate_name) { - snprintf(connection->name, NAME_LEN, "tcp%u", RANDBYTE()); + snprintf(connection->name, SYMBOLIC_NAME_LEN, "tcp%u", RANDBYTE()); } else { - memset(connection->name, 0, NAME_LEN); + memset(connection->name, 0, SYMBOLIC_NAME_LEN); } snprintf(connection->interface_name, INTERFACE_LEN, "%s", f->netdevice.name); @@ -1493,21 +1798,21 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; if (generate_name) { - snprintf(connection->name, NAME_LEN, "udp%u", RANDBYTE()); + snprintf(connection->name, SYMBOLIC_NAME_LEN, "udp%u", RANDBYTE()); } else { - memset(connection->name, 0, NAME_LEN); + memset(connection->name, 0, SYMBOLIC_NAME_LEN); } snprintf(connection->interface_name, INTERFACE_LEN, "%s", f->netdevice.name); break; default: - return LIBHICNCTRL_FAILURE; + return -1; } snprintf(connection->interface_name, INTERFACE_LEN, "%s", f->netdevice.name); - return LIBHICNCTRL_SUCCESS; + return 0; } /* CONNECTION -> FACE */ @@ -1570,14 +1875,14 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) }; break; default: - return LIBHICNCTRL_FAILURE; + return -1; } face->face.netdevice.name[0] = '\0'; face->face.netdevice.index = 0; - snprintf(face->name, NAME_LEN, "%s", connection->name); + snprintf(face->name, SYMBOLIC_NAME_LEN, "%s", connection->name); snprintf(face->face.netdevice.name, INTERFACE_LEN, "%s", connection->interface_name); netdevice_update_index(&face->face.netdevice); - return LIBHICNCTRL_SUCCESS; + return 0; } /* CONNECTION -> LISTENER */ @@ -1592,9 +1897,9 @@ hc_connection_to_local_listener(const hc_connection_t * connection, hc_listener_ .local_addr = connection->local_addr, .local_port = connection->local_port, }; - snprintf(listener->name, NAME_LEN, "lst%u", RANDBYTE()); // generate name + snprintf(listener->name, SYMBOLIC_NAME_LEN, "lst%u", RANDBYTE()); // generate name snprintf(listener->interface_name, INTERFACE_LEN, "%s", connection->interface_name); - return LIBHICNCTRL_SUCCESS; + return 0; } /* FACE CREATE */ @@ -1615,18 +1920,18 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) case FACE_TYPE_UDP: if (hc_face_to_connection(face, &connection, true) < 0) { ERROR("[hc_face_create] Could not convert face to connection."); - return LIBHICNCTRL_FAILURE; + return -1; } /* Ensure we have a corresponding local listener */ if (hc_connection_to_local_listener(&connection, &listener) < 0) { ERROR("[hc_face_create] Could not convert face to local listener."); - return LIBHICNCTRL_FAILURE; + return -1; } if (hc_listener_get(s, &listener, &listener_found) < 0) { ERROR("[hc_face_create] Could not retrieve listener"); - return LIBHICNCTRL_FAILURE; + return -1; } if (!listener_found) { @@ -1634,7 +1939,7 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) if (hc_listener_create(s, &listener) < 0) { ERROR("[hc_face_create] Could not create listener."); free(listener_found); - return LIBHICNCTRL_FAILURE; + return -1; } } else { free(listener_found); @@ -1643,7 +1948,7 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) /* Create corresponding connection */ if (hc_connection_create(s, &connection) < 0) { ERROR("[hc_face_create] Could not create connection."); - return LIBHICNCTRL_FAILURE; + return -1; } /* @@ -1652,12 +1957,12 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) */ if (hc_connection_get(s, &connection, &connection_found) < 0) { ERROR("[hc_face_create] Could not retrieve connection"); - return LIBHICNCTRL_FAILURE; + return -1; } if (!connection_found) { ERROR("[hc_face_create] Could not find newly created connection."); - return LIBHICNCTRL_FAILURE; + return -1; } face->id = connection_found->id; @@ -1670,21 +1975,21 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) case FACE_TYPE_UDP_LISTENER: if (hc_face_to_listener(face, &listener) < 0) { ERROR("Could not convert face to listener."); - return LIBHICNCTRL_FAILURE; + return -1; } if (hc_listener_create(s, &listener) < 0) { ERROR("[hc_face_create] Could not create listener."); - return LIBHICNCTRL_FAILURE; + return -1; } - return LIBHICNCTRL_FAILURE; + return -1; break; default: ERROR("[hc_face_create] Unknwon face type."); - return LIBHICNCTRL_FAILURE; + return -1; }; - return LIBHICNCTRL_SUCCESS; + return 0; } int @@ -1702,12 +2007,12 @@ hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found) case FACE_TYPE_TCP: case FACE_TYPE_UDP: if (hc_face_to_connection(face, &connection, false) < 0) - return LIBHICNCTRL_FAILURE; + return -1; if (hc_connection_get(s, &connection, &connection_found) < 0) - return LIBHICNCTRL_FAILURE; + return -1; if (!connection_found) { *face_found = NULL; - return LIBHICNCTRL_SUCCESS; + return 0; } *face_found = malloc(sizeof(face_t)); hc_connection_to_face(connection_found, *face_found); @@ -1718,12 +2023,12 @@ hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found) case FACE_TYPE_TCP_LISTENER: case FACE_TYPE_UDP_LISTENER: if (hc_face_to_listener(face, &listener) < 0) - return LIBHICNCTRL_FAILURE; + return -1; if (hc_listener_get(s, &listener, &listener_found) < 0) - return LIBHICNCTRL_FAILURE; + return -1; if (!listener_found) { *face_found = NULL; - return LIBHICNCTRL_SUCCESS; + return 0; } *face_found = malloc(sizeof(face_t)); hc_listener_to_face(listener_found, *face_found); @@ -1731,10 +2036,10 @@ hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found) break; default: - return LIBHICNCTRL_FAILURE; + return -1; } - return LIBHICNCTRL_SUCCESS; + return 0; } @@ -1743,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 LIBHICNCTRL_FAILURE; + 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 */ @@ -1762,7 +2118,7 @@ hc_face_list(hc_sock_t * s, hc_data_t ** pdata) if (hc_connection_list(s, &connection_data) < 0) { ERROR("[hc_face_list] Could not list connections."); - return LIBHICNCTRL_FAILURE; + return -1; } hc_data_t * face_data = hc_data_create(sizeof(hc_connection_t), sizeof(hc_face_t)); @@ -1776,11 +2132,55 @@ hc_face_list(hc_sock_t * s, hc_data_t ** pdata) *pdata = face_data; hc_data_free(connection_data); - return LIBHICNCTRL_SUCCESS; + return 0; ERR: hc_data_free(connection_data); - return LIBHICNCTRL_FAILURE; + return -1; +} + +int +hc_connection_parse_to_face(void * in, hc_face_t * face) +{ + hc_connection_t connection; + + if (hc_connection_parse(in, &connection) < 0) { + ERROR("[hc_connection_parse_to_face] Could not parse connection"); + return -1; + } + + if (hc_connection_to_face(&connection, face) < 0) { + ERROR("[hc_connection_parse_to_face] Could not convert connection to face."); + return -1; + } + + return 0; +} + + +int +hc_face_list_async(hc_sock_t * s) //, hc_data_t ** pdata) +{ + struct { + header_control_message hdr; + } msg = { + .hdr = { + .messageType = REQUEST_LIGHT, + .commandID = LIST_CONNECTIONS, + .length = 0, + .seqNum = 0, + }, + }; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = LIST_CONNECTIONS, + .size_in = sizeof(list_connections_command), + .size_out = sizeof(hc_face_t), + .parse = (HC_PARSE)hc_connection_parse_to_face, + }; + + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, true); } /* /!\ Please update constants in header file upon changes */ @@ -1824,7 +2224,7 @@ hc_face_snprintf(char * s, size_t size, hc_face_t * face) return rc; break; default: - return LIBHICNCTRL_FAILURE; + return -1; } // [#ID NAME] TYPE LOCAL_URL REMOTE_URL STATE/ADMIN_STATE (TAGS) @@ -1852,7 +2252,7 @@ hc_face_snprintf(char * s, size_t size, hc_face_t * face) face_state_str[face->face.state], face_state_str[face->face.admin_state]); #endif /* WITH_POLICY */ - return LIBHICNCTRL_SUCCESS; + return 0; } int @@ -1866,10 +2266,11 @@ hc_face_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, // XXX wron * Punting *----------------------------------------------------------------------------*/ -int hc_punting_create(hc_sock_t * s, hc_punting_t * punting) +int +_hc_punting_create(hc_sock_t * s, hc_punting_t * punting, bool async) { if (hc_punting_validate(punting) < 0) - return LIBHICNCTRL_FAILURE; + return -1; struct { header_control_message hdr; @@ -1879,7 +2280,7 @@ int hc_punting_create(hc_sock_t * s, hc_punting_t * punting) .messageType = REQUEST_LIGHT, .commandID = ADD_PUNTING, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { /* we use IPv6 which is the longest address */ @@ -1888,7 +2289,7 @@ int hc_punting_create(hc_sock_t * s, hc_punting_t * punting) .len = punting->prefix_len, } }; - snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%d", punting->face_id); + snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", punting->face_id); hc_command_params_t params = { .cmd = ACTION_CREATE, @@ -1898,37 +2299,54 @@ int hc_punting_create(hc_sock_t * s, hc_punting_t * punting) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_punting_create(hc_sock_t * s, hc_punting_t * punting) +{ + return _hc_punting_create(s, punting, false); +} + +int +hc_punting_create_async(hc_sock_t * s, hc_punting_t * punting) +{ + return _hc_punting_create(s, punting, true); } int hc_punting_get(hc_sock_t * s, hc_punting_t * punting, hc_punting_t ** punting_found) { - return LIBHICNCTRL_NOT_IMPLEMENTED; + ERROR("hc_punting_get not (yet) implemented."); + return -1; } int hc_punting_delete(hc_sock_t * s, hc_punting_t * punting) { - return LIBHICNCTRL_NOT_IMPLEMENTED; + ERROR("hc_punting_delete not (yet) implemented."); + return -1; } int hc_punting_list(hc_sock_t * s, hc_data_t ** pdata) { - return LIBHICNCTRL_NOT_IMPLEMENTED; + ERROR("hc_punting_list not (yet) implemented."); + return -1; } int hc_punting_validate(const hc_punting_t * punting) { if (!IS_VALID_FAMILY(punting->family)) - return LIBHICNCTRL_FAILURE; + return -1; /* * We might use the zero value to add punting on all faces but this is not * (yet) implemented */ - if (punting->face_id == 0) - return LIBHICNCTRL_NOT_IMPLEMENTED; + if (punting->face_id == 0) { + ERROR("Punting on all faces is not (yet) implemented."); + return -1; + } - return LIBHICNCTRL_SUCCESS; + return 0; } int hc_punting_cmp(const hc_punting_t * p1, const hc_punting_t * p2) @@ -1937,18 +2355,20 @@ int hc_punting_cmp(const hc_punting_t * p1, const hc_punting_t * p2) (p1->family == p2->family) && (ip_address_cmp(&p1->prefix, &p2->prefix, p1->family) == 0) && (p1->prefix_len == p2->prefix_len)) - ? LIBHICNCTRL_SUCCESS - : LIBHICNCTRL_FAILURE; + ? 0 + : -1; } int hc_punting_parse(void * in, hc_punting_t * punting) { - return LIBHICNCTRL_NOT_IMPLEMENTED; + ERROR("hc_punting_parse not (yet) implemented."); + return -1; } int hc_punting_snprintf(char * s, size_t size, hc_punting_t * punting) { - return LIBHICNCTRL_NOT_IMPLEMENTED; + ERROR("hc_punting_snprintf not (yet) implemented."); + return -1; } @@ -1957,7 +2377,7 @@ int hc_punting_snprintf(char * s, size_t size, hc_punting_t * punting) *----------------------------------------------------------------------------*/ int -hc_cache_set_store(hc_sock_t * s, int enabled) +_hc_cache_set_store(hc_sock_t * s, int enabled, bool async) { struct { header_control_message hdr; @@ -1967,7 +2387,7 @@ hc_cache_set_store(hc_sock_t * s, int enabled) .messageType = REQUEST_LIGHT, .commandID = CACHE_STORE, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { .activate = enabled, @@ -1982,11 +2402,23 @@ hc_cache_set_store(hc_sock_t * s, int enabled) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); } int -hc_cache_set_serve(hc_sock_t * s, int enabled) +hc_cache_set_store(hc_sock_t * s, int enabled) +{ + return _hc_cache_set_store(s, enabled, false); +} + +int +hc_cache_set_store_async(hc_sock_t * s, int enabled) +{ + return _hc_cache_set_store(s, enabled, true); +} + +int +_hc_cache_set_serve(hc_sock_t * s, int enabled, bool async) { struct { header_control_message hdr; @@ -1996,7 +2428,7 @@ hc_cache_set_serve(hc_sock_t * s, int enabled) .messageType = REQUEST_LIGHT, .commandID = CACHE_SERVE, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { .activate = enabled, @@ -2011,9 +2443,20 @@ hc_cache_set_serve(hc_sock_t * s, int enabled) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); } +int +hc_cache_set_serve(hc_sock_t * s, int enabled) +{ + return _hc_cache_set_serve(s, enabled, false); +} + +int +hc_cache_set_serve_async(hc_sock_t * s, int enabled) +{ + return _hc_cache_set_serve(s, enabled, true); +} /*----------------------------------------------------------------------------* * Strategy @@ -2023,7 +2466,7 @@ hc_cache_set_serve(hc_sock_t * s, int enabled) int hc_strategy_set(hc_sock_t * s /* XXX */) { - return LIBHICNCTRL_SUCCESS; + return 0; } /* How to retrieve that from the forwarder ? */ @@ -2042,12 +2485,12 @@ hc_strategy_list(hc_sock_t * s, hc_data_t ** data) for (unsigned i = 0; i < ARRAY_SIZE(strategies); i++) { hc_strategy_t * strategy = (hc_strategy_t*)hc_data_get_next(*data); if (!strategy) - return LIBHICNCTRL_FAILURE; + return -1; snprintf(strategy->name, MAXSZ_HC_STRATEGY, "%s", strategies[i]); (*data)->size++; } - return LIBHICNCTRL_SUCCESS; + return 0; } /* /!\ Please update constants in header file upon changes */ @@ -2065,7 +2508,7 @@ hc_strategy_snprintf(char * s, size_t size, hc_strategy_t * strategy) int hc_wldr_set(hc_sock_t * s /* XXX */) { - return LIBHICNCTRL_SUCCESS; + return 0; } /*----------------------------------------------------------------------------* @@ -2075,25 +2518,25 @@ hc_wldr_set(hc_sock_t * s /* XXX */) int hc_mapme_set(hc_sock_t * s, int enabled) { - return LIBHICNCTRL_SUCCESS; + return 0; } int hc_mapme_set_discovery(hc_sock_t * s, int enabled) { - return LIBHICNCTRL_SUCCESS; + return 0; } int hc_mapme_set_timescale(hc_sock_t * s, double timescale) { - return LIBHICNCTRL_SUCCESS; + return 0; } int hc_mapme_set_retx(hc_sock_t * s, double timescale) { - return LIBHICNCTRL_SUCCESS; + return 0; } /*----------------------------------------------------------------------------* @@ -2105,10 +2548,10 @@ hc_mapme_set_retx(hc_sock_t * s, double timescale) /* POLICY CREATE */ int -hc_policy_create(hc_sock_t * s, hc_policy_t * policy) +_hc_policy_create(hc_sock_t * s, hc_policy_t * policy, bool async) { if (!IS_VALID_FAMILY(policy->family)) - return LIBHICNCTRL_FAILURE; + return -1; struct { header_control_message hdr; @@ -2118,7 +2561,7 @@ hc_policy_create(hc_sock_t * s, hc_policy_t * policy) .messageType = REQUEST_LIGHT, .commandID = ADD_POLICY, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { /* we use IPv6 which is the longest address */ @@ -2137,16 +2580,28 @@ hc_policy_create(hc_sock_t * s, hc_policy_t * policy) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_policy_create(hc_sock_t * s, hc_policy_t * policy) +{ + return _hc_policy_create(s, policy, false); +} + +int +hc_policy_create_async(hc_sock_t * s, hc_policy_t * policy) +{ + return _hc_policy_create(s, policy, true); } /* POLICY DELETE */ int -hc_policy_delete(hc_sock_t * s, hc_policy_t * policy) +_hc_policy_delete(hc_sock_t * s, hc_policy_t * policy, bool async) { if (!IS_VALID_FAMILY(policy->family)) - return LIBHICNCTRL_FAILURE; + return -1; struct { header_control_message hdr; @@ -2156,7 +2611,7 @@ hc_policy_delete(hc_sock_t * s, hc_policy_t * policy) .messageType = REQUEST_LIGHT, .commandID = REMOVE_POLICY, .length = 1, - .seqNum = s->send_seq, + .seqNum = 0, }, .payload = { /* we use IPv6 which is the longest address */ @@ -2174,13 +2629,25 @@ hc_policy_delete(hc_sock_t * s, hc_policy_t * policy) .parse = NULL, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); +} + +int +hc_policy_delete(hc_sock_t * s, hc_policy_t * policy) +{ + return _hc_policy_delete(s, policy, false); +} + +int +hc_policy_delete_async(hc_sock_t * s, hc_policy_t * policy) +{ + return _hc_policy_delete(s, policy, true); } /* POLICY LIST */ int -hc_policy_list(hc_sock_t * s, hc_data_t ** pdata) +_hc_policy_list(hc_sock_t * s, hc_data_t ** pdata, bool async) { struct { header_control_message hdr; @@ -2189,7 +2656,7 @@ hc_policy_list(hc_sock_t * s, hc_data_t ** pdata) .messageType = REQUEST_LIGHT, .commandID = LIST_POLICIES, .length = 0, - .seqNum = s->send_seq, + .seqNum = 0, }, }; @@ -2201,7 +2668,19 @@ hc_policy_list(hc_sock_t * s, hc_data_t ** pdata) .parse = (HC_PARSE)hc_policy_parse, }; - return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata); + return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata, async); +} + +int +hc_policy_list(hc_sock_t * s, hc_data_t ** pdata) +{ + return _hc_policy_list(s, pdata, false); +} + +int +hc_policy_list_async(hc_sock_t * s, hc_data_t ** pdata) +{ + return _hc_policy_list(s, pdata, true); } /* POLICY PARSE */ @@ -2212,11 +2691,11 @@ hc_policy_parse(void * in, hc_policy_t * policy) list_policies_command * cmd = (list_policies_command *) in; if (!IS_VALID_ADDR_TYPE(cmd->addressType)) - return LIBHICNCTRL_FAILURE; + return -1; int family = map_from_addr_type[cmd->addressType]; if (!IS_VALID_FAMILY(family)) - return LIBHICNCTRL_FAILURE; + return -1; *policy = (hc_policy_t) { .family = family, @@ -2224,7 +2703,7 @@ hc_policy_parse(void * in, hc_policy_t * policy) .len = cmd->len, .policy = cmd->policy, }; - return LIBHICNCTRL_SUCCESS; + return 0; } /* POLICY SNPRINTF */ @@ -2233,7 +2712,7 @@ hc_policy_parse(void * in, hc_policy_t * policy) int hc_policy_snprintf(char * s, size_t size, hc_policy_t * policy) { - return LIBHICNCTRL_SUCCESS; + return 0; } #endif /* WITH_POLICY */ diff --git a/ctrl/libhicnctrl/src/cli.c b/ctrl/libhicnctrl/src/cli.c index 6798b5aec..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 */ - snprintf(command->listener.name, NAME_LEN, "%s", argv[optind++]); - // conn type + 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++]); command->listener.type = connection_type_from_str(argv[optind++]); if (command->listener.type == CONNECTION_TYPE_UNDEFINED) goto ERR_PARAM; @@ -158,23 +329,63 @@ 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 */ - snprintf(command->connection.name, NAME_LEN, "%s", argv[optind++]); + 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) goto ERR_PARAM; @@ -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/ctrl/libhicnctrl/src/util/map.h b/ctrl/libhicnctrl/src/util/map.h new file mode 100644 index 000000000..334f12cc1 --- /dev/null +++ b/ctrl/libhicnctrl/src/util/map.h @@ -0,0 +1,234 @@ +/* + * 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. + */ + +#ifndef UTIL_MAP_H +#define UTIL_MAP_H + +#include <stdlib.h> + +#include "set.h" + +#define ERR_MAP_EXISTS -2 +#define ERR_MAP_NOT_FOUND -3 + +#define TYPEDEF_MAP_H(NAME, KEY_T, VAL_T) \ + \ +typedef struct { \ + KEY_T key; \ + VAL_T value; \ +} NAME ## _pair_t; \ + \ +NAME ## _pair_t * NAME ## _pair_create(KEY_T key, VAL_T value); \ + \ +void NAME ## _pair_free(NAME ## _pair_t * pair); \ + \ +int NAME ## _pair_cmp(const NAME ## _pair_t * p1, const NAME ## _pair_t * p2); \ + \ +TYPEDEF_SET_H(NAME ## _pair_set, NAME ## _pair_t *) \ + \ +typedef struct NAME ## _s { \ + NAME ## _pair_set_t pair_set; \ +} NAME ## _t; \ + \ +int NAME ## _initialize(NAME ## _t * map); \ + \ +int NAME ## _finalize(NAME ## _t * map); \ + \ +NAME ## _t * NAME ## _create(); \ + \ +void NAME ## _free(NAME ## _t * map); \ + \ +int NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value); \ + \ +int NAME ## _remove(NAME ## _t * map, KEY_T key, VAL_T * value); \ + \ +int NAME ## _get(NAME ## _t * map, KEY_T key, VAL_T * value); \ + \ +void NAME ## _dump(NAME ## _t * map); + + + + +#define TYPEDEF_MAP(NAME, KEY_T, VAL_T, CMP, KEY_SNPRINTF, VALUE_SNPRINTF) \ + \ +NAME ## _pair_t * NAME ## _pair_create(KEY_T key, VAL_T value) \ +{ \ + /* Create pair */ \ + NAME ## _pair_t * pair = malloc(sizeof(NAME ## _pair_t)); \ + if (!pair) \ + return NULL; \ + \ + pair->key = key; \ + pair->value = value; \ + \ + return pair; \ +} \ + \ +void NAME ## _pair_free(NAME ## _pair_t * pair) \ +{ \ + free(pair); \ +} \ + \ +int \ +NAME ## _pair_cmp(const NAME ## _pair_t * p1, const NAME ## _pair_t * p2) \ +{ \ + return (CMP(p1->key, p2->key)); \ +} \ + \ +int \ +NAME ## _pair_snprintf(char * buf, size_t size, const NAME ## _pair_t * pair) { \ + int rc; \ + rc = KEY_SNPRINTF(buf, BUFSIZE/2, (KEY_T)pair->key); \ + if (rc < 0) \ + return rc; \ + rc = VALUE_SNPRINTF(buf+rc, BUFSIZE/2, (VAL_T)pair->value); \ + return rc; \ +} \ + \ +TYPEDEF_SET(NAME ## _pair_set, NAME ## _pair_t *, NAME ## _pair_cmp, NAME ## _pair_snprintf); \ + \ +int \ +NAME ## _initialize(NAME ## _t * map) \ +{ \ + return NAME ## _pair_set_initialize(&map->pair_set); \ +} \ + \ +int \ +NAME ## _finalize(NAME ## _t * map) \ +{ \ + return NAME ## _pair_set_finalize(&map->pair_set); \ +} \ + \ +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) \ +{ \ + int rc; \ + NAME ## _pair_t * found = NULL; \ + \ + NAME ## _pair_t * pair = NAME ## _pair_create(key, value); \ + if (!pair) \ + return -1; \ + \ + rc = NAME ## _pair_set_get(&map->pair_set, pair, &found); \ + 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) { \ + NAME ## _pair_free(pair); \ + return -1; \ + } \ + return 0; \ +} \ + \ +int \ +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) \ + return ERR_MAP_NOT_FOUND; \ + if (value) \ + *value = found->value; \ + NAME ## _pair_free(found); \ + return 0; \ +} \ + \ +int \ +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 (found) \ + *value = found->value; \ + return 0; \ +} \ + \ +void \ +NAME ## _dump(NAME ## _t * map) { \ + NAME ## _pair_set_dump(&map->pair_set); \ +} \ + \ +int \ +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; \ + /* Allocate result array */ \ + *array = malloc(n * sizeof(KEY_T)); \ + if (!array) { \ + free(pair_array); \ + return -1; \ + } \ + /* Copy keys */ \ + for (int i = 0; i < n; i++) \ + (*array)[i] = pair_array[i]->key; \ + free(pair_array); \ + return 0; \ +} \ + \ +int \ +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; \ + /* Allocate result array */ \ + *array = malloc(n * sizeof(VAL_T)); \ + if (!*array) { \ + free(pair_array); \ + return -1; \ + } \ + /* Copy values */ \ + for (int i = 0; i < n; i++) \ + (*array)[i] = pair_array[i]->value; \ + free(pair_array); \ + return 0; \ +} + +#endif /* UTIL_MAP_H */ diff --git a/ctrl/libhicnctrl/src/util/set.h b/ctrl/libhicnctrl/src/util/set.h new file mode 100644 index 000000000..3706e36f4 --- /dev/null +++ b/ctrl/libhicnctrl/src/util/set.h @@ -0,0 +1,213 @@ +/* + * 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. + */ + +#ifndef UTIL_SET_H +#define UTIL_SET_H + +#include <search.h> +#include <string.h> +//#if !defined(__ANDROID__) && !defined(__APPLE__) +//#include <threads.h> +//#else +#define thread_local _Thread_local +//#endif /* ! __ANDROID__ */ +#include "util/log.h" + +#define ERR_SET_EXISTS -2 +#define ERR_SET_NOT_FOUND -3 + +/* FIXME: buffer overflow when this is too small... investigate */ +#define BUFSIZE 1024 + +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); +} + +static inline +int +string_snprintf(char * buf, size_t size, const char * s) { + return snprintf(buf, size, "%s", s); +} + +static inline +int +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 { \ + size_t size; \ + void * root; \ +} NAME ## _t; \ + \ +int NAME ## _initialize(NAME ## _t * set); \ + \ +int NAME ## _finalize(NAME ## _t * set); \ + \ +NAME ## _t * NAME ## _create(); \ + \ +void NAME ## _free(NAME ## _t * set); \ + \ +int NAME ## _add(NAME ## _t * set, const T element); \ + \ +int NAME ## _remove(NAME ## _t * set, const T search, T * element); \ + \ +int NAME ## _get(const NAME ## _t * set, const T search, T * element); \ + \ +int NAME ## _get_array(const NAME ## _t * set, T ** element); \ + \ +void NAME ## _dump(NAME ## _t * set); + + + + +#define TYPEDEF_SET(NAME, T, CMP, SNPRINTF) \ +int \ +NAME ## _initialize(NAME ## _t * set) \ +{ \ + set->root = NULL; \ + set->size = 0; \ + return 0; \ +} \ + \ +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) \ +{ \ + void * ptr = tsearch(element, &set->root, (cmp_t)CMP); \ + if (!ptr) \ + return -1; \ + set->size++; \ + return 0; \ +} \ + \ +int \ +NAME ## _remove(NAME ## _t * set, const T search, T * element) \ +{ \ + T * found = tfind(search, &set->root, (cmp_t)CMP); \ + if (!found) \ + return ERR_SET_NOT_FOUND; \ + if (element) \ + *element = *found; \ + tdelete(search, &set->root, (cmp_t)CMP); \ + set->size--; \ + return 0; \ +} \ + \ +int \ +NAME ## _get(const NAME ## _t * set, const T search, T * element) \ +{ \ + T * found = tfind(search, &set->root, (cmp_t)CMP); \ + if (element) \ + *element = found ? *found : NULL; \ + return 0; \ +} \ + \ +static void \ +NAME ## _dump_node(const void *nodep, const VISIT which, \ + const int depth) \ +{ \ + char buf[BUFSIZE]; \ + switch (which) { \ + case preorder: \ + case endorder: \ + break; \ + case postorder: \ + case leaf: \ + SNPRINTF(buf, BUFSIZE, *(T*)nodep); \ + INFO("%s", buf); \ + break; \ + } \ +} \ + \ +void \ +NAME ## _dump(NAME ## _t * set) { \ + twalk(set->root, NAME ## _dump_node); \ +} \ + \ +thread_local \ +T * NAME ## _array_pos = NULL; \ + \ +static void \ +NAME ## _add_node_to_array(const void *nodep, const VISIT which, \ + const int depth) \ +{ \ + if (!NAME ## _array_pos) \ + return; \ + switch (which) { \ + case preorder: \ + case endorder: \ + break; \ + case postorder: \ + case leaf: \ + *NAME ## _array_pos = *(T*)nodep; \ + NAME ## _array_pos++; \ + break; \ + } \ +} \ + \ +int \ +NAME ## _get_array(const NAME ## _t * set, T ** element) \ +{ \ + *element = malloc(set->size * sizeof(T)); \ + if (!*element) \ + return -1; \ + NAME ## _array_pos = *element; \ + twalk(set->root, NAME ## _add_node_to_array); \ + NAME ## _array_pos = NULL; \ + return set->size; \ +} + +#endif /* UTIL_SET_H */ diff --git a/hicn-light/cmake/Modules/Packaging.cmake b/hicn-light/cmake/Modules/Packaging.cmake index 006261b03..2b9f4a7b9 100644 --- a/hicn-light/cmake/Modules/Packaging.cmake +++ b/hicn-light/cmake/Modules/Packaging.cmake @@ -25,7 +25,22 @@ set(${HICN_LIGHT}_DEB_DEPENDENCIES CACHE STRING "Dependencies for deb/rpm package." ) +set(${HICN_LIGHT}_DEB_PACKAGE_CONTROL_EXTRA + "${CMAKE_CURRENT_SOURCE_DIR}/config/postinst;${CMAKE_CURRENT_SOURCE_DIR}/config/prerm" + CACHE STRING "Control scripts conffiles, postinst, postrm, prerm." +) + set(${HICN_LIGHT}_RPM_DEPENDENCIES "lib${LIBHICN} >= stable_version, libparc >= 1.0" CACHE STRING "Dependencies for deb/rpm package." -)
\ No newline at end of file +) + +set(${HICN_LIGHT}_RPM_POST_INSTALL_SCRIPT_FILE + "${CMAKE_CURRENT_SOURCE_DIR}/config/post" + CACHE STRING "Install script that will be copied in the %post section" +) + +set(${HICN_LIGHT}_RPM_PRE_UNINSTALL_SCRIPT_FILE + "${CMAKE_CURRENT_SOURCE_DIR}/config/preun" + CACHE STRING "Install script that will be copied in the %post section" +) diff --git a/hicn-light/config/hicn-light.service b/hicn-light/config/hicn-light.service index 0f976fc6c..f269b2f26 100644 --- a/hicn-light/config/hicn-light.service +++ b/hicn-light/config/hicn-light.service @@ -21,8 +21,8 @@ Environment=LOG_FILE=/tmp/hicn_light.log Environment=CS_SIZE=1000 Environment=CONFIG=/etc/hicn/hicn_light.conf # This will overrride the default environment -EnvironmentFile=-/etc/default/source -ExecStart=/usr/bin/hicnLightDaemon --port ${PORT} --log-file ${LOG_FILE} --capacity ${CS_SIZE} --config ${CONFIG} +EnvironmentFile=-/etc/default/hicn-light +ExecStart=/usr/bin/hicn-light-daemon --port ${PORT} --log-file ${LOG_FILE} --capacity ${CS_SIZE} --config ${CONFIG} Restart=on-failure [Install] diff --git a/hicn-light/config/post b/hicn-light/config/post new file mode 100755 index 000000000..dced2a093 --- /dev/null +++ b/hicn-light/config/post @@ -0,0 +1,3 @@ +#!/bin/bash + +systemctl enable hicn-light
\ No newline at end of file diff --git a/hicn-light/config/postinst b/hicn-light/config/postinst new file mode 100755 index 000000000..dced2a093 --- /dev/null +++ b/hicn-light/config/postinst @@ -0,0 +1,3 @@ +#!/bin/bash + +systemctl enable hicn-light
\ No newline at end of file diff --git a/hicn-light/config/prerm b/hicn-light/config/prerm new file mode 100755 index 000000000..4584c7057 --- /dev/null +++ b/hicn-light/config/prerm @@ -0,0 +1,3 @@ +#!/bin/bash + +systemctl disable hicn-light
\ No newline at end of file diff --git a/hicn-light/config/preun b/hicn-light/config/preun new file mode 100755 index 000000000..4584c7057 --- /dev/null +++ b/hicn-light/config/preun @@ -0,0 +1,3 @@ +#!/bin/bash + +systemctl disable hicn-light
\ No newline at end of file diff --git a/hicn-light/src/hicn/config/configuration.c b/hicn-light/src/hicn/config/configuration.c index 2b63a32a0..4771c4073 100644 --- a/hicn-light/src/hicn/config/configuration.c +++ b/hicn-light/src/hicn/config/configuration.c @@ -688,10 +688,10 @@ struct iovec *configuration_ProcessConnectionList(Configuration *config, listConnectionsCommand->connid = connection_GetConnectionId(original); const char *connectionName = symbolicNameTable_GetNameByIndex(config->symbolicNameTable, connection_GetConnectionId(original)); - snprintf(listConnectionsCommand->connectionName, 16, "%s", connectionName); + snprintf(listConnectionsCommand->connectionName, SYMBOLIC_NAME_LEN, "%s", connectionName); _strlwr(listConnectionsCommand->connectionName); - snprintf(listConnectionsCommand->interfaceName, 16, "%s", ioOperations_GetInterfaceName(connection_GetIoOperations(original))); + snprintf(listConnectionsCommand->interfaceName, SYMBOLIC_NAME_LEN, "%s", ioOperations_GetInterfaceName(connection_GetIoOperations(original))); listConnectionsCommand->state = connection_IsUp(original) ? IFACE_UP : IFACE_DOWN; @@ -801,11 +801,11 @@ struct iovec *configuration_ProcessListenersList(Configuration *config, } const char * listenerName = listenerEntry->getListenerName(listenerEntry); - snprintf(listListenersCommand->listenerName, 16, "%s", listenerName); + snprintf(listListenersCommand->listenerName, SYMBOLIC_NAME_LEN, "%s", listenerName); if (listenerEntry->getEncapType(listenerEntry) == ENCAP_TCP || listenerEntry->getEncapType(listenerEntry) == ENCAP_UDP) { const char * interfaceName = listenerEntry->getInterfaceName(listenerEntry); - snprintf(listListenersCommand->interfaceName, 16, "%s", interfaceName); + snprintf(listListenersCommand->interfaceName, SYMBOLIC_NAME_LEN, "%s", interfaceName); } } diff --git a/hicn-light/src/hicn/config/configurationListeners.c b/hicn-light/src/hicn/config/configurationListeners.c index c321007e2..8abbeb781 100644 --- a/hicn-light/src/hicn/config/configurationListeners.c +++ b/hicn-light/src/hicn/config/configurationListeners.c @@ -595,11 +595,11 @@ void configurationListeners_SetupAll(const Configuration *config, uint16_t port, const Address *address = addressListGetItem(addresses, j); // Do not start on link address - char listenerName[16]; + char listenerName[SYMBOLIC_NAME_LEN]; #ifdef __ANDROID__ - snprintf(listenerName, 16, "local_%zu", i); + snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%zu", i); #else - snprintf(listenerName, 16, "local_%ld", i); + snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%ld", i); #endif if (addressGetType(address) != ADDR_LINK) { _setupListenersOnAddress(forwarder, listenerName, address, port, @@ -617,8 +617,8 @@ void configurationListeners_SetutpLocalIPv4(const Configuration *config, in_addr_t addr = inet_addr("127.0.0.1"); uint16_t network_byte_order_port = htons(port); - char listenerNameUdp[16] = "lo_udp"; - char listenerNameTcp[16] = "lo_tcp"; + char listenerNameUdp[SYMBOLIC_NAME_LEN] = "lo_udp"; + char listenerNameTcp[SYMBOLIC_NAME_LEN] = "lo_tcp"; char *loopback_interface = "lo"; _setupUdpListenerOnInet(forwarder, listenerNameUdp,(ipv4_addr_t *)&(addr), &network_byte_order_port, loopback_interface); diff --git a/hicn-light/src/hicn/config/controlAddListener.c b/hicn-light/src/hicn/config/controlAddListener.c index cfd061131..1a94ff252 100644 --- a/hicn-light/src/hicn/config/controlAddListener.c +++ b/hicn-light/src/hicn/config/controlAddListener.c @@ -120,7 +120,7 @@ static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops, } // Fill remaining payload fields - memcpy(addListenerCommand->interfaceName, interfaceName, 16); + memcpy(addListenerCommand->interfaceName, interfaceName, SYMBOLIC_NAME_LEN); addListenerCommand->listenerMode = mode; addListenerCommand->connectionType = type; addListenerCommand->port = htons((uint16_t)atoi(port)); diff --git a/hicn-light/src/hicn/config/controlListListeners.c b/hicn-light/src/hicn/config/controlListListeners.c index 5be7b0a9b..1489470a8 100644 --- a/hicn-light/src/hicn/config/controlListListeners.c +++ b/hicn-light/src/hicn/config/controlListListeners.c @@ -95,7 +95,7 @@ static CommandReturn _controlListListeners_Execute(CommandParser *parser, char *addrString = NULL; if (receivedHeader->length > 0) { - printf("%6.6s %16s %50.70s %6s %10s\n", "iface", "name", "address", "type", "interface"); + printf("%6.6s %.*s %50.70s %6s %10s\n", "iface", SYMBOLIC_NAME_LEN, "name", "address", "type", "interface"); } else { printf(" --- No entry in the list \n"); @@ -114,15 +114,17 @@ static CommandReturn _controlListListeners_Execute(CommandParser *parser, if (strcmp(listenerType[listListenersCommand->encapType], "UDP") == 0 || strcmp(listenerType[listListenersCommand->encapType], "TCP") == 0) { - parcBufferComposer_Format(composer, "%6u %16s %50.70s %6s %10s", + parcBufferComposer_Format(composer, "%6u %.*s %50.70s %6s %10s", listListenersCommand->connid, - listListenersCommand->listenerName,addrString, + SYMBOLIC_NAME_LEN, listListenersCommand->listenerName, + addrString, listenerType[listListenersCommand->encapType], listListenersCommand->interfaceName); } else { - parcBufferComposer_Format(composer, "%6u %16s %50.70s %6s", + parcBufferComposer_Format(composer, "%6u %.*s %50.70s %6s", listListenersCommand->connid, - listListenersCommand->listenerName,addrString, + SYMBOLIC_NAME_LEN, listListenersCommand->listenerName, + addrString, listenerType[listListenersCommand->encapType]); } diff --git a/hicn-light/src/hicn/config/controlRemoveListener.c b/hicn-light/src/hicn/config/controlRemoveListener.c index 50581a8d9..545e189c0 100644 --- a/hicn-light/src/hicn/config/controlRemoveListener.c +++ b/hicn-light/src/hicn/config/controlRemoveListener.c @@ -99,7 +99,7 @@ if (!utils_ValidateSymbolicName(listenerId) && parcMemory_AllocateAndClear(sizeof(remove_listener_command)); // fill payload //removeListenerCommand->listenerId = atoi(listenerId); - strncpy(removeListenerCommand->symbolicOrListenerid, listenerId, strlen(listenerId)); + snprintf(removeListenerCommand->symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%s", listenerId); // send message and receive response struct iovec *response = diff --git a/hicn-light/src/hicn/utils/commands.h b/hicn-light/src/hicn/utils/commands.h index 1a313de6a..60d4cd5fa 100644 --- a/hicn-light/src/hicn/utils/commands.h +++ b/hicn-light/src/hicn/utils/commands.h @@ -35,6 +35,8 @@ #include <hicn/policy.h> #endif /* WITH_POLICY */ +#define SYMBOLIC_NAME_LEN 16 + typedef struct in6_addr ipv6_addr_t; typedef uint32_t ipv4_addr_t; @@ -115,8 +117,8 @@ typedef struct { typedef enum { ETHER_MODE, IP_MODE, HICN_MODE } listener_mode; typedef struct { - char symbolic[16]; - char interfaceName[16]; + char symbolic[SYMBOLIC_NAME_LEN]; + char interfaceName[SYMBOLIC_NAME_LEN]; union commandAddr address; uint16_t port; // uint16_t etherType; @@ -130,8 +132,8 @@ typedef struct { //========== [01] ADD CONNECTION ========== typedef struct { - char symbolic[16]; - //char interfaceName[16]; + char symbolic[SYMBOLIC_NAME_LEN]; + //char interfaceName[SYMBOLIC_NAME_LEN]; union commandAddr remoteIp; union commandAddr localIp; uint16_t remotePort; @@ -168,8 +170,8 @@ typedef struct { uint32_t connid; uint8_t state; uint8_t admin_state; - char interfaceName[16]; - char connectionName[16]; + char interfaceName[SYMBOLIC_NAME_LEN]; + char connectionName[SYMBOLIC_NAME_LEN]; } list_connections_command; // SIZE=80 @@ -177,7 +179,7 @@ typedef struct { //========== [03] ADD ROUTE ========== typedef struct { - char symbolicOrConnid[16]; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; union commandAddr address; uint16_t cost; uint8_t addressType; @@ -200,12 +202,12 @@ typedef struct { //========== [05] REMOVE CONNECTION ========== typedef struct { - char symbolicOrConnid[16]; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; } remove_connection_command; //========== [06] REMOVE LISTENER ========== typedef struct { - char symbolicOrListenerid[16]; + char symbolicOrListenerid[SYMBOLIC_NAME_LEN]; } remove_listener_command; // SIZE=16 @@ -213,7 +215,7 @@ typedef struct { //========== [07] REMOVE ROUTE ========== typedef struct { - char symbolicOrConnid[16]; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; union commandAddr address; uint8_t addressType; uint8_t len; @@ -259,7 +261,7 @@ typedef struct { //========== [11] SET WLDR ========== typedef struct { - char symbolicOrConnid[16]; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; uint8_t activate; } set_wldr_command; @@ -268,7 +270,7 @@ typedef struct { //========== [12] ADD PUNTING ========== typedef struct { - char symbolicOrConnid[16]; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; union commandAddr address; uint8_t addressType; uint8_t len; @@ -280,8 +282,8 @@ typedef struct { typedef struct { union commandAddr address; - char listenerName[16]; - char interfaceName[16]; + char listenerName[SYMBOLIC_NAME_LEN]; + char interfaceName[SYMBOLIC_NAME_LEN]; uint32_t connid; uint16_t port; uint8_t addressType; @@ -307,7 +309,7 @@ typedef struct { // SIZE=1 typedef struct { - char symbolicOrConnid[16]; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; uint8_t admin_state; uint16_t pad16; } connection_set_admin_state_command; @@ -335,7 +337,7 @@ typedef struct { } remove_policy_command; typedef struct { - char symbolicOrConnid[16]; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; uint8_t admin_state; policy_tags_t tags; } update_connection_command; 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; } |