aboutsummaryrefslogtreecommitdiffstats
path: root/ctrl/libhicnctrl
diff options
context:
space:
mode:
Diffstat (limited to 'ctrl/libhicnctrl')
-rw-r--r--ctrl/libhicnctrl/CMakeLists.txt31
-rw-r--r--[l---------]ctrl/libhicnctrl/includes/ctrl.h26
-rw-r--r--ctrl/libhicnctrl/includes/hicn/ctrl/api.h249
-rwxr-xr-xctrl/libhicnctrl/includes/hicn/ctrl/commands.h14
-rw-r--r--ctrl/libhicnctrl/includes/hicn/ctrl/face.h90
-rw-r--r--ctrl/libhicnctrl/src/CMakeLists.txt29
-rw-r--r--ctrl/libhicnctrl/src/api.c1283
-rw-r--r--ctrl/libhicnctrl/src/cli.c462
-rw-r--r--ctrl/libhicnctrl/src/face.c308
-rw-r--r--ctrl/libhicnctrl/src/util/ip_address.h316
-rw-r--r--ctrl/libhicnctrl/src/util/map.h234
-rw-r--r--ctrl/libhicnctrl/src/util/policy.c53
-rw-r--r--ctrl/libhicnctrl/src/util/policy.h266
-rw-r--r--ctrl/libhicnctrl/src/util/set.h213
-rw-r--r--ctrl/libhicnctrl/src/util/token.h40
-rw-r--r--ctrl/libhicnctrl/src/util/types.h36
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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, pdata);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, pdata);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, pdata);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, NULL);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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), &params, pdata);
+ return hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), &params, 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 */