diff options
Diffstat (limited to 'ctrl/libhicnctrl')
-rw-r--r-- | ctrl/libhicnctrl/CMakeLists.txt | 31 | ||||
-rw-r--r--[l---------] | ctrl/libhicnctrl/includes/ctrl.h | 26 | ||||
-rw-r--r-- | ctrl/libhicnctrl/includes/hicn/ctrl/api.h | 249 | ||||
-rwxr-xr-x | ctrl/libhicnctrl/includes/hicn/ctrl/commands.h | 14 | ||||
-rw-r--r-- | ctrl/libhicnctrl/includes/hicn/ctrl/face.h | 90 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/CMakeLists.txt | 29 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/api.c | 1283 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/cli.c | 462 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/face.c | 308 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/util/ip_address.h | 316 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/util/map.h | 234 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/util/policy.c | 53 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/util/policy.h | 266 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/util/set.h | 213 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/util/token.h | 40 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/util/types.h | 36 |
16 files changed, 2203 insertions, 1447 deletions
diff --git a/ctrl/libhicnctrl/CMakeLists.txt b/ctrl/libhicnctrl/CMakeLists.txt index cb1bd722c..6b67544ee 100644 --- a/ctrl/libhicnctrl/CMakeLists.txt +++ b/ctrl/libhicnctrl/CMakeLists.txt @@ -26,21 +26,38 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" ) +include(BuildMacros) + set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_MACOSX_RPATH ON) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - set(HICN_CTRL hicn-ctrl) - set(LIBHICN_CTRL hicn-ctrl) - set(LIBHICN_CTRL_SHARED ${LIBHICNCTRL}.shared) - set(LIBHICN_CTRL_STATIC ${LIBHICNCTRL}.static) -endif() -set(LIBHICNCTRL_COMPONENT lib${LIBHICN_CTRL}) + find_package_wrapper(Libhicn REQUIRED) + + set(HICNCTRL hicnctrl) + set(LIBHICNCTRL hicnctrl) + set(LIBHICNCTRL_SHARED ${LIBHICNCTRL}.shared) + set(LIBHICNCTRL_STATIC ${LIBHICNCTRL}.static) + +else() + if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + set(HICN_LIBRARIES ${LIBHICN_STATIC}) + list(APPEND DEPENDENCIES + ${LIBHICN_STATIC} + ) + else () + set(HICN_LIBRARIES ${LIBHICN_SHARED}) + list(APPEND DEPENDENCIES + ${LIBHICN_SHARED} + ) + endif () + +endif() -set(TO_INSTALL_HEADER_FILES) +set(LIBHICNCTRL_COMPONENT lib${LIBHICNCTRL}) add_subdirectory(includes) add_subdirectory(src) diff --git a/ctrl/libhicnctrl/includes/ctrl.h b/ctrl/libhicnctrl/includes/ctrl.h index 646630968..e61b7a482 120000..100644 --- a/ctrl/libhicnctrl/includes/ctrl.h +++ b/ctrl/libhicnctrl/includes/ctrl.h @@ -1 +1,25 @@ -hicn/ctrl.h
\ No newline at end of file +/* + * 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 ctrl.h + * \brief Main interface for hICN control library + */ +#ifndef HICNCTRL_H +#define HICNCTRL_H + +#include <hicn/ctrl/api.h> + +#endif /* HICNCTRL_H */ diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index 45efb39f9..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 @@ -68,42 +68,14 @@ #include <stdbool.h> #include <stdint.h> +#include <hicn/util/ip_address.h> #include "face.h" -#include "util/types.h" -#define LIBHICNCTRL_SUCCESS 0 -#define LIBHICNCTRL_FAILURE -1 -#define LIBHICNCTRL_NOT_IMPLEMENTED -99 -#define LIBHICNCTRL_IS_ERROR(x) (x < 0) +#define HICN_DEFAULT_PORT 9695 - -/** - * This allows to selectively define convenience types to avoid any collision - * when using the library in conjunction with other frameworks including similar - * defines - */ -#ifdef _HICNTRL_NO_DEFS -#define _HICNTRL_NO_DEF_TYPES -#define _HICNTRL_NO_DEF_IPADDR -#define _HICNTRL_NO_DEF_UNIONCAST -#endif - -#ifndef _HICNTRL_NO_DEF_TYPES -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; -#endif /* _HICNTRL_NO_DEF_TYPES */ - -#ifndef _HICNTRL_NO_DEF_IPADDR -#include "util/ip_address.h" -#endif /* _HICNTRL_NO_DEF_IPADDR */ - -#ifndef _HICNTRL_NO_DEF_UNIONCAST /* Helper for avoiding warnings about type-punning */ #define UNION_CAST(x, destType) \ (((union {__typeof__(x) a; destType b;})x).b) -#endif /* _HICNTRL_NO_DEF_UNIONCAST */ /****************************************************************************** * Message helper types and aliases @@ -242,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; \ } /****************************************************************************** @@ -259,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 @@ -418,28 +380,14 @@ hc_sock_reset(hc_sock_t * s); #define NULLTERM 1 #endif -#define NAME_LEN 16 /* NULL-terminated right ? */ -#ifdef __linux__ +#define SYMBOLIC_NAME_LEN 16 /* NULL-terminated right ? */ #define INTERFACE_LEN 16 -#endif -#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 */ #define MAXSZ_HC_ID MAXSZ_HC_ID_ + NULLTERM -#define MAXSZ_HC_PROTO_ 8 /* inetX:// */ -#define MAXSZ_HC_PROTO MAXSZ_HC_PROTO_ + NULLTERM - -#define MAXSZ_HC_URL4_ MAXSZ_HC_PROTO_ + MAXSZ_IP4_ADDRESS_ + MAXSZ_PORT_ -#define MAXSZ_HC_URL6_ MAXSZ_HC_PROTO_ + MAXSZ_IP6_ADDRESS_ + MAXSZ_PORT_ -#define MAXSZ_HC_URL_ MAXSZ_HC_URL6_ -#define MAXSZ_HC_URL4 MAXSZ_HC_URL4_ + NULLTERM -#define MAXSZ_HC_URL6 MAXSZ_HC_URL6_ + NULLTERM -#define MAXSZ_HC_URL MAXSZ_HC_URL_ + NULLTERM - -int hc_url_snprintf(char * s, size_t size, int family, - const ip_address_t * ip_address, u16 port); #define foreach_type(TYPE, VAR, data) \ for (TYPE * VAR = (TYPE*)data->buffer; \ @@ -497,10 +445,8 @@ 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 -#ifdef __linux__ + char name[SYMBOLIC_NAME_LEN]; /* K.w */ // XXX clarify what used for char interface_name[INTERFACE_LEN]; /* Kr. */ -#endif u32 id; hc_connection_type_t type; /* .rw */ int family; /* .rw */ @@ -509,7 +455,8 @@ typedef struct { } hc_listener_t; int hc_listener_create(hc_sock_t * s, hc_listener_t * listener); -int hc_listener_get(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, 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); @@ -520,7 +467,7 @@ int hc_listener_parse(void * in, hc_listener_t * listener); #define foreach_listener(VAR, data) foreach_type(hc_listener_t, VAR, data) -#define MAXSZ_HC_LISTENER_ MAXSZ_HC_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ +#define MAXSZ_HC_LISTENER_ INTERFACE_LEN + SPACE + MAXSZ_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ #define MAXSZ_HC_LISTENER MAXSZ_HC_LISTENER_ + NULLTERM GENERATE_FIND_HEADER(listener); @@ -531,9 +478,15 @@ int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener); * Connections *----------------------------------------------------------------------------*/ +/* + * NOTE : + * - interface_name is mainly used to derive listeners from connections, but is + * not itself used to create connections. + */ 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 */ ip_address_t local_addr; /* .rw */ @@ -549,7 +502,8 @@ typedef struct { int hc_connection_create(hc_sock_t * s, hc_connection_t * connection); -int hc_connection_get(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, hc_connection_t ** connection_found); int hc_connection_update_by_id(hc_sock_t * s, int hc_connection_id, hc_connection_t * connection); @@ -567,13 +521,14 @@ int hc_connection_cmp(const hc_connection_t * c1, const hc_connection_t * c2); int hc_connection_parse(void * in, hc_connection_t * connection); #ifdef WITH_POLICY -int hc_connection_set_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); +int hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); #endif /* WITH_POLICY */ #define foreach_connection(VAR, data) foreach_type(hc_connection_t, VAR, data) -#define MAXSZ_HC_CONNECTION_ MAXSZ_HC_CONNECTION_STATE_ + \ - 2 * MAXSZ_HC_URL_ + MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) +#define MAXSZ_HC_CONNECTION_ MAXSZ_HC_CONNECTION_STATE_ + \ + INTERFACE_LEN + SPACE + \ + 2 * MAXSZ_URL_ + MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) #define MAXSZ_HC_CONNECTION MAXSZ_HC_CONNECTION_ + NULLTERM GENERATE_FIND_HEADER(connection); @@ -581,38 +536,6 @@ GENERATE_FIND_HEADER(connection); int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection); /*----------------------------------------------------------------------------* - * Routes - *----------------------------------------------------------------------------*/ - -typedef struct { - u8 face_id; /* Kr. */ - int family; /* Krw */ - ip_address_t remote_addr; /* krw */ - u8 len; /* krw */ - u16 cost; /* .rw */ -} hc_route_t; - -int hc_route_parse(void * in, hc_route_t * route); - -int hc_route_create(hc_sock_t * s, hc_route_t * route); -int hc_route_delete(hc_sock_t * s, hc_route_t * route); -int hc_route_list(hc_sock_t * s, hc_data_t ** pdata); - -#define foreach_route(VAR, data) foreach_type(hc_route_t, VAR, data) - -#define MAX_FACE_ID 255 -#define MAXSZ_FACE_ID 3 -#define MAX_COST 65535 -#define MAXSZ_COST 5 -#define MAX_LEN 255 -#define MAXSZ_LEN 3 - -#define MAXSZ_HC_ROUTE_ MAXSZ_FACE_ID + 1 + MAXSZ_COST + 1 + MAXSZ_IP_ADDRESS + 1 + MAXSZ_LEN -#define MAXSZ_HC_ROUTE MAXSZ_HC_ROUTE_ + NULLTERM - -int hc_route_snprintf(char * s, size_t size, hc_route_t * route); - -/*----------------------------------------------------------------------------* * Faces * * A face is an abstraction introduced by the control library to abstract the @@ -623,8 +546,8 @@ int hc_route_snprintf(char * s, size_t size, hc_route_t * route); *----------------------------------------------------------------------------*/ typedef struct { - u32 id; - char name[NAME_LEN]; + u8 id; + char name[SYMBOLIC_NAME_LEN]; face_t face; // or embed ? //face_id_t parent; /* Pointer from connection to listener */ } hc_face_t; @@ -641,15 +564,51 @@ 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 MAXSZ_HC_FACE_ 0 +#define MAX_FACE_ID 255 +#define MAXSZ_FACE_ID_ 3 +#define MAXSZ_FACE_ID MAXSZ_FACE_ID_ + NULLTERM +#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 #define MAXSZ_HC_FACE MAXSZ_HC_FACE_ + NULLTERM int hc_face_snprintf(char * s, size_t size, hc_face_t * face); -/////// XXX XXX XXX XXX missing face api functions, cf punting now... +/*----------------------------------------------------------------------------* + * Routes + *----------------------------------------------------------------------------*/ + +typedef struct { + u8 face_id; /* Kr. */ + int family; /* Krw */ + ip_address_t remote_addr; /* krw */ + u8 len; /* krw */ + u16 cost; /* .rw */ +} hc_route_t; + +int hc_route_parse(void * in, hc_route_t * route); + +int hc_route_create(hc_sock_t * s, hc_route_t * route); +int hc_route_delete(hc_sock_t * s, hc_route_t * route); +int hc_route_list(hc_sock_t * s, hc_data_t ** pdata); + +#define foreach_route(VAR, data) foreach_type(hc_route_t, VAR, data) + +#define MAX_COST 65535 +#define MAXSZ_COST 5 +#define MAX_LEN 255 +#define MAXSZ_LEN 3 + +#define MAXSZ_HC_ROUTE_ MAXSZ_FACE_ID + 1 + MAXSZ_COST + 1 + MAXSZ_IP_ADDRESS + 1 + MAXSZ_LEN +#define MAXSZ_HC_ROUTE MAXSZ_HC_ROUTE_ + NULLTERM + +int hc_route_snprintf(char * s, size_t size, hc_route_t * route); + /*----------------------------------------------------------------------------* * Punting diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h b/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h index 1d07c9b72..e69c93932 100755 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h @@ -32,7 +32,7 @@ #include <stdlib.h> #ifdef WITH_POLICY -#include "util/policy.h" +#include <hicn/policy.h> #endif /* WITH_POLICY */ typedef struct in6_addr ipv6_addr_t; @@ -58,6 +58,7 @@ typedef enum { ADD_ROUTE, LIST_ROUTES, REMOVE_CONNECTION, + REMOVE_LISTENER, REMOVE_ROUTE, CACHE_STORE, CACHE_SERVE, @@ -77,7 +78,6 @@ typedef enum { REMOVE_POLICY, UPDATE_CONNECTION, #endif /* WITH_POLICY */ - REMOVE_LISTENER, LAST_COMMAND_VALUE } command_id; @@ -131,6 +131,7 @@ typedef struct { typedef struct { char symbolic[16]; + //char interfaceName[16]; union commandAddr remoteIp; union commandAddr localIp; uint16_t remotePort; @@ -166,9 +167,9 @@ typedef struct { add_connection_command connectionData; uint32_t connid; uint8_t state; -#ifdef WITH_UPDATE + uint8_t admin_state; + char interfaceName[16]; char connectionName[16]; -#endif /* WITH_UPDATE */ } list_connections_command; // SIZE=64 @@ -282,10 +283,8 @@ typedef struct { typedef struct { union commandAddr address; -#ifdef WITH_UPDATE char listenerName[16]; char interfaceName[16]; -#endif /* WITH_UPDATE */ uint32_t connid; uint16_t port; uint8_t addressType; @@ -310,11 +309,10 @@ typedef struct { // SIZE=1 -//========== NEW COMMANDS ========== - typedef struct { char symbolicOrConnid[16]; uint8_t admin_state; + uint8_t pad8[3]; } connection_set_admin_state_command; #ifdef WITH_POLICY diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h b/ctrl/libhicnctrl/includes/hicn/ctrl/face.h index 2856ce89b..5c1fecd55 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/face.h @@ -30,12 +30,11 @@ #define NULLTERM 1 #endif -#ifndef _HICNTRL_NO_DEF_IPADDR -#include "util/ip_address.h" -#endif /* _HICNTRL_NO_DEF_IPADDR */ -#include "util/policy.h" -#include "util/types.h" +#include <hicn/policy.h> +#include <hicn/util/ip_address.h> + +typedef unsigned int hash_t; /* Netdevice type */ @@ -43,6 +42,7 @@ #define foreach_netdevice_type \ _(UNDEFINED) \ + _(LOOPBACK) \ _(WIRED) \ _(WIFI) \ _(CELLULAR) \ @@ -63,25 +63,48 @@ extern const char * netdevice_type_str[]; /* Netdevice */ +/** + * \brief Netdevice type + * + * NOTE + * - This struct cannot be made opaque as it is currently part of face_t + * - We recommand using the API as to keep redundant attributes consistent + */ typedef struct { u32 index; char name[IFNAMSIZ]; } netdevice_t; +#define NETDEVICE_EMPTY (netdevice_t) { \ + .index = 0, \ + .name = {0}, \ +} + +netdevice_t * netdevice_create_from_index(u32 index); +netdevice_t * netdevice_create_from_name(const char * name); +#define netdevice_initialize_from_index netdevice_set_index +#define netdevice_initialize_from_name netdevice_set_name +void netdevice_free(netdevice_t * netdevice); +int netdevice_get_index(const netdevice_t * netdevice, u32 * index); +int netdevice_set_index(netdevice_t * netdevice, u32 index); +int netdevice_get_name(const netdevice_t * netdevice, const char ** name); +int netdevice_set_name(netdevice_t * netdevice, const char * name); +int netdevice_update_index(netdevice_t * netdevice); +int netdevice_update_name(netdevice_t * netdevice); +int netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2); + #define NETDEVICE_UNDEFINED_INDEX 0 /* Face state */ #define foreach_face_state \ _(UNDEFINED) \ - _(PENDING_UP) \ - _(UP) \ - _(PENDING_DOWN) \ _(DOWN) \ - _(ERROR) \ + _(UP) \ _(N) -#define MAXSZ_FACE_STATE_ 12 + +#define MAXSZ_FACE_STATE_ 9 #define MAXSZ_FACE_STATE MAXSZ_FACE_STATE_ + 1 typedef enum { @@ -116,49 +139,49 @@ foreach_face_type extern const char * face_type_str[]; -#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_IP_ADDRESS + 2 * MAXSZ_PORT + 9 +#ifdef WITH_POLICY +#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + MAXSZ_POLICY_TAGS_ + 7 +#else +#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + 4 +#endif /* WITH_POLICY */ #define MAXSZ_FACE MAXSZ_FACE_ + 1 /* Face */ -typedef union { - int family; /* To access family independently of face type */ - struct { - int family; - netdevice_t netdevice; - ip_address_t local_addr; - ip_address_t remote_addr; - } hicn; - struct { - int family; - ip_address_t local_addr; - u16 local_port; - ip_address_t remote_addr; - u16 remote_port; - } tunnel; -} face_params_t; - typedef struct { face_type_t type; - face_params_t params; face_state_t admin_state; face_state_t state; #ifdef WITH_POLICY policy_tags_t tags; /**< \see policy_tag_t */ #endif /* WITH_POLICY */ + + /* + * Depending on the face type, some of the following fields will be unused + */ + netdevice_t netdevice; + int family; /* To access family independently of face type */ + ip_address_t local_addr; + ip_address_t remote_addr; + u16 local_port; + u16 remote_port; } face_t; int face_initialize(face_t * face); -int face_initialize_udp(face_t * face, const ip_address_t * local_addr, - u16 local_port, const ip_address_t * remote_addr, u16 remote_port, +int face_initialize_udp(face_t * face, const char * interface_name, + const ip_address_t * local_addr, u16 local_port, + const ip_address_t * remote_addr, u16 remote_port, int family); int face_initialize_udp_sa(face_t * face, + const char * interface_name, const struct sockaddr * local_addr, const struct sockaddr * remote_addr); face_t * face_create(); -face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port, +face_t * face_create_udp(const char * interface_name, + const ip_address_t * local_addr, u16 local_port, const ip_address_t * remote_addr, u16 remote_port, int family); -face_t * face_create_udp_sa(const struct sockaddr * local_addr, +face_t * face_create_udp_sa(const char * interface_name, + const struct sockaddr * local_addr, const struct sockaddr * remote_addr); int face_finalize(face_t * face); @@ -173,6 +196,7 @@ hash_t face_hash(const face_t * face); size_t face_snprintf(char * s, size_t size, const face_t * face); +policy_tags_t face_get_tags(const face_t * face); int face_set_tags(face_t * face, policy_tags_t tags); #endif /* HICN_FACE_H */ diff --git a/ctrl/libhicnctrl/src/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index 204311c39..4708595e0 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -11,11 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(BuildMacros) - list(APPEND COMPILER_DEFINITIONS "-DWITH_POLICY" -# "-DWITH_UPDATE" ) set(HEADER_FILES @@ -26,34 +23,35 @@ set(HEADER_FILES set(UTIL_HEADER_FILES face.h - util/ip_address.h util/log.h - util/policy.h - util/token.h - util/types.h + util/map.h ) set(SOURCE_FILES api.c - util/policy.c + face.c util/log.c ) set(LIBRARIES m + ${HICN_LIBRARIES} ) set(INCLUDE_DIRS ./ ../includes/ + ${HICN_INCLUDE_DIRS} ) -if (ANDROID_API) - build_library(${LIBHICN_CTRL} +if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + set(HICN_LIBRARIES ${LIBHICN_STATIC}) + build_library(${LIBHICNCTRL} STATIC SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${LIBHICN_STATIC} COMPONENT ${LIBHICNCTRL_COMPONENT} DEPENDS ${LIBHICN_STATIC} INCLUDE_DIRS ${INCLUDE_DIRS} @@ -61,11 +59,12 @@ if (ANDROID_API) DEFINITIONS ${COMPILER_DEFINITIONS} ) else () - build_library(${LIBHICN_CTRL} + build_library(${LIBHICNCTRL} SHARED STATIC SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${LIBHICN_SHARED} COMPONENT ${LIBHICNCTRL_COMPONENT} DEPENDS ${LIBHICN_SHARED} INCLUDE_DIRS ${INCLUDE_DIRS} @@ -74,14 +73,14 @@ else () ) endif () -if(NOT ANDROID_API AND NOT COMPILE_FOR_IOS) +if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android" AND NOT COMPILE_FOR_IOS) list(APPEND DAEMON_SRC cli.c ) - build_executable(${HICN_CTRL} + build_executable(${HICNCTRL} SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${LIBHICN_CTRL_SHARED} - DEPENDS ${LIBHICN_CTRL_SHARED} + LINK_LIBRARIES ${LIBHICNCTRL_SHARED} ${LIBHICN_SHARED} + DEPENDS ${LIBHICNCTRL_SHARED} ${LIBHICN_SHARED} COMPONENT ${LIBHICNCTRL_COMPONENT} INCLUDE_DIRS ${INCLUDE_DIRS} DEFINITIONS ${COMPILER_DEFINITIONS} diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 3d8a2c166..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 @@ -28,13 +29,95 @@ #include <hicn/ctrl/api.h> #include <hicn/ctrl/commands.h> +#include <hicn/util/token.h> #include "util/log.h" -#include "util/token.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) +#else +#define RANDBYTE() (u8)(random() & 0xFF) +#endif +#endif +#define RANDBYTE() (u8)(rand() & 0xFF) + +/* * list was working with all seq set to 0, but it seems hicnLightControl uses * 1, and replies with the same seqno */ @@ -159,8 +242,8 @@ static const hc_connection_state_t map_from_list_connections_state[] = { }; -#define connection_state_to_face_state(x) ((face_state_t)x) -#define face_state_to_connection_state(x) ((hc_connection_state_t)x) +#define connection_state_to_face_state(x) ((face_state_t)(x)) +#define face_state_to_connection_state(x) ((hc_connection_state_t)(x)) #define IS_VALID_ADDR_TYPE(x) ((x >= ADDR_INET) && (x <= ADDR_UNIX)) @@ -230,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; @@ -265,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 @@ -307,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 @@ -316,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; } /****************************************************************************** @@ -342,6 +425,8 @@ hc_sock_parse_url(const char * url, struct sockaddr * sa) /* FIXME URL parsing is currently not implemented */ assert(!url); + srand(time(NULL)); + /* * A temporary solution is to inspect the sa_family fields of the passed in * sockaddr, which defaults to AF_UNSPEC (0) and thus creates an IPv4/TCP @@ -366,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 * @@ -388,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); @@ -407,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); @@ -414,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 }; @@ -433,17 +554,24 @@ 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) { - return send(s->fd, msg, msglen, 0); + int rc; + msg->hdr.seqNum = seq; + rc = send(s->fd, msg, msglen, 0); + if (rc < 0) { + perror("hc_sock_send"); + return -1; + } + return 0; } int @@ -452,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; @@ -468,23 +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) { - /* Error occurred */ - // XXX check for EWOULDBLOCK; - // XXX - return LIBHICNCTRL_FAILURE; + /* + * Let's not return 0 which currently means the socket has been closed + */ + if (errno == EWOULDBLOCK) + return -1; + perror("hc_sock_recv"); + 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; @@ -493,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 */ @@ -501,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; } } @@ -587,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; } /****************************************************************************** @@ -612,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: @@ -637,80 +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; - - hc_sock_send(s, msg, msg_len); - while(!data->complete) { - if (hc_sock_recv(s, data) < 0) - break; - if (hc_sock_process(s, data, params->parse) < 0) { - goto ERR_PROCESS; - } } - if (pdata) - *pdata = data; - - return LIBHICNCTRL_SUCCESS; - -ERR_PROCESS: - free(data); -ERR_DATA: - return LIBHICNCTRL_FAILURE; -} + int seq = hc_sock_get_next_seq(s); + if (seq < 0) { + ERROR("[hc_execute_command] Could not get next sequence number"); + goto ERR_SEQ; + } -/* /!\ Please update constants in header file upon changes */ -int -hc_url_snprintf(char * s, size_t size, int family, - const ip_address_t * ip_address, u16 port) -{ - char * cur = s; - int rc; + /* 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; + } - /* Other address are currently not supported */ - if (!IS_VALID_FAMILY(family)) { - ERROR("Invalid family %d for IP address", family); - return -1; + /* 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; } - rc = snprintf(cur, s + size - cur, "inet%c://", - (family == AF_INET) ? '4' : '6'); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; + if (hc_sock_send(s, msg, msg_len, seq) < 0) { + ERROR("[hc_execute_command] Error sending message"); + goto ERR_PROCESS; + } - rc = ip_address_snprintf(cur, s + size - cur, ip_address, family); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; + if (async) + return 0; - rc = snprintf(cur, s + size - cur, ":"); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; + while(!data->complete) { + /* + * 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; + } + } - rc = snprintf(cur, s + size - cur, "%d", port); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; + return 0; - return cur - s; +ERR_PROCESS: +ERR_MAP: + hc_sock_request_free(request); +ERR_REQUEST: +ERR_SEQ: + free(data); +ERR_DATA: + return -1; } /*----------------------------------------------------------------------------* @@ -720,13 +884,13 @@ hc_url_snprintf(char * s, size_t size, int family, /* 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; @@ -736,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 = { @@ -749,10 +913,8 @@ hc_listener_create(hc_sock_t * s, hc_listener_t * listener) } }; - snprintf(msg.payload.symbolic, NAME_LEN, "%s", listener->name); -#ifdef __linux__ + snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", listener->name); snprintf(msg.payload.interfaceName, INTERFACE_LEN, "%s", listener->interface_name); -#endif hc_command_params_t params = { .cmd = ACTION_CREATE, @@ -762,34 +924,58 @@ 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, listener_found) < 0) - return LIBHICNCTRL_FAILURE; + if (hc_listener_find(listeners, listener, &found) < 0) { + hc_data_free(listeners); + return -1; + } + + if (found) { + *listener_found = malloc(sizeof(hc_listener_t)); + if (!*listener_found) + return -1; + **listener_found = *found; + } else { + *listener_found = NULL; + } 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; @@ -799,25 +985,22 @@ 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); } hc_command_params_t params = { @@ -828,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; @@ -843,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, }, }; @@ -855,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 */ @@ -864,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 */ @@ -879,10 +1087,11 @@ hc_listener_cmp(const hc_listener_t * l1, const hc_listener_t * l2) { return ((l1->type == l2->type) && (l1->family == l2->family) && + (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 */ @@ -893,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, @@ -913,8 +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), }; - memset(listener->name, 0, NAME_LEN); - return LIBHICNCTRL_SUCCESS; + snprintf(listener->name, SYMBOLIC_NAME_LEN, "%s", cmd->listenerName); + snprintf(listener->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); + return 0; } GENERATE_FIND(listener) @@ -925,14 +1135,15 @@ GENERATE_FIND(listener) int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener) { - char local[MAXSZ_HC_URL]; + char local[MAXSZ_URL]; int rc; - rc = hc_url_snprintf(local, MAXSZ_HC_URL, + rc = url_snprintf(local, MAXSZ_URL, listener->family, &listener->local_addr, listener->local_port); if (rc < 0) return rc; - return snprintf(s, size+17, "%s %s", + return snprintf(s, size+17, "%s %s %s", + listener->interface_name, local, connection_type_str[listener->type]); } @@ -944,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; @@ -957,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 */ @@ -973,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, @@ -983,34 +1194,58 @@ 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, connection_found) < 0) - return LIBHICNCTRL_FAILURE; + if (hc_connection_find(connections, connection, &found) < 0) { + hc_data_free(connections); + return -1; + } + + if (found) { + *connection_found = malloc(sizeof(hc_connection_t)); + if (!*connection_found) + return -1; + **connection_found = *found; + } else { + *connection_found = NULL; + } 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; @@ -1020,25 +1255,22 @@ 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); } hc_command_params_t params = { @@ -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,8 +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); - return LIBHICNCTRL_SUCCESS; + snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", cmd->connectionData.symbolic); + snprintf(connection->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); + return 0; } GENERATE_FIND(connection) @@ -1169,23 +1425,24 @@ GENERATE_FIND(connection) int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection) { - char local[MAXSZ_HC_URL]; - char remote[MAXSZ_HC_URL]; + char local[MAXSZ_URL]; + char remote[MAXSZ_URL]; int rc; // assert(connection->connection_state) - rc = hc_url_snprintf(local, MAXSZ_HC_URL, connection->family, + rc = url_snprintf(local, MAXSZ_URL, connection->family, &connection->local_addr, connection->local_port); if (rc < 0) return rc; - rc = hc_url_snprintf(remote, MAXSZ_HC_URL, connection->family, + rc = url_snprintf(remote, MAXSZ_URL, connection->family, &connection->remote_addr, connection->remote_port); if (rc < 0) return rc; - return snprintf(s, size, "%s %s %s %s", + return snprintf(s, size, "%s %s %s %s %s", connection_state_str[connection->state], + connection->interface_name, local, remote, connection_type_str[connection->type]); @@ -1194,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, - hc_connection_state_t admin_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; @@ -1205,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 = admin_state, + .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, @@ -1221,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); } /*----------------------------------------------------------------------------* @@ -1231,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; @@ -1244,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 */ @@ -1259,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, @@ -1269,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; @@ -1288,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 */ @@ -1306,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; @@ -1321,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, }, }; @@ -1333,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 */ @@ -1344,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, @@ -1357,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 */ @@ -1414,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 */ @@ -1424,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 */ @@ -1436,13 +1743,12 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool switch(f->type) { case FACE_TYPE_HICN: - /* FIXME truncations, collisions, ... */ *connection = (hc_connection_t) { .type = CONNECTION_TYPE_HICN, - .family = f->params.hicn.family, - .local_addr = f->params.hicn.local_addr, + .family = f->family, + .local_addr = f->local_addr, .local_port = 0, - .remote_addr = f->params.hicn.remote_addr, + .remote_addr = f->remote_addr, .remote_port = 0, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), @@ -1450,17 +1756,19 @@ 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", - f->params.hicn.netdevice.name); + snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", + f->netdevice.name); + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); break; case FACE_TYPE_TCP: *connection = (hc_connection_t) { .type = CONNECTION_TYPE_TCP, - .family = f->params.hicn.family, - .local_addr = f->params.tunnel.local_addr, - .local_port = f->params.tunnel.local_port, - .remote_addr = f->params.tunnel.remote_addr, - .remote_port = f->params.tunnel.remote_port, + .family = f->family, + .local_addr = f->local_addr, + .local_port = f->local_port, + .remote_addr = f->remote_addr, + .remote_port = f->remote_port, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), #ifdef WITH_POLICY @@ -1468,23 +1776,21 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; if (generate_name) { -#ifdef __APPLE__ - snprintf(connection->name, NAME_LEN, "tcp%d", arc4random() & 0xFF); -#else - snprintf(connection->name, NAME_LEN, "tcp%ld", random() & 0xFF); -#endif + 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); break; case FACE_TYPE_UDP: *connection = (hc_connection_t) { .type = CONNECTION_TYPE_UDP, .family = AF_INET, - .local_addr = f->params.tunnel.local_addr, - .local_port = f->params.tunnel.local_port, - .remote_addr = f->params.tunnel.remote_addr, - .remote_port = f->params.tunnel.remote_port, + .local_addr = f->local_addr, + .local_port = f->local_port, + .remote_addr = f->remote_addr, + .remote_port = f->remote_port, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), #ifdef WITH_POLICY @@ -1492,20 +1798,21 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; if (generate_name) { -#ifdef __APPLE__ - snprintf(connection->name, NAME_LEN, "udp%d", arc4random() & 0xFF); -#else - snprintf(connection->name, NAME_LEN, "udp%ld", random() & 0xFF); -#endif + 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; } - return LIBHICNCTRL_SUCCESS; + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); + + return 0; } /* CONNECTION -> FACE */ @@ -1519,13 +1826,11 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_TCP, - .params.tunnel = { - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - }, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + .remote_addr = connection->remote_addr, + .remote_port = connection->remote_port, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1539,13 +1844,11 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - }, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + .remote_addr = connection->remote_addr, + .remote_port = connection->remote_port, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1559,12 +1862,10 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_HICN, - .params.hicn = { - .family = connection->family, - .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX - .local_addr = connection->local_addr, - .remote_addr = connection->remote_addr, - }, + .family = connection->family, + .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX + .local_addr = connection->local_addr, + .remote_addr = connection->remote_addr, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1574,10 +1875,14 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) }; break; default: - return LIBHICNCTRL_FAILURE; + return -1; } - snprintf(face->name, NAME_LEN, "%s", connection->name); - return LIBHICNCTRL_SUCCESS; + face->face.netdevice.name[0] = '\0'; + face->face.netdevice.index = 0; + 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 0; } /* CONNECTION -> LISTENER */ @@ -1592,7 +1897,9 @@ hc_connection_to_local_listener(const hc_connection_t * connection, hc_listener_ .local_addr = connection->local_addr, .local_port = connection->local_port, }; - return LIBHICNCTRL_SUCCESS; + snprintf(listener->name, SYMBOLIC_NAME_LEN, "lst%u", RANDBYTE()); // generate name + snprintf(listener->interface_name, INTERFACE_LEN, "%s", connection->interface_name); + return 0; } /* FACE CREATE */ @@ -1613,32 +1920,35 @@ 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) { /* We need to create the listener if it does not exist */ if (hc_listener_create(s, &listener) < 0) { ERROR("[hc_face_create] Could not create listener."); - return LIBHICNCTRL_FAILURE; + free(listener_found); + return -1; } + } else { + free(listener_found); } /* Create corresponding connection */ if (hc_connection_create(s, &connection) < 0) { ERROR("[hc_face_create] Could not create connection."); - return LIBHICNCTRL_FAILURE; + return -1; } /* @@ -1647,15 +1957,16 @@ 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; + free(connection_found); break; @@ -1664,20 +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 @@ -1695,35 +2007,39 @@ 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); + free(connection_found); break; case FACE_TYPE_HICN_LISTENER: 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); + free(listener_found); break; default: - return LIBHICNCTRL_FAILURE; + return -1; } - return LIBHICNCTRL_SUCCESS; + return 0; } @@ -1732,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; + } + + 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; } - return hc_connection_delete(s, &connection); + + 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 */ @@ -1751,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)); @@ -1765,35 +2132,145 @@ 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 */ int hc_face_snprintf(char * s, size_t size, hc_face_t * face) { - return LIBHICNCTRL_SUCCESS; + /* URLs are also big enough to contain IP addresses in the hICN case */ + char local[MAXSZ_URL]; + char remote[MAXSZ_URL]; +#ifdef WITH_POLICY + char tags[MAXSZ_POLICY_TAGS]; +#endif /* WITH_POLICY */ + int rc; + + switch(face->face.type) { + case FACE_TYPE_HICN: + case FACE_TYPE_HICN_LISTENER: + rc = ip_address_snprintf(local, MAXSZ_URL, + &face->face.local_addr, + face->face.family); + if (rc < 0) + return rc; + rc = ip_address_snprintf(remote, MAXSZ_URL, + &face->face.remote_addr, + face->face.family); + if (rc < 0) + return rc; + break; + case FACE_TYPE_TCP: + case FACE_TYPE_UDP: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_UDP_LISTENER: + rc = url_snprintf(local, MAXSZ_URL, face->face.family, + &face->face.local_addr, + face->face.local_port); if (rc < 0) + return rc; + rc = url_snprintf(remote, MAXSZ_URL, face->face.family, + &face->face.remote_addr, + face->face.remote_port); if (rc < 0) + if (rc < 0) + return rc; + break; + default: + return -1; + } + + // [#ID NAME] TYPE LOCAL_URL REMOTE_URL STATE/ADMIN_STATE (TAGS) +#ifdef WITH_POLICY + rc = policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->face.tags); + if (rc < 0) + return rc; + + return snprintf(s, size, "[#%d %s] %s %s %s %s/%s (%s)", + face->id, + face->name, + face_type_str[face->face.type], + local, + remote, + face_state_str[face->face.state], + face_state_str[face->face.admin_state], + tags); +#else + return snprintf(s, size, "[#%d %s] %s %s %s %s/%s", + face->id, + face->name, + face_type_str[face->face.type], + local, + remote, + face_state_str[face->face.state], + face_state_str[face->face.admin_state]); +#endif /* WITH_POLICY */ + return 0; } int hc_face_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, // XXX wrong identifier face_state_t admin_state) { - return hc_connection_set_admin_state(s, conn_id_or_name, (hc_connection_state_t)admin_state); + return hc_connection_set_admin_state(s, conn_id_or_name, admin_state); } /*----------------------------------------------------------------------------* * 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; @@ -1803,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 */ @@ -1812,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, @@ -1822,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) @@ -1861,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; } @@ -1881,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; @@ -1891,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, @@ -1906,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; @@ -1920,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, @@ -1935,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 @@ -1947,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 ? */ @@ -1966,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 */ @@ -1989,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; } /*----------------------------------------------------------------------------* @@ -1999,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; } /*----------------------------------------------------------------------------* @@ -2029,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; @@ -2042,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 */ @@ -2061,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; @@ -2080,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 */ @@ -2098,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; @@ -2113,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, }, }; @@ -2125,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 */ @@ -2136,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, @@ -2148,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 */ @@ -2157,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 70620a84f..81400f8ee 100644 --- a/ctrl/libhicnctrl/src/cli.c +++ b/ctrl/libhicnctrl/src/cli.c @@ -17,14 +17,14 @@ * \file cli.c * \brief Command line interface */ +#include <ctype.h> // isalpha isalnum #include <stdlib.h> #include <stdio.h> #include <unistd.h> // getopt #include <hicn/ctrl.h> - -#include "util/ip_address.h" -#include "util/token.h" +#include <hicn/util/ip_address.h> +#include <hicn/util/token.h> #define die(LABEL, MESSAGE) do { \ @@ -35,10 +35,11 @@ #define foreach_object \ _(UNDEFINED) \ - _(LISTENER) \ - _(CONNECTION) \ + _(FACE) \ _(ROUTE) \ _(STRATEGY) \ + _(LISTENER) \ + _(CONNECTION) \ _(N) typedef enum { @@ -49,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"); @@ -57,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]); @@ -131,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; @@ -159,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; @@ -192,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; @@ -247,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]; @@ -264,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); @@ -318,6 +512,7 @@ int main(int argc, char *argv[]) break; } break; + case OBJECT_ROUTE: switch(command.action) { case ACTION_CREATE: @@ -344,6 +539,7 @@ int main(int argc, char *argv[]) break; } break; + case OBJECT_STRATEGY: switch(command.action) { case ACTION_LIST: @@ -364,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/face.c b/ctrl/libhicnctrl/src/face.c index 9e0fbb597..41ff58f81 100644 --- a/ctrl/libhicnctrl/src/face.c +++ b/ctrl/libhicnctrl/src/face.c @@ -21,10 +21,10 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <hicn/util/token.h> -#include "face.h" +#include <hicn/ctrl/face.h> #include "util/hash.h" -#include "util/token.h" #define member_size(type, member) sizeof(((type *)0)->member) @@ -37,6 +37,112 @@ foreach_netdevice_type #undef _ }; +netdevice_t * +netdevice_create_from_index(u32 index) +{ + netdevice_t * netdevice = malloc(sizeof(netdevice_t)); + if (!netdevice) + goto ERR_MALLOC; + + int rc = netdevice_set_index(netdevice, index); + if (rc < 0) + goto ERR_INIT; + + return netdevice; + +ERR_INIT: + free(netdevice); +ERR_MALLOC: + return NULL; +} + +netdevice_t * +netdevice_create_from_name(const char * name) +{ + netdevice_t * netdevice = malloc(sizeof(netdevice_t)); + if (!netdevice) + goto ERR_MALLOC; + + int rc = netdevice_set_name(netdevice, name); + if (rc < 0) + goto ERR_INIT; + + return netdevice; + +ERR_INIT: + free(netdevice); +ERR_MALLOC: + return NULL; +} + +/** + * \brief Update the index of the netdevice based on the name + */ +int +netdevice_update_index(netdevice_t * netdevice) +{ + netdevice->index = if_nametoindex(netdevice->name); + if (netdevice->index == 0) + return -1; + return 0; +} + +int +netdevice_update_name(netdevice_t * netdevice) +{ + if (!if_indextoname(netdevice->index, netdevice->name)) + return -1; + return 0; +} + +void +netdevice_free(netdevice_t * netdevice) +{ + free(netdevice); +} + +int +netdevice_get_index(const netdevice_t * netdevice, u32 * index) +{ + if (netdevice->index == 0) + return -1; + *index = netdevice->index; + return 0; +} + +int +netdevice_set_index(netdevice_t * netdevice, u32 index) +{ + netdevice->index = index; + return netdevice_update_name(netdevice); +} + +int +netdevice_get_name(const netdevice_t * netdevice, const char ** name) +{ + if (netdevice->name[0] == '\0') + return -1; + *name = netdevice->name; + return 0; +} + +int +netdevice_set_name(netdevice_t * netdevice, const char * name) +{ + int rc = snprintf(netdevice->name, IFNAMSIZ, "%s", name); + if (rc < 0) + return -1; + if (rc >= IFNAMSIZ) + return -2; /* truncated */ + return netdevice_update_index(netdevice); +} + +int +netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2) +{ + return (nd1->index - nd2->index); +} + /* Face state */ @@ -61,33 +167,42 @@ foreach_face_type int face_initialize(face_t * face) { - bzero(face, sizeof(face_t)); /* 0'ed for hash */ + memset(face, 0, sizeof(face_t)); /* 0'ed for hash */ return 1; } int -face_initialize_udp(face_t * face, const ip_address_t * local_addr, - u16 local_port, const ip_address_t * remote_addr, u16 remote_port, +face_initialize_udp(face_t * face, const char * interface_name, const + ip_address_t * local_addr, u16 local_port, + const ip_address_t * remote_addr, u16 remote_port, int family) { + if (!local_addr) + return -1; + *face = (face_t) { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = family, - .local_addr = *local_addr, - .local_port = local_port, - .remote_addr = *remote_addr, - .remote_port = remote_port, - }, + .family = family, + .local_addr = *local_addr, + .local_port = local_port, + .remote_addr = remote_addr ? *remote_addr : IP_ADDRESS_EMPTY, + .remote_port = remote_port, }; + + snprintf(face->netdevice.name, IFNAMSIZ, "%s", interface_name); + return 1; } int -face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr, +face_initialize_udp_sa(face_t * face, const char * interface_name, + const struct sockaddr * local_addr, const struct sockaddr * remote_addr) { - if (local_addr->sa_family != remote_addr->sa_family) + if (!local_addr) + return -1; + + if (remote_addr && (local_addr->sa_family != remote_addr->sa_family)) return -1; switch (local_addr->sa_family) { @@ -97,14 +212,14 @@ face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr, struct sockaddr_in *rsai = (struct sockaddr_in *)remote_addr; *face = (face_t) { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = AF_INET, - .local_addr.v4.as_inaddr = lsai->sin_addr, - .local_port = ntohs(lsai->sin_port), - .remote_addr.v4.as_inaddr = rsai->sin_addr, - .remote_port = ntohs(rsai->sin_port), - }, + .family = AF_INET, + .local_addr.v4.as_inaddr = lsai->sin_addr, + .local_port = lsai ? ntohs(lsai->sin_port) : 0, + .remote_addr = IP_ADDRESS_EMPTY, + .remote_port = rsai ? ntohs(rsai->sin_port) : 0, }; + if (rsai) + face->remote_addr.v4.as_inaddr = rsai->sin_addr; } break; case AF_INET6: @@ -113,19 +228,22 @@ face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr, struct sockaddr_in6 *rsai = (struct sockaddr_in6 *)remote_addr; *face = (face_t) { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = AF_INET6, - .local_addr.v6.as_in6addr = lsai->sin6_addr, - .local_port = ntohs(lsai->sin6_port), - .remote_addr.v6.as_in6addr = rsai->sin6_addr, - .remote_port = ntohs(rsai->sin6_port), - }, + .family = AF_INET6, + .local_addr.v6.as_in6addr = lsai->sin6_addr, + .local_port = lsai ? ntohs(lsai->sin6_port) : 0, + .remote_addr = IP_ADDRESS_EMPTY, + .remote_port = rsai ? ntohs(rsai->sin6_port) : 0, }; + if (rsai) + face->remote_addr.v6.as_in6addr = rsai->sin6_addr; } break; default: return -1; } + + snprintf(face->netdevice.name, IFNAMSIZ, "%s", interface_name); + return 1; } @@ -135,11 +253,12 @@ face_t * face_create() return face; } -face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port, +face_t * face_create_udp(const char * interface_name, + const ip_address_t * local_addr, u16 local_port, const ip_address_t * remote_addr, u16 remote_port, int family) { face_t * face = face_create(); - if (face_initialize_udp(face, local_addr, local_port, remote_addr, remote_port, family) < 0) + if (face_initialize_udp(face, interface_name, local_addr, local_port, remote_addr, remote_port, family) < 0) goto ERR_INIT; return face; @@ -148,11 +267,12 @@ ERR_INIT: return NULL; } -face_t * face_create_udp_sa(const struct sockaddr * local_addr, +face_t * face_create_udp_sa(const char * interface_name, + const struct sockaddr * local_addr, const struct sockaddr * remote_addr) { face_t * face = face_create(); - if (face_initialize_udp_sa(face, local_addr, remote_addr) < 0) + if (face_initialize_udp_sa(face, interface_name, local_addr, remote_addr) < 0) goto ERR_INIT; return face; @@ -166,10 +286,6 @@ void face_free(face_t * face) free(face); } -#define face_param_cmp(f1, f2, face_param_type) \ - memcmp(&f1->type, &f2->type, \ - member_size(face_params_t, face_param_type)); - /** * \brief Compare two faces * \param [in] f1 - First face @@ -182,18 +298,61 @@ void face_free(face_t * face) int face_cmp(const face_t * f1, const face_t * f2) { - if (f1->type != f2->type) - return false; + + int ret = f1->type - f2->type; + if (ret != 0) + return ret; + + ret = f1->family - f2->family; + if (ret != 0) + return ret; + + /* + * FIXME As hicn-light API might not return the netdevice, we can discard the + * comparison when one of the two is not set for now... + */ + if ((f1->netdevice.index != 0) && (f2->netdevice.index != 0)) { + ret = netdevice_cmp(&f1->netdevice, &f2->netdevice); + if (ret != 0) + return ret; + } switch(f1->type) { case FACE_TYPE_HICN: - return face_param_cmp(f1, f2, hicn); + ret = ip_address_cmp(&f1->local_addr, &f2->local_addr, f1->family); + if (ret != 0) + return ret; + + ret = ip_address_cmp(&f1->remote_addr, &f2->remote_addr, f1->family); + if (ret != 0) + return ret; + + break; + case FACE_TYPE_TCP: case FACE_TYPE_UDP: - return face_param_cmp(f1, f2, tunnel); + ret = ip_address_cmp(&f1->local_addr, &f2->local_addr, f1->family); + if (ret != 0) + return ret; + + ret = f1->local_port - f2->local_port; + if (ret != 0) + return ret; + + ret = ip_address_cmp(&f1->remote_addr, &f2->remote_addr, f1->family); + if (ret != 0) + return ret; + + ret = f1->remote_port - f2->remote_port; + if (ret != 0) + return ret; + + break; default: - return false; + break; } + + return 0; } hash_t @@ -209,34 +368,59 @@ face_snprintf(char * s, size_t size, const face_t * face) { switch(face->type) { case FACE_TYPE_HICN: - return 0; // XXX Not implemented + { + char local[MAXSZ_IP_ADDRESS]; + char remote[MAXSZ_IP_ADDRESS]; + char tags[MAXSZ_POLICY_TAGS]; + + ip_address_snprintf(local, MAXSZ_IP_ADDRESS, + &face->local_addr, + face->family); + ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, + &face->remote_addr, + face->family); + policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); + return snprintf(s, size, "%s [%s -> %s] [%s]", + face_type_str[face->type], + local, + remote, + tags); + } + case FACE_TYPE_UNDEFINED: case FACE_TYPE_TCP: case FACE_TYPE_UDP: - { - char local[MAXSZ_IP_ADDRESS]; - char remote[MAXSZ_IP_ADDRESS]; - - ip_address_snprintf(local, MAXSZ_IP_ADDRESS, - &face->params.tunnel.local_addr, - face->params.tunnel.family); - ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, - &face->params.tunnel.remote_addr, - face->params.tunnel.family); - - return snprintf(s, size, "%s [%s:%d -> %s:%d]", - face_type_str[face->type], - local, - face->params.tunnel.local_port, - remote, - face->params.tunnel.remote_port); - } - break; + { + char local[MAXSZ_IP_ADDRESS]; + char remote[MAXSZ_IP_ADDRESS]; + char tags[MAXSZ_POLICY_TAGS]; + + ip_address_snprintf(local, MAXSZ_IP_ADDRESS, + &face->local_addr, + face->family); + ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, + &face->remote_addr, + face->family); + policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); + + return snprintf(s, size, "%s [%s:%d -> %s:%d] [%s]", + face_type_str[face->type], + local, + face->local_port, + remote, + face->remote_port, + tags); + } default: - return 0; + return -1; } } +policy_tags_t face_get_tags(const face_t * face) +{ + return face->tags; +} + int face_set_tags(face_t * face, policy_tags_t tags) { diff --git a/ctrl/libhicnctrl/src/util/ip_address.h b/ctrl/libhicnctrl/src/util/ip_address.h deleted file mode 100644 index 472cceeea..000000000 --- a/ctrl/libhicnctrl/src/util/ip_address.h +++ /dev/null @@ -1,316 +0,0 @@ -/* - * 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 ip_address.h - * \brief IP address type support - */ -#ifndef UTIL_IP_ADDRESS_H -#define UTIL_IP_ADDRESS_H - -#include <arpa/inet.h> // inet_ntop -#ifdef __APPLE__ -#include <libkern/OSByteOrder.h> -#define __bswap_constant_32(x) OSSwapInt32(x) -#include <machine/endian.h> -#else -#ifdef __ANDROID__ -#include <byteswap.h> -#endif -#include <endian.h> -#endif -#include <errno.h> -#include <netdb.h> // struct addrinfo -#include <netinet/in.h> // INET*_ADDRSTRLEN, IN*ADDR_LOOPBACK -#include <stdlib.h> -#include <string.h> // memset - -#include "types.h" - - -#define bytes_to_bits(x) (x * 8) -#define IPV6_ADDR_LEN 16 /* bytes */ -#define IPV4_ADDR_LEN 4 /* bytes */ -#define IPV6_ADDR_LEN_BITS bytes_to_bits(IPV6_ADDR_LEN) -#define IPV4_ADDR_LEN_BITS bytes_to_bits(IPV4_ADDR_LEN) - -#define IP_MAX_ADDR_LEN IPV6_ADDR_LEN - -#define DUMMY_PORT 1234 - -typedef union { - union { - struct in_addr as_inaddr; - u8 as_u8[4]; - u16 as_u16[2]; - u32 as_u32; - } v4; - union { - struct in6_addr as_in6addr; - u8 as_u8[16]; - u16 as_u16[8]; - u32 as_u32[4]; - u64 as_u64[2]; - } v6; - u8 buffer[IP_MAX_ADDR_LEN]; - u8 as_u8[IP_MAX_ADDR_LEN]; - u16 as_u16[IP_MAX_ADDR_LEN >> 1]; - u32 as_u32[IP_MAX_ADDR_LEN >> 2]; - u64 as_u64[IP_MAX_ADDR_LEN >> 3]; -} ip_address_t; - -#define MAXSZ_IP4_ADDRESS_ INET_ADDRSTRLEN - 1 -#define MAXSZ_IP6_ADDRESS_ INET6_ADDRSTRLEN - 1 -#define MAXSZ_IP_ADDRESS_ MAXSZ_IP6_ADDRESS_ -#define MAXSZ_IP4_ADDRESS MAXSZ_IP4_ADDRESS_ + 1 -#define MAXSZ_IP6_ADDRESS MAXSZ_IP6_ADDRESS_ + 1 -#define MAXSZ_IP_ADDRESS MAXSZ_IP_ADDRESS_ + 1 - - -typedef struct { - int family; - ip_address_t address; - u8 len; -} ip_prefix_t; - -#define MAXSZ_PREFIX_ MAXSZ_IP_ADDRESS_ + 1 + 3 -#define MAXSZ_PREFIX MAXSZ_PREFIX_ + 1 - -/* No htonl() with const */ -static const ip_address_t IPV4_LOOPBACK = { -#if __BYTE_ORDER == __LITTLE_ENDIAN -#ifdef __ANDROID__ - .v4.as_inaddr.s_addr = bswap_32(INADDR_LOOPBACK), -#else - .v4.as_inaddr.s_addr = __bswap_constant_32(INADDR_LOOPBACK), -#endif -#else - .v4.as_inaddr.s_addr = INADDR_LOOPBACK, -#endif -}; - -static const ip_address_t IPV6_LOOPBACK = { - .v6.as_in6addr = IN6ADDR_LOOPBACK_INIT, -}; - -static const ip_address_t IPV4_ANY = { - .v4.as_inaddr.s_addr = INADDR_ANY, -}; - -static const ip_address_t IPV6_ANY = { - .v6.as_in6addr = IN6ADDR_ANY_INIT, -}; - -#define IP_ANY(family) (family == AF_INET) ? IPV4_ANY : IPV6_ANY - -#define MAX_PORT 1 << (8 * sizeof(u16)) -#define IS_VALID_PORT(x) ((x > 0) && (x < MAX_PORT)) - -#define MAXSZ_PORT_ 5 -#define MAXSZ_PORT MAXSZ_PORT_ + 1 - -#define IS_VALID_FAMILY(x) ((x == AF_INET) || (x == AF_INET6)) - -static inline -int -ip_address_get_family (const char * ip_address) -{ - struct addrinfo hint, *res = NULL; - int rc; - - memset (&hint, '\0', sizeof hint); - - hint.ai_family = PF_UNSPEC; - hint.ai_flags = AI_NUMERICHOST; - - rc = getaddrinfo (ip_address, NULL, &hint, &res); - if (rc) - { - return -1; - } - rc = res->ai_family; - freeaddrinfo (res); - return rc; -} - -static inline -int -ip_address_len (const ip_address_t * ip_address, int family) -{ - return (family == AF_INET6) ? IPV6_ADDR_LEN : - (family == AF_INET) ? IPV4_ADDR_LEN : 0; -} - -static inline -int -ip_address_ntop (const ip_address_t * ip_address, char *dst, const size_t len, - int family) -{ - const char * s = inet_ntop (family, ip_address->buffer, dst, len); - return (s ? 1 : -1); -} - -/* - * Parse ip addresses in presentation format - */ -static inline -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); - - switch (family) - { - case AF_INET6: - pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer); - break; - case AF_INET: - pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer); - break; - default: - goto ERR; - } - - // 0 = not in presentation format - // < 0 = other error (use perror) - if (pton_fd <= 0) - { - goto ERR; - } - - return 1; -ERR: - free (addr); - return -1; -} - - - -static inline -int -ip_address_snprintf(char * s, size_t size, const ip_address_t * ip_address, int family) -{ - size_t len = family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; - const char * rc = inet_ntop (family, ip_address->buffer, s, len); - return rc ? strlen(rc) : -1; -} - - -static inline -int -ip_address_to_sockaddr(const ip_address_t * ip_address, - struct sockaddr *sockaddr_address, int family) -{ - struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sockaddr_address; - struct sockaddr_in *tmp4 = (struct sockaddr_in *) sockaddr_address; - - switch (family) - { - case AF_INET6: - tmp6->sin6_family = AF_INET6; - tmp6->sin6_port = DUMMY_PORT; - tmp6->sin6_scope_id = 0; - memcpy (&tmp6->sin6_addr, ip_address->buffer, IPV6_ADDR_LEN); - break; - case AF_INET: - tmp4->sin_family = AF_INET; - tmp4->sin_port = DUMMY_PORT; - memcpy (&tmp4->sin_addr, ip_address->buffer, IPV4_ADDR_LEN); - break; - default: - return -1; - } - - return 1; -} - -static inline -int -ip_address_cmp(const ip_address_t * ip1, const ip_address_t * ip2, int family) -{ - return memcmp(ip1, ip2, ip_address_len(ip1, family)); -} - -/* Parse IP Prefixes in presentation format (in bits, separated by a slash) */ -static inline -int -ip_prefix_pton (const char *ip_address_str, ip_prefix_t * ip_prefix) -{ - int pton_fd; - char *p; - char *eptr; - char *addr = strdup (ip_address_str); - - p = strchr (addr, '/'); - if (!p) - { - ip_prefix->len = 0; // until we get the ip address family - } - else - { - ip_prefix->len = strtoul (p + 1, &eptr, 10); - *p = 0; - } - - ip_prefix->family = ip_address_get_family (addr); - - switch (ip_prefix->family) - { - case AF_INET6: - if (ip_prefix->len > IPV6_ADDR_LEN_BITS) - goto ERR; - pton_fd = inet_pton (AF_INET6, addr, &ip_prefix->address.buffer); - break; - case AF_INET: - if (ip_prefix->len > IPV4_ADDR_LEN_BITS) - goto ERR; - pton_fd = inet_pton (AF_INET, addr, &ip_prefix->address.buffer); - break; - default: - goto ERR; - } - - // 0 = not in presentation format - // < 0 = other error (use perror) - if (pton_fd <= 0) - { - goto ERR; - } - - return 1; -ERR: - free (addr); - return -1; -} - -static inline -int -ip_prefix_ntop (const ip_prefix_t * ip_prefix, char *dst, size_t size) -{ - char ip_s[MAXSZ_IP_ADDRESS]; - const char * s = inet_ntop (ip_prefix->family, ip_prefix->address.buffer, ip_s, MAXSZ_IP_ADDRESS); - if (!s) - return -1; - size_t n = snprintf(dst, size, "%s/%d", ip_s, ip_prefix->len); - - return (n > 0 ? 1 : -1); -} - -#endif /* UTIL_IP_ADDRESS_H */ 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/policy.c b/ctrl/libhicnctrl/src/util/policy.c deleted file mode 100644 index 90dbc72cd..000000000 --- a/ctrl/libhicnctrl/src/util/policy.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 policy.h - * \brief Implementation of policy description - */ - -#include <stdio.h> -#include "policy.h" - -const char * policy_tag_str[] = { - #define _(x) [POLICY_TAG_ ## x] = STRINGIZE(x), - foreach_policy_tag - #undef _ -}; - -const char * policy_state_str[] = { - #define _(x) [POLICY_STATE_ ## x] = STRINGIZE(x), - foreach_policy_state - #undef _ -}; - -int -policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state) -{ - char *cur = s; - int rc; - - if (tag_state->disabled > 1) - return -1; - - rc = snprintf(cur, s + size - cur, "%s%s", (tag_state->disabled == 1) ? "!" : "", policy_state_str[tag_state->state]); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - return cur - s; -} diff --git a/ctrl/libhicnctrl/src/util/policy.h b/ctrl/libhicnctrl/src/util/policy.h deleted file mode 100644 index 231e53f73..000000000 --- a/ctrl/libhicnctrl/src/util/policy.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * 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 policy.h - * \brief Policy description - */ -#ifndef HICN_POLICY_H -#define HICN_POLICY_H - -#include <netinet/in.h> // INET*_ADDRSTRLEN -#include "token.h" - -/* POLICY TAG */ - -#define foreach_policy_tag \ - /* Interface type */ \ - _(WIRED) \ - _(WIFI) \ - _(CELLULAR) \ - /* QoS */ \ - _(BEST_EFFORT) \ - _(REALTIME) \ - _(MULTIPATH) \ - /* Security */ \ - _(TRUSTED) - -typedef enum { -#define _(x) POLICY_TAG_ ## x, -foreach_policy_tag -#undef _ - POLICY_TAG_N -} policy_tag_t; - -#define MAXSZ_POLICY_TAG_ 11 -#define MAXSZ_POLICY_TAG MAXSZ_POLICY_TAG_ + 1 - -extern const char * policy_tag_str[]; - - -/* POLICY_TAGS */ - -typedef int policy_tags_t; - -static inline -void policy_tags_add(policy_tags_t * tags, policy_tag_t tag) -{ - *tags |= (1 << tag); -} - -static inline -void policy_tags_remove(policy_tags_t * tags, policy_tag_t tag) -{ - *tags &= ~(1 << tag); -} - -static inline -int policy_tags_has(policy_tags_t tags, policy_tag_t tag) -{ - return tags & (1 << tag); -} - -#define POLICY_TAGS_EMPTY 0 - - -/* POLICY STATE */ - -/* TODO vs. weight */ - -#define foreach_policy_state \ - _(NEUTRAL) \ - _(REQUIRE) \ - _(PREFER) \ - _(AVOID) \ - _(PROHIBIT) \ - _(N) - -typedef enum { -#define _(x) POLICY_STATE_ ## x, -foreach_policy_state -#undef _ -} policy_state_t; - -#define MAXSZ_POLICY_STATE_ 8 -#define MAXSZ_POLICY_STATE MAXSZ_POLICY_STATE_ + 1 - -extern const char * policy_state_str[]; - - -/* POLICY TAG STATE */ - -typedef struct { - policy_state_t state; - uint8_t disabled; -} policy_tag_state_t; - -#define MAXSZ_POLICY_TAG_STATE_ 8 -#define MAXSZ_POLICY_TAG_STATE MAXSZ_POLICY_TAG_STATE_ + 1 - -int policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state); - - -/* INTERFACE STATS */ - -typedef struct { - float throughput; - float latency; - float loss_rate; -} interface_stats_t; - -#define INTERFACE_STATS_NONE { \ - .throughput = 0, \ - .latency = 0, \ - .loss_rate = 0, \ -} - - -/* POLICY STATS */ - -typedef struct { - interface_stats_t wired; - interface_stats_t wifi; - interface_stats_t cellular; - interface_stats_t all; -} policy_stats_t; - -#define POLICY_STATS_NONE { \ - .wired = INTERFACE_STATS_NONE, \ - .wifi = INTERFACE_STATS_NONE, \ - .cellular = INTERFACE_STATS_NONE, \ - .all = INTERFACE_STATS_NONE, \ -} - -typedef struct { - uint32_t num_packets; - uint32_t num_bytes; - uint32_t num_losses; - uint32_t latency_idle; -} interface_counters_t; - -#define INTERFACE_COUNTERS_NONE { \ - .num_packets = 0, \ - .num_bytes = 0, \ - .num_losses = 0, \ - .latency_idle = 0, \ -} - -typedef struct { - interface_counters_t wired; - interface_counters_t wifi; - interface_counters_t cellular; - interface_counters_t all; - uint64_t last_update; -} policy_counters_t; - -#define POLICY_COUNTERS_NONE (policy_counters_t) { \ - .wired = INTERFACE_COUNTERS_NONE, \ - .wifi = INTERFACE_COUNTERS_NONE, \ - .cellular = INTERFACE_COUNTERS_NONE, \ - .all = INTERFACE_COUNTERS_NONE, \ - .last_update = 0, \ -} - -/* POLICY */ - -#define APP_NAME_LEN 128 - -typedef struct { - char app_name[APP_NAME_LEN]; - policy_tag_state_t tags[POLICY_TAG_N]; - policy_stats_t stats; -} policy_t; - -static const policy_t POLICY_NONE = { - .app_name = { 0 }, - .tags = { -#define _(x) [POLICY_TAG_ ## x] = { POLICY_STATE_NEUTRAL, 0 }, -foreach_policy_tag -#undef _ - }, - .stats = POLICY_STATS_NONE, -}; - - -/* POLICY DESCRIPTION */ - -#define PFX_STRLEN 4 /* eg. /128 */ - -typedef struct { - int family; - union { - char ipv4_prefix[INET_ADDRSTRLEN + PFX_STRLEN]; - char ipv6_prefix[INET6_ADDRSTRLEN + PFX_STRLEN]; - }; - policy_t policy; -} policy_description_t; - -/* DEFAULT POLICY */ - -static const policy_description_t default_policy[] = { - { - .family = AF_INET6, - .ipv6_prefix = "a001::/16", - .policy = { - .app_name = "Webex", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_AVOID, 1 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 1 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_REQUIRE, 1 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, - { - .family = AF_INET6, - .ipv6_prefix = "b001::/16", - .policy = { - .app_name = "Video Streaming", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 0 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_PREFER, 0 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, - { - .family = AF_INET6, - .ipv6_prefix = "c001::/16", - .policy = { - .app_name = "*", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 0 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_PROHIBIT, 1 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, -}; - -#endif /* HICN_POLICY_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/ctrl/libhicnctrl/src/util/token.h b/ctrl/libhicnctrl/src/util/token.h deleted file mode 100644 index 43e0a77b2..000000000 --- a/ctrl/libhicnctrl/src/util/token.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ - -/* Token concatenation */ - -/* - * Concatenate preprocessor tokens A and B without expanding macro definitions - * (however, if invoked from a macro, macro arguments are expanded). - */ -#define PPCAT_NX(A, B) A ## B - -/* - * Concatenate preprocessor tokens A and B after macro-expanding them. - */ -#define PPCAT(A, B) PPCAT_NX(A, B) - -/* Token stringification */ - -/* - * Turn A into a string literal without expanding macro definitions - * (however, if invoked from a macro, macro arguments are expanded). - */ -#define STRINGIZE_NX(A) #A - -/* - * Turn A into a string literal after macro-expanding it. - */ -#define STRINGIZE(A) STRINGIZE_NX(A) diff --git a/ctrl/libhicnctrl/src/util/types.h b/ctrl/libhicnctrl/src/util/types.h deleted file mode 100644 index 10a0bdca0..000000000 --- a/ctrl/libhicnctrl/src/util/types.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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_TYPES -#define UTIL_TYPES - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -/* Helper for avoiding warnings about type-punning */ -#define UNION_CAST(x, destType) \ - (((union {__typeof__(x) a; destType b;})x).b) - -typedef unsigned int hash_t; - -typedef int (*cmp_t)(const void *, const void *); - -/* Enums */ - -#define IS_VALID_ENUM_TYPE(NAME, x) ((x > NAME ## _UNDEFINED) && (x < NAME ## _N)) - -#endif /* UTIL_TYPES */ |