aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt11
-rw-r--r--apps/CMakeLists.txt2
-rw-r--r--cmake/Modules/BuildMacros.cmake18
-rwxr-xr-xcmake/Modules/FindLibhicnctrl.cmake6
-rw-r--r--cmake/Modules/Packager.cmake49
-rw-r--r--cmake/Modules/ServiceScript.cmake42
-rw-r--r--ctrl/facemgr/CMakeLists.txt35
-rw-r--r--ctrl/facemgr/README.md10
-rw-r--r--ctrl/facemgr/cmake/Modules/Packaging.cmake12
-rw-r--r--ctrl/facemgr/doc/interface.md358
-rw-r--r--ctrl/facemgr/examples/facemgr.conf217
-rwxr-xr-xctrl/facemgr/examples/run-bonjour.sh178
-rw-r--r--ctrl/facemgr/examples/updowncli/Makefile25
-rw-r--r--ctrl/facemgr/examples/updowncli/updowncli.c57
-rw-r--r--ctrl/facemgr/examples/updownsrv/Makefile25
-rw-r--r--ctrl/facemgr/examples/updownsrv/updownsrv.c237
-rw-r--r--ctrl/facemgr/includes/CMakeLists.txt46
-rw-r--r--ctrl/facemgr/includes/facemgr.h (renamed from ctrl/facemgr/src/netdevice.c)18
-rw-r--r--ctrl/facemgr/includes/hicn/android_utility/android_utility.h48
-rw-r--r--ctrl/facemgr/includes/hicn/facemgr.h (renamed from ctrl/facemgr/src/interface_map.h)15
-rw-r--r--ctrl/facemgr/includes/hicn/facemgr/api.h93
-rw-r--r--ctrl/facemgr/includes/hicn/facemgr/cfg.h197
-rw-r--r--ctrl/facemgr/includes/hicn/facemgr/loop.h90
-rw-r--r--ctrl/facemgr/includes/hicn/util/log.h (renamed from ctrl/facemgr/src/util/log.h)0
-rw-r--r--ctrl/facemgr/src/CMakeLists.txt95
-rw-r--r--ctrl/facemgr/src/api.c1504
-rw-r--r--ctrl/facemgr/src/cfg.c1040
-rw-r--r--ctrl/facemgr/src/cfg_file.c548
-rw-r--r--ctrl/facemgr/src/cfg_file.h42
-rw-r--r--ctrl/facemgr/src/common.h38
-rw-r--r--ctrl/facemgr/src/event.c39
-rw-r--r--ctrl/facemgr/src/event.h59
-rw-r--r--ctrl/facemgr/src/face.c262
-rw-r--r--ctrl/facemgr/src/face.h177
-rw-r--r--ctrl/facemgr/src/face_rules.c21
-rw-r--r--ctrl/facemgr/src/facelet.c980
-rw-r--r--ctrl/facemgr/src/facelet.h192
-rw-r--r--ctrl/facemgr/src/facemgr.c298
-rw-r--r--ctrl/facemgr/src/facemgr.h77
-rw-r--r--ctrl/facemgr/src/interface.c116
-rw-r--r--ctrl/facemgr/src/interface.h84
-rw-r--r--ctrl/facemgr/src/interface_map.c21
-rw-r--r--ctrl/facemgr/src/interface_ops_map.c21
-rw-r--r--ctrl/facemgr/src/interfaces/CMakeLists.txt11
-rw-r--r--ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt27
-rw-r--r--ctrl/facemgr/src/interfaces/android_utility/android_utility.c138
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt32
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/bonjour.c410
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/bonjour.h35
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE24
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/mdns/README.md9
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c192
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h879
-rw-r--r--ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt1
-rw-r--r--ctrl/facemgr/src/interfaces/dummy/dummy.c98
-rw-r--r--ctrl/facemgr/src/interfaces/dummy/dummy.h (renamed from ctrl/facemgr/src/interface_ops_map.h)22
-rw-r--r--ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c403
-rw-r--r--ctrl/facemgr/src/interfaces/netlink/netlink.c491
-rw-r--r--ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt1
-rw-r--r--ctrl/facemgr/src/interfaces/network_framework/network_framework.c296
-rw-r--r--ctrl/facemgr/src/interfaces/network_framework/network_framework.h (renamed from ctrl/facemgr/src/face_cache.c)11
-rw-r--r--ctrl/facemgr/src/interfaces/updown/CMakeLists.txt31
-rw-r--r--ctrl/facemgr/src/interfaces/updown/updown.c138
-rw-r--r--ctrl/facemgr/src/loop_dispatcher.c75
-rw-r--r--ctrl/facemgr/src/loop_libevent.c425
-rw-r--r--ctrl/facemgr/src/main.c297
-rw-r--r--ctrl/facemgr/src/netdevice.h52
-rw-r--r--ctrl/facemgr/src/util/log.c60
-rw-r--r--ctrl/facemgr/src/util/map.h139
-rw-r--r--ctrl/facemgr/src/util/policy.c59
-rw-r--r--ctrl/facemgr/src/util/set.h134
-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
-rw-r--r--ctrl/sysrepo-plugins/README.md200
-rw-r--r--hicn-light/CMakeLists.txt13
-rw-r--r--hicn-light/src/hicn/CMakeLists.txt5
-rw-r--r--hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c1
-rw-r--r--hicn-light/src/hicn/config/CMakeLists.txt2
-rw-r--r--hicn-light/src/hicn/config/configuration.c155
-rw-r--r--hicn-light/src/hicn/config/configurationListeners.c199
-rw-r--r--hicn-light/src/hicn/config/controlAddConnection.c22
-rw-r--r--hicn-light/src/hicn/config/controlAddListener.c57
-rw-r--r--hicn-light/src/hicn/config/controlListConnections.c15
-rw-r--r--hicn-light/src/hicn/config/controlListListeners.c23
-rw-r--r--hicn-light/src/hicn/config/controlRemove.c7
-rw-r--r--hicn-light/src/hicn/config/controlRemoveListener.c115
-rw-r--r--hicn-light/src/hicn/config/controlRemoveListener.h (renamed from ctrl/facemgr/src/face_rules.h)26
-rw-r--r--hicn-light/src/hicn/config/controlUpdateConnection.c2
-rw-r--r--hicn-light/src/hicn/config/symbolicNameTable.c38
-rw-r--r--hicn-light/src/hicn/core/connection.c11
-rw-r--r--hicn-light/src/hicn/core/connection.h4
-rw-r--r--hicn-light/src/hicn/core/mapMe.c6
-rw-r--r--hicn-light/src/hicn/core/nameBitvector.c14
-rw-r--r--hicn-light/src/hicn/core/nameBitvector.h3
-rw-r--r--hicn-light/src/hicn/io/hicnConnection.c16
-rw-r--r--hicn-light/src/hicn/io/hicnConnection.h2
-rw-r--r--hicn-light/src/hicn/io/hicnListener.c222
-rw-r--r--hicn-light/src/hicn/io/hicnTunnel.c2
-rw-r--r--hicn-light/src/hicn/io/ioOperations.c6
-rw-r--r--hicn-light/src/hicn/io/ioOperations.h11
-rw-r--r--hicn-light/src/hicn/io/listener.h18
-rw-r--r--hicn-light/src/hicn/io/listenerSet.c50
-rw-r--r--hicn-light/src/hicn/io/listenerSet.h51
-rw-r--r--hicn-light/src/hicn/io/streamConnection.c16
-rw-r--r--hicn-light/src/hicn/io/tcpListener.c37
-rw-r--r--hicn-light/src/hicn/io/tcpListener.h8
-rw-r--r--hicn-light/src/hicn/io/udpConnection.c17
-rw-r--r--hicn-light/src/hicn/io/udpConnection.h2
-rw-r--r--hicn-light/src/hicn/io/udpListener.c39
-rw-r--r--hicn-light/src/hicn/io/udpListener.h11
-rw-r--r--hicn-light/src/hicn/io/udpTunnel.c2
-rw-r--r--hicn-light/src/hicn/processor/fib.c2
-rw-r--r--hicn-light/src/hicn/processor/fibEntry.c21
-rw-r--r--hicn-light/src/hicn/processor/messageProcessor.c21
-rw-r--r--hicn-light/src/hicn/socket/api.c34
-rw-r--r--hicn-light/src/hicn/socket/api.h6
-rw-r--r--hicn-light/src/hicn/socket/ops.h18
-rw-r--r--hicn-light/src/hicn/socket/ops_linux.c107
-rw-r--r--hicn-light/src/hicn/strategies/loadBalancer.c11
-rw-r--r--hicn-light/src/hicn/utils/CMakeLists.txt2
-rw-r--r--hicn-light/src/hicn/utils/commands.h62
-rw-r--r--hicn-light/src/hicn/utils/policy.h232
-rw-r--r--hicn-light/src/hicn/utils/utils.c1
-rw-r--r--hicn-plugin/CMakeLists.txt43
-rw-r--r--hicn-plugin/scripts/post3
-rw-r--r--hicn-plugin/scripts/postinst3
-rw-r--r--hicn-plugin/src/data_fwd_node.c5
-rw-r--r--hicn-plugin/src/data_pcslookup_node.c79
-rw-r--r--hicn-plugin/src/faces/app/face_prod.c4
-rw-r--r--hicn-plugin/src/faces/ip/dpo_ip.c106
-rw-r--r--hicn-plugin/src/faces/ip/dpo_ip.h117
-rw-r--r--hicn-plugin/src/faces/ip/face_ip.c341
-rw-r--r--hicn-plugin/src/faces/ip/face_ip.h62
-rw-r--r--hicn-plugin/src/faces/ip/face_ip_cli.c4
-rw-r--r--hicn-plugin/src/faces/ip/face_ip_node.c3
-rw-r--r--hicn-plugin/src/hicn.h5
-rw-r--r--hicn-plugin/src/hicn_api.c2
-rw-r--r--hicn-plugin/src/mgmt.c4
-rw-r--r--hicn-plugin/src/pcs.h30
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/includes/CMakeLists.txt55
-rw-r--r--lib/includes/hicn/base.h (renamed from lib/src/base.h)0
-rw-r--r--lib/includes/hicn/common.h (renamed from lib/src/common.h)0
-rw-r--r--lib/includes/hicn/compat.h (renamed from lib/src/compat.h)12
-rw-r--r--lib/includes/hicn/error.h (renamed from lib/src/error.h)0
-rw-r--r--lib/includes/hicn/header.h (renamed from lib/src/header.h)0
-rw-r--r--lib/includes/hicn/hicn.h (renamed from lib/src/hicn.h)0
-rw-r--r--lib/includes/hicn/mapme.h (renamed from lib/src/mapme.h)0
-rw-r--r--lib/includes/hicn/name.h (renamed from lib/src/name.h)60
-rw-r--r--lib/includes/hicn/ops.h (renamed from lib/src/ops.h)0
-rw-r--r--lib/includes/hicn/policy.h (renamed from ctrl/facemgr/src/util/policy.h)10
-rw-r--r--lib/includes/hicn/protocol.h (renamed from lib/src/protocol.h)0
-rw-r--r--lib/includes/hicn/protocol/ah.h (renamed from lib/src/protocol/ah.h)0
-rw-r--r--lib/includes/hicn/protocol/icmp.h (renamed from lib/src/protocol/icmp.h)0
-rw-r--r--lib/includes/hicn/protocol/icmprd.h (renamed from lib/src/protocol/icmprd.h)0
-rw-r--r--lib/includes/hicn/protocol/ipv4.h (renamed from lib/src/protocol/ipv4.h)0
-rw-r--r--lib/includes/hicn/protocol/ipv6.h (renamed from lib/src/protocol/ipv6.h)0
-rw-r--r--lib/includes/hicn/protocol/tcp.h (renamed from lib/src/protocol/tcp.h)0
-rw-r--r--lib/includes/hicn/protocol/udp.h (renamed from lib/src/protocol/udp.h)0
-rw-r--r--lib/includes/hicn/util/ip_address.h160
-rw-r--r--lib/includes/hicn/util/token.h (renamed from ctrl/facemgr/src/util/token.h)0
-rw-r--r--lib/includes/hicn/util/types.h (renamed from ctrl/facemgr/src/util/types.h)2
-rw-r--r--lib/src/CMakeLists.txt63
-rw-r--r--lib/src/common.c3
-rw-r--r--lib/src/compat.c50
-rw-r--r--lib/src/error.c2
-rw-r--r--lib/src/mapme.c10
-rw-r--r--lib/src/name.c162
-rw-r--r--lib/src/ops.c4
-rw-r--r--lib/src/policy.c (renamed from hicn-light/src/hicn/utils/policy.c)2
-rw-r--r--lib/src/protocol/ah.c10
-rw-r--r--lib/src/protocol/icmp.c6
-rw-r--r--lib/src/protocol/ipv4.c10
-rw-r--r--lib/src/protocol/ipv6.c6
-rw-r--r--lib/src/protocol/tcp.c6
-rw-r--r--lib/src/util/ip_address.c (renamed from ctrl/facemgr/src/util/ip_address.h)246
-rw-r--r--libtransport/CMakeLists.txt4
-rw-r--r--libtransport/src/hicn/transport/CMakeLists.txt6
-rw-r--r--libtransport/src/hicn/transport/config.h.in4
-rw-r--r--libtransport/src/hicn/transport/core/content_object.cc7
-rw-r--r--libtransport/src/hicn/transport/core/content_object.h4
-rw-r--r--libtransport/src/hicn/transport/core/facade.h2
-rw-r--r--libtransport/src/hicn/transport/core/forwarder_interface.h6
-rw-r--r--libtransport/src/hicn/transport/core/hicn_binary_api.c22
-rw-r--r--libtransport/src/hicn/transport/core/hicn_binary_api.h15
-rw-r--r--libtransport/src/hicn/transport/core/interest.cc8
-rw-r--r--libtransport/src/hicn/transport/core/interest.h4
-rw-r--r--libtransport/src/hicn/transport/core/name.cc6
-rw-r--r--libtransport/src/hicn/transport/core/name.h2
-rw-r--r--libtransport/src/hicn/transport/core/packet.h4
-rw-r--r--libtransport/src/hicn/transport/core/portal.h12
-rw-r--r--libtransport/src/hicn/transport/core/prefix.cc30
-rw-r--r--libtransport/src/hicn/transport/core/prefix.h6
-rw-r--r--libtransport/src/hicn/transport/core/raw_socket_interface.cc2
-rw-r--r--libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc40
-rw-r--r--libtransport/src/hicn/transport/interfaces/CMakeLists.txt1
-rw-r--r--libtransport/src/hicn/transport/interfaces/callbacks.cc (renamed from ctrl/facemgr/src/face_cache.h)14
-rw-r--r--libtransport/src/hicn/transport/interfaces/callbacks.h4
-rw-r--r--libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc256
-rw-r--r--libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h34
-rw-r--r--libtransport/src/hicn/transport/interfaces/socket.h2
-rw-r--r--libtransport/src/hicn/transport/interfaces/socket_consumer.cc717
-rw-r--r--libtransport/src/hicn/transport/interfaces/socket_consumer.h673
-rw-r--r--libtransport/src/hicn/transport/interfaces/socket_options_default_values.h2
-rw-r--r--libtransport/src/hicn/transport/interfaces/socket_options_keys.h31
-rw-r--r--libtransport/src/hicn/transport/interfaces/socket_producer.cc659
-rw-r--r--libtransport/src/hicn/transport/interfaces/socket_producer.h508
-rw-r--r--libtransport/src/hicn/transport/protocols/protocol.cc15
-rw-r--r--libtransport/src/hicn/transport/protocols/protocol.h6
-rw-r--r--libtransport/src/hicn/transport/protocols/raaqm.cc40
-rw-r--r--libtransport/src/hicn/transport/protocols/rtc.cc376
-rw-r--r--libtransport/src/hicn/transport/protocols/rtc.h16
-rw-r--r--libtransport/src/hicn/transport/utils/content_store.cc7
-rw-r--r--libtransport/src/hicn/transport/utils/content_store.h5
-rw-r--r--utils/CMakeLists.txt2
-rw-r--r--utils/src/hiperf.cc35
230 files changed, 16301 insertions, 6465 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c0d689331..5977b7955 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,10 +72,11 @@ set(HICN_PLUGIN hicn-plugin)
set(HICN_EXTRA_PLUGIN hicn-extra-plugin)
set(LIBTRANSPORT hicntransport)
set(HICN_UTILS hicn-utils)
-set(HICN_CTRL hicn-ctrl)
-set(LIBHICN_CTRL hicn-ctrl)
+set(HICNCTRL hicnctrl)
+set(LIBHICNCTRL hicnctrl)
set(HICN_APPS hicn-apps)
-set(FACE_MGR facemgr)
+set(LIBFACEMGR facemgr)
+set(FACEMGR facemgr)
set(LIBMEMIF memif)
if (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
@@ -102,12 +103,12 @@ endif()
## Libraries targets
set(LIBHICN_SHARED ${LIBHICN}.shared)
set(LIBTRANSPORT_SHARED ${LIBTRANSPORT}.shared)
-set(LIBHICN_CTRL_SHARED ${LIBHICN_CTRL}.shared)
+set(LIBHICNCTRL_SHARED ${LIBHICNCTRL}.shared)
set(LIBMEMIF_SHARED ${LIBMEMIF}.shared)
set(LIBHICN_STATIC ${LIBHICN}.static)
set(LIBTRANSPORT_STATIC ${LIBTRANSPORT}.static)
-set(LIBHICN_CTRL_STATIC ${LIBHICN_CTRL}.static)
+set(LIBHICNCTRL_STATIC ${LIBHICNCTRL}.static)
set(LIBMEMIF_STATIC ${LIBMEMIF}.static)
## HEADER FILES
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index 933097892..e9f1e07de 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -31,7 +31,7 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
include_directories(${LIBTRANSPORT_INCLUDE_DIRS})
set(HICN_APPS hicn-apps)
else()
- if (ANDROID_API)
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
set(LIBTRANSPORT_LIBRARIES ${LIBTRANSPORT_STATIC})
diff --git a/cmake/Modules/BuildMacros.cmake b/cmake/Modules/BuildMacros.cmake
index 63d54502b..8b591d05b 100644
--- a/cmake/Modules/BuildMacros.cmake
+++ b/cmake/Modules/BuildMacros.cmake
@@ -25,12 +25,13 @@ macro(build_executable exec)
${ARGN}
)
- add_executable(${exec} ${ARG_SOURCES})
+ add_executable(${exec}-bin ${ARG_SOURCES})
set(BUILD_ROOT ${CMAKE_BINARY_DIR}/build-root)
- set_target_properties(${exec}
+ set_target_properties(${exec}-bin
PROPERTIES
+ OUTPUT_NAME ${exec}
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
INSTALL_RPATH_USE_LINK_PATH TRUE
ARCHIVE_OUTPUT_DIRECTORY "${BUILD_ROOT}/lib"
@@ -39,19 +40,19 @@ macro(build_executable exec)
)
if(ARG_LINK_LIBRARIES)
- target_link_libraries(${exec} ${ARG_LINK_LIBRARIES})
+ target_link_libraries(${exec}-bin ${ARG_LINK_LIBRARIES})
endif()
if(ARG_DEPENDS)
- add_dependencies(${exec} ${ARG_DEPENDS})
+ add_dependencies(${exec}-bin ${ARG_DEPENDS})
endif()
if(ARG_DEFINITIONS)
- target_compile_definitions(${exec} PRIVATE ${ARG_DEFINITIONS})
+ target_compile_definitions(${exec}-bin PRIVATE ${ARG_DEFINITIONS})
endif()
if(ARG_INCLUDE_DIRS)
- target_include_directories(${exec} BEFORE PUBLIC
+ target_include_directories(${exec}-bin BEFORE PUBLIC
${ARG_INCLUDE_DIRS}
${PROJECT_BINARY_DIR}
)
@@ -59,7 +60,7 @@ macro(build_executable exec)
if(NOT ARG_NO_INSTALL)
install(
- TARGETS ${exec}
+ TARGETS ${exec}-bin
RUNTIME
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT ${ARG_COMPONENT}
@@ -178,6 +179,9 @@ macro(build_library lib)
if ("${dir}" STREQUAL includes)
set(dir "")
endif()
+ if ("${dir}" STREQUAL ${ARG_INSTALL_ROOT_DIR})
+ set(dir "")
+ endif()
else()
set(dir "")
endif()
diff --git a/cmake/Modules/FindLibhicnctrl.cmake b/cmake/Modules/FindLibhicnctrl.cmake
index 1399b41bf..7c20420b4 100755
--- a/cmake/Modules/FindLibhicnctrl.cmake
+++ b/cmake/Modules/FindLibhicnctrl.cmake
@@ -31,14 +31,14 @@ find_path(LIBHICNCTRL_INCLUDE_DIR hicn/ctrl.h
DOC "Find the hICN control include"
)
-find_library(LIBHICNCTRL_LIBRARY NAMES hicn-ctrl
+find_library(LIBHICNCTRL_LIBRARY NAMES hicnctrl
HINTS ${HICN_SEARCH_PATH_LIST}
PATH_SUFFIXES lib
DOC "Find the hicn control library"
)
-set(LIBHICNCTRL_LIBRARIES ${HICNCTRL_LIBRARY})
-set(LIBHICNCTRL_INCLUDE_DIRS ${HICNCTRL_INCLUDE_DIR})
+set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_LIBRARY})
+set(LIBHICNCTRL_INCLUDE_DIRS ${LIBHICNCTRL_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(hicnctrl DEFAULT_MSG
diff --git a/cmake/Modules/Packager.cmake b/cmake/Modules/Packager.cmake
index 898e40bcb..6f77fd3a8 100644
--- a/cmake/Modules/Packager.cmake
+++ b/cmake/Modules/Packager.cmake
@@ -33,10 +33,35 @@ function(get_next_version VERSION NEXT_VERSION)
math(EXPR major "${major} + 1")
endif()
- set(minor "0${minor}")
+ if (minor LESS 10)
+ set(minor "0${minor}")
+ endif()
+
set(${NEXT_VERSION} "${major}.${minor}" PARENT_SCOPE)
endfunction()
+macro(extract_version)
+ # Extract version from git
+ execute_process(
+ COMMAND git describe --long --match v*
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ OUTPUT_VARIABLE VER
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ if (NOT VER)
+ set(VER "v1.0-0-gcafe")
+ endif()
+
+ message(STATUS "Git describe output: ${VER}")
+
+ string(REGEX REPLACE "v([0-9]+).([0-9]+)-([0-9]+)-(g[0-9a-f]+)" "\\1;\\2;\\3;\\4" VER ${VER})
+ list(GET VER 0 VERSION_MAJOR)
+ list(GET VER 1 VERSION_MINOR)
+ list(GET VER 2 VERSION_REVISION)
+ list(GET VER 3 COMMIT_NAME)
+endmacro(extract_version)
+
macro(make_packages)
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
# parse /etc/os-release
@@ -49,23 +74,17 @@ macro(make_packages)
set(OS_${_name} ${_value})
endforeach()
- # extract version from git
- execute_process(
- COMMAND git describe --long --match v*
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- OUTPUT_VARIABLE VER
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
+ extract_version()
- if (NOT VER)
- set(VER "v1.0-1-gcafe")
- endif()
+ message(STATUS "Version major: ${VERSION_MAJOR}")
+ message(STATUS "Version minor: ${VERSION_MINOR}")
+ message(STATUS "Revision: ${VERSION_REVISION}")
+ message(STATUS "Commit hash: ${COMMIT_NAME}")
- string(REGEX REPLACE "v(.*)-([0-9]+)-(g[0-9a-f]+)" "\\1;\\2;\\3" VER ${VER})
- list(GET VER 0 tag)
+ set(tag "${VERSION_MAJOR}.${VERSION_MINOR}")
string(REPLACE "-" "~" tag ${tag})
- list(GET VER 1 commit_num)
- list(GET VER 2 commit_name)
+ set(commit_num ${VERSION_REVISION})
+ set(commit_name ${COMMIT_NAME})
if (NOT DEFINED ENV{BUILD_NUMBER})
set(bld "b1")
diff --git a/cmake/Modules/ServiceScript.cmake b/cmake/Modules/ServiceScript.cmake
new file mode 100644
index 000000000..110aa816b
--- /dev/null
+++ b/cmake/Modules/ServiceScript.cmake
@@ -0,0 +1,42 @@
+# Copyright (c) 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.
+
+########################################
+#
+# Find the LongBow libraries and includes
+# This module sets:
+# SYSTEMD_FOUND: True if Systemd was found
+# SYSTEMD_SERVICES_INSTALL_DIR: The Systemd install directory
+
+set(SYSTEMD_SERVICE_FOLDER "/lib/systemd/system")
+
+macro(install_service_script script)
+cmake_parse_arguments(ARG
+ ""
+ "COMPONENT"
+ ""
+ ${ARGN}
+)
+
+ # Install service file only if
+ # 1) We are on a linux system
+ # 2) The installation prefix is /usr
+
+ if (NOT ARG_COMPONENT)
+ set(ARG_COMPONENT hicn)
+ endif()
+
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ${CMAKE_INSTALL_PREFIX} STREQUAL "/usr")
+ install (FILES ${script} DESTINATION ${SYSTEMD_SERVICE_FOLDER} COMPONENT ${ARG_COMPONENT})
+ endif()
+endmacro(install_service_script) \ No newline at end of file
diff --git a/ctrl/facemgr/CMakeLists.txt b/ctrl/facemgr/CMakeLists.txt
index f688dd2ca..377773c2d 100644
--- a/ctrl/facemgr/CMakeLists.txt
+++ b/ctrl/facemgr/CMakeLists.txt
@@ -20,6 +20,22 @@ endif()
project(facemgr)
+option(WITH_THREAD "Run library as thread" OFF)
+option(WITH_EXAMPLE_DUMMY "Compile dummy example interface" OFF)
+option(WITH_EXAMPLE_UPDOWN "Compile updown example interface" OFF)
+
+if(WITH_THREAD)
+ message("Building with thread support")
+endif()
+
+if(WITH_EXAMPLE_DUMMY)
+ message("Building with 'dummy' example interface")
+endif()
+
+if(WITH_EXAMPLE_UPDOWN)
+ message("Building with 'updown' example interface")
+endif()
+
if (NOT CMAKE_BUILD_TYPE)
message(STATUS "${PROJECT_NAME}: No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release")
@@ -42,22 +58,29 @@ find_package_wrapper(Config REQUIRED)
find_package_wrapper(LibEvent REQUIRED)
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+ find_package_wrapper(Libhicn REQUIRED)
find_package_wrapper(Libhicnctrl REQUIRED)
- set(FACE_MGR facemgr)
+ set(FACEMGR facemgr)
+ set(LIBFACEMGR facemgr)
else()
- if (ANDROID_API)
- set(LIBHICNCTRL_LIBRARIES ${LIBHICN_CTRL_STATIC})
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+ set(HICN_LIBRARIES ${LIBHICN_STATIC})
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_STATIC})
list(APPEND DEPENDENCIES
- ${LIBHICN_CTRL_STATIC}
+ ${LIBHICN_STATIC}
+ ${LIBHICNCTRL_STATIC}
)
else ()
- set(LIBHICNCTRL_LIBRARIES ${LIBHICN_CTRL_SHARED})
+ set(HICN_LIBRARIES ${LIBHICN_SHARED})
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_SHARED})
list(APPEND DEPENDENCIES
- ${LIBHICN_CTRL_SHARED}
+ ${LIBHICN_SHARED}
+ ${LIBHICNCTRL_SHARED}
)
endif ()
endif()
+add_subdirectory(includes)
add_subdirectory(src)
include(Packaging)
diff --git a/ctrl/facemgr/README.md b/ctrl/facemgr/README.md
index e1a1beb4f..0cad9bc11 100644
--- a/ctrl/facemgr/README.md
+++ b/ctrl/facemgr/README.md
@@ -1 +1,11 @@
# hICN Face Manager
+
+The bonjour interfaces uses SO_BINDTODEVICE to be able to send bonjour queries
+to the right interfaces. As such facemgr has to be run as root, or with the
+CAP_NET_RAW capability.
+
+```
+sudo getcap build-root/bin/facemgr
+sudo setcap cap_net_raw+ep build-root/bin/facemgr
+sudo getcap build-root/bin/facemgr
+```
diff --git a/ctrl/facemgr/cmake/Modules/Packaging.cmake b/ctrl/facemgr/cmake/Modules/Packaging.cmake
index 97a1b6260..3a7e5a85c 100644
--- a/ctrl/facemgr/cmake/Modules/Packaging.cmake
+++ b/ctrl/facemgr/cmake/Modules/Packaging.cmake
@@ -15,17 +15,17 @@
# Packages section
######################
-set(${FACE_MGR}_DESCRIPTION
- "hICN face manager, lib${LIBHICN_CTRL}"
+set(${FACEMGR}_DESCRIPTION
+ "hICN face manager, lib${LIBHICNCTRL}"
CACHE STRING "Description for deb/rpm package."
)
-set(${FACE_MGR}_DEB_DEPENDENCIES
- "libconfig9, libevent-dev, lib${LIBHICN_CTRL} (>= stable_version)"
+set(${FACEMGR}_DEB_DEPENDENCIES
+ "libconfig9, libevent-dev, lib${LIBHICNCTRL} (>= stable_version)"
CACHE STRING "Dependencies for deb/rpm package."
)
-set(${FACE_MGR}_RPM_DEPENDENCIES
- "libconfig, libevent-devel, lib${LIBHICN_CTRL} >= stable_version"
+set(${FACEMGR}_RPM_DEPENDENCIES
+ "libconfig, libevent-devel, lib${LIBHICNCTRL} >= stable_version"
CACHE STRING "Dependencies for deb/rpm package."
)
diff --git a/ctrl/facemgr/doc/interface.md b/ctrl/facemgr/doc/interface.md
new file mode 100644
index 000000000..c7168ef23
--- /dev/null
+++ b/ctrl/facemgr/doc/interface.md
@@ -0,0 +1,358 @@
+# Face manager : Interfaces
+
+## Overview
+
+The architecture of the face manager is built around the concept of interfaces,
+which allows for a modular and extensible deployment.
+
+Interfaces are used to implement in isolation various sources of information
+which help with the construction of faces (such as network interface and service
+discovery), and with handling the heterogeneity of host platforms.
+
+
+### Platform and supported interfaces
+
+Currently, Android, Linux and MacOS are supported through the following
+interfaces:
+
+- hicn-light [Linux, Android, MacOS, iOS]
+ An interface to the hicn-light forwarder, and more specifically to the Face
+ Table and FIB data structures. This component is responsible to effectively
+ create, update and delete faces in the forwarder, based on the information
+ provided by third party interfaces, plus adding default routes for each of
+ the newly created face. The communication with the forwarder is based on the
+ hicn control library (`libhicnctrl`).
+
+- netlink [Linux, Android]
+ The default interface on Linux systems (including Android) to communicate
+ with the kernel and receive information from various sources, including link
+ and address information (both IPv4 and IPv6) about network interfaces.
+
+- android\_utility [Android only]
+ Information available through Netlink is limited with respect to cellular
+ interfaces. This component allows querying the Android layer through SDK
+ functions to get the type of a given network interface (Wired, WiFi or
+ Cellular).
+
+- bonjour [Linux, Android]
+ This component performs remote service discovery based on the bonjour
+ protocol to discover a remote hICN forwarder that might be needed to
+ establish overlay faces.
+
+- network\_framework [MacOS, iOS]
+
+ This component uses the recommended Network framework on Apple devices,
+ which provided all required information to query faces in a unified API:
+ link and address information, interface types, and bonjour service
+ discovery.
+
+
+### Architectural overview
+
+#### Facelets
+
+TODO:
+- Key attributes (netdevice and protocol family)
+- Facelet API
+
+#### Events
+
+TODO
+
+#### Facelet cache & event scheduling
+
+TODO:
+ - Facelet cache
+ - Joins
+ - How synchronization work
+
+### Interface API
+
+TODO
+
+## Developing a new interface
+
+### Dummy template
+
+The face manager source code includes a template that can be used as a skeleton
+to develop new faces. It can be found in `src/interface/dummy/dummy.{h,c}`. Both
+include guard and specific interface functions are prefixed by a (short)
+identifier which acts as a namespace for interface specific code (in our case
+the string 'dummy\_').
+
+Registration and instanciation of the different interfaces is currently done at
+compile time in the file `src/api.c`, and the appropriate hooks to use the dummy
+interface are avaialble in the code between `#if 0/#endif` tags.
+
+#### Interface template header; configuration parameters
+
+All interfaces have a standard interface defined in `src/interface.{h,c}`, and
+as such the header file is only used to specify the configuration parameters of
+the interface, if any.
+
+In the template, these configuration options are empty:
+```
+/*
+ * Configuration data
+ */
+typedef struct {
+ /* ... */
+} dummy_cfg_t;
+```
+
+#### Overview of the interface template
+
+The file starts with useful includes:
+- the global include `<hicn/facemgr.h>` : this provides public facing elements
+ of the face manager, such the standard definition of faces (`face_t` from
+ `libhicnctrl`), helper classes (such as `ip_address_t` from `libhicn`), etc.
+- common.h
+- facelet.h : facelets are the basic unit of communication between the face
+manager and the different interfaces. They are used to construct the faces
+incrementally.
+- interface.h : the parent class of interfaces, such as the current dummy
+interface.
+
+Each interface can hold a pointer to an internal data structure, which is
+declared as follows:
+```
+/*
+ * Internal data
+ */
+typedef struct {
+ /* The configuration data will likely be allocated on the stack (or should
+ * be freed) by the caller, we recommend to make a copy of this data.
+ * This copy can further be altered with default values.
+ */
+ dummy_cfg_t cfg;
+
+ /* ... */
+
+ int fd; /* Sample internal data: file descriptor */
+} dummy_data_t;
+```
+
+We find here a copy of the configuration settings (which allows the called to
+instanciate the structure on the stack), as well as a file descriptor
+(assuming most interfaces will react on events on a file descriptor).
+
+The rest of the file consists in the implementation of the interface, in
+particular the different function required by the registration of a new
+interface to the system. They are grouped as part of the `interface_ops_t` data
+structure declared at the end of the file:
+
+```
+interface\_ops\_t dummy\_ops = {
+ .type = "dummy",
+ .initialize = dummy_initialize,
+ .finalize = dummy_finalize,
+ .callback = dummy_callback,
+ .on_event = dummy_on_event,
+};
+```
+
+The structure itself is declared and documented in `src/interface.h`
+```
+/**
+ * \brief Interface operations
+ */
+typedef struct {
+ /** The type given to the interfaces */
+ char * type;
+ /* Constructor */
+ int (*initialize)(struct interface\_s * interface, void * cfg);
+ /* Destructor */
+ int (*finalize)(struct interface_s * interface);
+ /* Callback upon file descriptor event (iif previously registered) */
+ int (*callback)(struct interface_s * interface);
+ /* Callback upon facelet events coming from the face manager */
+ int (*on_event)(struct interface_s * interface, const struct facelet_s * facelet);
+} interface\_ops\_t;
+```
+
+Such an interface has to be registered first, then one (or multiple) instance(s)
+can be created (see `src/interface.c` for the function prototypes, and
+`src/api.c` for their usage).
+
+- interface registration:
+
+```
+extern interface\_ops\_t dummy\_ops;
+
+/* [...] */
+
+rc = interface\_register(&dummy\_ops);
+if (rc < 0)
+ goto ERR_REGISTER;
+```
+
+- interface instanciation:
+
+```
+#include "interfaces/dummy/dummy.h"
+
+/* [...] */
+
+rc = facemgr_create_interface(facemgr, "dummy0", "dummy", &facemgr->dummy);
+if (rc < 0) {
+ ERROR("Error creating 'Dummy' interface\n");
+ goto ERR_DUMMY_CREATE;
+}
+```
+
+#### Implementation of the interface API
+
+We now quickly go other the different functions, but their usage will be better
+understood through the hands-on example treated in the following section.
+
+In the template, the constructor is the most involved as it need to:
+
+- initialize the internal data structure:
+
+```
+ dummy_data_t * data = malloc(sizeof(dummy_data_t));
+ if (!data)
+ goto ERR_MALLOC;
+ interface->data = data;
+```
+
+- process configuration parameters, eventually setting some default values:
+
+```
+ /* Use default values for unspecified configuration parameters */
+ if (cfg) {
+ data->cfg = *(dummy_cfg_t *)cfg;
+ } else {
+ memset(&data->cfg, 0, sizeof(data->cfg));
+ }
+```
+
+- open an eventually required file descriptor
+
+For the sake of simplicity, the current API only supports a single file
+descriptor per-interface, and it has to be created in the constructor, and
+set as the return value so as to be registered by the system, and added to the
+event loop for read events. A return value of 0 means the interface does not
+require any file descriptor. As usual, a negative return value indicates an
+error.
+
+```
+ data->fd = 0;
+
+ /* ... */
+
+ /*
+ * We should return a negative value in case of error, and a positive value
+ * otherwise:
+ * - a file descriptor (>0) will be added to the event loop; or
+ * - 0 if we don't use any file descriptor
+ */
+ return data->fd;
+```
+
+While support for multiple file descriptors might be added in the future, an
+alternative short-term implementation might consider the instanciation of
+multiple interface, as is done for Bonjour in the current codebase, in
+`src/api.c`.
+
+Data reception on the file descriptor will get the callback function called, in
+our case `dummy_callback`. Finally, the destructor `dummy_finalize` should close
+an eventual open file descriptor.
+
+In order to retrieve the internal data structure, that should in particular
+store such a file descriptor, all other function but the constructor can
+dereference it from the interface pointer they receive as parameter:
+
+```
+dummy\_data\_t * data = (dummy\_data\_t*)interface->data;
+```
+
+#### Raising and receiving events
+
+An interface will receive events in the form of a facelet through the `*_on_event`
+function. It can then use the facelet API we have describe above to read
+information about the face.
+
+As this information is declared const, the interface can either create a new
+facelet (identified by the same netdevice and protocol family), or eventually
+clone it.
+
+The facelet event can then be defined and raised to the face maanger for further
+processing through the following code:
+```
+ facelet_set_event(facelet, EVENT_TYPE_CREATE);
+ interface_raise_event(interface, facelet);
+```
+
+Here the event is a facelet creation (`EVENT_TYPE_CREATE`). The full facelet API
+and the list of possible event types is available in `src/facelet.h`
+
+
+#### Integration in the build system
+
+The build system is based on CMake. Each interface should declare its source
+files, private and public header files, as well as link dependencies in the
+local `CMakeLists.txt` file.
+
+TODO: detail the structure of the file
+
+
+### Hands-on example
+
+#### Overview
+
+In order to better illustrate the development of a new interface, we will
+consider the integration of a sample server providing a signal instructing the
+face manager to alternatively use either the WiFi or the LTE interface. The code
+of this server is available in the folder `examples/updownsrv/`, and the
+corresponding client code in `examples/updowncli`.
+
+Communication between client and server is done through unix sockets over an
+abstract namespace (thereby not using the file system, which would cause issues
+on Android). The server listens for client connections, and periodically
+broadcast a binary information to all connected clients, in the form of one byte
+equal to either \0 (which we might interpret as enable LTE, disable WiFi), or \1
+(enable WiFi, disable LTE).
+
+Our objective is to develop a new face manager interface that would listen to
+such event in order to update the administrative status of the current faces.
+This would thus alternatively set the different interfaces admnistratively up
+and down (which takes precedence over the actual status of the interface when
+the forwarder establishes the set of available next hops for a given prefix).
+The actual realization of such queries will be ultimately performed by the
+hicn-light interface.
+
+#### Sample server and client
+
+In the folder containing the source code of hICN, the following commands allow
+to run the sample server:
+
+```
+cd ctrl/facemgr/examples/updownsrv
+make
+./updownsrv
+```
+
+The server should display "Waiting for clients..."
+
+Similar commands allow to run the sample client:
+```
+cd ctrl/facemgr/examples/updowncli
+make
+./updowncli
+```
+
+The client should display "Waiting for server data...", then every couple of
+seconds display either "WiFi" or "LTE".
+
+#### Facemanager interface
+
+An example illustrating how to connect to the dummy service from `updownsrv` is
+provided as the `updown` interface in the facemgr source code.
+
+This interface periodically swaps the status of the LTE interface up and down.
+It is instanciated as part of the facemgr codebase when the code is compiled
+with the ``-DWITH_EXAMPLE_UPDOWN` cmake option.
+
+
+
diff --git a/ctrl/facemgr/examples/facemgr.conf b/ctrl/facemgr/examples/facemgr.conf
index 54c212c2b..4658d13e3 100644
--- a/ctrl/facemgr/examples/facemgr.conf
+++ b/ctrl/facemgr/examples/facemgr.conf
@@ -1,37 +1,194 @@
+#
# hICN facemgr configuration file
+#
-faces:
-{
- # A list of interfaces to ignore
- ignore = ("lo");
-
- # A list of rules used to assign tags to interfaces
- # Each rule follows the syntax { name = "NAME"; tags = ("TAG", ...); }
- # with TAG = WIRED | WIFI | CELLULAR | TRUSTED
- rules = (
- {
- name = "utun1";
- tags = ("WIRED", "TRUSTED");
- }
- );
-
- overlay = {
- ipv4 = {
- local_port = 9695;
- remote_port = 9695;
- remote_addr = "10.60.16.14";
- };
- ipv6 = {
- local_port = 9695;
- remote_port = 9695;
- remote_addr = "2001:420:44f1:10:20c:29ff:fef3:8f8f";
- };
- };
-}
+################################################################################
+# Global settings
+################################################################################
+
+global = {
+
+# Default type for face creation
+#
+# Values: "auto" | "native-udp" | "native-tcp" | "overlay-udp" | "overlay-tcp"
+# Default "auto"
+#
+#face_type = "auto";
+face_type = "overlay-udp"
+
+# Disable service discovery for overlay creation
+#
+# This is only meaningful for overlay_* face types. If service discovery is
+# disabled, only manually entered overlay information will be used, if any.
+# Otherwise, no face will be created.
+#
+# Values : true | false
+# Default: false
+#
+#disable_discovery = true;
+
+# TODO Disable IPv4 face creation
+#
+# Values : true | false
+# Default: false
+#
+#disable_ipv4 = true;
+
+# TODO Disable IPv6 face creation
+#
+# Values : true | false
+# Default: false
+#
+#disable_ipv6 = true;
+
+# TODO overlay
+#
+# By default, no address is specified, and local and remote ports are set to
+# the standard value for hICN (9695).
+#
+
+};
+
+################################################################################
+# Per-interface rules
+################################################################################
+#
+# Rules allow to override the default behaviour of the face manager.
+#
+# The list of rules must be specified as follows (note that the last one has no
+# coma at the end) :
+#
+# rules = (
+# { ... },
+# { ... },
+# { ... }
+# );
+#
+# A rule is composed of match and override attributes, and has the following
+# syntax:
+#
+# {
+# match = {
+# interface_name = STRING;
+# interface_type = STRING;
+# };
+# override = {
+# face_type = STRING;
+# disable_discovery = BOOL;
+# ignore = BOOL;
+# tags = (STRING, STRING, STRING);
+# overlay = {
+# ipv4 = {
+# local_port = PORT;
+# remote_addr = IP_ADDRESS;
+# remote_port = PORT;
+# };
+# ipv6 = {
+# local_port = PORT;
+# remote_addr = IP_ADDRESS;
+# remote_port = PORT;
+# };
+# };
+# };
+# }
+#
+# Match attributes:
+#
+# Match attributes serve to identify rules and as such defining two rules with
+# similar matches is not allowed. However, overlapping match definitions are
+# possible, in which case only the first matching rule is considered.
+#
+# A match is composed of the name of an interface and/or its type (either
+# attribute is optional but at least one has to be specified).
+#
+# * interface_name - a string representing an interface name
+#
+# * interface_type - the type of interface to match
+#
+# Values: "wired" | "wifi" | "cellular"
+#
+# Override attributes:
+#
+# Those attributes are applied when all specified match attributes correspond,
+# and override general settings or default values.
+#
+# * face_type - type used for face creation
+#
+# Values: "auto" | "native_udp" | "native_tcp" | "overlay_udp" | "overlay_tcp"
+#
+# * disable_discovery - disable service discovery for overlay creation
+#
+# Values : true | false
+#
+# * ignore - a boolean indicating whether that interface should be ignored
+#
+# * TODO tags - a (possibly empty) list of tags to be associated to the created face.
+#
+# Values: "wired" | "wifi" | "cellular" | "trusted"
+#
+# * overlay
+#
+# An overlay specification is used to complement any information retrieved
+# through service discovery (or replace it if service discovery is
+# disabled).
+#
+# It is possible to specify values for IPv4, IPv6 or both.
+#
+# Note that it is not currently possible to set different settings for IPv4 and
+# IPv6 but overlay specifications.
+#
+#
+# Here are a few example of rule definitions:
+#
+# rules = (
+# # Ignore localhost interface
+# {
+# match = {
+# interface_name = "lo";
+# };
+# override = {
+# ignore = true;
+# };
+# },
+# # Set tags for unknown tunnnel interface
+# {
+# match = {
+# interface_name = "utun1";
+# };
+# override = {
+# tags = ("WIRED", "TRUSTED");
+# };
+# },
+# # Force cellular connections to use manually specified overlay faces
+# {
+# match = {
+# interface_type = "cellular",
+# };
+# override = {
+# overlay = {
+# ipv4 = {
+# local_port = 9695;
+# remote_addr = "10.60.16.14";
+# remote_port = 9695;
+# };
+# ipv6 = {
+# local_port = 9695;
+# remote_addr = "2001:420:44f1:10:20c:29ff:fef3:8f8f";
+# remote_port = 9695;
+# };
+# };
+# };
+# }
+# );
+#
+#rules = (
+#);
+
+################################################################################
+# Logging
+################################################################################
log:
{
log_level = "DEBUG";
}
-
-
diff --git a/ctrl/facemgr/examples/run-bonjour.sh b/ctrl/facemgr/examples/run-bonjour.sh
new file mode 100755
index 000000000..cc1c28e27
--- /dev/null
+++ b/ctrl/facemgr/examples/run-bonjour.sh
@@ -0,0 +1,178 @@
+#!/bin/bash
+
+# Notes for MacOS:
+#
+# - Browse all discoverable services
+# dns-sd -B _services._dns-sd._udp local.
+#
+# - Browse all hICN services
+# dns-sd -B _hicn._udp local.
+#
+# - Lookup for specific options
+# dns-sd -L "hicn node" _hicn._udp local.
+#
+# - Lookup addresses
+# dns-sd -G v4v6 adreena.local.
+#
+# NOTE: trailing dot '.' is optional
+
+set -e
+
+PORT=9695
+
+#-------------------------------------------------------------------------------
+
+FN_AVAHI_CFG_SRC=$SCRIPT_PATH/etc_avahi_services_hicn.service
+FN_AVAHI_CFG=/etc/avahi/services/hicn.service
+
+# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression
+! read -r -d '' TPL_AVAHI_CFG <<-EOF
+<?xml version="1.0" standalone='no'?>
+<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
+<service-group>
+ <name>hicn node</name>
+ <service>
+ <type>_hicn._udp</type>
+ <port>$PORT</port>
+ </service>
+</service-group>
+EOF
+
+#-------------------------------------------------------------------------------
+
+# Reliably determine script's full path
+SCRIPT_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
+
+# https://unix.stackexchange.com/questions/325594/script-a-test-for-installed-debian-package-error-handling
+function pkg_is_installed()
+{
+ PKG="$1"
+ LISTF=$(mktemp)
+ dpkg-query -W -f '${Package} ${State}\n' >$LISTF
+ grep "^${PKG} " $LISTF >/dev/null
+ GREP_RC=$?
+ rm $LISTF
+
+ # for even moar strict error handling
+ test $GREP_RC == 0 -o $GREP_RC == 1
+
+ return $GREP_RC
+}
+
+# https://stackoverflow.com/questions/3466166/how-to-check-if-running-in-cygwin-mac-or-linux
+function detect_os()
+{
+ unameOut="$(uname -s)"
+ case "${unameOut}" in
+ Linux*) machine=linux;;
+ Darwin*) machine=mac;;
+ CYGWIN*) machine=cygwin;;
+ MINGW*) machine=mingw;;
+ *) machine=unknown;;
+ esac
+ echo ${machine}
+}
+
+function ensure_pkg_is_installed()
+{
+ PKG="$1"
+ pkg_is_installed $PKG && return
+ sudo apt install $PKG
+}
+
+function ensure_file_installed()
+{
+ SRC=$1
+ DST=$2
+
+ # Test whether destination exists and is up to date
+ [ -s $DST ] && cmp -s $SRC $DST && return
+
+ sudo cp $SRC $DST
+}
+
+function ensure_file_template()
+{
+ DST=$1
+ TPL=$2
+
+ echo "$TPL" | sudo tee $DST >/dev/null
+}
+
+function is_function()
+{
+ [ "$(type -t $1)" == "function" ]
+}
+
+function os_function()
+{
+ FUN=$1
+ shift
+ ARGS=$@
+
+ OS=$(detect_os)
+ if ! is_function ${FUN}_${OS}; then
+ echo "Platform $OS not supported for $FUN [${FUN}_${OS}]"
+ exit -1
+ fi
+ ${FUN}_${OS} $ARGS
+}
+
+#-------------------------------------------------------------------------------
+
+# NOTE: debian only
+function run_bonjour_server_linux()
+{
+ ensure_pkg_is_installed avahi-daemon
+ #ensure_file_installed $FN_AVAHI_CFG_SRC $FN_AVAHI_CFG
+ ensure_file_template $FN_AVAHI_CFG "$TPL_AVAHI_CFG"
+ sudo service avahi-daemon restart
+ echo >&2, "Bonjour is now served through avahi"
+}
+
+function run_bonjour_server_mac()
+{
+ dns-sd -R hicn _hicn._tcp local $PORT
+ # Proxy mode -P
+}
+
+function run_bonjour_client_linux()
+{
+ avahi-browse -ptr _hicn._udp
+}
+
+function run_bonjour_client_mac()
+{
+ dns-sd -B _hicn._udp local
+
+}
+
+# XXX function run_bonjour_proxy_linux() { }
+
+function run_bonjour_proxy_mac()
+{
+ if [[ $# != 2 ]]; then
+ echo "Usage: $0 proxy IP_ADDRESS"
+ exit -1
+ fi
+ IP=$1
+ dns-sd -P hicn _hicn._udp local $PORT hicn.local $IP path=/
+}
+
+#-------------------------------------------------------------------------------
+
+case $1 in
+ client)
+ os_function run_bonjour_client
+ ;;
+ server)
+ os_function run_bonjour_server
+ ;;
+ proxy)
+ os_function run_bonjour_proxy $@
+ ;;
+ *)
+ echo "$0 [client|server]"
+ exit -1
+ ;;
+esac
diff --git a/ctrl/facemgr/examples/updowncli/Makefile b/ctrl/facemgr/examples/updowncli/Makefile
new file mode 100644
index 000000000..5e6111c2a
--- /dev/null
+++ b/ctrl/facemgr/examples/updowncli/Makefile
@@ -0,0 +1,25 @@
+EXEC = $(shell basename $$(pwd))
+CC = gcc
+
+CFLAGS = -std=gnu11 -O3 -Wall -Wextra -Wpedantic -Wstrict-aliasing
+#CFLAGS += $(shell pkg-config --cflags glib-2.0 gio-2.0)
+#LDFLAGS = $(shell pkg-config --libs glib-2.0 gio-2.0)
+
+SRC = $(wildcard *.c)
+OBJ = $(SRC:.c=.o)
+
+all: $(EXEC)
+
+${EXEC}: $(OBJ)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) -o $@ -c $< $(CFLAGS)
+
+.PHONY: clean mrproper
+
+clean:
+ @rm -rf *.o
+
+mrproper: clean
+ @rm -rf $(EXEC)
diff --git a/ctrl/facemgr/examples/updowncli/updowncli.c b/ctrl/facemgr/examples/updowncli/updowncli.c
new file mode 100644
index 000000000..4f5a14165
--- /dev/null
+++ b/ctrl/facemgr/examples/updowncli/updowncli.c
@@ -0,0 +1,57 @@
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * \brief Default unix socket path (the leading \0 means using the abstract
+ * namespace instead of the filesystem).
+ */
+#define UNIX_PATH "\0updownsrv"
+
+int main() {
+ struct sockaddr_un addr;
+ char buf[100];
+ int fd,rc;
+
+ char * socket_path = UNIX_PATH;
+
+ if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ perror("socket error");
+ exit(-1);
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ if (*socket_path == '\0') {
+ *addr.sun_path = '\0';
+ strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
+ } else {
+ strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
+ }
+
+ if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ perror("connect error");
+ exit(-1);
+ }
+
+ printf("Waiting for server data...\n");
+ while( (rc=read(fd, buf, sizeof(buf))) > 0) {
+ assert(rc == 1);
+ switch(buf[0]) {
+ case '\0':
+ printf("WiFi\n");
+ break;
+ case '\1':
+ printf("LTE\n");
+ break;
+ default:
+ printf("Unknown\n");
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/ctrl/facemgr/examples/updownsrv/Makefile b/ctrl/facemgr/examples/updownsrv/Makefile
new file mode 100644
index 000000000..5e6111c2a
--- /dev/null
+++ b/ctrl/facemgr/examples/updownsrv/Makefile
@@ -0,0 +1,25 @@
+EXEC = $(shell basename $$(pwd))
+CC = gcc
+
+CFLAGS = -std=gnu11 -O3 -Wall -Wextra -Wpedantic -Wstrict-aliasing
+#CFLAGS += $(shell pkg-config --cflags glib-2.0 gio-2.0)
+#LDFLAGS = $(shell pkg-config --libs glib-2.0 gio-2.0)
+
+SRC = $(wildcard *.c)
+OBJ = $(SRC:.c=.o)
+
+all: $(EXEC)
+
+${EXEC}: $(OBJ)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) -o $@ -c $< $(CFLAGS)
+
+.PHONY: clean mrproper
+
+clean:
+ @rm -rf *.o
+
+mrproper: clean
+ @rm -rf $(EXEC)
diff --git a/ctrl/facemgr/examples/updownsrv/updownsrv.c b/ctrl/facemgr/examples/updownsrv/updownsrv.c
new file mode 100644
index 000000000..5d624583b
--- /dev/null
+++ b/ctrl/facemgr/examples/updownsrv/updownsrv.c
@@ -0,0 +1,237 @@
+/*
+ * Dummy server sending alternating bytes to all clients.
+ *
+ * This is used by the face manager to illustrate the creation of interfaces
+ * using unix domains that sets a face up and down.
+ */
+
+#include <arpa/inet.h> // inet_ntop
+#include <errno.h> // EINTR,. ..
+#include <netinet/in.h> // INET_ADDRSTRLEN, INET6_ADDRSTRLEN
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+#include <sys/un.h> // sockaddr_un
+#include <unistd.h> // fcntl
+#include <fcntl.h> // fcntl
+
+
+/**
+ * \brief Default unix socket path (the leading \0 means using the abstract
+ * namespace instead of the filesystem).
+ */
+#define UNIX_PATH "\0updownsrv"
+
+/**
+ * \brief Default interval (in seconds) between timer events */
+#define DEFAULT_INTERVAL 100000
+
+/**
+ * \brief Maximum allowed number of connected clients
+ */
+#define MAX_CLIENTS 5
+
+/**
+ * \brief Maximum backlog of listening unix socket
+ */
+#define LISTEN_BACKLOG MAX_CLIENTS
+
+
+/**
+ * \brief Creates a unix server socket
+ * \param [in] path - string representing the path on which to listen for
+ * connections
+ * \return int - fd associated to the socket
+ */
+int
+create_unix_server(char * path)
+{
+ struct sockaddr_un addr;
+ int fd;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ perror("socket error");
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ perror("fcntl");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ if (*path == '\0') {
+ *addr.sun_path = '\0';
+ strncpy(addr.sun_path+1, path+1, sizeof(addr.sun_path)-2);
+ } else {
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+ unlink(path);
+ }
+
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ perror("bind error");
+ return -1;
+ }
+
+ if (listen(fd, LISTEN_BACKLOG) == -1) {
+ perror("listen error");
+ return -1;
+ }
+
+ return fd;
+}
+
+
+/**
+ * \brief Main function
+ */
+int main() {
+ int fd, tfd;
+ int rc;
+
+ /* Alternating state of the server : 0 / 1 */
+ unsigned state = 0;
+
+ /*
+ * This server has to send a signal to all connected clients at periodic
+ * intervals. Since we don't expect a large number of connected clients for
+ * such a simple program, we simply use a statically allocated array.
+ */
+ int clients[MAX_CLIENTS];
+ size_t num_clients = 0;
+
+ fd_set active_fd_set, read_fd_set;
+ FD_ZERO (&active_fd_set);
+
+ /* Create listening unix socket */
+ fd = create_unix_server(UNIX_PATH);
+ if (fd < 0)
+ exit(EXIT_FAILURE);
+
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ perror("fcntl");
+ exit(EXIT_FAILURE);
+ }
+
+ FD_SET (fd, &active_fd_set);
+
+ /* Create timer */
+ tfd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (tfd == -1) {
+ perror("timer error");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fcntl(tfd, F_SETFL, O_NONBLOCK) < 0) {
+ perror("fcntl");
+ exit(EXIT_FAILURE);
+ }
+
+ FD_SET (tfd, &active_fd_set);
+
+ struct itimerspec ts = {
+ .it_interval = {
+ .tv_sec = DEFAULT_INTERVAL,
+ .tv_nsec = 0,
+ },
+ .it_value = {
+ .tv_sec = DEFAULT_INTERVAL,
+ .tv_nsec = 0,
+ }
+ };
+ rc = timerfd_settime(tfd, 0, &ts, NULL);
+ if (rc == -1) {
+ perror("timerfd_settime");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Waiting for clients...\n");
+
+ for(;;) {
+ /* Block until input arrives on one or more active sockets. */
+ read_fd_set = active_fd_set;
+ rc = select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL);
+ if (rc < 0) {
+ if (rc == EINTR)
+ break;
+ perror("select");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Service all the sockets with input pending. */
+ for (int i = 0; i < FD_SETSIZE; ++i) {
+ if (!FD_ISSET (i, &read_fd_set))
+ continue;
+ if (i == fd) {
+ /* Connection request on original socket. */
+ int client_fd = accept(fd, NULL, NULL);
+ if (client_fd < 0) {
+ perror("accept");
+ continue;
+ }
+
+ fprintf(stderr, "Server: connect from new client\n");
+ clients[num_clients++] = client_fd;
+ FD_SET(client_fd, &active_fd_set);
+ } else if (i == tfd) {
+ /* Timer event */
+ uint64_t res;
+
+ read(tfd, &res, sizeof(res));
+// while (read(fd, &missed, sizeof(missed)) > 0)
+// ;
+ for (unsigned j = 0; j < num_clients; j++) {
+ write(clients[j], state ? "\1" : "\0", 1);
+ }
+ printf("STATE=%d\n", state);
+ state = 1 - state;
+ } else {
+ char buf[1024];
+ rc = read(i, buf, sizeof(buf));
+ /* Client event : we close the connection on any event... */
+ for (unsigned j = 0; j < num_clients; j++) {
+ if (i == clients[j]) {
+ clients[j] = clients[num_clients--];
+ break;
+ }
+ }
+ close(i);
+ FD_CLR(i, &active_fd_set);
+ }
+ }
+
+ }
+
+ int ret = EXIT_SUCCESS;
+
+ /* Close all active client connections */
+ for (unsigned i = 0; i < num_clients; i++) {
+ rc = close(clients[i]);
+ if (rc == -1) {
+ perror("close");
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ /* Close server */
+ rc = close(fd);
+ if (rc == -1) {
+ perror("close");
+ ret = EXIT_FAILURE;
+ }
+
+ /* Terminate timer */
+ ts.it_value.tv_sec = 0;
+ rc = timerfd_settime(tfd, 0, &ts, NULL);
+ if (rc == -1) {
+ perror("timerfd_settime");
+ exit(EXIT_FAILURE);
+ }
+
+ exit(ret);
+}
diff --git a/ctrl/facemgr/includes/CMakeLists.txt b/ctrl/facemgr/includes/CMakeLists.txt
new file mode 100644
index 000000000..e7265eebb
--- /dev/null
+++ b/ctrl/facemgr/includes/CMakeLists.txt
@@ -0,0 +1,46 @@
+# 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.
+
+# XXX
+
+set(LIBFACEMGR_INCLUDE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR} ""
+ CACHE INTERNAL
+ "" FORCE
+)
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+
+ set(TO_INSTALL_HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/facemgr.h
+
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/api.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/cfg.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/loop.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/android_utility/android_utility.h
+ PARENT_SCOPE
+ )
+
+else ()
+
+ set(TO_INSTALL_HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/facemgr.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/api.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/cfg.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h
+ PARENT_SCOPE
+ )
+
+endif ()
+
+
diff --git a/ctrl/facemgr/src/netdevice.c b/ctrl/facemgr/includes/facemgr.h
index 817b0e47b..b322e7b1f 100644
--- a/ctrl/facemgr/src/netdevice.c
+++ b/ctrl/facemgr/includes/facemgr.h
@@ -14,15 +14,15 @@
*/
/**
- * \file netdevice.c
- * \brief Implementation of Netdevice abstraction
+ * \file facemgr.h
+ * \brief Main interface for hICN face manager library
*/
+#ifndef HICN_FACEMGR_H
+#define HICN_FACEMGR_H
-#include "common.h"
-#include "netdevice.h"
+#include <hicn/policy.h>
+#include <hicn/facemgr/api.h>
+#include <hicn/facemgr/cfg.h>
+
+#endif /* HICN_FACEMGR_H */
-const char * netdevice_type_str[] = {
-#define _(x) [NETDEVICE_TYPE_ ## x] = STRINGIZE(x),
-foreach_netdevice_type
-#undef _
-}
diff --git a/ctrl/facemgr/includes/hicn/android_utility/android_utility.h b/ctrl/facemgr/includes/hicn/android_utility/android_utility.h
new file mode 100644
index 000000000..53adfedf6
--- /dev/null
+++ b/ctrl/facemgr/includes/hicn/android_utility/android_utility.h
@@ -0,0 +1,48 @@
+/*
+ * 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 android_utility/android_utility.h
+ * \brief Android utility.
+ *
+ * This class relies on a small utility wrapper shipped with the Android
+ * application to access to Java SDK APIs for information not available to
+ * native code.
+ *
+ * For instance, we currently don't have on Linux any mean to get the type
+ * associated to an interface, especially for cellular interfaces. WiFi and
+ * Bluetooth information is for instance available through specific netlink
+ * subsystems, or by means of a support library, but cellular detection mostly
+ * relies on heuristics based on interface names (eg. in network manager).
+ *
+ * Android ship a Radio Interface Layer (RIL) daemon that exposes a control
+ * socket to the Java API to control the radio layer, but there is no working
+ * code exploiting it and no proper documentation.
+ */
+
+#ifndef FACEMGR_INTERFACE_ANDROID_UTILITY_H
+#define FACEMGR_INTERFACE_ANDROID_UTILITY_H
+
+#ifdef __ANDROID__
+
+#include <jni.h>
+
+typedef struct {
+ JavaVM *jvm;
+} android_utility_cfg_t;
+
+#endif /* __ANDROID__ */
+
+#endif /* FACEMGR_INTERFACE_ANDROID_UTILITY_H */
diff --git a/ctrl/facemgr/src/interface_map.h b/ctrl/facemgr/includes/hicn/facemgr.h
index 5930b3001..4165a8fc4 100644
--- a/ctrl/facemgr/src/interface_map.h
+++ b/ctrl/facemgr/includes/hicn/facemgr.h
@@ -13,12 +13,15 @@
* limitations under the License.
*/
-#ifndef INTERFACE_MAP_H
-#define INTERFACE_MAP_H
+/**
+ * \file facemgr.h
+ * \brief Main interface for hICN face manager library
+ */
+#ifndef HICN_FACEMGR_H
+#define HICN_FACEMGR_H
-#include "interface.h"
-#include "util/map.h"
+#include <hicn/policy.h>
+#include <hicn/facemgr/api.h>
-TYPEDEF_MAP_H(interface_map, const char *, interface_t *);
+#endif /* HICN_FACEMGR_H */
-#endif /* INTERFACE_MAP_H */
diff --git a/ctrl/facemgr/includes/hicn/facemgr/api.h b/ctrl/facemgr/includes/hicn/facemgr/api.h
new file mode 100644
index 000000000..e6151da11
--- /dev/null
+++ b/ctrl/facemgr/includes/hicn/facemgr/api.h
@@ -0,0 +1,93 @@
+/*
+ * 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 facemgr.h
+ * \brief Face manager library interface
+ */
+#ifndef FACEMGR_H
+#define FACEMGR_H
+
+#include <hicn/facemgr/cfg.h>
+#include <hicn/util/ip_address.h>
+#ifdef __ANDROID__
+#include <hicn/android_utility/android_utility.h>
+#endif
+
+/* facemgr callbacks */
+
+typedef enum {
+ FACEMGR_CB_TYPE_REGISTER_FD,
+ FACEMGR_CB_TYPE_UNREGISTER_FD,
+ FACEMGR_CB_TYPE_REGISTER_TIMER,
+ FACEMGR_CB_TYPE_UNREGISTER_TIMER,
+} facemgr_cb_type_t;
+
+typedef int (*facemgr_cb_t)(void * loop, facemgr_cb_type_t type, void * data);
+
+
+/*
+ * \brief Manual overlay settings (alternative to service discovery)
+ */
+
+typedef struct {
+ uint16_t local_port;
+ ip_address_t remote_addr;
+ uint16_t remote_port;
+} facemgr_overlay_setting_t;
+
+#define FACEMGR_OVERLAY_SETTING_EMPTY (facemgr_overlay_setting_t) { \
+ .local_port = 0, \
+ .remote_addr = IP_ADDRESS_EMPTY, \
+ .remote_port = 0, \
+}
+
+typedef struct {
+ facemgr_overlay_setting_t v4;
+ facemgr_overlay_setting_t v6;
+} facemgr_overlay_t;
+
+#define FACEMGR_OVERLAY_EMPTY (facemgr_overlay_t) { \
+ .v4 = FACEMGR_OVERLAY_SETTING_EMPTY, \
+ .v6 = FACEMGR_OVERLAY_SETTING_EMPTY, \
+}
+
+/*
+ * \brief Face manager context
+ */
+typedef struct facemgr_s facemgr_t;
+
+int facemgr_initialize(facemgr_t *);
+int facemgr_finalize(facemgr_t *);
+facemgr_t * facemgr_create();
+facemgr_t * facemgr_create_with_config(facemgr_cfg_t * cfg);
+void facemgr_stop(facemgr_t *);
+void facemgr_free(facemgr_t *);
+
+
+void facemgr_set_callback(facemgr_t * facemgr, void * callback_owner, facemgr_cb_t callback);
+
+int facemgr_set_config(facemgr_t * facemgr, facemgr_cfg_t * cfg);
+int facemgr_reset_config(facemgr_t * facemgr);
+int facemgr_bootstrap(facemgr_t * facemgr);
+#ifdef __ANDROID__
+void facemgr_set_jvm(facemgr_t * facemgr, JavaVM *jvm);
+#endif /* __ANDROID__ */
+
+typedef int (*facemgr_list_faces_cb_t)(face_t * face, void * user_data);
+
+void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data);
+
+#endif /* FACEMGR_H */
diff --git a/ctrl/facemgr/includes/hicn/facemgr/cfg.h b/ctrl/facemgr/includes/hicn/facemgr/cfg.h
new file mode 100644
index 000000000..525e1a9e3
--- /dev/null
+++ b/ctrl/facemgr/includes/hicn/facemgr/cfg.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file cfg.h
+ * \brief Face manager configuration
+ */
+#ifndef FACEMGR_CFG_H
+#define FACEMGR_CFG_H
+
+#include <hicn/ctrl/face.h>
+#include <hicn/util/log.h>
+
+/* Face type */
+
+#define foreach_face_type_layer \
+ _(UNDEFINED) \
+ _(3) \
+ _(4) \
+ _(N)
+
+typedef enum {
+#define _(x) FACE_TYPE_LAYER_ ## x,
+ foreach_face_type_layer
+#undef _
+} face_type_layer_t;
+
+#define foreach_face_type_encap \
+ _(UNDEFINED) \
+ _(TCP) \
+ _(UDP) \
+ _(N)
+
+typedef enum {
+#define _(x) FACE_TYPE_ENCAP_ ## x,
+ foreach_face_type_encap
+#undef _
+} face_type_encap_t;
+
+typedef struct {
+ face_type_layer_t layer;
+ face_type_encap_t encap;
+} facemgr_face_type_t;
+
+#define FACEMGR_FACE_TYPE_UNDEFINED (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_UNDEFINED, \
+ .encap = FACE_TYPE_ENCAP_UNDEFINED, \
+}
+
+#define FACEMGR_FACE_TYPE_NATIVE_UDP (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_3, \
+ .encap = FACE_TYPE_ENCAP_UDP, \
+}
+
+#define FACEMGR_FACE_TYPE_NATIVE_TCP (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_3, \
+ .encap = FACE_TYPE_ENCAP_TCP, \
+}
+
+#define FACEMGR_FACE_TYPE_OVERLAY_UDP (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_4, \
+ .encap = FACE_TYPE_ENCAP_UDP, \
+}
+
+#define FACEMGR_FACE_TYPE_OVERLAY_TCP (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_4, \
+ .encap = FACE_TYPE_ENCAP_TCP, \
+}
+
+/* Face manager configuration */
+
+#ifdef __ANDROID__
+#define FACEMGR_FACE_TYPE_DEFAULT FACEMGR_FACE_TYPE_OVERLAY_UDP
+#else
+#define FACEMGR_FACE_TYPE_DEFAULT FACEMGR_FACE_TYPE_NATIVE_TCP
+#endif /* __ANDROID__ */
+
+#define DEFAULT_FACE_TYPE FACE_TYPE_AUTO
+#define FACEMGR_CFG_DEFAULT_DISCOVERY true
+//#define DEFAULT_IGNORE "lo"
+#define FACEMGR_CFG_DEFAULT_IPV4 true
+#define FACEMGR_CFG_DEFAULT_IPV6 false
+
+
+
+typedef struct facemgr_cfg_s facemgr_cfg_t;
+
+facemgr_cfg_t * facemgr_cfg_create();
+void facemgr_cfg_free(facemgr_cfg_t * cfg);
+int facemgr_cfg_initialize(facemgr_cfg_t * cfg);
+int facemgr_cfg_finalize(facemgr_cfg_t * cfg);
+void facemgr_cfg_dump(facemgr_cfg_t * cfg);
+
+/* Rules */
+
+typedef struct facemgr_cfg_rule_s facemgr_cfg_rule_t;
+
+facemgr_cfg_rule_t * facemgr_cfg_rule_create();
+void facemgr_cfg_rule_free(facemgr_cfg_rule_t * rule);
+int facemgr_cfg_rule_initialize(facemgr_cfg_rule_t * rule);
+int facemgr_cfg_rule_finalize(facemgr_cfg_rule_t * rule);
+
+int facemgr_cfg_rule_set_match(facemgr_cfg_rule_t * rule,
+ const char * interface_name, netdevice_type_t interface_type);
+
+int facemgr_cfg_rule_set_face_type(facemgr_cfg_rule_t * cfg_rule, facemgr_face_type_t * face_type);
+int facemgr_cfg_rule_unset_face_type(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_discovery(facemgr_cfg_rule_t * cfg_rule, bool status);
+int facemgr_cfg_rule_unset_discovery(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_ignore(facemgr_cfg_rule_t * cfg_rule, bool status);
+int facemgr_cfg_rule_unset_ignore(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_ipv4(facemgr_cfg_rule_t * cfg_rule, bool status);
+int facemgr_cfg_rule_unset_ipv4(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_ipv6(facemgr_cfg_rule_t * cfg_rule, bool status);
+int facemgr_cfg_rule_unset_ipv6(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_overlay(facemgr_cfg_rule_t * rule, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port);
+int facemgr_rule_unset_overlay(facemgr_cfg_rule_t * rule, int family);
+
+/* General */
+int facemgr_cfg_set_face_type(facemgr_cfg_t * cfg, facemgr_face_type_t * face_type);
+int facemgr_cfg_unset_face_type(facemgr_cfg_t * cfg);
+int facemgr_cfg_set_discovery(facemgr_cfg_t * cfg, bool status);
+int facemgr_cfg_unset_discovery(facemgr_cfg_t * cfg);
+int facemgr_cfg_set_ipv4(facemgr_cfg_t * cfg, bool status);
+int facemgr_cfg_unset_ipv4(facemgr_cfg_t * cfg);
+int facemgr_cfg_set_ipv6(facemgr_cfg_t * cfg, bool status);
+int facemgr_cfg_unset_ipv6(facemgr_cfg_t * cfg);
+
+int facemgr_cfg_set_overlay(facemgr_cfg_t * cfg, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port);
+int facemgr_cfg_unset_overlay(facemgr_cfg_t * cfg, int family);
+
+
+int facemgr_cfg_add_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule);
+int facemgr_cfg_del_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule);
+int facemgr_cfg_get_rule(const facemgr_cfg_t * cfg, const char * interface_name,
+ netdevice_type_t interface_type, facemgr_cfg_rule_t ** rule);
+
+/* Log */
+
+/*
+ * Query API
+ *
+ * Takes the overrides into account
+ *
+ * TODO : interface_types are currently not taken into account by this API
+ */
+
+int facemgr_cfg_get_face_type(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ facemgr_face_type_t * face_type);
+int facemgr_cfg_get_discovery(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * discovery);
+int facemgr_cfg_get_ignore(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ignore);
+int facemgr_cfg_get_ipv4(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ipv4);
+int facemgr_cfg_get_ipv6(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ipv6);
+int facemgr_cfg_get_overlay_local_addr(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, ip_address_t * addr);
+int facemgr_cfg_get_overlay_local_port(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, u16 * port);
+int facemgr_cfg_get_overlay_remote_addr(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, ip_address_t * addr);
+int facemgr_cfg_get_overlay_remote_port(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, u16 * port);
+
+#endif /* FACEMGR_CFG_H */
diff --git a/ctrl/facemgr/includes/hicn/facemgr/loop.h b/ctrl/facemgr/includes/hicn/facemgr/loop.h
new file mode 100644
index 000000000..77cbedb21
--- /dev/null
+++ b/ctrl/facemgr/includes/hicn/facemgr/loop.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file loop.h
+ * \brief Face manager main loop
+ */
+
+#ifndef FACEMGR_LOOP_H
+#define FACEMGR_LOOP_H
+
+#include <hicn/facemgr/api.h>
+
+/* fd & timer callbacks */
+
+typedef int (*fd_callback_t)(void * owner, int fd, void * data);
+
+typedef struct {
+ int fd;
+ void *owner;
+ fd_callback_t callback;
+ //int (*callback)(void * owner, int fd, void * data);
+ void *data;
+} fd_callback_data_t;
+
+/* timer callbacks */
+typedef struct {
+ unsigned delay_ms;
+ void *owner;
+ fd_callback_t callback;
+ //int (*callback)(void * owner, int fd, void * data);
+ void *data;
+} timer_callback_data_t;
+
+/* loop */
+
+typedef struct loop_s loop_t;
+
+/**
+ * \brief Creates a main loop
+ * \return Pointer to the newly created loop, or NULL in case of error
+ */
+loop_t * loop_create();
+
+/**
+ * \brief Releases a loop instance and frees all associated memory
+ * \param [in] loop - Pointer to the loop instance to free
+ */
+void loop_free(loop_t * loop);
+
+/**
+ * \brief Runs the loop instance to process events
+ * \param [in] loop - Pointer to the loop instance
+ */
+void loop_dispatch(loop_t * loop);
+
+/**
+ * \brief Terminates the dispatching of events
+ * \param [in] loop - Pointer to the loop instance
+ */
+void loop_undispatch(loop_t * loop);
+
+/**
+ * \brief Breaks out of the loop
+ * \param [in] loop - Pointer to the loop instance
+ */
+void loop_break(loop_t * loop);
+
+
+/**
+ * \brief Callback for loop helpers
+ * \param [in] loop - Pointer to the loop instance
+ * \param [in] type - Type of service to be requested
+ * \param [in] data - Service specific data
+ */
+int loop_callback(loop_t * loop, facemgr_cb_type_t type, void * data);
+
+#endif /* FACEMGR_LOOP_H */
diff --git a/ctrl/facemgr/src/util/log.h b/ctrl/facemgr/includes/hicn/util/log.h
index f1cafba47..f1cafba47 100644
--- a/ctrl/facemgr/src/util/log.h
+++ b/ctrl/facemgr/includes/hicn/util/log.h
diff --git a/ctrl/facemgr/src/CMakeLists.txt b/ctrl/facemgr/src/CMakeLists.txt
index e7dbda5c1..88f554c40 100644
--- a/ctrl/facemgr/src/CMakeLists.txt
+++ b/ctrl/facemgr/src/CMakeLists.txt
@@ -20,92 +20,121 @@ set(COMPILER_DEFINITIONS
)
set(HEADER_FILES
-#cache.h
common.h
error.h
- event.h
- face.h
- face_cache.h
- face_rules.h
+ facelet.h
interface.h
- interface_map.h
- interface_ops_map.h
+ loop.h
util/hash.h
- util/ip_address.h
- util/log.h
util/map.h
- util/policy.h
util/set.h
- util/token.h
- util/types.h
-
)
set(SOURCE_FILES
-# cache.c
+ api.c
+ cfg.c
+ cfg_file.c
error.c
- event.c
- face.c
- face_cache.c
- face_rules.c
+ facelet.c
interface.c
- interface_map.c
- interface_ops_map.c
- facemgr.c
util/log.c
- util/policy.c
)
+if(APPLE)
+set(SOURCE_FILES
+ ${SOURCE_FILES}
+ loop_dispatcher.c
+)
+endif()
+
+if (LINUX)
+set(SOURCE_FILES
+ ${SOURCE_FILES}
+ loop_libevent.c
+)
+endif()
+
set(INCLUDE_DIRS
./
../includes/
${CONFIG_INCLUDE_DIR}
${LIBEVENT_INCLUDE_DIR}
+ ${HICN_INCLUDE_DIRS}
${LIBHICNCTRL_INCLUDE_DIRS}
)
set(LIBRARIES
${CONFIG_LIBRARY}
${LIBEVENT_LIBRARY}
+ ${HICN_LIBRARIES}
${LIBHICNCTRL_LIBRARIES}
)
+
add_subdirectory(interfaces)
-if (ANDROID_API)
- build_library(${FACE_MGR}
+if(WITH_THREAD)
+ set(LIBRARIES
+ ${LIBRARIES}
+ "pthread"
+ "event_pthreads"
+ )
+ set(COMPILER_DEFINITIONS
+ ${COMPILER_DEFINITIONS}
+ "-DWITH_THREAD"
+ )
+endif()
+
+if(WITH_EXAMPLE_DUMMY)
+ set(COMPILER_DEFINITIONS
+ ${COMPILER_DEFINITIONS}
+ "-DWITH_EXAMPLE_DUMMY"
+ )
+endif()
+
+if(WITH_EXAMPLE_UPDOWN)
+ set(COMPILER_DEFINITIONS
+ ${COMPILER_DEFINITIONS}
+ "-DWITH_EXAMPLE_UPDOWN"
+ )
+endif()
+
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+ build_library(${LIBFACEMGR}
STATIC
SOURCES ${SOURCE_FILES}
INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES}
DEPENDS ${DEPENDENCIES}
- COMPONENT ${FACE_MGR}
+ LINK_LIBRARIES ${LIBRARIES}
+ COMPONENT ${FACEMGR}
INCLUDE_DIRS ${INCLUDE_DIRS}
INSTALL_ROOT_DIR hicn
DEFINITIONS ${COMPILER_DEFINITIONS}
)
else ()
- build_library(${FACE_MGR}
- STATIC NO_DEV
+ build_library(${LIBFACEMGR}
+ SHARED STATIC NO_DEV
SOURCES ${SOURCE_FILES}
INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES}
DEPENDS ${DEPENDENCIES}
- COMPONENT ${FACE_MGR}
+ LINK_LIBRARIES ${LIBRARIES}
+ COMPONENT ${FACEMGR}
INCLUDE_DIRS ${INCLUDE_DIRS}
INSTALL_ROOT_DIR hicn
DEFINITIONS ${COMPILER_DEFINITIONS}
)
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
main.c
)
- build_executable(${FACE_MGR}
+ build_executable(${FACEMGR}
SOURCES ${DAEMON_SRC}
- LINK_LIBRARIES ${FACE_MGR}.static ${LIBRARIES}
- DEPENDS ${FACE_MGR}.static
- COMPONENT ${FACE_MGR}
+ LINK_LIBRARIES ${LIBFACEMGR}.static ${LIBRARIES}
+ DEPENDS ${LIBFACEMGR}.static
+ COMPONENT ${FACEMGR}
INCLUDE_DIRS ${INCLUDE_DIRS}
DEFINITIONS ${COMPILER_DEFINITIONS}
)
diff --git a/ctrl/facemgr/src/api.c b/ctrl/facemgr/src/api.c
new file mode 100644
index 000000000..a1507bd70
--- /dev/null
+++ b/ctrl/facemgr/src/api.c
@@ -0,0 +1,1504 @@
+/*
+ * 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 facemgr.c
+ * \brief Implementation of Face manager library interface
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <hicn/facemgr/api.h>
+#include <hicn/facemgr/cfg.h>
+#include <hicn/util/log.h>
+
+#ifdef __APPLE__
+#include "interfaces/network_framework/network_framework.h"
+#endif /* __APPLE__ */
+
+#ifdef __linux__
+#include "interfaces/bonjour/bonjour.h"
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+#include <hicn/android_utility/android_utility.h>
+#endif /* __ANDROID__ */
+
+#include <hicn/ctrl/face.h>
+#include "common.h"
+#include "facelet.h"
+#include "interface.h"
+#include "util/map.h"
+#include "util/set.h"
+
+#define RAND_NAME_LEN 5
+
+#define DEFAULT_PORT 9695
+
+#define MAX_FDS 10
+
+typedef struct {
+ interface_t * interface;
+ int fds[MAX_FDS];
+ size_t num_fds;
+} interface_map_data_t;
+
+TYPEDEF_SET_H(facelet_cache, facelet_t *);
+TYPEDEF_SET(facelet_cache, facelet_t *, facelet_cmp, facelet_snprintf);
+
+TYPEDEF_MAP_H(interface_map, const char *, interface_map_data_t *);
+TYPEDEF_MAP(interface_map, const char *, interface_map_data_t *, strcmp, string_snprintf, generic_snprintf);
+
+TYPEDEF_MAP_H(bonjour_map, netdevice_t *, interface_t *);
+TYPEDEF_MAP(bonjour_map, netdevice_t *, interface_t *, netdevice_cmp, generic_snprintf, generic_snprintf);
+
+/* TODO automatically register interfaces */
+
+#ifdef __APPLE__
+extern interface_ops_t network_framework_ops;
+#endif
+#ifdef __linux__
+extern interface_ops_t netlink_ops;
+extern interface_ops_t bonjour_ops;
+#endif
+#ifdef __ANDROID__
+extern interface_ops_t android_utility_ops;
+#endif /* __ANDROID__ */
+#ifdef WITH_EXAMPLE_DUMMY
+extern interface_ops_t dummy_ops;
+#endif
+#ifdef WITH_EXAMPLE_UPDOWN
+extern interface_ops_t updown_ops;
+#endif
+extern interface_ops_t hicn_light_ops;
+
+
+int
+facemgr_overlay_snprintf(char * s, size_t size, const facemgr_overlay_t * overlay)
+{
+ return -1;
+}
+
+struct facemgr_s {
+ /**************************************************/
+ /* Configuration parameters (exposed through API) */
+
+ facemgr_cfg_t * cfg;
+
+#ifdef __ANDROID__
+ /*
+ * Those two pointers are needed to call java functions from the face
+ * manager.
+ */
+ JavaVM *jvm;
+#endif /* __ANDROID__ */
+
+ /* Callback */
+ facemgr_cb_t callback;
+ void * callback_owner;
+
+ /****************************/
+ /* Internal data structures */
+
+ /* Map of interfaces index by name */
+ interface_map_t interface_map;
+
+ /* Faces under construction */
+ facelet_cache_t facelet_cache;
+
+ /********************************************************/
+ /* Interfaces - Those should be fully replaced by a map */
+
+ interface_t * hl;
+
+#ifdef __ANDROID__
+ interface_t * au; /* android_utility */
+#endif /* __ANDROID__ */
+
+#ifdef __APPLE__
+ interface_t * nf; /* network_framework */
+#endif /* __APPLE__ */
+
+#ifdef __linux__
+ interface_t * nl; /* netlink */
+
+ /*
+ * We maintain a map of dynamically created bonjour interfaces, one for each
+ * found netdevice
+ */
+ bonjour_map_t bonjour_map;
+#endif /* __linux__ */
+
+#ifdef WITH_EXAMPLE_DUMMY
+ interface_t * dummy;
+#endif
+#ifdef WITH_EXAMPLE_UPDOWN
+ interface_t * updown;
+#endif
+};
+
+int
+facemgr_initialize(facemgr_t * facemgr)
+{
+ int rc;
+
+ rc = interface_map_initialize(&facemgr->interface_map);
+ if (rc < 0)
+ goto ERR_INTERFACE_MAP;
+
+ rc = facelet_cache_initialize(&facemgr->facelet_cache);
+ if (rc < 0)
+ goto ERR_FACE_CACHE_PENDING;
+
+#ifdef __linux__
+ rc = bonjour_map_initialize(&facemgr->bonjour_map);
+ if (rc < 0)
+ goto ERR_BJ;
+#endif /* __linux */
+
+ facemgr->cfg = facemgr_cfg_create();
+ if (!facemgr->cfg)
+ goto ERR_CFG;
+
+ return 0;
+
+ERR_CFG:
+#ifdef __linux__
+ bonjour_map_finalize(&facemgr->bonjour_map);
+ERR_BJ:
+#endif /* __linux__ */
+ facelet_cache_finalize(&facemgr->facelet_cache);
+ERR_FACE_CACHE_PENDING:
+ interface_map_finalize(&facemgr->interface_map);
+ERR_INTERFACE_MAP:
+ return -1;
+}
+
+int
+facemgr_finalize(facemgr_t * facemgr)
+{
+ int ret = 0;
+ int rc;
+
+ rc = interface_map_finalize(&facemgr->interface_map);
+ if (rc < 0) {
+ ERROR("[facemgr_finalize] Could not finalize interface_map");
+ ret = -1;
+ }
+
+ /* Free all facelets from cache */
+ facelet_t ** facelet_array;
+ int n = facelet_cache_get_array(&facemgr->facelet_cache, &facelet_array);
+ if (n < 0) {
+ ERROR("[facemgr_finalize] Could not retrieve facelets in cache");
+ } else {
+ for (unsigned i = 0; i < n; i++) {
+ facelet_t * facelet = facelet_array[i];
+ if (facelet_cache_remove(&facemgr->facelet_cache, facelet, NULL)) {
+ ERROR("[facemgr_finalize] Could not purge facelet from cache");
+ }
+ facelet_free(facelet);
+ }
+ free(facelet_array);
+ }
+
+ rc = facelet_cache_finalize(&facemgr->facelet_cache);
+ if (rc < 0)
+ ret = -1;
+
+#ifdef __linux__
+ rc = bonjour_map_finalize(&facemgr->bonjour_map);
+ if (rc < 0)
+ ret = -1;
+#endif /* __linux__ */
+
+ return ret;
+}
+
+AUTOGENERATE_CREATE_FREE(facemgr);
+
+int
+facemgr_set_config(facemgr_t * facemgr, facemgr_cfg_t * cfg)
+{
+ if (facemgr->cfg) {
+ facemgr_cfg_free(facemgr->cfg);
+ }
+ facemgr->cfg = cfg;
+ return 0;
+}
+
+int facemgr_reset_config(facemgr_t * facemgr)
+{
+ assert(facemgr->cfg);
+ facemgr_cfg_free(facemgr->cfg);
+ facemgr->cfg = facemgr_cfg_create();
+ if (!facemgr->cfg)
+ return -1;
+ return 0;
+}
+
+facemgr_t *
+facemgr_create_with_config(facemgr_cfg_t * cfg)
+{
+ facemgr_t * facemgr = facemgr_create();
+ if (!facemgr)
+ return NULL;
+ int rc = facemgr_set_config(facemgr, cfg);
+ if (rc < 0) {
+ free(facemgr);
+ return NULL;
+ }
+ return facemgr;
+}
+
+int facemgr_callback(facemgr_t * facemgr, interface_cb_type_t type, void * data);
+
+int
+facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, void * cfg, interface_t ** pinterface)
+{
+ int fd;
+ char rand_name[RAND_NAME_LEN+1];
+ interface_t * interface;
+
+ if (!name) {
+ /*
+ * We can manipulate the name on the stack as it will be strdup'ed by
+ * interface_create
+ */
+ rand_str(rand_name, RAND_NAME_LEN);
+ name = rand_name;
+ }
+
+ INFO("Creating interface %s [%s]...", name, type);
+ interface = interface_create(name, type);
+ if (!interface) {
+ ERROR("Error creating interface %s [%s]", name, type);
+ goto ERR_CREATE;
+ }
+ interface_set_callback(interface, facemgr, facemgr_callback);
+
+ fd = interface_initialize(interface, cfg);
+ if (fd < 0)
+ goto ERR_INIT;
+
+ interface_map_data_t * interface_map_data = malloc(sizeof(interface_map_data_t));
+ if (!interface_map_data)
+ goto ERR_MAP_DATA;
+
+ *interface_map_data = (interface_map_data_t) {
+ .interface = interface,
+ .fds = {0},
+ .num_fds = 0,
+ };
+
+ if (interface_map_add(&facemgr->interface_map, interface->name, interface_map_data) < 0)
+ goto ERR_MAP_ADD;
+
+ DEBUG("Interface %s created successfully.", name);
+ if (pinterface)
+ *pinterface = interface;
+ return 0;
+
+ERR_MAP_ADD:
+ free(interface_map_data);
+ERR_MAP_DATA:
+ interface_finalize(interface);
+ERR_INIT:
+ interface_free(interface);
+ERR_CREATE:
+ if (pinterface)
+ *pinterface = NULL;
+ return -1;
+}
+
+int
+facemgr_delete_interface(facemgr_t * facemgr, interface_t * interface)
+{
+ int rc;
+
+ interface_map_data_t * interface_map_data = NULL;
+
+ DEBUG("Removing interface %s", interface->name);
+ rc = interface_map_remove(&facemgr->interface_map, interface->name, &interface_map_data);
+ if (rc < 0)
+ return -1;
+
+ if (!interface_map_data)
+ return -1;
+
+ for (unsigned i = 0; i < interface_map_data->num_fds; i++) {
+ int fd = interface_map_data->fds[i];
+ facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_UNREGISTER_FD, &fd);
+ if (rc < 0)
+ WARN("[facemgr_delete_interface] Error unregistering fd %d for interface", fd);
+ }
+
+ free(interface_map_data);
+
+ interface_finalize(interface);
+ interface_free(interface);
+
+ return 0;
+}
+
+#ifdef __linux__
+int facemgr_query_bonjour(facemgr_t * facemgr, netdevice_t * netdevice)
+{
+ interface_t * bj = NULL;
+
+ int rc = bonjour_map_get(&facemgr->bonjour_map, netdevice, &bj);
+ if (rc < 0)
+ return rc;
+
+ if (!bj) {
+ /* Create a new bonjour interface */
+ bonjour_cfg_t bj_cfg = {
+ .netdevice = *netdevice,
+ };
+ rc = facemgr_create_interface(facemgr, NULL, "bonjour", &bj_cfg, &bj);
+ if (rc < 0) {
+ ERROR("Error creating 'Bonjour' interface for '%s'\n", netdevice->name);
+ return -1;
+ }
+ }
+
+ DEBUG("sending event to bonjour interface");
+
+ /* Send an event to the interface (GET ?) */
+ return interface_on_event(bj, NULL);
+}
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+int facemgr_query_android_utility(facemgr_t * facemgr, netdevice_t netdevice)
+{
+ /* Send an event to the interface */
+ facelet_t * facelet = facelet_create();
+ if (!facelet)
+ goto ERR_MALLOC;
+
+ int rc = facelet_set_netdevice(facelet, netdevice);
+ if (rc < 0)
+ goto ERR_ND;
+
+ rc = interface_on_event(facemgr->au, facelet);
+ if (rc < 0)
+ goto ERR_EVENT;
+
+ return 0;
+
+ERR_EVENT:
+ERR_ND:
+ facelet_free(facelet);
+ERR_MALLOC:
+ return -1;
+}
+#endif /* __ANDROID__ */
+
+
+/**
+ * \brief Performs a cache lookup to find matching facelets
+ * \param [in] facelet_cache - Facelet cache on which to perform lookup
+ * \param [in] facelet - Facelet to lookup
+ * \param [out] cached_facelet - Pointer used to return a newly allocated
+ * facelet array corresponding to the result of the cache lookup.
+ * \return The number of entries in the array in case of success (positive
+ * value), or -1 in case of error.
+ */
+int
+facelet_cache_lookup(const facelet_cache_t * facelet_cache, facelet_t * facelet,
+ facelet_t ***cached_facelets)
+{
+ /*
+ * If the facelet is uniquely identified by its key, it is used to perform
+ * an efficient lookup directly...
+ */
+ if (facelet_has_key(facelet)) {
+ facelet_t * found = NULL;
+ if (facelet_cache_get(facelet_cache, facelet, &found) < 0) {
+ ERROR("[facelet_cache_lookup] Error during cache lookup");
+ return -1;
+ }
+ if (!found)
+ return 0;
+ *cached_facelets = malloc(sizeof(facelet_t*));
+ *cached_facelets[0] = found;
+ return 1;
+ }
+
+ /* ...otherwise, we iterate over the facelet
+ * cache to find matching elements.
+ */
+ facelet_t ** facelet_array;
+ int n = facelet_cache_get_array(facelet_cache, &facelet_array);
+ if (n < 0) {
+ ERROR("[facelet_cache_lookup] Error during cache match");
+ return -1;
+ }
+ *cached_facelets = malloc(n * sizeof(facelet_t*));
+
+ int num_match = 0;
+ for (unsigned i = 0; i < n; i++) {
+ char buf[128];
+ facelet_snprintf(buf, 128, facelet_array[i]);
+ facelet_snprintf(buf, 128, facelet);
+
+ if (!facelet_match(facelet_array[i], facelet)) {
+ continue;
+ }
+ (*cached_facelets)[num_match++] = facelet_array[i];
+ }
+ free(facelet_array);
+ return num_match;
+}
+
+
+/**
+ * \brief Checks whether the facelet satisfies face creation rules
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet to process
+ * \return 0 in case of success, -2 if we don't have enough information to
+ * decide, -3 if the face does not satisfy rules, and -1 in case of error
+ */
+int
+facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet)
+{
+ /* As key, netdevice and family should always be present */
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ int family = AF_UNSPEC;
+ if (facelet_has_family(facelet)) {
+ if (facelet_get_family(facelet, &family) < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving family from facelet");
+ return -1;
+ }
+ }
+
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+#ifdef __ANDROID__
+ /*
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
+ */
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet");
+ return -2;
+ }
+#endif /* __ANDROID__ */
+
+ /* Ignore */
+ bool ignore;
+ if (facemgr_cfg_get_ignore(facemgr->cfg, &netdevice, netdevice_type,
+ &ignore) < 0)
+ return -1;
+ if (ignore) {
+ DEBUG("Ignored interface '%s/%s'...", netdevice.name,
+ netdevice_type_str[netdevice_type]);
+ return -3;
+ }
+
+ switch(family) {
+ case AF_INET:
+ {
+ bool ipv4;
+ if (facemgr_cfg_get_ipv4(facemgr->cfg, &netdevice, netdevice_type,
+ &ipv4) < 0)
+ return -1;
+ if (!ipv4) {
+ DEBUG("Ignored IPv4 facelet...");
+ return -3;
+ }
+ break;
+ }
+
+ case AF_INET6:
+ {
+ bool ipv6;
+ if (facemgr_cfg_get_ipv6(facemgr->cfg, &netdevice, netdevice_type,
+ &ipv6) < 0)
+ return -1;
+ if (!ipv6) {
+ DEBUG("Ignored IPv6 facelet...");
+ return -3;
+ }
+ break;
+ }
+
+ default:
+ DEBUG("Ignored facelet with unknown family");
+ return -2;
+ }
+
+ return 0;
+}
+
+#ifdef __ANDROID__
+/**
+ * \brief Complements facelet information through Android Utility interface
+ * \return 0 if request was successful, -1 in case of error, and -2 if the
+ * interface is not applicable
+ *
+ * This function returnds _after_ completion.
+ */
+int
+facemgr_complement_facelet_au(facemgr_t * facemgr, facelet_t * facelet)
+{
+
+ if (facelet_has_netdevice_type(facelet))
+ return -2;
+
+ if (facelet_is_au_done(facelet))
+ return -2;
+
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ DEBUG("Querying android utility...");
+ facelet_set_au_done(facelet);
+
+ /* /!\ Synchronous code here /!\ */
+ if (facemgr_query_android_utility(facemgr, netdevice) < 0)
+ return -1;
+ return 0;
+}
+#endif /* __ANDROID__ */
+
+#ifdef __linux__
+/**
+ * \brief Complements facelet information through Bonjour interface.
+ * \return 0 if request was successful, -1 in case of error, and -2 if the
+ * interface is not applicable
+ *
+ * This function returnds _before_ completion as bonjour querying is
+ * asynchronous.
+ */
+int
+facemgr_complement_facelet_bj(facemgr_t * facemgr, facelet_t * facelet)
+{
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+#ifdef __ANDROID__
+ /*
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
+ */
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice_type from facelet");
+ return -2;
+ }
+#endif /* __ANDROID__ */
+
+ bool discovery;
+ if (facemgr_cfg_get_discovery(facemgr->cfg, &netdevice, netdevice_type,
+ &discovery) < 0)
+ return -2;
+
+ DEBUG("Discovery: %s", discovery ? "ON" : "OFF");
+
+ if (!discovery)
+ return -2;
+
+ facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+ if (facelet_get_face_type(facelet, &face_type) < 0) {
+ ERROR("[facemgr_complement_facelet_bj] Error retrieving face type from facelet");
+ return -1;
+ }
+
+ bool discovery_needed = (face_type.layer == FACE_TYPE_LAYER_4) &&
+ ((!facelet_has_remote_addr(facelet)) || (!facelet_has_remote_port(facelet)));
+
+ DEBUG("Discovery needed: %s", discovery ? "ON" : "OFF");
+
+ if (!discovery_needed) {
+ return -2;
+ }
+
+ if (!facelet_has_local_addr(facelet)) {
+ DEBUG("No discovery possible without local address");
+ return -2;
+ }
+
+ if (facelet_is_bj_done(facelet)) {
+ DEBUG("Bonjour already queried");
+ return -2;
+ }
+
+ facelet_set_bj_done(facelet);
+ return facemgr_query_bonjour(facemgr, &netdevice);
+}
+#endif /* __linux__ */
+
+/**
+ * \brief Complements facelet information through Manual settings.
+ * \return 0 if request was successful, -1 in case of error, and -2 if the
+ * interface is not applicable
+ *
+ * This function returnds _before_ completion as bonjour querying is
+ * asynchronous.
+ */
+int
+facemgr_complement_facelet_manual(facemgr_t * facemgr, facelet_t * facelet)
+{
+
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+#ifdef __ANDROID__
+ /*
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
+ */
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error retrieving netdevice_type from facelet");
+ return -2;
+ }
+#endif /* __ANDROID__ */
+
+ int family = AF_UNSPEC;
+ if (facelet_has_family(facelet)) {
+ if (facelet_get_family(facelet, &family) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error retrieving family from facelet");
+ return -1;
+ }
+ }
+
+ /* Do not query manual is there is a change to go through bonjour */
+ bool discovery;
+ if (facemgr_cfg_get_discovery(facemgr->cfg, &netdevice, netdevice_type,
+ &discovery) < 0)
+ return -2;
+
+ facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+ if (facelet_get_face_type(facelet, &face_type) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error retrieving face type from facelet");
+ return -1;
+ }
+
+ bool discovery_needed = (face_type.layer == FACE_TYPE_LAYER_4) &&
+ ((!facelet_has_remote_addr(facelet)) || (!facelet_has_remote_port(facelet)));
+
+ if (!discovery_needed) {
+ DEBUG("manual settings not considered as no discovery is needed");
+ return -2;
+ }
+
+ if (discovery && !facelet_is_bj_done(facelet)) {
+ DEBUG("manual settings not considered as discovery is enabled and Bonjour has not yet been done");
+ return -2;
+ }
+
+ DEBUG("Applying manual settings...");
+ /*
+ * Manual overlay specification (remote addr/port)
+ * We never override a result we have obtained through bonjour
+ */
+ if (!facelet_has_remote_addr(facelet)) {
+ ip_address_t remote_addr;
+ if (facemgr_cfg_get_overlay_remote_addr(facemgr->cfg,
+ &netdevice, netdevice_type, family, &remote_addr) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error getting remote addr information from cfg");
+ return -1;
+ }
+ if (ip_address_empty(&remote_addr)) {
+ ERROR("[facemgr_complement_facelet_manual] Got empty remote addr information from cfg");
+ } else {
+ DEBUG(" - remote address");
+ facelet_set_remote_addr(facelet, remote_addr);
+ }
+ }
+
+ if (!facelet_has_remote_port(facelet)) {
+ uint16_t remote_port;
+ int rc = facemgr_cfg_get_overlay_remote_port(facemgr->cfg,
+ &netdevice, netdevice_type, family, &remote_port);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error getting remote port information from cfg");
+ return -1;
+ }
+ DEBUG(" - remote port");
+ facelet_set_remote_port(facelet, remote_port);
+ }
+
+ /*
+ * Complementing local addr/port XXX this should be done somewhere
+ * else : manual settings have the lowest priority
+ *
+ * Local IP address is specific as it allows to override the source
+ * address just before creating the face... we would need to check
+ * whether this is an address that belong to us... it might be used
+ * to arbitrate amongst several IP addresses instead...
+ */
+ ip_address_t local_addr;
+ if (facemgr_cfg_get_overlay_local_addr(facemgr->cfg, &netdevice,
+ netdevice_type, family, &local_addr) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error getting local addr information from cfg");
+ return -1;
+ }
+ if (ip_address_empty(&local_addr)) {
+ ERROR("[facemgr_complement_facelet_manual] Got empty local addr information from cfg");
+ } else {
+ DEBUG(" - local addres");
+ facelet_set_local_addr(facelet, local_addr);
+ }
+
+ /* Sets a default local port, so far nobody sets it */
+ uint16_t local_port;
+ if (facemgr_cfg_get_overlay_local_port(facemgr->cfg,
+ &netdevice, netdevice_type, family, &local_port) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error getting local port information from cfg");
+ return -1;
+ }
+ DEBUG(" - local port");
+ facelet_set_local_port(facelet, local_port);
+ return 0;
+}
+
+int
+facemgr_complement_facelet(facemgr_t * facemgr, facelet_t * facelet)
+{
+ int rc;
+
+ if (!facelet_has_key(facelet))
+ return -2;
+
+#ifdef __ANDROID__
+ rc = facemgr_complement_facelet_au(facemgr, facelet);
+ if (rc != -2)
+ return rc;
+#endif /* __ANDROID__ */
+
+ /* We continue only if the current call was not applicable. In the current
+ * setting we have no interface that can be requested in parallel, and no
+ * need to. This might evolve in future releases.
+ */
+
+#ifdef __linux__
+ rc = facemgr_complement_facelet_bj(facemgr, facelet);
+ if (rc != -2)
+ return rc;
+#endif /* __linux__ */
+
+ DEBUG("Complement manual");
+
+ rc = facemgr_complement_facelet_manual(facemgr, facelet);
+ if (rc != -2)
+ return rc;
+
+ INFO("[facemgr_complement_facelet] No more interfaces to query... incomplete face");
+ return 0;
+}
+
+/**
+ * \brief Process facelet CREATE event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ */
+int
+facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet)
+{
+ /*
+ * We create an interface locally, which does not means it should not exist
+ * remotely. Once such codepath is enabled, the two facelets will have been
+ * merged and we need to handle an eventual update on our side.
+ *
+ * In the same way, we need to check for the equivalence of face types etc.
+ */
+ int rc;
+
+ /*
+ * If the facelet does not satisfy filters, we do not lose any information
+ * but do not take any action to complement the face
+ */
+ rc = facemgr_facelet_satisfy_rules(facemgr, facelet);
+ if (rc == -3) {
+ facelet_set_status(facelet, FACELET_STATUS_IGNORED);
+ /* Does not satisfy rules */
+ return 0;
+ }
+
+ // FIXME: we should complement a part of the facelet, so that we don't
+ // necessarily keep this information if we get more locally. Or at least we
+ // should remember that.
+ if (rc == -2) {
+ /*
+ * We don't have equivalent for linux right now, heuristic is only used
+ * at the end... might change.
+ */
+#ifdef __ANDROID__
+ /* Priority is given to information that complements a face */
+ if (facemgr_complement_facelet_au(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by rule application");
+ return -1;
+ }
+ return 0;
+#endif /* __ANDROID__ */
+ }
+ if (rc < 0)
+ return -1;
+
+// netdevice_t netdevice = NETDEVICE_EMPTY;
+// if (facelet_get_netdevice(facelet, &netdevice) < 0) {
+// ERROR("[facemgr_process_create] Error retrieving netdevice from facelet");
+// return -1;
+// }
+//
+// netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+//#ifdef __ANDROID__
+// /*
+// * In addition to netdevice, netdevice_type should be present to correctly
+// * apply rules
+// */
+// if (facelet_get_netdevice_type(facelet, &netdevice_type) < 0) {
+// ERROR("[facemgr_process_create] Error retrieving netdevice_type from facelet");
+// return -2;
+// }
+//#endif /* __ANDROID__ */
+
+
+ char facelet_s[MAXSZ_FACELET];
+ facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet);
+ //DEBUG("---[ FACELET CREATE : %s ] ---", facelet_s);
+
+ /* Do we have enough information about the facelet ? */
+ if (!facelet_validate_face(facelet)) {
+ if (facemgr_complement_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation");
+ return -1;
+ }
+ // we should not stop after complement_manual but create a face if
+ // possible... so we add a second validation
+ }
+
+ if (!facelet_validate_face(facelet))
+ return 0;
+
+ /*
+ * Is the forwarder connected, and has the facelet cache already sync'ed the
+ * remote faces ?
+ */
+ // TODO
+
+ /*
+ * Actually create the face on the forwarder
+ *
+ * FIXME Currently hicn-light is hardcoded
+ */
+ if (interface_on_event(facemgr->hl, facelet) < 0)
+ return -1;
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ return 0;
+}
+
+/**
+ * \brief Process facelet GET event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ * -2 means we ignored the face purposedly
+ */
+int
+facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet)
+{
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ if (facelet_has_netdevice(facelet)) {
+ netdevice_t netdevice;
+ if (facelet_get_netdevice(facelet, &netdevice) < 0)
+ return -1;
+ if (!IS_VALID_NETDEVICE(netdevice))
+ return -2;
+ return facelet_cache_add(&facemgr->facelet_cache, facelet);
+ }
+ return -2;
+}
+
+/**
+ * \brief Process facelet UPDATE event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ */
+int
+facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet)
+{
+ /* This is the most complex operation since we have the same problems as in
+ * CREATE + the need to manage changes...
+ *
+ * This might eventually trigger a face deletion...
+ */
+
+ /*
+ * Update in local does not mean the face should not be created remotely as
+ * it might be the first time we have enough information to create it
+ */
+
+ char facelet_s[MAXSZ_FACELET];
+ facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet);
+ //DEBUG("---[ FACELET UPDATE : %s ] ---", facelet_s);
+
+ /* Sets face type */
+ if (!facelet_has_face_type(facelet)) {
+
+ /* As key, netdevice and family should always be present */
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+#ifdef __ANDROID__
+ /*
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
+ */
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet");
+ return -2;
+ }
+#endif /* __ANDROID__ */
+
+ facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+ if (facemgr_cfg_get_face_type(facemgr->cfg, &netdevice, netdevice_type, &face_type) < 0)
+ return rc;
+ facelet_set_face_type(facelet, face_type);
+ }
+
+ /* Process GET/UDPATE... */
+ int rc;
+ switch(facelet_get_status(facelet)) {
+ case FACELET_STATUS_UNDEFINED:
+ ERROR("[facemgr_process_update] Unexpected facelet status");
+ return -1;
+
+ case FACELET_STATUS_DELETED:
+ case FACELET_STATUS_NEW:
+ /*
+ * If the remote action should be a CREATE, then we need to check
+ * whether we have enough information about the face...
+ */
+ if (!facelet_validate_face(facelet)) {
+ if (facemgr_complement_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_update] Error while attempting to complement face for fields required by face creation");
+ return -1;
+ }
+ }
+
+ rc = facemgr_facelet_satisfy_rules(facemgr, facelet);
+ if (rc == -3) {
+ facelet_set_status(facelet, FACELET_STATUS_IGNORED);
+ /* Does not satisfy rules */
+ return 0;
+ }
+
+ if (!facelet_validate_face(facelet))
+ return 0;
+
+ facelet_set_event(facelet, FACELET_EVENT_CREATE);
+ interface_on_event(facemgr->hl, facelet);
+
+ /* This works assuming the call to hicn-light is blocking */
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ break;
+
+ case FACELET_STATUS_CLEAN:
+ /* Nothing to do */
+ break;
+
+ case FACELET_STATUS_DIRTY:
+ /*
+ * For now we assume only local changes, and proceed to try and
+ * update the hICN forwarder.
+ *
+ * In case of update, the face exists which means we should already
+ * have enough information
+ */
+ if (!facelet_validate_face(facelet)) {
+ if (facemgr_complement_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation");
+ return -1;
+ }
+ }
+
+ rc = facemgr_facelet_satisfy_rules(facemgr, facelet);
+ if (rc == -3) {
+ facelet_set_status(facelet, FACELET_STATUS_IGNORED);
+ /* Does not satisfy rules */
+ return 0;
+ }
+
+ if (!facelet_validate_face(facelet))
+ return 0;
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ if (interface_on_event(facemgr->hl, facelet) < 0)
+ return -1;
+
+ /* This works assuming the call to hicn-light is blocking and we
+ * have proceeded to all udpates */
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ break;
+
+ case FACELET_STATUS_CONFLICT:
+ ERROR("[facemgr_process_update] Conflict resolution (not) yet implemented");
+ return -1;
+
+ case FACELET_STATUS_ERROR:
+ ERROR("[facemgr_process_update] Case ERROR (not) yet implemented");
+ break;
+
+ case FACELET_STATUS_IGNORED:
+ ERROR("[facemgr_process_update] Case IGNORED (not) yet implemented");
+ break;
+
+ case FACELET_STATUS_N:
+ ERROR("[facemgr_process_update] Facelet in error");
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * \brief Process facelet DELETE event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ */
+int
+facemgr_process_delete(facemgr_t * facemgr, facelet_t * facelet)
+{
+
+ DEBUG("[facemgr_process_delete] Deleting facelet on hicn-light");
+ if (interface_on_event(facemgr->hl, facelet) < 0)
+ return -1;
+
+ /*
+ * It might be tempting to cache old information, but for now we reset the
+ * facelet state that might change (such as IP addresses etc).
+ * netdevice, netdevice_type and admin_state should not be affected.
+ */
+ DEBUG("[facemgr_process_delete] Cleaning cached data");
+ facelet_unset_local_addr(facelet);
+ facelet_unset_local_port(facelet);
+ facelet_unset_remote_addr(facelet);
+ facelet_unset_remote_port(facelet);
+
+ facelet_set_status(facelet, FACELET_STATUS_DELETED);
+
+ facelet_unset_bj_done(facelet);
+
+ return 0;
+}
+
+
+/**
+ * \brief Process incoming events from interfaces
+ *
+ * Implementation notes:
+ * - Any event or timeout due to an interface triggers either a local cache
+ * update, as well a face operations needed to resync the state.
+ */
+int
+facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in)
+{
+ bool remove_facelet = true;
+ int ret = 0;
+ int rc;
+ assert(facelet_in);
+
+ char facelet_s[MAXSZ_FACELET];
+ facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet_in);
+ //DEBUG("----------------------------------");
+ DEBUG("EVENT %s", facelet_s);
+
+ facelet_t ** cached_facelets = NULL;
+ int n = facelet_cache_lookup(&facemgr->facelet_cache, facelet_in, &cached_facelets);
+ if (n < 0) {
+ ERROR("[facemgr_on_event] Error during cache lookup");
+ goto ERR;
+ }
+ if (n == 0) {
+ /* This is a new facelet... we expect a CREATE event. */
+ switch(facelet_get_event(facelet_in)) {
+ case FACELET_EVENT_CREATE:
+
+ if (facelet_cache_add(&facemgr->facelet_cache, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error adding facelet to cache");
+ return -1;
+ }
+ //DEBUG("Facelet added to cache");
+
+ remove_facelet = false;
+
+ if (facemgr_process_create(facemgr, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error processing CREATE event");
+ goto ERR;
+ }
+ break;
+
+ case FACELET_EVENT_GET:
+ /* Insert new facelet in cached */
+ rc = facemgr_process_get(facemgr, facelet_in);
+ if (rc == 0)
+ remove_facelet = false;
+ if (rc == -1) {
+ ERROR("[facemgr_on_event] Error processing GET event");
+ goto ERR;
+ }
+ break;
+
+ case FACELET_EVENT_UPDATE:
+ /* Might be because we previously ignored the facelet... */
+ //ERROR("[facemgr_on_event] Unexpected UPDATE... face does not exist");
+ //goto ERR;
+ INFO("Ignored UPDATE for non-existing face");
+ break;
+
+ case FACELET_EVENT_DELETE:
+ ERROR("[facemgr_on_event] Unexpected DELETE... face does not exist");
+ goto ERR;
+
+ case FACELET_EVENT_UNDEFINED:
+ ERROR("[facemgr_on_event] Unexpected UNDEFINED event.");
+ goto ERR;
+
+ default: /* XXX Some events should be deprecated */
+ ERROR("[facemgr_on_event] Deprecated event");
+ goto ERR;
+ }
+ goto DUMP_CACHE;
+ }
+
+ /*
+ * From now on, it should not make any difference whether we have one or
+ * more facelet.
+ */
+ for (unsigned i = 0; i < n; i ++) {
+ /*
+ * We merge each cached facelet with incoming one, and perform state
+ * reconciliation by sending appropriate updates to the forwarder
+ */
+ facelet_t * facelet = cached_facelets[i];
+ switch(facelet_get_event(facelet_in)) {
+ case FACELET_EVENT_CREATE:
+ // This case will occur when we try to re-create existing faces,
+ // eg. in the situation of a forwarder restarting.
+ // likely this occurs when the interface receives a (potentially new) address
+ if (facelet_merge(facelet, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error merging facelets");
+ continue;
+ }
+ if (facemgr_process_create(facemgr, facelet) < 0) {
+ ERROR("[facemgr_on_event] Error processing CREATE event");
+ ret = -1;
+ }
+ continue;
+
+ case FACELET_EVENT_GET: /* should be an INFORM message */
+ // FIXME, this might occur if the forwarder restarts and we
+ // resync faces...
+ ERROR("[facemgr_on_event] GET event for a face that already exists...");
+ ret = -1;
+ continue;
+
+ case FACELET_EVENT_UPDATE:
+ if (facelet_merge(facelet, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error merging facelets");
+ continue;
+ }
+ if (facemgr_process_update(facemgr, facelet) < 0) {
+ ERROR("[facemgr_on_event] Error processing UPDATE event");
+ ret = -1;
+ }
+ continue;
+
+ case FACELET_EVENT_DELETE:
+ if (facelet_merge(facelet, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error merging facelets");
+ continue;
+ }
+ if (facemgr_process_delete(facemgr, facelet) < 0) {
+ ERROR("[facemgr_on_event] Error processing DELETE event");
+ ret = -1;
+ }
+ continue;
+
+ default: /* XXX Some events should be deprecated */
+ ERROR("[facemgr_on_event] Deprecated event");
+ ret = -1;
+ }
+
+ }
+ free(cached_facelets);
+ goto DUMP_CACHE;
+
+ERR:
+ ret = -1;
+
+DUMP_CACHE:
+#if 1
+ DEBUG(" <CACHE>");
+ facelet_cache_dump(&facemgr->facelet_cache);
+ DEBUG(" </CACHE>");
+ DEBUG("</EVENT ret=%d>", ret);
+ DEBUG("----------------------------------");
+#endif
+
+ if (remove_facelet)
+ facelet_free(facelet_in);
+
+ return ret;
+}
+
+int facemgr_callback(facemgr_t * facemgr, interface_cb_type_t type, void * data)
+{
+ switch(type) {
+ case INTERFACE_CB_TYPE_RAISE_EVENT:
+ return facemgr_on_event(facemgr, data);
+ case INTERFACE_CB_TYPE_REGISTER_FD:
+ return facemgr->callback(facemgr->callback_owner,
+ FACEMGR_CB_TYPE_REGISTER_FD, data);
+ case INTERFACE_CB_TYPE_REGISTER_TIMER:
+ return facemgr->callback(facemgr->callback_owner,
+ FACEMGR_CB_TYPE_REGISTER_TIMER, data);
+ case INTERFACE_CB_TYPE_UNREGISTER_TIMER:
+ return facemgr->callback(facemgr->callback_owner,
+ FACEMGR_CB_TYPE_UNREGISTER_TIMER, data);
+ case INTERFACE_CB_TYPE_UNREGISTER_FD:
+ return facemgr->callback(facemgr->callback_owner,
+ FACEMGR_CB_TYPE_UNREGISTER_FD, data);
+ }
+ return -1;
+}
+
+int
+facemgr_bootstrap(facemgr_t * facemgr)
+{
+ int rc;
+
+ DEBUG("Registering interfaces...");
+ rc = interface_register(&hicn_light_ops);
+ if (rc < 0) {
+ ERROR("Could not register interfaces");
+ goto ERR_REGISTER;
+ }
+
+#ifdef __APPLE__
+ rc = interface_register(&network_framework_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif /* __APPLE__ */
+
+#ifdef __linux__
+ rc = interface_register(&netlink_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+ rc = interface_register(&bonjour_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+ rc = interface_register(&android_utility_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif /* __ANDROID__ */
+
+#ifdef WITH_EXAMPLE_DUMMY
+ rc = interface_register(&dummy_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif
+
+#ifdef WITH_EXAMPLE_UPDOWN
+ rc = interface_register(&updown_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif
+
+ rc = facemgr_create_interface(facemgr, "hl", "hicn_light", NULL, &facemgr->hl);
+ if (rc < 0) {
+ ERROR("Error creating 'hICN forwarder (hicn-light)' interface\n");
+ goto ERR_HL_CREATE;
+ }
+
+#ifdef __APPLE__
+ network_framework_cfg_t nf_cfg = {
+ };
+ rc = facemgr_create_interface(facemgr, "nf", "network_framework", &nf_cfg, &facemgr->nf);
+ if (rc < 0) {
+ ERROR("Error creating 'Apple Network Framework' interface\n");
+ goto ERR_NF_CREATE;
+ }
+#endif /* __APPLE__ */
+
+#ifdef __linux__
+ rc = facemgr_create_interface(facemgr, "nl", "netlink", NULL, &facemgr->nl);
+ if (rc < 0) {
+ ERROR("Error creating 'Netlink' interface\n");
+ goto ERR_NL_CREATE;
+ }
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+ android_utility_cfg_t au_cfg = {
+ .jvm = facemgr->jvm,
+ };
+ rc = facemgr_create_interface(facemgr, "au", "android_utility", &au_cfg, &facemgr->au);
+ if (rc < 0) {
+ ERROR("Error creating 'Android Utility' interface\n");
+ goto ERR_AU_CREATE;
+ }
+#endif /* __ANDROID__ */
+
+#ifdef WITH_EXAMPLE_DUMMY
+ rc = facemgr_create_interface(facemgr, "dummy0", "dummy", NULL, &facemgr->dummy);
+ if (rc < 0) {
+ ERROR("Error creating 'dummy' interface\n");
+ goto ERR_DUMMY_CREATE;
+ }
+#endif
+
+#ifdef WITH_EXAMPLE_UPDOWN
+ rc = facemgr_create_interface(facemgr, "updown0", "updown", NULL, &facemgr->updown);
+ if (rc < 0) {
+ ERROR("Error creating 'updown' interface\n");
+ goto ERR_UPDOWN_CREATE;
+ }
+#endif
+
+ DEBUG("Facemgr successfully initialized...");
+
+ return 0;
+
+ /* FIXME facemgr_delete_interface */
+#ifdef WITH_EXAMPLE_UPDOWN
+ interface_free(facemgr->updown);
+ERR_UPDOWN_CREATE:
+#endif
+#ifdef WITH_EXAMPLE_DUMMY
+ interface_free(facemgr->dummy);
+ERR_DUMMY_CREATE:
+#endif
+#ifdef __ANDROID__
+ interface_free(facemgr->au);
+ERR_AU_CREATE:
+#endif /* __ANDROID__ */
+#ifdef __linux__
+ interface_free(facemgr->nl);
+ERR_NL_CREATE:
+#endif /* __linux__ */
+#ifdef __APPLE__
+ interface_free(facemgr->nf);
+ERR_NF_CREATE:
+#endif /* __APPLE__ */
+ interface_free(facemgr->hl);
+ERR_HL_CREATE:
+ERR_REGISTER:
+ return -1;
+}
+
+void facemgr_stop(facemgr_t * facemgr)
+{
+ // FIXME we should iterate on interface map
+
+#ifdef __APPLE__
+ facemgr_delete_interface(facemgr, facemgr->nf);
+#endif /* __APPLE__ */
+
+
+#ifdef __linux__
+ facemgr_delete_interface(facemgr, facemgr->nl);
+
+ /* Delete all bonjour interfaces */
+ interface_t ** bonjour_array = NULL;
+ int n = bonjour_map_get_value_array(&facemgr->bonjour_map, &bonjour_array);
+ if (n >= 0) {
+ netdevice_t ** netdevice_array = NULL;
+ int m = bonjour_map_get_key_array(&facemgr->bonjour_map, &netdevice_array);
+ if (m >= 0) {
+ assert(m == n);
+ for (int i = 0; i < n; i++) { /* Fail silently */
+ DEBUG("Deleting bonjour interface associated to %s (%p)",
+ netdevice_array[i]->name, bonjour_array[i]);
+ facemgr_delete_interface(facemgr, bonjour_array[i]);
+ }
+ free(netdevice_array);
+ }
+ free(bonjour_array);
+ }
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+ facemgr_delete_interface(facemgr, facemgr->au);
+#endif /* __ANDROID__ */
+
+ facemgr_delete_interface(facemgr, facemgr->hl);
+
+#ifdef WITH_EXAMPLE_DUMMY
+ facemgr_delete_interface(facemgr, facemgr->dummy);
+#endif
+
+#ifdef WITH_EXAMPLE_UPDOWN
+ facemgr_delete_interface(facemgr, facemgr->updown);
+#endif
+}
+
+#ifdef __ANDROID__
+void facemgr_set_jvm(facemgr_t * facemgr, JavaVM *jvm)
+{
+ facemgr->jvm = jvm;
+}
+#endif /* __ANDROID__ */
+
+void
+facemgr_set_callback(facemgr_t * facemgr, void * callback_owner, facemgr_cb_t callback)
+{
+ facemgr->callback = callback;
+ facemgr->callback_owner = callback_owner;
+}
+
+void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data)
+{
+ //face_cache_iter(&facemgr->face_cache, cb, user_data);
+ facelet_cache_dump(&facemgr->facelet_cache);
+}
diff --git a/ctrl/facemgr/src/cfg.c b/ctrl/facemgr/src/cfg.c
new file mode 100644
index 000000000..527da54e7
--- /dev/null
+++ b/ctrl/facemgr/src/cfg.c
@@ -0,0 +1,1040 @@
+/**
+ * \file cfg.c
+ * \brief Implementation of Face manager configuration
+ */
+
+#include <assert.h>
+#include <hicn/ctrl.h> // HICN_DEFAULT_PORT
+#include <hicn/facemgr/cfg.h>
+#include <hicn/policy.h>
+#include <hicn/util/ip_address.h>
+#include "util/set.h"
+
+/* Overlay */
+
+typedef struct {
+ bool is_local_port;
+ uint16_t local_port;
+ bool is_local_addr;
+ ip_address_t local_addr;
+ bool is_remote_port;
+ uint16_t remote_port;
+ bool is_remote_addr;
+ ip_address_t remote_addr;
+} facemgr_cfg_overlay_t;
+
+int
+facemgr_cfg_overlay_initialize(facemgr_cfg_overlay_t * overlay)
+{
+ overlay->is_local_port = false;
+ overlay->local_port = 0;
+ overlay->is_local_addr = false;
+ overlay->local_addr = IP_ADDRESS_EMPTY;
+
+ overlay->is_remote_port = false;
+ overlay->remote_port = 0;
+ overlay->is_remote_addr = false;
+ overlay->remote_addr = IP_ADDRESS_EMPTY;
+
+ return 0;
+}
+
+int
+facemgr_cfg_overlay_finalize(facemgr_cfg_overlay_t * overlay)
+{
+ return 0;
+}
+
+facemgr_cfg_overlay_t * facemgr_cfg_overlay_create()
+{
+ facemgr_cfg_overlay_t * overlay = malloc(sizeof(facemgr_cfg_overlay_t));
+ if (!overlay)
+ return NULL;
+
+ int rc = facemgr_cfg_overlay_initialize(overlay);
+ if (rc < 0) {
+ free(overlay);
+ return NULL;
+ }
+
+ return overlay;
+}
+
+void facemgr_cfg_overlay_free(facemgr_cfg_overlay_t * overlay)
+{
+ facemgr_cfg_overlay_finalize(overlay);
+ free(overlay);
+}
+
+typedef struct {
+ facemgr_cfg_overlay_t * v4;
+ facemgr_cfg_overlay_t * v6;
+} facemgr_cfg_overlays_t;
+
+typedef struct {
+ const char * interface_name;
+ netdevice_type_t interface_type;
+} facemgr_cfg_match_t;
+
+
+typedef struct {
+ /* Interface specific */
+ bool is_face_type; // default is auto
+ facemgr_face_type_t face_type;
+
+ /* This should be defaut for the global settings */
+ bool is_ignore;
+ bool ignore;
+ bool is_discovery;
+ bool discovery;
+ bool is_ipv4;
+ bool ipv4;
+ bool is_ipv6;
+ bool ipv6;
+
+ facemgr_cfg_overlays_t overlays; // fallback unless discovery is disabled
+} facemgr_cfg_override_t;
+
+struct facemgr_cfg_rule_s {
+ facemgr_cfg_match_t match;
+ facemgr_cfg_override_t override;
+};
+
+int
+facemgr_cfg_override_initialize(facemgr_cfg_override_t * override)
+{
+ override->is_face_type = false;
+ override->face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+
+ override->is_ignore = false;
+ override->ignore = false;
+
+ override->is_discovery = false;
+ override->discovery = false;
+
+ override->is_ipv4 = false;
+ override->ipv6 = false;
+ override->is_ipv6 = false;
+ override->ipv6 = false;
+
+ override->overlays.v4 = NULL;
+ override->overlays.v6 = NULL;
+
+ return 0;
+}
+
+int
+facemgr_cfg_override_finalize(facemgr_cfg_override_t * override)
+{
+ if (override->overlays.v4) {
+ facemgr_cfg_overlay_free(override->overlays.v4);
+ override->overlays.v4 = NULL;
+ }
+ if (override->overlays.v6) {
+ facemgr_cfg_overlay_free(override->overlays.v6);
+ override->overlays.v6 = NULL;
+ }
+
+ return 0;
+}
+
+
+/* Rule */
+facemgr_cfg_rule_t * facemgr_cfg_rule_create()
+{
+ facemgr_cfg_rule_t * rule = malloc(sizeof(facemgr_cfg_rule_t));
+ if (!rule)
+ return NULL;
+
+ int rc = facemgr_cfg_rule_initialize(rule);
+ if (rc < 0)
+ return NULL;
+
+ return rule;
+}
+
+void facemgr_cfg_rule_free(facemgr_cfg_rule_t * rule)
+{
+ facemgr_cfg_rule_finalize(rule);
+ free(rule);
+}
+
+int
+facemgr_cfg_rule_initialize(facemgr_cfg_rule_t * rule)
+{
+ rule->match.interface_name = NULL;
+ rule->match.interface_type = NETDEVICE_TYPE_UNDEFINED;
+
+ int rc = facemgr_cfg_override_initialize(&rule->override);
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int
+facemgr_cfg_rule_finalize(facemgr_cfg_rule_t * rule)
+{
+ if (rule->match.interface_name) {
+ free((void*)rule->match.interface_name);
+ rule->match.interface_name = NULL;
+ }
+ return facemgr_cfg_override_finalize(&rule->override);
+}
+
+void
+facemgr_cfg_rule_dump(facemgr_cfg_rule_t * rule)
+{
+ DEBUG(" <rule>");
+ DEBUG(" <match interface_name=%s interface_type=%s>",
+ rule->match.interface_name,
+ netdevice_type_str[rule->match.interface_type]);
+ DEBUG(" <override>");
+ if (rule->override.is_face_type) {
+ DEBUG(" <face_type>%d</face_type>", rule->override.face_type);
+ }
+ if (rule->override.is_ignore) {
+ DEBUG(" <ignore>%d</ignore>", rule->override.ignore);
+ }
+ if (rule->override.is_discovery) {
+ DEBUG(" <discovery>%d</discovery>", rule->override.discovery);
+ }
+ if (rule->override.is_ipv4) {
+ DEBUG(" <ipv4>%d</ipv4>", rule->override.ipv4);
+ }
+ if (rule->override.is_ipv6) {
+ DEBUG(" <ipv6>%d</ipv6>", rule->override.ipv6);
+ }
+ DEBUG(" <overlays>");
+ if (rule->override.overlays.v4) {
+ DEBUG(" <ipv4>");
+ if (rule->override.overlays.v4->is_local_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &rule->override.overlays.v4->local_addr, AF_INET);
+ DEBUG(" <local_addr>%s</local_addr>", buf);
+ }
+ if (rule->override.overlays.v4->is_local_port) {
+ DEBUG(" <local_port>%d</local_port>",
+ rule->override.overlays.v4->local_port);
+ }
+ if (rule->override.overlays.v4->is_remote_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &rule->override.overlays.v4->remote_addr, AF_INET);
+ DEBUG(" <remote_addr>%s</remote_addr>", buf);
+ }
+ if (rule->override.overlays.v4->is_remote_port) {
+ DEBUG(" <remote_port>%d</remote_port>",
+ rule->override.overlays.v4->remote_port);
+ }
+ DEBUG(" </ipv4>");
+ }
+ if (rule->override.overlays.v6) {
+ DEBUG(" <ipv6>");
+ if (rule->override.overlays.v6->is_local_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &rule->override.overlays.v6->local_addr, AF_INET6);
+ DEBUG(" <local_addr>%s</local_addr>", buf);
+ }
+ if (rule->override.overlays.v6->is_local_port) {
+ DEBUG(" <local_port>%d</local_port>",
+ rule->override.overlays.v6->local_port);
+ }
+ if (rule->override.overlays.v6->is_remote_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &rule->override.overlays.v6->remote_addr, AF_INET6);
+ DEBUG(" <remote_addr>%s</remote_addr>", buf);
+ }
+ if (rule->override.overlays.v6->is_remote_port) {
+ DEBUG(" <remote_port>%d</remote_port>",
+ rule->override.overlays.v6->remote_port);
+ }
+ DEBUG(" </ipv6>");
+ }
+ DEBUG(" </overlays>");
+ DEBUG(" </override>");
+ DEBUG(" </rule>");
+}
+
+int
+facemgr_cfg_rule_set_match(facemgr_cfg_rule_t * rule, const char * interface_name,
+ netdevice_type_t interface_type)
+{
+ rule->match.interface_name = interface_name ? strdup(interface_name) : NULL;
+ rule->match.interface_type = interface_type;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_face_type(facemgr_cfg_rule_t * rule, facemgr_face_type_t * face_type)
+{
+ rule->override.is_face_type = true;
+ rule->override.face_type = *face_type;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_face_type(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_face_type = false;
+ rule->override.face_type = FACEMGR_FACE_TYPE_UNDEFINED; /* optional */
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_discovery(facemgr_cfg_rule_t * rule, bool status)
+{
+ rule->override.is_discovery = true;
+ rule->override.discovery = status;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_discovery(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_discovery = false;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_ignore(facemgr_cfg_rule_t * rule, bool status)
+{
+ rule->override.is_ignore = true;
+ rule->override.ignore = status;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_ignore(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_ignore = false;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_ipv4(facemgr_cfg_rule_t * rule, bool status)
+{
+ rule->override.is_ipv4 = true;
+ rule->override.ipv4 = status;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_ipv4(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_ipv4 = false;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_ipv6(facemgr_cfg_rule_t * rule, bool status)
+{
+ rule->override.is_ipv6 = true;
+ rule->override.ipv6 = status;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_ipv6(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_ipv6 = false;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_overlay(facemgr_cfg_rule_t * rule, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port) {
+ if ((family != AF_INET) && (family != AF_INET6))
+ return -1;
+
+ facemgr_cfg_overlay_t * overlay = facemgr_cfg_overlay_create();
+ if (local_addr) {
+ overlay->is_local_addr = true;
+ overlay->local_addr = *local_addr;
+ }
+ if (IS_VALID_PORT(local_port)) {
+ overlay->is_local_port = true;
+ overlay->local_port = local_port;
+ }
+ if (remote_addr) {
+ overlay->is_remote_addr = true;
+ overlay->remote_addr = *remote_addr;
+ }
+ if (IS_VALID_PORT(remote_port)) {
+ overlay->is_remote_port = true;
+ overlay->remote_port = remote_port;
+ }
+
+ switch(family) {
+ case AF_INET:
+ rule->override.overlays.v4 = overlay;
+ break;
+
+ case AF_INET6:
+ rule->override.overlays.v6 = overlay;
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+facemgr_rule_unset_overlay(facemgr_cfg_rule_t * rule, int family)
+{
+ if ((family != AF_INET) && (family != AF_INET6) && (family != AF_UNSPEC))
+ return -1;
+
+ if ((family == AF_UNSPEC) || (family == AF_INET)) {
+ if (rule->override.overlays.v4) {
+ facemgr_cfg_overlay_free(rule->override.overlays.v4);
+ rule->override.overlays.v4 = NULL;
+ }
+ }
+ if ((family == AF_UNSPEC) || (family == AF_INET6)) {
+ if (rule->override.overlays.v6) {
+ facemgr_cfg_overlay_free(rule->override.overlays.v6);
+ rule->override.overlays.v6 = NULL;
+ }
+ }
+ return 0;
+}
+
+int
+facemgr_cfg_rule_cmp(const facemgr_cfg_rule_t * r1, const facemgr_cfg_rule_t * r2)
+{
+ /*
+ * We implement a lexicographic order on the tuple (interface_name,
+ * interface_type)
+ */
+
+ /* We need to handle NULL cases out of strcmp */
+ if (!r1->match.interface_name) {
+ if (r2->match.interface_name)
+ return 1;
+ else
+ goto BOTH_NULL;
+ } else {
+ if (!r2->match.interface_name)
+ return -1;
+ }
+
+
+ /* Only if both are non-NULL, we proceed to strcmp */
+ int rc = strcmp(r1->match.interface_name, r2->match.interface_name);
+ if (rc != 0)
+ return rc;
+
+BOTH_NULL:
+ return r1->match.interface_type - r2->match.interface_type;
+}
+
+/* General */
+
+TYPEDEF_SET_H(facemgr_cfg_rule_set, facemgr_cfg_rule_t *);
+TYPEDEF_SET(facemgr_cfg_rule_set, facemgr_cfg_rule_t *, facemgr_cfg_rule_cmp, generic_snprintf);
+
+struct facemgr_cfg_s {
+ facemgr_cfg_override_t global;
+ facemgr_cfg_rule_set_t * rule_set;
+ //log_cfg_t log;
+};
+
+facemgr_cfg_t * facemgr_cfg_create()
+{
+ facemgr_cfg_t * cfg = malloc(sizeof(facemgr_cfg_t));
+ if (!cfg)
+ return NULL;
+
+ int rc = facemgr_cfg_initialize(cfg);
+ if (rc < 0) {
+ free(cfg);
+ return NULL;
+ }
+
+ return cfg;
+}
+
+void facemgr_cfg_free(facemgr_cfg_t * cfg)
+{
+ facemgr_cfg_finalize(cfg);
+ free(cfg);
+}
+
+int
+facemgr_cfg_initialize(facemgr_cfg_t * cfg)
+{
+ int rc = facemgr_cfg_override_initialize(&cfg->global);
+ if (rc < 0)
+ goto ERR_OVERRIDE;
+
+ cfg->rule_set = facemgr_cfg_rule_set_create();
+ if (!cfg->rule_set)
+ goto ERR_RULE_SET;
+
+ return 0;
+
+ERR_RULE_SET:
+ facemgr_cfg_override_finalize(&cfg->global);
+ERR_OVERRIDE:
+ return -1;
+}
+
+int
+facemgr_cfg_finalize(facemgr_cfg_t * cfg)
+{
+ /* TODO Free all rules */
+ facemgr_cfg_rule_t ** rule_array;
+ int n = facemgr_cfg_rule_set_get_array(cfg->rule_set, &rule_array);
+ if (n < 0) {
+ ERROR("[facemgr_cfg_finalize] Could not retrieve rule set array from configuration");
+ } else {
+ for (unsigned i = 0; i < n; i++) {
+ facemgr_cfg_rule_t * rule = rule_array[i];
+ if (facemgr_cfg_rule_set_remove(cfg->rule_set, rule, NULL) < 0) {
+ ERROR("[facemgr_cfg_finalize] Could not remove rule from set");
+ }
+ facemgr_cfg_rule_free(rule);
+ }
+ free(rule_array);
+ }
+ facemgr_cfg_rule_set_free(cfg->rule_set);
+ return facemgr_cfg_override_finalize(&cfg->global);
+}
+
+void facemgr_cfg_dump(facemgr_cfg_t * cfg)
+{
+ return; /* NOT IMPLEMENTED */
+}
+
+/* General */
+int
+facemgr_cfg_set_face_type(facemgr_cfg_t * cfg, facemgr_face_type_t * face_type)
+{
+ cfg->global.is_face_type = true;
+ cfg->global.face_type = *face_type;
+ return 0;
+}
+
+int
+facemgr_cfg_unset_face_type(facemgr_cfg_t * cfg)
+{
+ cfg->global.is_face_type = false;
+ cfg->global.face_type = FACEMGR_FACE_TYPE_UNDEFINED; /* optional */
+ return 0;
+}
+
+int
+facemgr_cfg_set_discovery(facemgr_cfg_t * cfg, bool status)
+{
+ cfg->global.is_discovery = true;
+ cfg->global.discovery = status;
+ return 0;
+}
+
+int
+facemgr_cfg_unset_discovery(facemgr_cfg_t * cfg)
+{
+ cfg->global.is_discovery = false;
+ return 0;
+}
+
+int facemgr_cfg_set_ipv4(facemgr_cfg_t * cfg, bool status)
+{
+ cfg->global.is_ipv4 = true;
+ cfg->global.ipv4 = status;
+ DEBUG("<global>");
+ DEBUG(" <ipv4>%d</ipv4>", cfg->global.ipv4);
+ DEBUG("</global>");
+ return 0;
+}
+
+int facemgr_cfg_unset_ipv4(facemgr_cfg_t * cfg)
+{
+ cfg->global.is_ipv4 = false;
+ return 0;
+}
+
+int facemgr_cfg_set_ipv6(facemgr_cfg_t * cfg, bool status)
+{
+ cfg->global.is_ipv6 = true;
+ cfg->global.ipv6 = status;
+ DEBUG("<global>");
+ DEBUG(" <ipv6>%d</ipv6>", cfg->global.ipv6);
+ DEBUG("</global>");
+ return 0;
+}
+
+int facemgr_cfg_unset_ipv6(facemgr_cfg_t * cfg)
+{
+ cfg->global.is_ipv6 = false;
+ return 0;
+}
+
+int
+facemgr_cfg_set_overlay(facemgr_cfg_t * cfg, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port)
+{
+ if ((family != AF_INET) && (family != AF_INET6))
+ return -1;
+
+ facemgr_cfg_overlay_t * overlay = facemgr_cfg_overlay_create();
+ if (local_addr) {
+ overlay->is_local_addr = true;
+ overlay->local_addr = *local_addr;
+ }
+ if (IS_VALID_PORT(local_port)) {
+ overlay->is_local_port = true;
+ overlay->local_port = local_port;
+ }
+ if (remote_addr) {
+ overlay->is_remote_addr = true;
+ overlay->remote_addr = *remote_addr;
+ }
+ if (IS_VALID_PORT(remote_port)) {
+ overlay->is_remote_port = true;
+ overlay->remote_port = remote_port;
+ }
+
+ DEBUG("facemgr_cfg_set_overlay");
+
+ switch(family) {
+ case AF_INET:
+ cfg->global.overlays.v4 = overlay;
+ break;
+
+ case AF_INET6:
+ cfg->global.overlays.v6 = overlay;
+ break;
+
+ default:
+ return -1;
+ }
+
+ DEBUG("<global>");
+ DEBUG(" <overlay>");
+ if (overlay) {
+ DEBUG(" <ipv4>");
+ if (overlay->is_local_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &overlay->local_addr, AF_INET);
+ DEBUG(" <local_addr>%s</local_addr>", buf);
+ }
+ if (overlay->is_local_port) {
+ DEBUG(" <local_port>%d</local_port>",
+ overlay->local_port);
+ }
+ if (overlay->is_remote_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &overlay->remote_addr, AF_INET);
+ DEBUG(" <remote_addr>%s</remote_addr>", buf);
+ }
+ if (overlay->is_remote_port) {
+ DEBUG(" <remote_port>%d</remote_port>",
+ overlay->remote_port);
+ }
+ DEBUG(" </ipv4>");
+ }
+ DEBUG(" </overlay>");
+ DEBUG("</global>");
+
+ return 0;
+}
+
+int
+facemgr_cfg_unset_overlay(facemgr_cfg_t * cfg, int family)
+{
+ if ((family != AF_INET) && (family != AF_INET6) && (family != AF_UNSPEC))
+ return -1;
+
+ if ((family == AF_UNSPEC) || (family == AF_INET)) {
+ if (cfg->global.overlays.v4) {
+ facemgr_cfg_overlay_free(cfg->global.overlays.v4);
+ cfg->global.overlays.v4 = NULL;
+ }
+ }
+ if ((family == AF_UNSPEC) || (family == AF_INET6)) {
+ if (cfg->global.overlays.v6) {
+ facemgr_cfg_overlay_free(cfg->global.overlays.v6);
+ cfg->global.overlays.v6 = NULL;
+ }
+ }
+ return 0;
+}
+
+int
+facemgr_cfg_add_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule)
+{
+ facemgr_cfg_rule_dump(rule);
+ return facemgr_cfg_rule_set_add(cfg->rule_set, rule);
+}
+
+int
+facemgr_cfg_del_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule)
+{
+ return facemgr_cfg_rule_set_remove(cfg->rule_set, rule, NULL);
+}
+
+int facemgr_cfg_get_rule(const facemgr_cfg_t * cfg, const char * interface_name,
+ netdevice_type_t interface_type, facemgr_cfg_rule_t ** rule) {
+ facemgr_cfg_rule_t rule_search = {
+ .match = {
+ .interface_name = interface_name,
+ .interface_type = interface_type,
+ },
+ };
+ return facemgr_cfg_rule_set_get(cfg->rule_set, &rule_search, rule);
+}
+
+/* Query API */
+
+/*
+ * Check whether there are override rules for the given netdevice
+ *
+ * TODO:
+ * - until we have proper indexes we loop through the whole structure
+ */
+int
+facemgr_cfg_get_override(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ facemgr_cfg_override_t ** override)
+{
+ if (!netdevice) {
+ *override = NULL;
+ return 0;
+ }
+
+ facemgr_cfg_rule_t **rule_array;
+ int rc = facemgr_cfg_rule_set_get_array(cfg->rule_set, &rule_array);
+ if (rc < 0) {
+ ERROR("facemgr_cfg_rule_set_get_array failed");
+ return rc;
+ }
+ for (unsigned i = 0; i < rc; i++) {
+ const char * interface_name = rule_array[i]->match.interface_name;
+ /* Check match for interface name */
+ if (interface_name && (strcmp(interface_name, netdevice->name) != 0))
+ continue;
+ /* Check match for interface type */
+ if (rule_array[i]->match.interface_type != NETDEVICE_TYPE_UNDEFINED) {
+#ifdef __ANDROID__
+ if (netdevice_type != rule_array[i]->match.interface_type)
+ continue;
+#else
+ ERROR("Match on interface type is currently not implemented");
+ goto ERR_ARRAY;
+#endif /* __ANDROID__ */
+ }
+ /* Found match... do we have an override for face_type */
+ *override = &rule_array[i]->override;
+ goto FOUND;
+ }
+
+ *override = NULL;
+
+FOUND:
+ free(rule_array);
+ return 0;
+
+#ifndef __ANDROID__
+ERR_ARRAY:
+ free(rule_array);
+ return -1;
+#endif /* __ANDROID__ */
+}
+
+int
+facemgr_cfg_get_face_type(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ facemgr_face_type_t * face_type)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0) {
+ ERROR("get override failed");
+ return rc;
+ }
+
+ if ((override) && (override->is_face_type)) {
+ *face_type = override->face_type;
+ return 0;
+ }
+
+ *face_type = cfg->global.is_face_type
+ ? cfg->global.face_type
+ : FACEMGR_FACE_TYPE_DEFAULT;
+
+ return 0;
+}
+
+int
+facemgr_cfg_get_discovery(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * discovery)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ if ((override) && (override->is_discovery)) {
+ *discovery = override->discovery;
+ return 0;
+ }
+
+ *discovery = cfg->global.is_discovery
+ ? cfg->global.discovery
+ : FACEMGR_CFG_DEFAULT_DISCOVERY;
+ return 0;
+}
+
+int
+facemgr_cfg_get_ipv4(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ipv4)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ if ((override) && (override->is_ipv4)) {
+ *ipv4 = override->ipv4;
+ return 0;
+ }
+
+ *ipv4 = cfg->global.is_ipv4
+ ? cfg->global.ipv4
+ : FACEMGR_CFG_DEFAULT_IPV4;
+ return 0;
+}
+
+int
+facemgr_cfg_get_ipv6(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ipv6)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ if ((override) && (override->is_ipv6)) {
+ *ipv6 = override->ipv6;
+ return 0;
+ }
+
+ *ipv6 = cfg->global.is_ipv6
+ ? cfg->global.ipv6
+ : FACEMGR_CFG_DEFAULT_IPV6;
+ return 0;
+}
+
+int
+facemgr_cfg_get_ignore(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ignore)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ if ((override) && (override->is_ignore)) {
+ *ignore = override->ignore;
+ return 0;
+ }
+
+ assert (!cfg->global.is_ignore);
+
+ *ignore = (netdevice && (netdevice->name[0] != '\0') && strcmp(netdevice->name, "lo") == 0);
+
+ return 0;
+}
+
+int
+facemgr_cfg_get_overlay_local_addr(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, ip_address_t * addr)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ switch (family) {
+ case AF_INET:
+ if ((override) && (override->overlays.v4) && (override->overlays.v4->is_local_addr)) {
+ *addr = override->overlays.v4->local_addr;
+ return 0;
+ }
+ if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_local_addr)) {
+ *addr = cfg->global.overlays.v4->local_addr;
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if ((override) && (override->overlays.v6) && (override->overlays.v6->is_local_addr)) {
+ *addr = override->overlays.v6->local_addr;
+ return 0;
+ }
+ if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_local_addr)) {
+ *addr = cfg->global.overlays.v6->local_addr;
+ return 0;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ default:
+ return -1;
+ }
+
+ *addr = IP_ADDRESS_EMPTY;
+ return 0;
+}
+
+int
+facemgr_cfg_get_overlay_local_port(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, u16 * port)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ switch (family) {
+ case AF_INET:
+ if ((override) && (override->overlays.v4) && (override->overlays.v4->is_local_port)) {
+ *port = override->overlays.v4->local_port;
+ return 0;
+ }
+ if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_local_port)) {
+ *port = cfg->global.overlays.v4->local_port;
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if ((override) && (override->overlays.v6) && (override->overlays.v6->is_local_port)) {
+ *port = override->overlays.v6->local_port;
+ return 0;
+ }
+ if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_local_port)) {
+ *port = cfg->global.overlays.v6->local_port;
+ return 0;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ default:
+ return -1;
+ }
+
+ *port = HICN_DEFAULT_PORT;
+ return 0;
+}
+
+int
+facemgr_cfg_get_overlay_remote_addr(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, ip_address_t * addr)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ switch (family) {
+ case AF_INET:
+ if ((override) && (override->overlays.v4) && (override->overlays.v4->is_remote_addr)) {
+ DEBUG("remote addr v4 from override");
+ *addr = override->overlays.v4->remote_addr;
+ return 0;
+ }
+ if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_remote_addr)) {
+ DEBUG("remote addr v4 from global");
+ *addr = cfg->global.overlays.v4->remote_addr;
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if ((override) && (override->overlays.v6) && (override->overlays.v6->is_remote_addr)) {
+ DEBUG("remote addr v6 from override");
+ *addr = override->overlays.v6->remote_addr;
+ return 0;
+ }
+ if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_remote_addr)) {
+ DEBUG("remote addr v6 from global");
+ *addr = cfg->global.overlays.v6->remote_addr;
+ return 0;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ default:
+ return -1;
+ }
+
+ DEBUG("remote addr empty");
+ *addr = IP_ADDRESS_EMPTY;
+ return 0;
+}
+
+int
+facemgr_cfg_get_overlay_remote_port(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, u16 * port)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ switch (family) {
+ case AF_INET:
+ if ((override) && (override->overlays.v4) && (override->overlays.v4->is_remote_port)) {
+ *port = override->overlays.v4->remote_port;
+ return 0;
+ }
+ if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_remote_port)) {
+ *port = cfg->global.overlays.v4->remote_port;
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if ((override) && (override->overlays.v6) && (override->overlays.v6->is_remote_port)) {
+ *port = override->overlays.v6->remote_port;
+ return 0;
+ }
+ if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_remote_port)) {
+ *port = cfg->global.overlays.v6->remote_port;
+ return 0;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ default:
+ return -1;
+ }
+
+ *port = HICN_DEFAULT_PORT;
+ return 0;
+}
diff --git a/ctrl/facemgr/src/cfg_file.c b/ctrl/facemgr/src/cfg_file.c
new file mode 100644
index 000000000..5c187e0a2
--- /dev/null
+++ b/ctrl/facemgr/src/cfg_file.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file cfg_file.c
+ * \brief Implementation of configuration file parsing
+ */
+
+#include <unistd.h> // access
+#include <libconfig.h>
+#include "cfg_file.h"
+
+#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x))
+
+static const char * DEFAULT_CFGFILES[] = {
+ "/etc/facemgr.conf",
+ "~/facemgr.conf",
+};
+
+int
+probe_cfgfile(char * f)
+{
+ for (unsigned i = 0; i < ARRAYSIZE(DEFAULT_CFGFILES); i++) {
+ if (access(DEFAULT_CFGFILES[i], F_OK ) != -1) {
+ if (!realpath(DEFAULT_CFGFILES[i], f))
+ continue;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+parse_config_global(facemgr_cfg_t * cfg, config_setting_t * setting)
+{
+ /* - face_type */
+
+ const char *face_type_str;
+ facemgr_face_type_t face_type;
+ if (config_setting_lookup_string(setting, "face_type", &face_type_str)) {
+ if (strcasecmp(face_type_str, "auto") == 0) {
+ face_type = FACEMGR_FACE_TYPE_DEFAULT;
+ } else
+ if (strcasecmp(face_type_str, "native-udp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_NATIVE_UDP;
+ } else
+ if (strcasecmp(face_type_str, "native-tcp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_NATIVE_TCP;
+ } else
+ if (strcasecmp(face_type_str, "overlay-udp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP;
+ } else
+ if (strcasecmp(face_type_str, "overlay-tcp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP;
+ } else {
+ ERROR("Invalid face type in section 'global'");
+ return -1;
+ }
+
+ int rc = facemgr_cfg_set_face_type(cfg, &face_type);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* - disable_discovery */
+
+ int disable_discovery;
+ if (config_setting_lookup_bool(setting, "disable_discovery",
+ &disable_discovery)) {
+ int rc = facemgr_cfg_set_discovery(cfg, !disable_discovery);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* - disable_ipv4 */
+
+ int disable_ipv4;
+ if (config_setting_lookup_bool(setting, "disable_ipv4",
+ &disable_ipv4)) {
+ int rc = facemgr_cfg_set_ipv4(cfg, !disable_ipv4);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* - disable ipv6 */
+
+ int disable_ipv6;
+ if (config_setting_lookup_bool(setting, "disable_ipv6",
+ &disable_ipv6)) {
+ int rc = facemgr_cfg_set_ipv6(cfg, !disable_ipv6);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* - overlay */
+ config_setting_t *overlay = config_setting_get_member(setting, "overlay");
+ if (overlay) {
+
+ /* ipv4 */
+ config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4");
+ if (overlay_v4) {
+ const char * local_addr_str, * remote_addr_str;
+ ip_address_t local_addr = IP_ADDRESS_EMPTY;
+ ip_address_t remote_addr = IP_ADDRESS_EMPTY;
+ ip_address_t * local_addr_p = NULL;
+ ip_address_t * remote_addr_p = NULL;
+ int local_port = 0;
+ int remote_port = 0;
+
+ if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) {
+ if (ip_address_pton(local_addr_str, &local_addr) < 0) {
+ ERROR("Error parsing v4 local addr");
+ goto ERR;
+ }
+ local_addr_p = &local_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) {
+ if (!IS_VALID_PORT(local_port))
+ goto ERR;
+ }
+
+ if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) {
+ if (ip_address_pton(remote_addr_str, &remote_addr) < 0) {
+ ERROR("Error parsing v4 remote addr");
+ goto ERR;
+ }
+ remote_addr_p = &remote_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) {
+ if (!IS_VALID_PORT(remote_port))
+ goto ERR;
+ }
+ int rc = facemgr_cfg_set_overlay(cfg, AF_INET,
+ local_addr_p, local_port,
+ remote_addr_p, remote_port);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* ipv6 */
+ config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6");
+ if (overlay_v6) {
+ const char * local_addr_str, * remote_addr_str;
+ ip_address_t local_addr = IP_ADDRESS_EMPTY;
+ ip_address_t remote_addr = IP_ADDRESS_EMPTY;
+ ip_address_t * local_addr_p = NULL;
+ ip_address_t * remote_addr_p = NULL;
+ int local_port = 0;
+ int remote_port = 0;
+
+ if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) {
+ if (ip_address_pton(local_addr_str, &local_addr) < 0) {
+ ERROR("Error parsing v6 local addr");
+ goto ERR;
+ }
+ local_addr_p = &local_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) {
+ if (!IS_VALID_PORT(local_port))
+ goto ERR;
+ }
+
+ if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) {
+ if (ip_address_pton(remote_addr_str, &remote_addr) < 0) {
+ ERROR("Error parsing v6 remote addr");
+ goto ERR;
+ }
+ remote_addr_p = &remote_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) {
+ if (!IS_VALID_PORT(remote_port))
+ goto ERR;
+ }
+ int rc = facemgr_cfg_set_overlay(cfg, AF_INET6,
+ local_addr_p, local_port,
+ remote_addr_p, remote_port);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ } /* overlay */
+
+ return 0;
+
+ERR:
+ return -1;
+}
+
+int
+parse_config_rules(facemgr_cfg_t * cfg, config_setting_t * setting)
+{
+ /* List of match-override tuples */
+ facemgr_cfg_rule_t * rule;
+
+ int count = config_setting_length(setting);
+ for (unsigned i = 0; i < count; ++i) {
+ config_setting_t * rule_setting = config_setting_get_elem(setting, i);
+
+ /* Sanity check */
+
+ config_setting_t * match_setting = config_setting_get_member(rule_setting, "match");
+ if (!match_setting) {
+ ERROR("Missing match section in rule #%d", i);
+ goto ERR_CHECK;
+ }
+
+ config_setting_t * override_setting = config_setting_get_member(rule_setting, "override");
+ if (!override_setting) {
+ ERROR("Missing override section in rule #%d", i);
+ goto ERR_CHECK;
+ }
+
+ rule = facemgr_cfg_rule_create();
+ if (!rule)
+ goto ERR_RULE;
+
+ /* Parse match */
+
+ const char * interface_name = NULL;
+ config_setting_lookup_string(match_setting, "interface_name", &interface_name);
+
+ const char * interface_type_str;
+ netdevice_type_t interface_type = NETDEVICE_TYPE_UNDEFINED;
+ if (config_setting_lookup_string(match_setting, "interface_type", &interface_type_str)) {
+ if (strcasecmp(interface_type_str, "wired") == 0) {
+ interface_type = NETDEVICE_TYPE_WIRED;
+ } else
+ if (strcasecmp(interface_type_str, "wifi") == 0) {
+ interface_type = NETDEVICE_TYPE_WIFI;
+ } else
+ if (strcasecmp(interface_type_str, "cellular") == 0) {
+ interface_type = NETDEVICE_TYPE_CELLULAR;
+ } else {
+ ERROR("Unknown interface type in rule #%d", i);
+ goto ERR;
+ }
+ }
+
+ if ((!interface_name) && (interface_type == NETDEVICE_TYPE_UNDEFINED)) {
+ ERROR("Empty match section in rule #%d", i);
+ goto ERR;
+ }
+
+ /* Associate match to rule */
+
+ int rc = facemgr_cfg_rule_set_match(rule, interface_name, interface_type);
+ if (rc < 0)
+ goto ERR;
+
+ /* Parse override */
+
+ /* - face_type */
+
+ const char *face_type_str;
+ facemgr_face_type_t face_type;
+ if (config_setting_lookup_string(override_setting, "face_type", &face_type_str)) {
+ if (strcasecmp(face_type_str, "auto")) {
+ /* We currently hardcode different behaviours based on the OS */
+#ifdef __ANDROID__
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP;
+#else
+ face_type = FACEMGR_FACE_TYPE_NATIVE_TCP;
+#endif
+ } else
+ if (strcasecmp(face_type_str, "native-udp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_NATIVE_UDP;
+ } else
+ if (strcasecmp(face_type_str, "native-tcp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_NATIVE_TCP;
+ } else
+ if (strcasecmp(face_type_str, "overlay-udp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP;
+ } else
+ if (strcasecmp(face_type_str, "overlay-tcp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP;
+ } else {
+ ERROR("Invalid face type in section 'global'");
+ return -1;
+ }
+
+ int rc = facemgr_cfg_rule_set_face_type(rule, &face_type);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* - disable_discovery */
+
+ int disable_discovery;
+ if (config_setting_lookup_bool(override_setting, "disable_discovery",
+ &disable_discovery)) {
+ int rc = facemgr_cfg_rule_set_discovery(rule, !disable_discovery);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* - disable_ipv4 */
+
+ int disable_ipv4;
+ if (config_setting_lookup_bool(override_setting, "disable_ipv4",
+ &disable_ipv4)) {
+ INFO("Ignored setting 'disable_ipv4' in rule #%d (not implemented).", i);
+#if 0
+ int rc = facemgr_cfg_rule_set_ipv4(rule, !disable_ipv4);
+ if (rc < 0)
+ goto ERR;
+#endif
+ }
+
+ /* - disable ipv6 */
+
+ int disable_ipv6;
+ if (config_setting_lookup_bool(override_setting, "disable_ipv6",
+ &disable_ipv6)) {
+ INFO("Ignored setting 'disable_ipv6' in rule #%d (not implemented).", i);
+#if 0
+ int rc = facemgr_cfg_rule_set_ipv6(rule, !disable_ipv6);
+ if (rc < 0)
+ goto ERR;
+#endif
+ }
+
+ /* - ignore */
+ int ignore;
+ if (config_setting_lookup_bool(override_setting, "ignore", &ignore)) {
+ int rc = facemgr_cfg_rule_set_ignore(rule, !!ignore);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* - tags */
+ config_setting_t *tag_settings = config_setting_get_member(override_setting, "tags");
+ if (tag_settings) {
+ INFO("Ignored setting 'tags' in rule #%d (not implemented).", i);
+#if 0
+ policy_tags_t tags = POLICY_TAGS_EMPTY;
+ for (unsigned j = 0; j < config_setting_length(tag_settings); j++) {
+ const char * tag_str = config_setting_get_string_elem(tag_settings, j);
+ policy_tag_t tag = policy_tag_from_str(tag_str);
+ if (tag == POLICY_TAG_N)
+ goto ERR;
+ policy_tags_add(&tags, tag);
+ }
+
+ int rc = facemgr_cfg_rule_set_tags(rule, tags);
+ if (rc < 0)
+ goto ERR;
+
+#if 0
+ char tags_str[MAXSZ_POLICY_TAGS];
+ policy_tags_snprintf(tags_str, MAXSZ_POLICY_TAGS, tags);
+ DEBUG("Added tags tags=%s", tags_str);
+#endif
+#endif
+ }
+
+ /* - overlay */
+ config_setting_t *overlay = config_setting_get_member(override_setting, "overlay");
+ if (overlay) {
+
+ /* ipv4 */
+ config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4");
+ if (overlay_v4) {
+ const char * local_addr_str, * remote_addr_str;
+ ip_address_t local_addr = IP_ADDRESS_EMPTY;
+ ip_address_t remote_addr = IP_ADDRESS_EMPTY;
+ ip_address_t * local_addr_p = NULL;
+ ip_address_t * remote_addr_p = NULL;
+ int local_port = 0;
+ int remote_port = 0;
+
+ if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) {
+ ip_address_pton(local_addr_str, &local_addr);
+ local_addr_p = &local_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) {
+ if (!IS_VALID_PORT(local_port))
+ goto ERR;
+ }
+
+ if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) {
+ ip_address_pton(remote_addr_str, &remote_addr);
+ remote_addr_p = &remote_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) {
+ if (!IS_VALID_PORT(remote_port))
+ goto ERR;
+ }
+ int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET,
+ local_addr_p, local_port,
+ remote_addr_p, remote_port);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* ipv6 */
+ config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6");
+ if (overlay_v6) {
+ const char * local_addr_str, * remote_addr_str;
+ ip_address_t local_addr = IP_ADDRESS_EMPTY;
+ ip_address_t remote_addr = IP_ADDRESS_EMPTY;
+ ip_address_t * local_addr_p = NULL;
+ ip_address_t * remote_addr_p = NULL;
+ int local_port = 0;
+ int remote_port = 0;
+
+ if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) {
+ ip_address_pton(local_addr_str, &local_addr);
+ local_addr_p = &local_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) {
+ if (!IS_VALID_PORT(local_port))
+ goto ERR;
+ }
+
+ if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) {
+ ip_address_pton(remote_addr_str, &remote_addr);
+ remote_addr_p = &remote_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) {
+ if (!IS_VALID_PORT(remote_port))
+ goto ERR;
+ }
+ int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET6,
+ local_addr_p, local_port,
+ remote_addr_p, remote_port);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ } /* overlay */
+
+ /* Add newly created rule */
+
+ rc = facemgr_cfg_add_rule(cfg, rule);
+ if (rc < 0)
+ goto ERR;
+ }
+ return 0;
+
+ERR:
+ facemgr_cfg_rule_free(rule);
+ERR_RULE:
+ERR_CHECK:
+ return -1;
+}
+
+/* Currently not using facemgr_cfg_t */
+int
+parse_config_log(facemgr_cfg_t * cfg, config_setting_t * setting)
+{
+ const char *log_level_str;
+ if (config_setting_lookup_string(setting, "log_level", &log_level_str)) {
+ if (strcasecmp(log_level_str, "FATAL") == 0) {
+ log_conf.log_level = LOG_FATAL;
+ } else
+ if (strcasecmp(log_level_str, "ERROR") == 0) {
+ log_conf.log_level = LOG_ERROR;
+ } else
+ if (strcasecmp(log_level_str, "WARN") == 0) {
+ log_conf.log_level = LOG_WARN;
+ } else
+ if (strcasecmp(log_level_str, "INFO") == 0) {
+ log_conf.log_level = LOG_INFO;
+ } else
+ if (strcasecmp(log_level_str, "DEBUG") == 0) {
+ log_conf.log_level = LOG_DEBUG;
+ } else
+ if (strcasecmp(log_level_str, "TRACE") == 0) {
+ log_conf.log_level = LOG_TRACE;
+ } else {
+ ERROR("Invalid log level in section 'log'");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+parse_config_file(const char * cfgpath, facemgr_cfg_t * cfg)
+{
+ /* Reading configuration file */
+ config_t cfgfile;
+ config_setting_t *setting;
+
+ config_init(&cfgfile);
+
+ /* Read the file. If there is an error, report it and exit. */
+ if(!config_read_file(&cfgfile, cfgpath))
+ goto ERR_FILE;
+
+ setting = config_lookup(&cfgfile, "global");
+ if (setting) {
+ int rc = parse_config_global(cfg, setting);
+ if (rc < 0)
+ goto ERR_PARSE;
+ }
+
+ setting = config_lookup(&cfgfile, "rules");
+ if (setting) {
+ int rc = parse_config_rules(cfg, setting);
+ if (rc < 0)
+ goto ERR_PARSE;
+ }
+
+ setting = config_lookup(&cfgfile, "log");
+ if (setting) {
+ int rc = parse_config_log(cfg, setting);
+ if (rc < 0)
+ goto ERR_PARSE;
+ }
+
+ config_destroy(&cfgfile);
+ return 0;
+
+ERR_FILE:
+ ERROR("Could not read configuration file %s", cfgpath);
+ fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile),
+ config_error_line(&cfgfile), config_error_text(&cfgfile));
+ config_destroy(&cfgfile);
+ exit(EXIT_FAILURE);
+ return -1;
+ERR_PARSE:
+ fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile),
+ config_error_line(&cfgfile), config_error_text(&cfgfile));
+ config_destroy(&cfgfile);
+ return -1;
+}
+
diff --git a/ctrl/facemgr/src/cfg_file.h b/ctrl/facemgr/src/cfg_file.h
new file mode 100644
index 000000000..dfce041d8
--- /dev/null
+++ b/ctrl/facemgr/src/cfg_file.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file cfg_file.h
+ * \brief Configuration file parsing
+ */
+
+#ifndef FACEMGR_CFG_FILE_H
+#define FACEMGR_CFG_FILE_H
+
+#include <hicn/facemgr/cfg.h>
+
+/**
+ * \brief Probe for the configuration file location
+ * \param [in] f - File name
+ * \return 0 in case of success, -1 otherwise.
+ */
+int probe_cfgfile(char * f);
+
+/**
+ * \brief Parses the provided configuration file into the facemgr configuration
+ * data structure.
+ * \param [in] cfgpath - Path to the configuration file
+ * \param [out] cfg - Pre-allocated configuration data structure
+ * \return 0 in case of success, -1 otherwise.
+ */
+int parse_config_file(const char * cfgpath, facemgr_cfg_t * cfg);
+
+#endif /* FACEMGR_CFG_FILE_H */
diff --git a/ctrl/facemgr/src/common.h b/ctrl/facemgr/src/common.h
index a73964b6d..56bd706f1 100644
--- a/ctrl/facemgr/src/common.h
+++ b/ctrl/facemgr/src/common.h
@@ -22,39 +22,47 @@
#include <stdbool.h>
#include <stdint.h>
+#include <stdlib.h>
-#include "util/types.h"
-#include "util/ip_address.h"
-#include "util/token.h" // XXX debug
+#include <hicn/util/ip_address.h>
//#define DEBUG
-/* Return value conventions */
-#define FACEMGR_SUCCESS 0
-#define FACEMGR_FAILURE -1
-#define FACEMGR_IS_ERROR(rc) (rc < 0)
-
-/* Useful types and macros for comparisons */
-typedef int(*cmp_t)(const void * x, const void * y);
-
#define INT_CMP(x, y) x < y ? -1 : (x == y ? 0 : 1)
/* Dump with indent */
#define INDENT(n, fmt) "%*s" fmt, n, ""
#define printfi(n, fmt, ...) printf(INDENT(n*4, fmt), ##__VA_ARGS__)
+#define _unused(x) ((void)(x))
+
+/* Random strings */
+
+static inline
+void rand_str(char *dest, size_t length) {
+ char charset[] = "0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ while (length-- > 0) {
+ size_t index = (double) rand() / RAND_MAX * (sizeof charset - 1);
+ *dest++ = charset[index];
+ }
+ *dest = '\0';
+}
+
/* Boilerplate code */
#define NO_INITIALIZE(NAME) \
int \
NAME ## _initialize(NAME ## _t * obj) { \
- return FACEMGR_SUCCESS; \
+ return 0; \
}
#define NO_FINALIZE(NAME) \
int \
NAME ## _finalize(NAME ## _t * obj) { \
- return FACEMGR_SUCCESS; \
+ return 0; \
}
#define AUTOGENERATE_CREATE_FREE(NAME) \
@@ -66,7 +74,7 @@ NAME ## _create() \
if (!obj) \
goto ERR_MALLOC; \
\
- if (FACEMGR_IS_ERROR(NAME ## _initialize(obj))) \
+ if (NAME ## _initialize(obj) < 0) \
goto ERR_INIT; \
\
return obj; \
@@ -80,7 +88,7 @@ ERR_MALLOC: \
void \
NAME ## _free(NAME ## _t * obj) \
{ \
- if (FACEMGR_IS_ERROR(NAME ## _finalize(obj))) \
+ if (NAME ## _finalize(obj) < 0) \
(void)0; /* XXX */ \
free(obj); \
} \
diff --git a/ctrl/facemgr/src/event.c b/ctrl/facemgr/src/event.c
deleted file mode 100644
index 446c51c22..000000000
--- a/ctrl/facemgr/src/event.c
+++ /dev/null
@@ -1,39 +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 event.h
- * \brief Implementatino of face events
- */
-
-#include "common.h"
-#include "event.h"
-#include "interface.h"
-#include "util/token.h"
-
-const char * event_type_str[] = {
-#define _(x) [EVENT_TYPE_ ## x] = STRINGIZE(x),
-foreach_event_type
-#undef _
-};
-
-int
-event_raise(event_type_t type, const face_t * face, const interface_t * interface)
-{
- event_t event = { .type = type, .face = face };
- if (interface->callback)
- interface->callback(interface->callback_data, &event);
- return FACEMGR_SUCCESS;
-}
diff --git a/ctrl/facemgr/src/event.h b/ctrl/facemgr/src/event.h
deleted file mode 100644
index 53295d009..000000000
--- a/ctrl/facemgr/src/event.h
+++ /dev/null
@@ -1,59 +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 event.h
- * \brief Face event
- */
-#ifndef FACEMGR_EVENT_H
-#define FACEMGR_EVENT_H
-
-#include "face.h"
-#include "interface.h"
-
-#define foreach_event_type \
- _(UNDEFINED) \
- _(CREATE) \
- _(UPDATE) \
- _(DELETE) \
- _(SET_PARAMS) \
- _(SET_UP) \
- _(SET_DOWN) \
- _(SET_TAGS) \
- _(CLEAR_TAGS) \
- _(ADD_TAG) \
- _(REMOVE_TAG) \
- _(N)
-
-#define MAXSZ_EVENT_TYPE_ 10
-#define MAXSZ_EVENT_TYPE MAXSZ_EVENT_TYPE_ + 1
-
-typedef enum {
-#define _(x) EVENT_TYPE_ ## x,
-foreach_event_type
-#undef _
-} event_type_t;
-
-extern const char * event_type_str[];
-
-typedef struct event_s {
- event_type_t type;
- const face_t * face; /* + bitfield for face fields ? */
-} event_t;
-
-int
-event_raise(event_type_t type, const face_t * face, const interface_t * interface);
-
-#endif /* FACEMGR_EVENT_H */
diff --git a/ctrl/facemgr/src/face.c b/ctrl/facemgr/src/face.c
deleted file mode 100644
index 270a6fa9f..000000000
--- a/ctrl/facemgr/src/face.c
+++ /dev/null
@@ -1,262 +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 face.c
- * \brief Implementation of face abstraction
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "face.h"
-#include "util/hash.h"
-#include "util/token.h"
-
-#ifndef bzero
-#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
-#endif
-
-#define member_size(type, member) sizeof(((type *)0)->member)
-
-
-/* Netdevice */
-
-const char * netdevice_type_str[] = {
-#define _(x) [NETDEVICE_TYPE_ ## x] = STRINGIZE(x),
-foreach_netdevice_type
-#undef _
-};
-
-
-/* Face state */
-
-const char * face_state_str[] = {
-#define _(x) [FACE_STATE_ ## x] = STRINGIZE(x),
-foreach_face_state
-#undef _
-};
-
-
-/* Face type */
-
-const char * face_type_str[] = {
-#define _(x) [FACE_TYPE_ ## x] = STRINGIZE(x),
-foreach_face_type
-#undef _
-};
-
-
-/* Face */
-
-int
-face_initialize(face_t * face)
-{
- bzero(face, 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,
- 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_addr : IP_ADDRESS_EMPTY,
- .remote_port = remote_port,
- },
- };
- return 1;
-}
-
-int
-face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr,
- const struct sockaddr * remote_addr)
-{
- if (!local_addr)
- return -1;
-
- if (remote_addr && (local_addr->sa_family != remote_addr->sa_family))
- return -1;
-
- switch (local_addr->sa_family) {
- case AF_INET:
- {
- struct sockaddr_in *lsai = (struct sockaddr_in *)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 = lsai ? ntohs(lsai->sin_port) : 0,
- .remote_addr = IP_ADDRESS_EMPTY,
- .remote_port = rsai ? ntohs(rsai->sin_port) : 0,
- },
- };
- if (rsai)
- face->params.tunnel.remote_addr.v4.as_inaddr = rsai->sin_addr;
- }
- break;
- case AF_INET6:
- {
- struct sockaddr_in6 *lsai = (struct sockaddr_in6 *)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 = lsai ? ntohs(lsai->sin6_port) : 0,
- .remote_addr = IP_ADDRESS_EMPTY,
- .remote_port = rsai ? ntohs(rsai->sin6_port) : 0,
- },
- };
- if (rsai)
- face->params.tunnel.remote_addr.v6.as_in6addr = rsai->sin6_addr;
- }
- break;
- default:
- return -1;
- }
- return 1;
-}
-
-face_t * face_create()
-{
- face_t * face = calloc(1, sizeof(face_t)); /* 0'ed for hash */
- return face;
-}
-
-face_t * face_create_udp(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)
- goto ERR_INIT;
- return face;
-
-ERR_INIT:
- free(face);
- return NULL;
-}
-
-face_t * face_create_udp_sa(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)
- goto ERR_INIT;
- return face;
-
-ERR_INIT:
- free(face);
- return NULL;
-}
-
-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
- * \param [in] f2 - Second face
- * \return whether faces are equal, ie both their types are parameters are
- * equal.
- *
- * NOTE: this function implements a partial order.
- */
-int
-face_cmp(const face_t * f1, const face_t * f2)
-{
- if (f1->type != f2->type)
- return false;
-
- switch(f1->type) {
- case FACE_TYPE_HICN:
- return face_param_cmp(f1, f2, hicn);
- case FACE_TYPE_TCP:
- case FACE_TYPE_UDP:
- return face_param_cmp(f1, f2, tunnel);
- default:
- return false;
- }
-}
-
-hash_t
-face_hash(const face_t * face)
-{
- /* Assuming the unused part of the struct is set to zero */
- return hash_struct(face);
-}
-
-/* /!\ Please update constants in header file upon changes */
-size_t
-face_snprintf(char * s, size_t size, const face_t * face)
-{
- switch(face->type) {
- case FACE_TYPE_HICN:
- return 0; // XXX Not implemented
- case FACE_TYPE_TCP:
- case FACE_TYPE_UDP:
- {
- char local[MAXSZ_IP_ADDRESS];
- char remote[MAXSZ_IP_ADDRESS];
- char tags[MAXSZ_POLICY_TAGS];
-
- 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);
- 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->params.tunnel.local_port,
- remote,
- face->params.tunnel.remote_port,
- tags);
- }
- break;
- default:
- return 0;
- }
-
-}
-
-int
-face_set_tags(face_t * face, policy_tags_t tags)
-{
- face->tags = tags;
- return 1;
-}
diff --git a/ctrl/facemgr/src/face.h b/ctrl/facemgr/src/face.h
deleted file mode 100644
index 8b553f685..000000000
--- a/ctrl/facemgr/src/face.h
+++ /dev/null
@@ -1,177 +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 face.h
- * \brief Face abstraction
- */
-#ifndef HICN_FACE_H
-#define HICN_FACE_H
-
-#ifndef SPACES
-#define SPACES(x) x
-#endif
-#ifndef SPACE
-#define SPACE 1
-#endif
-#ifndef NULLTERM
-#define NULLTERM 1
-#endif
-
-#include "util/ip_address.h"
-#include "util/policy.h"
-#include "util/types.h"
-
-
-/* Netdevice type */
-
-#include <net/if.h> // IFNAMSIZ
-
-#define foreach_netdevice_type \
- _(UNDEFINED) \
- _(WIRED) \
- _(WIFI) \
- _(CELLULAR) \
- _(VPN) \
- _(N)
-
-#define MAXSZ_NETDEVICE_TYPE_ 9
-#define MAXSZ_NETDEVICE_TYPE MAXSZ_NETDEVICE_TYPE_ + NULLTERM
-
-typedef enum {
-#define _(x) NETDEVICE_TYPE_ ## x,
-foreach_netdevice_type
-#undef _
-} netdevice_type_t;
-
-extern const char * netdevice_type_str[];
-
-
-/* Netdevice */
-
-typedef struct {
- u32 index;
- char name[IFNAMSIZ];
-} netdevice_t;
-
-#define NETDEVICE_UNDEFINED_INDEX 0
-
-/* Face state */
-
-#define foreach_face_state \
- _(UNDEFINED) \
- _(PENDING_UP) \
- _(UP) \
- _(PENDING_DOWN) \
- _(DOWN) \
- _(ERROR) \
- _(N)
-
-#define MAXSZ_FACE_STATE_ 12
-#define MAXSZ_FACE_STATE MAXSZ_FACE_STATE_ + 1
-
-typedef enum {
-#define _(x) FACE_STATE_ ## x,
-foreach_face_state
-#undef _
-} face_state_t;
-
-extern const char * face_state_str[];
-
-
-/* Face type */
-
-#define foreach_face_type \
- _(UNDEFINED) \
- _(HICN) \
- _(HICN_LISTENER) \
- _(TCP) \
- _(TCP_LISTENER) \
- _(UDP) \
- _(UDP_LISTENER) \
- _(N)
-
-#define MAXSZ_FACE_TYPE_ 13
-#define MAXSZ_FACE_TYPE MAXSZ_FACE_TYPE_ + 1
-
-typedef enum {
-#define _(x) FACE_TYPE_ ## x,
-foreach_face_type
-#undef _
-} face_type_t;
-
-extern const char * face_type_str[];
-
-#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_IP_ADDRESS_ + 2 * MAXSZ_PORT_ + 9 + MAXSZ_POLICY_TAGS_
-#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 */
-} 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 family);
-int face_initialize_udp_sa(face_t * face,
- 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,
- const ip_address_t * remote_addr, u16 remote_port, int family);
-face_t * face_create_udp_sa(const struct sockaddr * local_addr,
- const struct sockaddr * remote_addr);
-
-int face_finalize(face_t * face);
-
-void face_free(face_t * face);
-
-typedef int (*face_cmp_t)(const face_t * f1, const face_t * f2);
-
-int face_cmp(const face_t * f1, const face_t * f2);
-hash_t face_hash(const face_t * face);
-
-size_t
-face_snprintf(char * s, size_t size, const face_t * face);
-
-int face_set_tags(face_t * face, policy_tags_t tags);
-
-#endif /* HICN_FACE_H */
-
diff --git a/ctrl/facemgr/src/face_rules.c b/ctrl/facemgr/src/face_rules.c
deleted file mode 100644
index ddefc15f9..000000000
--- a/ctrl/facemgr/src/face_rules.c
+++ /dev/null
@@ -1,21 +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.
- */
-
-#include "face_rules.h"
-
-#include <string.h>
-#include "util/policy.h"
-
-TYPEDEF_MAP(face_rules, const char *, policy_tags_t, strcmp, string_snprintf, policy_tags_snprintf);
diff --git a/ctrl/facemgr/src/facelet.c b/ctrl/facemgr/src/facelet.c
new file mode 100644
index 000000000..6d6d74c2b
--- /dev/null
+++ b/ctrl/facemgr/src/facelet.c
@@ -0,0 +1,980 @@
+/*
+ * 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 facelet.c
+ * \brief Implementation of facelet
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <hicn/ctrl/face.h>
+#include <hicn/facemgr/cfg.h>
+#include <hicn/util/log.h>
+
+#include "facelet.h"
+
+const char * face_type_layer_str[] = {
+#define _(x) [FACE_TYPE_LAYER_ ## x] = STRINGIZE(x),
+ foreach_face_type_layer
+#undef _
+};
+
+const char * face_type_encap_str[] = {
+#define _(x) [FACE_TYPE_ENCAP_ ## x] = STRINGIZE(x),
+ foreach_face_type_encap
+#undef _
+};
+
+#define FACEMGR_FACE_TYPE_STR(x) \
+ face_type_layer_str[x.layer], face_type_encap_str[x.encap]
+
+
+const char * facelet_status_str[] = {
+#define _(x) [FACELET_STATUS_ ## x] = STRINGIZE(x),
+ foreach_facelet_status
+#undef _
+};
+
+/* Facelet attribute status */
+
+
+const char * facelet_attr_status_str[] = {
+#define _(x, str) [FACELET_ATTR_STATUS_ ## x] = STRINGIZE(x),
+ foreach_facelet_attr_status
+#undef _
+};
+
+const char * facelet_attr_status_str_short[] = {
+#define _(x, str) [FACELET_ATTR_STATUS_ ## x] = STRINGIZE(str),
+ foreach_facelet_attr_status
+#undef _
+};
+
+
+/* Facelet */
+
+struct facelet_s {
+#define _(TYPE, NAME) TYPE NAME;
+ foreach_facelet_attr
+#undef _
+#define _(TYPE, NAME) facelet_attr_status_t NAME ## _status;
+ foreach_facelet_attr
+#undef _
+
+ facelet_status_t status;
+ facelet_event_t event;
+
+ /* Joins */
+ bool bj_done;
+ bool au_done;
+};
+
+const char * facelet_event_str[] = {
+#define _(x) [FACELET_EVENT_ ## x] = STRINGIZE(x),
+foreach_facelet_event
+#undef _
+};
+
+facelet_t *
+facelet_create()
+{
+ facelet_t * facelet = calloc(1, sizeof(facelet_t));
+ if (!facelet)
+ goto ERR_MALLOC;
+
+ facelet->netdevice_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->netdevice_type_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->family_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->local_port_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->admin_state_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->state_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->face_type_status = FACELET_ATTR_STATUS_UNSET;
+
+ facelet->status = FACELET_STATUS_NEW;
+
+ facelet->bj_done = false;
+ facelet->au_done = false;
+
+ facelet->event = FACELET_EVENT_UNDEFINED;
+
+ return facelet;
+
+ERR_MALLOC:
+ return NULL;
+}
+
+facelet_t *
+facelet_create_from_netdevice(netdevice_t * netdevice)
+{
+ facelet_t * facelet = facelet_create();
+ if (!facelet)
+ goto ERR_FACELET;
+
+ int rc = facelet_set_netdevice(facelet, *netdevice);
+ if (rc < 0)
+ goto ERR_NETDEV;
+
+ return facelet;
+
+ERR_NETDEV:
+ facelet_free(facelet);
+ERR_FACELET:
+ return NULL;
+}
+
+/**
+ * \brief Validate whether the facelet has all required fields to construct a
+ * face of the given type
+ * \param [in) facelet - Pointer to the facelet to verify
+ * \return 0 in case of success, -1 otherwise
+ */
+int
+facelet_validate_face(const facelet_t * facelet)
+{
+ if (!facelet_has_face_type(facelet))
+ return false;
+ switch(facelet->face_type.layer) {
+ case FACE_TYPE_LAYER_4:
+ if (!facelet_has_remote_port(facelet))
+ return false;
+ if (!facelet_has_remote_addr(facelet))
+ return false;
+ case FACE_TYPE_LAYER_3:
+ if (!facelet_has_local_addr(facelet))
+ return false;
+ if (!facelet_has_netdevice(facelet))
+ return false;
+ return true;
+
+ default:
+ return false; /* Error */
+ }
+ // FIXME Not implemented
+ return 0;
+}
+
+
+netdevice_type_t
+netdevice_type_from_face_tags(const face_t * face)
+{
+ policy_tags_t tags = face->tags;
+ if (policy_tags_has(tags, POLICY_TAG_WIRED))
+ return NETDEVICE_TYPE_WIRED;
+ else if (policy_tags_has(tags, POLICY_TAG_WIFI))
+ return NETDEVICE_TYPE_WIFI;
+ else if (policy_tags_has(tags, POLICY_TAG_CELLULAR))
+ return NETDEVICE_TYPE_CELLULAR;
+ return NETDEVICE_TYPE_UNDEFINED;
+}
+
+facelet_t *
+facelet_create_from_face(face_t * face)
+{
+ facelet_t * facelet = malloc(sizeof(facelet_t));
+ if (!facelet)
+ goto ERR_MALLOC;
+
+ /* Go through the face attributes to update the local representation */
+
+ /* Attribute : netdevice */
+ /* NOTE index is not set */
+ if (IS_VALID_NETDEVICE(face->netdevice)) {
+ facelet->netdevice = face->netdevice;
+ facelet->netdevice_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->netdevice_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : netdevice_type */
+ facelet->netdevice_type = netdevice_type_from_face_tags(face);
+ if (facelet->netdevice_type != NETDEVICE_TYPE_UNDEFINED) {
+ facelet->netdevice_type_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->netdevice = NETDEVICE_EMPTY;
+ facelet->netdevice_type_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : family */
+ if (IS_VALID_FAMILY(face->family)) {
+ facelet->family = face->family;
+ facelet->family_status = FACELET_ATTR_STATUS_CLEAN;
+
+ /* Attribute : local_addr */
+ if (ip_address_cmp(&face->local_addr, &IP_ADDRESS_EMPTY, face->family) != 0) {
+ facelet->local_addr = face->local_addr;
+ facelet->local_addr_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : local_port */
+ if (IS_VALID_PORT(face->local_port)) {
+ facelet->local_port = face->local_port;
+ facelet->local_port_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->local_port_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : remote_addr */
+ if (ip_address_cmp(&face->remote_addr, &IP_ADDRESS_EMPTY, face->family) != 0) {
+ facelet->remote_addr = face->remote_addr;
+ facelet->remote_addr_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : remote_port */
+ if (IS_VALID_PORT(face->remote_port)) {
+ facelet->remote_port = face->remote_port;
+ facelet->remote_port_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ } else {
+ facelet->family_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->local_port_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : admin_state */
+ if ((face->admin_state == FACE_STATE_UP) ||
+ (face->admin_state == FACE_STATE_DOWN)) {
+ facelet->admin_state = face->admin_state;
+ facelet->admin_state_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->admin_state_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : state */
+ if ((face->state == FACE_STATE_UP) ||
+ (face->state == FACE_STATE_DOWN)) {
+ facelet->state = face->state;
+ facelet->state_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->state_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : face_type */
+ if ((face->type != FACE_TYPE_UNDEFINED) && (face->type != FACE_TYPE_N)) {
+ switch(face->type) {
+ case FACE_TYPE_UDP:
+ facelet->face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP;
+ break;
+ case FACE_TYPE_TCP:
+ facelet->face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP;
+ break;
+ case FACE_TYPE_HICN:
+ facelet->face_type = FACEMGR_FACE_TYPE_NATIVE_TCP;
+ break;
+ default:
+ ERROR("[facelet_create_from_face] Face type not (yet) implemented");
+ goto ERR_FACE;
+ }
+ facelet->face_type_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->face_type_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Status */
+ facelet->status = FACELET_STATUS_CLEAN;
+
+ /* TODO Consistency check between face type and found attributes */
+ if (facelet_validate_face(facelet) < 0)
+ goto ERR_FACE;
+
+ facelet->bj_done = false;
+ facelet->au_done = false;
+
+ facelet->event = FACELET_EVENT_UNDEFINED;
+
+ return facelet;
+
+ERR_FACE:
+ free(facelet);
+ERR_MALLOC:
+ return NULL;
+}
+
+
+void
+facelet_free(facelet_t * facelet)
+{
+ free(facelet);
+}
+
+facelet_t *
+facelet_dup(const facelet_t * current_facelet)
+{
+ facelet_t * facelet = facelet_create();
+ if (!facelet)
+ goto ERR_CREATE;
+
+#define _(TYPE, NAME) facelet-> NAME = current_facelet-> NAME;
+ foreach_facelet_attr
+#undef _
+#define _(TYPE, NAME) facelet-> NAME ## _status = current_facelet-> NAME ## _status;
+ foreach_facelet_attr
+#undef _
+
+ facelet->status = current_facelet->status;
+ facelet->event = current_facelet->event;
+
+ facelet->bj_done = current_facelet->bj_done;
+ facelet->au_done = current_facelet->au_done;
+
+ return facelet;
+
+ERR_CREATE:
+ return NULL;
+}
+
+int
+facelet_cmp(const facelet_t * f1, const facelet_t * f2)
+{
+ /*
+ * Under the assumption we only create a face per physical interface, a
+ * facelet is uniquely identified by its netdevice attribute, and address
+ * family if any.
+ *
+ * This function is mostly used for lookups into the cache, and the face
+ * thus needs to have a netdevice associated, and optionally, an address
+ * family.
+ *
+ * For other situations, the `facelet_match` function is more appropriate.
+ */
+
+ if ((f1->netdevice_status != FACELET_ATTR_STATUS_UNSET) &&
+ (f2->netdevice_status != FACELET_ATTR_STATUS_UNSET)) {
+ int rc = netdevice_cmp(&f1->netdevice, &f2->netdevice);
+ if (rc != 0)
+ return rc;
+
+ } else {
+ /* Both unset : we might have the face without netdevice due to hicn
+ * light not returning it currently, but we cannot skip it in the match
+ * otherwise we cannot distinguish with other faces except matching on
+ * other fields which might unfortunately not be determined yet...
+ */
+ return (f1->netdevice_status == FACELET_ATTR_STATUS_UNSET) ? -1 : 1;
+ }
+
+ assert(f1->family_status != FACELET_ATTR_STATUS_UNSET);
+ assert(f2->family_status != FACELET_ATTR_STATUS_UNSET);
+
+ if ((f1->family == AF_UNSPEC) || (f2->family == AF_UNSPEC))
+ return 0;
+ int diff = f1->family - f2->family;
+ return (diff > 0) ? 1 :
+ (diff < 0) ? -1 : 0;
+}
+
+/*
+ * If the match has a field set, then the facelet only matches iif it has the
+ * same field set, and both values are equal
+ */
+#define MATCH_ATTRIBUTE(TYPE, NAME) \
+do { \
+ if (facelet_match->NAME ## _status == FACELET_ATTR_STATUS_CLEAN) { \
+ if (facelet_has_ ## NAME(facelet_match)) { \
+ TYPE NAME; \
+ TYPE NAME ## _match; \
+ if (!facelet_has_ ## NAME(facelet)) \
+ return false; \
+ if (facelet_get_ ## NAME (facelet, & NAME) < 0) \
+ return false; \
+ if (facelet_get_ ## NAME (facelet_match, & NAME ## _match) < 0) \
+ return false; \
+ if (memcmp(& NAME, & NAME ## _match, sizeof(NAME)) != 0) \
+ return false; \
+ } \
+ } \
+} while(0)
+
+/* facelet_match is the incoming one */
+bool
+facelet_match(const facelet_t * facelet, const facelet_t * facelet_match)
+{
+#define _(TYPE, NAME) MATCH_ATTRIBUTE(TYPE, NAME);
+ foreach_facelet_attr
+#undef _
+ return true;
+}
+
+bool facelet_has_key(const facelet_t * facelet) {
+ return (facelet_has_netdevice(facelet) && facelet_has_family(facelet));
+}
+
+/*
+ * Implementation note:
+ * - facelet_set_* is equivalent to merge with a CLEAN remote attribute
+ */
+#define FACELET_ACCESSORS(TYPE, NAME) \
+bool \
+facelet_has_ ## NAME(const facelet_t * facelet) \
+{ \
+ assert(facelet); \
+ assert(facelet->NAME ## _status != FACELET_ATTR_STATUS_UNDEFINED); \
+ assert(facelet->NAME ## _status != FACELET_ATTR_STATUS_N); \
+ return ((facelet-> NAME ## _status != FACELET_ATTR_STATUS_UNSET)); \
+} \
+ \
+facelet_attr_status_t \
+facelet_get_ ## NAME ## _status(const facelet_t * facelet) \
+{ \
+ return (facelet->NAME ## _status); \
+} \
+ \
+int \
+facelet_get_ ## NAME(const facelet_t * facelet, TYPE * NAME) \
+{ \
+ assert(facelet); \
+ if (!facelet_has_ ## NAME(facelet)) \
+ return -1; \
+ *NAME = facelet-> NAME; \
+ return 0; \
+} \
+ \
+int \
+facelet_set_local_ ## NAME(facelet_t * facelet, TYPE NAME) \
+{ \
+ assert(facelet); \
+ switch(facelet->NAME ## _status) { \
+ case FACELET_ATTR_STATUS_UNSET: \
+ case FACELET_ATTR_STATUS_CLEAN: \
+ case FACELET_ATTR_STATUS_DIRTY: \
+ case FACELET_ATTR_STATUS_PENDING: \
+ facelet-> NAME = NAME; \
+ facelet->NAME ## _status = FACELET_ATTR_STATUS_DIRTY; \
+ if (facelet->status == FACELET_STATUS_CLEAN) \
+ facelet->status = FACELET_STATUS_DIRTY; \
+ break; \
+ case FACELET_ATTR_STATUS_CONFLICT: \
+ break; \
+ case FACELET_ATTR_STATUS_UNDEFINED: \
+ case FACELET_ATTR_STATUS_N: \
+ ERROR("Unexpected attribute status value"); \
+ return -1; \
+ } \
+ return 0; \
+} \
+ \
+int \
+facelet_set_remote_ ## NAME(facelet_t * facelet, TYPE NAME) \
+{ \
+ assert(facelet); \
+ switch(facelet->NAME ## _status) { \
+ case FACELET_ATTR_STATUS_UNSET: \
+ facelet-> NAME = NAME; \
+ facelet->NAME ## _status = FACELET_ATTR_STATUS_CLEAN; \
+ break; \
+ case FACELET_ATTR_STATUS_CLEAN: \
+ facelet->NAME = NAME; \
+ break; \
+ case FACELET_ATTR_STATUS_DIRTY: \
+ ERROR("Discarded remote value for status reasons"); \
+ break; \
+ case FACELET_ATTR_STATUS_PENDING: \
+ ERROR("Received remote value on pending attribute"); \
+ facelet->NAME ## _status = FACELET_ATTR_STATUS_CONFLICT; \
+ if (facelet->status != FACELET_STATUS_CONFLICT) \
+ facelet->status = FACELET_STATUS_CONFLICT; \
+ break; \
+ case FACELET_ATTR_STATUS_CONFLICT: \
+ return -1; \
+ case FACELET_ATTR_STATUS_UNDEFINED: \
+ case FACELET_ATTR_STATUS_N: \
+ ERROR("Unexpected attribute status value"); \
+ return -1; \
+ } \
+ return 0; \
+} \
+ \
+int \
+facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME) \
+{ \
+ return facelet_set_local_ ## NAME(facelet, NAME); \
+} \
+ \
+int \
+facelet_unset_ ## NAME(facelet_t * facelet) \
+{ \
+ return facelet->NAME ## _status = FACELET_ATTR_STATUS_UNSET; \
+}
+
+#define _(TYPE, NAME) FACELET_ACCESSORS(TYPE, NAME)
+foreach_facelet_attr
+#undef _
+
+/*
+ * This function is called for every facelet attribute. It is responsible for
+ * comparing both the current and new value, and set the attribute and facelet
+ * status appropriately.
+ */
+
+// FIXME CLEAN for key fields, dirty for fields to update.
+
+#define MERGE_ATTRIBUTE(TYPE, NAME) \
+do { \
+ switch(facelet_to_merge->NAME ## _status) { \
+ case FACELET_ATTR_STATUS_UNDEFINED: \
+ case FACELET_ATTR_STATUS_N: \
+ case FACELET_ATTR_STATUS_PENDING: \
+ case FACELET_ATTR_STATUS_CONFLICT: \
+ ERROR("Unexpected facelet attribute status"); \
+ return -1; \
+ case FACELET_ATTR_STATUS_UNSET: \
+ break; \
+ case FACELET_ATTR_STATUS_CLEAN: \
+ case FACELET_ATTR_STATUS_DIRTY: \
+ facelet_set_ ## NAME(facelet, facelet_to_merge-> NAME); \
+ break; \
+ } \
+} while (0)
+
+int facelet_merge(facelet_t * facelet, const facelet_t * facelet_to_merge)
+{
+ assert(facelet && facelet_to_merge);
+#define _(TYPE, NAME) MERGE_ATTRIBUTE(TYPE, NAME);
+ foreach_facelet_attr
+#undef _
+ facelet->event = facelet_to_merge->event;
+ return 0;
+}
+
+#define MERGE_ATTRIBUTE_REMOTE(TYPE, NAME) \
+do { \
+ switch(facelet_to_merge->NAME ## _status) { \
+ case FACELET_ATTR_STATUS_UNDEFINED: \
+ case FACELET_ATTR_STATUS_N: \
+ case FACELET_ATTR_STATUS_DIRTY: \
+ case FACELET_ATTR_STATUS_PENDING: \
+ case FACELET_ATTR_STATUS_CONFLICT: \
+ ERROR("Unexpected facelet attribute status"); \
+ return -1; \
+ case FACELET_ATTR_STATUS_UNSET: \
+ break; \
+ case FACELET_ATTR_STATUS_CLEAN: \
+ facelet_set_ ## NAME(facelet, facelet_to_merge-> NAME); \
+ break; \
+ \
+ } \
+} while (0)
+
+int facelet_merge_remote(facelet_t * facelet, const facelet_t * facelet_to_merge)
+{
+ assert(facelet && facelet_to_merge);
+#define _(TYPE, NAME) MERGE_ATTRIBUTE_REMOTE(TYPE, NAME);
+ foreach_facelet_attr
+#undef _
+ facelet->event = facelet_to_merge->event;
+ return 0;
+}
+
+int
+facelet_get_face(const facelet_t * facelet, face_t ** pface)
+{
+ assert(pface);
+
+ /* Facelet has all the required information to create a face */
+ if (facelet_validate_face(facelet) < 0)
+ return 0;
+
+ face_t * face = face_create();
+ if (!face)
+ goto ERR_CREATE;
+
+ assert(facelet_has_netdevice(facelet));
+ face->netdevice = facelet->netdevice;
+
+ /* Face type */
+ switch(facelet->face_type.layer) {
+ case FACE_TYPE_LAYER_4:
+ switch(facelet->face_type.encap) {
+ case FACE_TYPE_ENCAP_UDP:
+ face->type = FACE_TYPE_UDP;
+ break;
+ case FACE_TYPE_ENCAP_TCP:
+ face->type = FACE_TYPE_TCP;
+ break;
+ case FACE_TYPE_ENCAP_UNDEFINED:
+ case FACE_TYPE_ENCAP_N:
+ ERROR("[facelet_get_face] Unsupported face encapsulation");
+ goto ERR;
+ }
+
+ if (facelet_get_family(facelet, &face->family) < 0)
+ goto ERR;
+ if (facelet_get_local_addr(facelet, &face->local_addr) < 0)
+ goto ERR;
+ if (facelet_get_local_port(facelet, &face->local_port) < 0)
+ goto ERR;
+ if (facelet_get_remote_addr(facelet, &face->remote_addr) < 0)
+ goto ERR;
+ if (facelet_get_remote_port(facelet, &face->remote_port) < 0)
+ goto ERR;
+ break;
+
+ case FACE_TYPE_LAYER_3:
+ ERROR("{facelet_get_face] hICN face not (yet) implemented");
+ goto ERR;
+
+ case FACE_TYPE_LAYER_UNDEFINED:
+ case FACE_TYPE_LAYER_N:
+ ERROR("[facelet_get_face] Unsupported face type");
+ goto ERR;
+ }
+
+ if (facelet_has_admin_state(facelet)) {
+ if (facelet_get_admin_state(facelet, &face->admin_state) < 0)
+ goto ERR;
+ } else {
+ face->admin_state = FACE_STATE_UP;
+ }
+
+ if (facelet_has_state(facelet)) {
+ if (facelet_get_state(facelet, &face->state) < 0)
+ goto ERR;
+ } else {
+ face->state = FACE_STATE_UP;
+ }
+
+ /* Tags */
+
+ /* - based on netdevice type */
+ policy_tags_t tags = POLICY_TAGS_EMPTY;
+ if (facelet_has_netdevice_type(facelet)) {
+ netdevice_type_t netdevice_type;
+ if (facelet_get_netdevice_type(facelet, &netdevice_type) < 0) {
+ ERROR("error getting netdevice_type");
+ goto ERR;
+ }
+
+
+ switch(netdevice_type) {
+ case NETDEVICE_TYPE_UNDEFINED:
+ case NETDEVICE_TYPE_LOOPBACK:
+ break;
+ case NETDEVICE_TYPE_WIRED:
+ policy_tags_add(&tags, POLICY_TAG_WIRED);
+ break;
+ case NETDEVICE_TYPE_WIFI:
+ policy_tags_add(&tags, POLICY_TAG_WIFI);
+ break;
+ case NETDEVICE_TYPE_CELLULAR:
+ policy_tags_add(&tags, POLICY_TAG_CELLULAR);
+ break;
+ default:
+ goto ERR;
+ }
+ }
+#ifdef __linux__
+#ifndef __ANDROID__
+ else {
+ /*
+ * Heuristics to determine face type based on name, until a better
+ * solution is found
+ */
+ if (strncmp(facelet->netdevice.name, "eth", 3) == 0) {
+ policy_tags_add(&tags, POLICY_TAG_WIRED);
+ goto DONE;
+ }
+ if (strncmp(facelet->netdevice.name, "en", 2) == 0) {
+ policy_tags_add(&tags, POLICY_TAG_WIRED);
+ goto DONE;
+ }
+ if (strncmp(facelet->netdevice.name, "wl", 2) == 0) {
+ /* wlan* wlp* wlx* */
+ policy_tags_add(&tags, POLICY_TAG_WIFI);
+ goto DONE;
+ }
+
+DONE:
+ ;
+ }
+#endif /* ! __ANDROID__ */
+#endif /* __linux__ */
+ face->tags = tags;
+
+ *pface = face;
+
+ return 0;
+
+ERR:
+ free(face);
+ERR_CREATE:
+ *pface = NULL;
+ return -1;
+}
+
+facelet_status_t
+facelet_get_status(const facelet_t * facelet)
+{
+ return facelet->status;
+}
+
+#define SET_ATTR_STATUS_CLEAN(TYPE, NAME) \
+do { \
+ if (facelet->NAME ## _status == FACELET_ATTR_STATUS_DIRTY) \
+ facelet->NAME ## _status = FACELET_ATTR_STATUS_CLEAN; \
+} while (0)
+
+void
+facelet_set_status(facelet_t * facelet, facelet_status_t status)
+{
+ if (status == FACELET_STATUS_CLEAN) {
+#define _(TYPE, NAME) SET_ATTR_STATUS_CLEAN(TYPE, NAME);
+ foreach_facelet_attr
+#undef _
+ }
+ facelet->status = status;
+}
+
+void
+facelet_set_bj_done(facelet_t * facelet)
+{
+ facelet->bj_done = true;
+}
+
+void
+facelet_unset_bj_done(facelet_t * facelet)
+{
+ facelet->bj_done = false;
+}
+
+bool
+facelet_is_bj_done(const facelet_t * facelet)
+{
+ return facelet->bj_done;
+}
+
+void
+facelet_set_au_done(facelet_t * facelet)
+{
+ facelet->au_done = true;
+}
+
+bool
+facelet_is_au_done(const facelet_t * facelet)
+{
+ return facelet->au_done;
+}
+
+facelet_event_t
+facelet_get_event(const facelet_t * facelet)
+{
+ return facelet->event;
+}
+
+void
+facelet_set_event(facelet_t * facelet, facelet_event_t event)
+{
+ facelet->event = event;
+}
+
+int
+facelet_snprintf(char * s, size_t size, facelet_t * facelet)
+{
+ char * cur = s;
+ int rc;
+
+ assert(facelet);
+
+ /* Header + key attributes (netdevice + family) */
+ rc = snprintf(cur, s + size - cur, "<Facelet %s (%s)",
+ // FIXME, better than the event would be the action to be performed next
+ facelet_event_str[facelet->event],
+ (facelet->family == AF_INET) ? "AF_INET" :
+ (facelet->family == AF_INET6) ? "AF_INET6" :
+ (facelet->family == AF_UNSPEC) ? "AF_UNSPEC" :
+ "unknown");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ /* Netdevice */
+ if (facelet_has_netdevice(facelet)) {
+ rc = snprintf(cur, s + size - cur, " netdevice=%s",
+ facelet->netdevice.name[0] ? facelet->netdevice.name : "*");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ rc = snprintf(cur, s + size - cur, "/%d", facelet->netdevice.index);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ } else {
+ rc = snprintf(cur, s + size - cur, " netdevice=*/*");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Netdevice type */
+ if (facelet_has_netdevice_type(facelet)) {
+ rc = snprintf(cur, s + size - cur, " type=%s",
+ netdevice_type_str[facelet->netdevice_type]);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+#ifdef __linux__
+#ifndef __ANDROID__
+ else {
+ /*
+ * Heuristics to determine face type based on name, until a better
+ * solution is found
+ */
+ if ((strncmp(facelet->netdevice.name, "eth", 3) == 0) ||
+ (strncmp(facelet->netdevice.name, "en", 2) == 0)) {
+ rc = snprintf(cur, s + size - cur, " [type=WIRED]");
+ goto HEURISTIC_DONE;
+ }
+ if (strncmp(facelet->netdevice.name, "wl", 2) == 0) {
+ /* wlan* wlp* wlx* */
+ rc = snprintf(cur, s + size - cur, " [type=WIFI]");
+ goto HEURISTIC_DONE;
+ }
+ goto HEURISTIC_END;
+
+HEURISTIC_DONE:
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+HEURISTIC_END:
+ ;
+ }
+#endif /* ! __ANDROID__ */
+#endif /* __linux__ */
+
+ /* Local ip address */
+ if (facelet_has_local_addr(facelet)) {
+ rc = snprintf(cur, s + size - cur, " local_addr=");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ rc = ip_address_snprintf(cur, s + size - cur, &facelet->local_addr,
+ facelet->family);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Local port */
+ if (facelet_has_local_port(facelet)) {
+ rc = snprintf(cur, s + size - cur, " local_port=%d",
+ facelet->local_port);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Remote ip address */
+ if (facelet_has_remote_addr(facelet)) {
+ rc = snprintf(cur, s + size - cur, " remote_addr=");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ rc = ip_address_snprintf(cur, s + size - cur, &facelet->remote_addr,
+ facelet->family);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Remote port */
+ if (facelet_has_remote_port(facelet)) {
+ rc = snprintf(cur, s + size - cur, " remote_port=%d",
+ facelet->remote_port);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Admin state */
+ if (facelet_has_admin_state(facelet)) {
+ rc = snprintf(cur, s + size - cur, " admin_state=%s",
+ face_state_str[facelet->admin_state]);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* State */
+ if (facelet_has_state(facelet)) {
+ rc = snprintf(cur, s + size - cur, " state=%s",
+ face_state_str[facelet->state]);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ if (facelet_has_face_type(facelet)) {
+ rc = snprintf(cur, s + size - cur, " face_type=LAYER%s/%s",
+ FACEMGR_FACE_TYPE_STR(facelet->face_type));
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ rc = snprintf(cur, s + size - cur, ">");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ return cur - s;
+}
diff --git a/ctrl/facemgr/src/facelet.h b/ctrl/facemgr/src/facelet.h
new file mode 100644
index 000000000..16c23b12e
--- /dev/null
+++ b/ctrl/facemgr/src/facelet.h
@@ -0,0 +1,192 @@
+/*
+ * 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 facelet.h
+ * \brief Facelet
+ *
+ * A facelet consists in partial information and annotations collected towards
+ * the contruction of the final face that will be sent to the forwarder.
+ *
+ * It might also consist in a pattern allowing the deletion of a group of face
+ * for instance.
+ */
+#ifndef FACEMGR_FACELET_H
+#define FACEMGR_FACELET_H
+
+#include <stdbool.h>
+
+#include <hicn/ctrl/face.h>
+#include <hicn/facemgr.h>
+
+#define MAXSZ_FACELET 1024
+
+/* NOTE: Any test should be sufficient */
+#define IS_VALID_NETDEVICE(netdevice) ((netdevice.index != 0) && (netdevice.name[0] != '\0'))
+
+typedef struct facelet_s facelet_t;
+
+/* Facelet status */
+#define foreach_facelet_status \
+ _(UNDEFINED) \
+ _(NEW) \
+ _(CLEAN) \
+ _(DIRTY) \
+ _(CONFLICT) \
+ _(DELETED) \
+ _(IGNORED) \
+ _(ERROR) \
+ _(N)
+
+typedef enum {
+#define _(x) FACELET_STATUS_ ## x,
+ foreach_facelet_status
+#undef _
+} facelet_status_t;
+
+extern const char * facelet_status_str[];
+
+/* Facelet attribute status */
+
+/*
+ * We expect an attribute in the cache to be able to take any value but
+ * UNDEFINED and N, which facelet events should either be UNSET or CLEAN
+ */
+#define foreach_facelet_attr_status \
+ _(UNDEFINED, '?') \
+ _(UNSET, 'X') \
+ _(CLEAN, ' ') \
+ _(DIRTY, '*') \
+ _(PENDING, 'P') \
+ _(CONFLICT, '!') \
+ _(N, '-')
+
+typedef enum {
+#define _(x, y) FACELET_ATTR_STATUS_ ## x,
+ foreach_facelet_attr_status
+#undef _
+} facelet_attr_status_t;
+
+extern const char * facelet_attr_status_str[];
+extern const char * facelet_attr_status_str_short[];
+
+/* Facelet attribute */
+
+#define foreach_facelet_attr \
+ _(netdevice_type_t, netdevice_type) \
+ _(netdevice_t, netdevice) \
+ _(int, family) \
+ _(ip_address_t, local_addr) \
+ _(u16, local_port) \
+ _(ip_address_t, remote_addr) \
+ _(u16, remote_port) \
+ _(face_state_t, admin_state) \
+ _(face_state_t, state) \
+ _(facemgr_face_type_t, face_type)
+
+#define foreach_facelet_event \
+ _(UNDEFINED) \
+ _(GET) \
+ _(CREATE) \
+ _(UPDATE) \
+ _(DELETE) \
+ _(SET_PARAMS) \
+ _(SET_UP) \
+ _(SET_DOWN) \
+ _(SET_TAGS) \
+ _(CLEAR_TAGS) \
+ _(ADD_TAG) \
+ _(REMOVE_TAG) \
+ _(N)
+
+#define MAXSZ_EVENT__ 10
+#define MAXSZ_EVENT_ MAXSZ_EVENT_ + 1
+
+/**
+ * \brief Enumeration of the possible types of event
+ */
+typedef enum {
+#define _(x) FACELET_EVENT_ ## x,
+foreach_facelet_event
+#undef _
+} facelet_event_t;
+
+extern const char * facelet_event_str[];
+
+/**
+ * \brief Create a facelet.
+ */
+facelet_t * facelet_create();
+
+facelet_t * facelet_create_from_netdevice(netdevice_t * netdevice);
+
+int facelet_validate_face(const facelet_t * facelet);
+
+facelet_t * facelet_create_from_face(face_t * face);
+
+void facelet_free(facelet_t * facelet);
+
+facelet_t * facelet_dup(const facelet_t * current_facelet);
+
+int facelet_cmp(const facelet_t * f1, const facelet_t * f2);
+
+/* NOTE: only clean attributes are matched */
+bool facelet_match(const facelet_t * facelet, const facelet_t * facelet_match);
+
+/**
+ * \brief Returns whether the specified facelet has all key attributes defined.
+ *
+ * Key attributes are netdevice and family. If both are present, this allows to
+ * uniquely identify a facelet, otherwise it is a 'wildcard' facelet
+ * specification and might match several facelets.
+ */
+bool facelet_has_key(const facelet_t * facelet);
+
+#define FACELET_ACCESSORS_H(TYPE, NAME) \
+bool facelet_has_ ## NAME(const facelet_t * facelet); \
+facelet_attr_status_t facelet_get_ ## NAME ## _status(const facelet_t * facelet);\
+int facelet_get_ ## NAME(const facelet_t * facelet, TYPE * NAME); \
+int facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME); \
+int facelet_unset_ ## NAME(facelet_t * facelet);
+
+#define _(TYPE, NAME) FACELET_ACCESSORS_H(TYPE, NAME)
+foreach_facelet_attr
+#undef _
+
+int facelet_get_face(const facelet_t * facelet, face_t ** pface);
+
+int facelet_merge(facelet_t * facelet, const facelet_t * facelet_to_merge);
+
+facelet_status_t facelet_get_status(const facelet_t * facelet);
+void facelet_set_status(facelet_t * facelet, facelet_status_t status);
+
+void facelet_set_bj_done(facelet_t * facelet);
+void facelet_unset_bj_done(facelet_t * facelet);
+bool facelet_is_bj_done(const facelet_t * facelet);
+void facelet_set_au_done(facelet_t * facelet);
+bool facelet_is_au_done(const facelet_t * facelet);
+
+facelet_event_t facelet_get_event(const facelet_t * facelet);
+void facelet_set_event(facelet_t * facelet, facelet_event_t event);
+
+int facelet_snprintf(char * buf, size_t size, facelet_t * facelet);
+
+#define DUMP_FACELET(msg, facelet) do { \
+ char buf[MAXSZ_FACELET]; \
+ facelet_snprintf(buf, MAXSZ_FACELET, facelet); \
+ DEBUG("%s : %s", msg, buf); \
+} while(0)
+
+#endif /* FACEMGR_FACELET_H */
diff --git a/ctrl/facemgr/src/facemgr.c b/ctrl/facemgr/src/facemgr.c
deleted file mode 100644
index 41e30de56..000000000
--- a/ctrl/facemgr/src/facemgr.c
+++ /dev/null
@@ -1,298 +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 facemgr.c
- * \brief Implementation of Face manager library interface
- */
-
-#include <stdio.h>
-
-#include "common.h"
-#include "event.h"
-#include "facemgr.h"
-#include "interface.h"
-#include "util/log.h"
-
-#ifdef __APPLE__
-extern interface_ops_t network_framework_ops;
-#endif
-#ifdef __linux__
-extern interface_ops_t netlink_ops;
-#endif
-#if 0
-extern interface_ops_t dummy_ops;
-#endif
-extern interface_ops_t hicn_light_ops;
-
-int
-facemgr_initialize(facemgr_t * facemgr)
-{
- int rc;
-
- rc = interface_map_initialize(&facemgr->interface_map);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_INTERFACE_MAP;
-
- rc = face_cache_initialize(&facemgr->face_cache);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_FACE_SET;
-
- rc = face_rules_initialize(&facemgr->rules);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_FACE_SET;
-
- return FACEMGR_SUCCESS;
-
-ERR_FACE_SET:
- interface_map_finalize(&facemgr->interface_map);
-
-ERR_INTERFACE_MAP:
- return FACEMGR_FAILURE;
-}
-
-int
-facemgr_finalize(facemgr_t * facemgr)
-{
- int rc;
-
- /* XXX Free all interfaces: pass free to map */
- rc = interface_map_finalize(&facemgr->interface_map);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR;
-
- rc = face_cache_finalize(&facemgr->face_cache);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR;
-
- rc = face_rules_finalize(&facemgr->rules);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR;
-
- return FACEMGR_SUCCESS;
-
-ERR:
- return FACEMGR_FAILURE;
-}
-
-AUTOGENERATE_CREATE_FREE(facemgr);
-
-int
-facemgr_on_event(facemgr_t * facemgr, event_t * event)
-{
- int rc;
- char face_s[MAXSZ_FACE];
- face_t * cached_face;
-
- if (!event->face) {
- printf("Event with empty face\n");
- return -1;
- }
-
- face_t face = *event->face;
-
- /* Complement unbound UDP faces */
- switch(face.type) {
- case FACE_TYPE_TCP:
- case FACE_TYPE_UDP:
- switch (face.params.tunnel.family) {
- case AF_INET:
- if ((ip_address_empty(&face.params.tunnel.remote_addr)) &&
- (!ip_address_empty(&facemgr->overlay_v4_remote_addr)))
- face.params.tunnel.remote_addr = facemgr->overlay_v4_remote_addr;
- if ((face.params.tunnel.local_port == 0) && (facemgr->overlay_v4_local_port != 0))
- face.params.tunnel.local_port = facemgr->overlay_v4_local_port;
- if ((face.params.tunnel.remote_port == 0) && (facemgr->overlay_v4_remote_port != 0))
- face.params.tunnel.remote_port = facemgr->overlay_v4_remote_port;
- break;
- case AF_INET6:
- if ((ip_address_empty(&face.params.tunnel.remote_addr)) &&
- (!ip_address_empty(&facemgr->overlay_v6_remote_addr)))
- face.params.tunnel.remote_addr = facemgr->overlay_v6_remote_addr;
- if ((face.params.tunnel.local_port == 0) && (facemgr->overlay_v6_local_port != 0))
- face.params.tunnel.local_port = facemgr->overlay_v6_local_port;
- if ((face.params.tunnel.remote_port == 0) && (facemgr->overlay_v6_remote_port != 0))
- face.params.tunnel.remote_port = facemgr->overlay_v6_remote_port;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- face_snprintf(face_s, MAXSZ_FACE, &face);
-
- /* TODO Here, we need to filter events based on our cache, and update the cache
- * based on our actions if they are successful */
-
- switch(event->type) {
- case EVENT_TYPE_CREATE:
- rc = face_cache_get(&facemgr->face_cache, &face, &cached_face);
- if (!FACEMGR_IS_ERROR(rc)) {
- DEBUG("Face found in cache");
- goto IGNORE_EVENT;
- }
- rc = face_cache_add(&facemgr->face_cache, &face);
- if (FACEMGR_IS_ERROR(rc))
- WARN("Failed to add face to cache");
- break;
- case EVENT_TYPE_DELETE:
- rc = face_cache_remove(&facemgr->face_cache, &face, &cached_face);
- if (FACEMGR_IS_ERROR(rc))
- WARN("Face not found in cache");
- break;
- case EVENT_TYPE_SET_UP:
- case EVENT_TYPE_SET_DOWN:
- /* TODO We need a return code to update the cache */
- break;
- default:
- printf("Not implemented!\n");
- break;
- }
-
- /* Process event */
- printf("[ FACE %s ] %s\n", event_type_str[event->type], face_s);
- /* Hardcoded hicn-light */
- rc = interface_on_event(facemgr->hl, event);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR;
-
-IGNORE_EVENT:
- return FACEMGR_SUCCESS;
-
-ERR:
- return FACEMGR_FAILURE;
-}
-
-#ifdef __linux__
-void interface_callback(evutil_socket_t fd, short what, void * arg) {
- interface_t * interface = (interface_t *)arg;
- interface->ops->callback(interface);
-}
-#endif /* __linux__ */
-
-int
-facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, interface_t ** interface)
-{
- int fd, rc;
-
- INFO("Creating interface %s [%s]...\n", name, type);
- *interface = interface_create(name, type);
- if (!*interface) {
- ERROR("Error creating interface %s [%s]\n", name, type);
- return -1;
- }
- interface_set_callback(*interface, facemgr_on_event, facemgr);
-
- fd = interface_initialize(*interface, &facemgr->rules);
- if (fd < 0)
- return -2;
- if (fd != 0) {
-#ifdef __linux__
- evutil_make_socket_nonblocking(fd);
- struct event * event = event_new(facemgr->loop, fd, EV_READ | EV_PERSIST, interface_callback, *interface);
- if (!event) {
- return -3;
- }
-
- if (event_add(event, NULL) < 0) {
- return -4;
- }
-#else
- ERROR("Not implemented\n");
- return FACEMGR_FAILURE;
-#endif /* __linux__ */
- }
-
- rc = interface_map_add(&facemgr->interface_map, (*interface)->name, *interface);
- if (FACEMGR_IS_ERROR(rc))
- return -5;
-
- DEBUG("Interface created successfully.\n");
- return FACEMGR_SUCCESS;
-}
-
-int
-facemgr_bootstrap(facemgr_t * facemgr)
-{
- int rc;
-
- DEBUG("Registering interfaces...");
- rc = interface_register(&hicn_light_ops);
- if (FACEMGR_IS_ERROR(rc)) {
- ERROR("Could not register interfaces");
- goto ERR_REGISTER;
- }
-
-#ifdef __APPLE__
- rc = interface_register(&network_framework_ops);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_REGISTER;
-#endif /* __APPLE__ */
-
-#ifdef __linux__
- rc = interface_register(&netlink_ops);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_REGISTER;
-#endif /* __linux__ */
-
-#if 0
- rc = interface_register(&dummy_ops);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_REGISTER;
-#endif
-
- rc = facemgr_create_interface(facemgr, "hl", "hicn_light", &facemgr->hl);
- if (rc < 0) {
- ERROR("Error creating 'hICN forwarder (hicn-light)' interface\n");
- goto ERR_HL_CREATE;
- }
-
-#ifdef __APPLE__
- rc = facemgr_create_interface(facemgr, "nf", "network_framework", &facemgr->nf);
- if (rc < 0) {
- ERROR("Error creating 'Apple Network Framework' interface\n");
- goto ERR_NF_CREATE;
- }
-#endif /* __APPLE__ */
-
-#ifdef __linux__
- rc = facemgr_create_interface(facemgr, "nl", "netlink", &facemgr->nl);
- if (rc < 0) {
- ERROR("Error creating 'Netlink' interface\n");
- goto ERR_NF_CREATE;
- }
-#endif /* __linux__ */
-
-#if 0
- rc = facemgr_create_interface(facemgr, "dummy", "dummy", &facemgr->dummy);
- if (rc < 0) {
- ERROR("Error creating 'Dummy' interface\n");
- goto ERR_NF_CREATE;
- }
-#endif
-
- DEBUG("Facemgr successfully initialized...");
-
- return FACEMGR_SUCCESS;
-
-ERR_NF_CREATE:
- interface_free(facemgr->hl);
-ERR_HL_CREATE:
- //interface_map_remove(&facemgr->interface_map, data->nf->name);
-ERR_REGISTER:
- return FACEMGR_FAILURE;
-}
diff --git a/ctrl/facemgr/src/facemgr.h b/ctrl/facemgr/src/facemgr.h
deleted file mode 100644
index 6505a1bd8..000000000
--- a/ctrl/facemgr/src/facemgr.h
+++ /dev/null
@@ -1,77 +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 facemgr.h
- * \brief Face manager library interface
- */
-#ifndef FACEMGR_H
-#define FACEMGR_H
-
-#include <string.h>
-#include "common.h"
-#include "face.h"
-#include "face_cache.h"
-#include "face_rules.h"
-#include "interface.h"
-#include "interface_map.h"
-#include "util/ip_address.h"
-#include "util/map.h"
-#include "util/policy.h"
-#ifndef __APPLE__
-#include <event2/event.h>
-#endif /* __APPLE__ */
-
-/*
- * \brief Face manager context
- */
-typedef struct {
-#ifndef APPLE
- /* Event loop */
- struct event_base * loop;
-#endif /* APPLE */
-
- interface_map_t interface_map;
- interface_t * hl;
-
-#ifdef __APPLE__
- interface_t * nf;
-#endif /* __APPLE__ */
-
-#ifdef __linux__
- interface_t * nl;
-#endif /* __linux__ */
-
-#if 0
- interface_t * dummy;
-#endif
-
- /* Overlay management */
- uint16_t overlay_v4_local_port;
- ip_address_t overlay_v4_remote_addr;
- uint16_t overlay_v4_remote_port;
- uint16_t overlay_v6_local_port;
- ip_address_t overlay_v6_remote_addr;
- uint16_t overlay_v6_remote_port;
-
- face_rules_t rules;
- face_cache_t face_cache;
-} facemgr_t;
-
-AUTOGENERATE_DEFS(facemgr);
-
-int facemgr_bootstrap(facemgr_t * facemgr);
-
-#endif /* FACEMGR_H */
diff --git a/ctrl/facemgr/src/interface.c b/ctrl/facemgr/src/interface.c
index af9f666a7..5cefcb98c 100644
--- a/ctrl/facemgr/src/interface.c
+++ b/ctrl/facemgr/src/interface.c
@@ -18,14 +18,17 @@
* \brief Implementation of interface base class.
*/
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "event.h"
-#include "face_rules.h"
+#include "facelet.h"
#include "interface.h"
-#include "interface_ops_map.h"
+#include <hicn/facemgr/loop.h> /* *_callback_data_t */
#include "util/map.h"
+TYPEDEF_MAP_H(interface_ops_map, const char *, const interface_ops_t *);
+TYPEDEF_MAP(interface_ops_map, const char *, const interface_ops_t *, strcmp, string_snprintf, generic_snprintf);
+
static interface_ops_map_t * interface_ops_map = NULL;
int
@@ -34,19 +37,41 @@ interface_register(const interface_ops_t * ops)
if (!interface_ops_map) {
interface_ops_map = interface_ops_map_create();
if (!interface_ops_map)
- return FACEMGR_FAILURE;
+ return -1;
}
interface_ops_map_add(interface_ops_map, ops->type, ops);
- return FACEMGR_SUCCESS;
+ return 0;
+}
+
+int
+interface_unregister_all()
+{
+ int ret = 0;
+ const char ** ops_name_array = NULL;
+ int n = interface_ops_map_get_key_array(interface_ops_map, &ops_name_array);
+ if (n < 0) {
+ ERROR("[interface_unregister_all] Could not get interface ops array");
+ ret = -1;
+ } else {
+ for (unsigned i = 0; i < n; i++) {
+ const char * ops_name = ops_name_array[i];
+ if (interface_ops_map_remove(interface_ops_map, ops_name, NULL) < 0) {
+ ERROR("[interface_unregister_all] Could not remove %s from interface ops map", ops_name);
+ ret = -1;
+ }
+ }
+ free(ops_name_array);
+ }
+ return ret;
}
interface_t *
interface_create(const char * name, const char * type)
{
- interface_ops_t * ops;
+ const interface_ops_t * ops = NULL;
int rc = interface_ops_map_get(interface_ops_map, type, &ops);
- if (FACEMGR_IS_ERROR(rc)) {
+ if (rc < 0) {
printf("Interface type not found %s\n", type);
return NULL;
}
@@ -59,7 +84,7 @@ interface_create(const char * name, const char * type)
/* this should use type */
interface->ops = ops;
interface->callback = NULL;
- interface->callback_data = NULL;
+ interface->callback_owner = NULL;
interface->data = NULL;
return interface;
@@ -73,32 +98,89 @@ interface_free(interface_t * interface)
}
void
-_interface_set_callback(interface_t * interface, callback_t callback, void * callback_data)
+interface_set_callback(interface_t * interface, void * callback_owner,
+ interface_cb_t callback)
{
interface->callback = callback;
- interface->callback_data = callback_data;
+ interface->callback_owner = callback_owner;
}
int
-interface_initialize(interface_t * interface, struct face_rules_s * rules)
+interface_initialize(interface_t * interface, void * cfg)
{
if (!interface->ops->initialize)
- return FACEMGR_FAILURE;
- return interface->ops->initialize(interface, rules, &interface->data);
+ return -1;
+ return interface->ops->initialize(interface, cfg);
}
int
interface_finalize(interface_t * interface)
{
if (!interface->ops->finalize)
- return FACEMGR_FAILURE;
+ return -1;
return interface->ops->finalize(interface);
}
int
-interface_on_event(interface_t * interface, const event_t * event)
+interface_on_event(interface_t * interface, const facelet_t * facelet)
{
if (!interface->ops->on_event)
- return FACEMGR_FAILURE;
- return interface->ops->on_event(interface, event);
+ return -1;
+ return interface->ops->on_event(interface, facelet);
+}
+
+int
+interface_raise_event(interface_t * interface, facelet_t * facelet)
+{
+ assert(interface->callback);
+ return interface->callback(interface->callback_owner,
+ INTERFACE_CB_TYPE_RAISE_EVENT, facelet);
+}
+
+int
+interface_register_fd(interface_t * interface, int fd, void * data)
+{
+ assert(interface->callback);
+ fd_callback_data_t fd_callback = {
+ .fd = fd,
+ .owner = interface,
+ .callback = (fd_callback_t)interface->ops->callback,
+ .data = data,
+ };
+ return interface->callback(interface->callback_owner,
+ INTERFACE_CB_TYPE_REGISTER_FD, &fd_callback);
+}
+
+int
+interface_unregister_fd(interface_t * interface, int fd)
+{
+ assert(interface->callback);
+ return interface->callback(interface->callback_owner,
+ INTERFACE_CB_TYPE_UNREGISTER_FD, &fd);
+}
+
+typedef int (*interface_fd_callback_t)(interface_t * interface, int fd, void * unused);
+
+int
+interface_register_timer(interface_t * interface, unsigned delay_ms,
+ interface_fd_callback_t callback, void * data)
+{
+ assert(interface->callback);
+ timer_callback_data_t timer_callback = {
+ .delay_ms = delay_ms,
+ .owner = interface,
+ .callback = (fd_callback_t)callback,
+ .data = data,
+ };
+ int rc = interface->callback(interface->callback_owner,
+ INTERFACE_CB_TYPE_REGISTER_TIMER, &timer_callback);
+ return rc;
+}
+
+int
+interface_unregister_timer(interface_t * interface, int fd)
+{
+ assert(interface->callback);
+ return interface->callback(interface->callback_owner,
+ INTERFACE_CB_TYPE_UNREGISTER_TIMER, &fd);
}
diff --git a/ctrl/facemgr/src/interface.h b/ctrl/facemgr/src/interface.h
index f38313182..d99f4fc8e 100644
--- a/ctrl/facemgr/src/interface.h
+++ b/ctrl/facemgr/src/interface.h
@@ -29,30 +29,42 @@
#define FACEMGR_INTERFACE_H
#include <stdbool.h>
+#include <hicn/facemgr/loop.h>
-struct event_s;
-typedef int (*callback_t)(struct event_s * event, void * callback_data);
+typedef enum {
+ INTERFACE_CB_TYPE_REGISTER_FD,
+ INTERFACE_CB_TYPE_UNREGISTER_FD,
+ INTERFACE_CB_TYPE_RAISE_EVENT,
+ INTERFACE_CB_TYPE_REGISTER_TIMER,
+ INTERFACE_CB_TYPE_UNREGISTER_TIMER,
+} interface_cb_type_t;
-struct interface_s;
-struct face_rules_s;
+typedef int (*interface_cb_t)(facemgr_t * facemgr, interface_cb_type_t type, void * data);
/**
* \brief Interface operations
*/
+struct interface_s;
typedef struct {
+ /** The type given to the interfaces */
char * type;
- bool is_singleton;
- int (*initialize)(struct interface_s * interface, struct face_rules_s * rules, void ** pdata);
+ /* Constructor */
+ int (*initialize)(struct interface_s * interface, void * cfg);
+ /* Destructor */
int (*finalize)(struct interface_s * interface);
- int (*callback)(struct interface_s * interface);
- int (*on_event)(struct interface_s * interface, const struct event_s * event);
+ /* Callback upon file descriptor event (iif previously registered) */
+ int (*callback)(struct interface_s * interface, int fd, void * data);
+ /* Callback upon face events coming from the face manager */
+ int (*on_event)(struct interface_s * interface, const struct facelet_s * facelet);
} interface_ops_t;
typedef struct interface_s {
char * name;
- interface_ops_t * ops;
- callback_t callback;
- void * callback_data;
+ const interface_ops_t * ops;
+
+ interface_cb_t callback;
+ void * callback_owner;
+
void * data;
} interface_t;
@@ -80,19 +92,51 @@ interface_t * interface_create(const char * name, const char * type);
*/
void interface_free(interface_t * interface);
+
+void interface_set_callback(interface_t * interface, void * callback_owner, interface_cb_t callback);
+
+int interface_initialize(interface_t * interface, void * cfg);
+
+int interface_finalize(interface_t * interface);
+
+int interface_on_event(interface_t * interface, const struct facelet_s * facelet);
+
/**
- * This function is equivalent to interface_set_callback, which should be
- * preferred. The difference is the lack of explicit type casts which should
- * simplify the calling syntax.
+ * \brief Raises a facelet event to the face manager
+ * \param [in] interface - Interface that raised the event (or NULL if it was
+ * created but the face manager itself, or is a joined event)
+ * \param [in] facelet - Facelet to communicate with the event
+ * \return Error code
*/
+int interface_callback(interface_t * interface, interface_cb_type_t type, void * data);
-void _interface_set_callback(interface_t * interface, callback_t callback, void * callback_data);
-#define interface_set_callback(interface, callback, callback_data) \
- _interface_set_callback(interface, (callback_t)callback, (void*)callback_data)
+int interface_raise_event(interface_t * interface, facelet_t * facelet);
-int interface_initialize(interface_t * interface, struct face_rules_s * rules);
-int interface_finalize(interface_t * interface);
+int interface_register_fd(interface_t * interface, int fd, void * data);
+
+int interface_unregister_fd(interface_t * interface, int fd);
-int interface_on_event(interface_t * interface, const struct event_s * event);
+typedef int (*interface_fd_callback_t)(interface_t * interface, int fd, void * unused);
+
+/**
+ * \brief Registers a timer event
+ * \param [in] interface - Pointer to the interface responsible for the timer
+ * \param [in] delay_ms - Delay in milliseconds between timer events (first
+ * occurence happends after this delay)
+ * \param [in] callback - Callback function to be triggered
+ * \param [in] data - User data
+ * \return A positive value uniquely identifying the timer, or -1 in case of
+ * error
+ */
+int interface_register_timer(interface_t * interface, unsigned delay_ms,
+ interface_fd_callback_t callback, void * data);
+
+/**
+ * \brief Unregisters a timer event
+ * \param [in] interface - Pointer to the interface responsible for the timer
+ * \param [in] fd - Timer identifier
+ * \return 0 in case of success, -1 otherwise
+ */
+int interface_unregister_timer(interface_t * interface, int fd);
#endif /* FACEMGR_INTERFACE_H */
diff --git a/ctrl/facemgr/src/interface_map.c b/ctrl/facemgr/src/interface_map.c
deleted file mode 100644
index 9f7c20cab..000000000
--- a/ctrl/facemgr/src/interface_map.c
+++ /dev/null
@@ -1,21 +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.
- */
-
-#include "interface_map.h"
-
-#include <string.h>
-#include "interface.h"
-
-TYPEDEF_MAP(interface_map, const char *, interface_t *, strcmp, string_snprintf, generic_snprintf);
diff --git a/ctrl/facemgr/src/interface_ops_map.c b/ctrl/facemgr/src/interface_ops_map.c
deleted file mode 100644
index 373f5d22f..000000000
--- a/ctrl/facemgr/src/interface_ops_map.c
+++ /dev/null
@@ -1,21 +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.
- */
-
-#include "interface_ops_map.h"
-
-#include <string.h>
-#include "util/map.h"
-
-TYPEDEF_MAP(interface_ops_map, const char *, interface_ops_t *, strcmp, string_snprintf, generic_snprintf);
diff --git a/ctrl/facemgr/src/interfaces/CMakeLists.txt b/ctrl/facemgr/src/interfaces/CMakeLists.txt
index e5a26177a..8d079612a 100644
--- a/ctrl/facemgr/src/interfaces/CMakeLists.txt
+++ b/ctrl/facemgr/src/interfaces/CMakeLists.txt
@@ -24,12 +24,21 @@ endif()
if(LINUX)
add_subdirectory(netlink)
+add_subdirectory(bonjour)
endif()
-if(false)
+if(ANDROID)
+add_subdirectory(android_utility)
+endif()
+
+if(WITH_EXAMPLE_DUMMY)
add_subdirectory(dummy)
endif()
+if(WITH_EXAMPLE_UPDOWN)
+add_subdirectory(updown)
+endif()
+
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt b/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt
new file mode 100644
index 000000000..0ebe87745
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt
@@ -0,0 +1,27 @@
+# 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.
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/android_utility.c
+)
+
+list(APPEND INCLUDE_DIRS
+)
+
+list(APPEND LIBRARIES
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
+set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
+set(LIBRARIES ${LIBRARIES} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/interfaces/android_utility/android_utility.c b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c
new file mode 100644
index 000000000..a4aa2cbfc
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c
@@ -0,0 +1,138 @@
+/*
+ * 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 interfaces/android_utility/android_utility.c
+ * \brief Implementation of Android utility.
+ */
+
+#include <assert.h>
+
+#include <hicn/facemgr.h>
+#include <hicn/ctrl/face.h>
+#include <hicn/util/log.h>
+#include "../../common.h"
+#include "../../facelet.h"
+#include "../../interface.h"
+#include <hicn/android_utility/android_utility.h>
+
+#define FACEMGR_ANDROID_UTILITY_CLASS "com/cisco/hicn/forwarder/supportlibrary/AndroidUtility"
+
+#define AU_INTERFACE_TYPE_UNDEFINED 0
+#define AU_INTERFACE_TYPE_WIRED 1
+#define AU_INTERFACE_TYPE_WIFI 2
+#define AU_INTERFACE_TYPE_CELLULAR 3
+#define AU_INTERFACE_TYPE_LOOPBACK 4 /* not supported yet */
+
+#define ERR_STR_JAVA "Java VM parameters are required in the interface configuration."
+
+typedef struct {
+ android_utility_cfg_t cfg;
+} au_data_t;
+
+int au_initialize(interface_t * interface, void * cfg)
+{
+ au_data_t * data = malloc(sizeof(au_data_t));
+ if (!data)
+ return -1;
+ interface->data = data;
+
+ if (!cfg)
+ goto ERR_CFG;
+
+ data->cfg = * (android_utility_cfg_t *) cfg;
+
+ if (!data->cfg.jvm)
+ goto ERR_CFG;
+
+ return 0;
+
+ERR_CFG:
+ fprintf(stderr, ERR_STR_JAVA);
+ return -1;
+}
+
+int au_finalize(interface_t * interface)
+{
+ /* Nothing to do */
+ return 0;
+}
+
+int au_on_event(interface_t * interface, const facelet_t * facelet)
+{
+ /*
+ * This function is responsible to annotate every face we receive with the
+ * correct interface type, based on the value returned by the Android
+ * utility shipped with the Android forwarder.
+ */
+ DEBUG("Android utility received request");
+ au_data_t * data = (au_data_t*)interface->data;
+
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0)
+ return -1;
+ DEBUG("[au_on_event] netdevice=%s", netdevice.name);
+
+ JNIEnv *env;
+ JavaVM *jvm = data->cfg.jvm;
+ (*jvm)->AttachCurrentThread(jvm, &env, NULL);
+ jclass cls = (*env)->FindClass(env, FACEMGR_ANDROID_UTILITY_CLASS);
+ jmethodID getNetworkType = (*env)->GetStaticMethodID(env, cls,
+ "getNetworkType", "(Ljava/lang/String;)I");
+ jint interface_type = (*env)->CallStaticIntMethod(env, cls, getNetworkType,
+ (*env)->NewStringUTF(env, netdevice.name));
+
+ DEBUG("Processing results for interface %s", netdevice.name);
+
+ netdevice_type_t netdevice_type = AU_INTERFACE_TYPE_UNDEFINED;
+ switch(interface_type) {
+ case AU_INTERFACE_TYPE_UNDEFINED:
+ break;
+ case AU_INTERFACE_TYPE_WIRED:
+ netdevice_type = NETDEVICE_TYPE_WIRED;
+ break;
+ case AU_INTERFACE_TYPE_WIFI:
+ netdevice_type = NETDEVICE_TYPE_WIFI;
+ break;
+ case AU_INTERFACE_TYPE_CELLULAR:
+ netdevice_type = NETDEVICE_TYPE_CELLULAR;
+ break;
+ case AU_INTERFACE_TYPE_LOOPBACK:
+ netdevice_type = NETDEVICE_TYPE_LOOPBACK;
+ break;
+ default:
+ return -1;
+ }
+
+ facelet_t * facelet_new = facelet_create();
+ facelet_set_netdevice(facelet_new, netdevice);
+ facelet_set_status(facelet_new, FACELET_STATUS_CLEAN);
+ facelet_set_netdevice_type(facelet_new, netdevice_type);
+
+ DEBUG("sending AU udpate");
+ facelet_set_event(facelet_new, FACELET_EVENT_UPDATE);
+ interface_raise_event(interface, facelet_new);
+
+ return 0;
+}
+
+const interface_ops_t android_utility_ops = {
+ .type = "android_utility",
+ .initialize = au_initialize,
+ .finalize = au_finalize,
+ .callback = NULL,
+ .on_event = au_on_event,
+};
diff --git a/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt b/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt
new file mode 100644
index 000000000..8a0ddc888
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt
@@ -0,0 +1,32 @@
+# 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.
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/bonjour.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mdns/mdns.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/bonjour.c
+)
+
+list(APPEND LIBRARIES
+)
+
+list(APPEND INCLUDE_DIRS
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
+set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
+set(LIBRARIES ${LIBRARIES} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/interfaces/bonjour/bonjour.c b/ctrl/facemgr/src/interfaces/bonjour/bonjour.c
new file mode 100644
index 000000000..4d09d89bb
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/bonjour.c
@@ -0,0 +1,410 @@
+/*
+ * 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 interfaces/bonjour/bonjour.c
+ * \brief Implementation of Bonjour interface
+ *
+ * TODO:
+ * - concurrent queries
+ * - interface binding
+ */
+
+#include <hicn/facemgr.h>
+#include <hicn/util/log.h>
+
+#include "../../common.h"
+#include "../../facelet.h"
+#include "../../interface.h"
+#include "../../util/map.h"
+#include "mdns/mdns.h"
+
+#include "bonjour.h"
+
+#define DEFAULT_BUFFER_SIZE 2048
+#define SERVICE_STRING_SIZE 256
+
+#define DEFAULT_SERVICE_NAME "hicn"
+#define DEFAULT_SERVICE_PROTOCOL "udp"
+#define DEFAULT_SERVICE_DOMAIN "local"
+
+typedef struct {
+ bonjour_cfg_t cfg;
+ int sock;
+ size_t buffer_size;
+ void* buffer;
+
+ /* The face being resolved, non-NULL values indicate interface is busy... */
+ face_t * face;
+} bj_data_t;
+
+int bj_initialize(interface_t * interface, void * cfg)
+{
+ bj_data_t * data = malloc(sizeof(bj_data_t));
+ if (!data)
+ goto ERR_MALLOC;
+ interface->data = data;
+
+ if (cfg) {
+#ifndef __linux__
+ if (cfg->netdevice)
+ WARN("Binding to interface is (currently) only supported on Linux");
+#endif /* ! __linux__ */
+ data->cfg = * (bonjour_cfg_t *) cfg;
+ } else {
+ memset(&data->cfg, 0, sizeof(bonjour_cfg_t));
+ }
+
+ if (!data->cfg.service_name)
+ data->cfg.service_name = DEFAULT_SERVICE_NAME;
+
+ if (!data->cfg.service_protocol)
+ data->cfg.service_protocol = DEFAULT_SERVICE_PROTOCOL;
+
+ if (!data->cfg.service_domain)
+ data->cfg.service_domain = DEFAULT_SERVICE_DOMAIN;
+
+ data->sock = mdns_socket_open_ipv4();
+ if (data->sock < 0) {
+ printf("Failed to open socket: %s\n", strerror(errno));
+ goto ERR_SOCK;
+ }
+
+ /* Netdevice configuration */
+#ifdef __linux__
+#ifndef __ANDROID__
+ if (IS_VALID_NETDEVICE(data->cfg.netdevice)) {
+ int rc = setsockopt(data->sock, SOL_SOCKET, SO_BINDTODEVICE,
+ &data->cfg.netdevice.name, strlen(data->cfg.netdevice.name) + 1);
+ if (rc == -1) {
+ ERROR("setsockopt");
+ goto ERR_SOCK_OPT;
+ }
+ }
+#endif
+#endif /* __linux__ */
+
+ data->buffer_size = DEFAULT_BUFFER_SIZE;
+ data->buffer = malloc(data->buffer_size);
+ if (!data->buffer)
+ goto ERR_BUFFER;
+
+#ifdef _WIN32
+ WORD versionWanted = MAKEWORD(1, 1);
+ WSADATA wsaData;
+ WSAStartup(versionWanted, &wsaData);
+#endif
+
+ interface_register_fd(interface, data->sock, NULL);
+
+ return 0;
+
+ERR_BUFFER:
+#ifndef __ANDROID__
+ERR_SOCK_OPT:
+#endif
+ mdns_socket_close(data->sock);
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ERR_SOCK:
+ free(data);
+ERR_MALLOC:
+ return -1;
+}
+
+/*
+ * We reuse the callback to be triggered upon external events
+ * TODO: move to a cleaner interface architecture later...
+ */
+int bj_on_event(interface_t * interface, const facelet_t * facelet)
+{
+ bj_data_t * data = (bj_data_t*)interface->data;
+
+ /*
+ printf("Sending DNS-SD discovery\n");
+ if (mdns_discovery_send(sock)) {
+ printf("Failed to send DNS-DS discovery: %s\n", strerror(errno));
+ goto quit;
+ }
+
+ printf("Reading DNS-SD replies\n");
+ for (int i = 0; i < 10; ++i) {
+ records = mdns_discovery_recv(sock, buffer, capacity, callback,
+ user_data);
+ sleep(1);
+ }
+ */
+
+ DEBUG("Sending mDNS query");
+ char service_string[SERVICE_STRING_SIZE];
+
+ int rc = snprintf(service_string, SERVICE_STRING_SIZE, "_%s._%s.%s.",
+ data->cfg.service_name, data->cfg.service_protocol,
+ data->cfg.service_domain);
+ if (rc < 0)
+ ; // error
+ else if (rc >= SERVICE_STRING_SIZE)
+ ; //truncated
+
+ if (mdns_query_send(data->sock, MDNS_RECORDTYPE_PTR,
+ service_string,
+ strlen(service_string),
+ data->buffer, data->buffer_size)) {
+ printf("Failed to send mDNS query: %s\n", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static char addrbuffer[64];
+static char namebuffer[256];
+static mdns_record_txt_t txtbuffer[128];
+
+static mdns_string_t
+ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in),
+ host, NI_MAXHOST, service, NI_MAXSERV,
+ NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin_port != 0)
+ len = snprintf(buffer, capacity, "%s:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str = {buffer, len};
+ return str;
+}
+
+static mdns_string_t
+ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in6),
+ host, NI_MAXHOST, service, NI_MAXSERV,
+ NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin6_port != 0)
+ len = snprintf(buffer, capacity, "[%s]:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str = {buffer, len};
+ return str;
+}
+
+static mdns_string_t
+ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr) {
+ if (addr->sa_family == AF_INET6)
+ return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr);
+ return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr);
+}
+
+int
+ip_address_set_sockaddr(ip_address_t * ip_address, struct sockaddr * sa)
+{
+ switch(sa->sa_family) {
+ case AF_INET:
+ ip_address->v4.as_inaddr = ((struct sockaddr_in *)sa)->sin_addr;
+ break;
+ case AF_INET6:
+ ip_address->v6.as_in6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+callback(const struct sockaddr* from, mdns_entry_type_t entry, uint16_t type,
+ uint16_t rclass, uint32_t ttl, const void* data, size_t size, size_t
+ offset, size_t length, void* user_data)
+{
+ interface_t * interface = (interface_t*)user_data;
+ bj_data_t * bj_data = (bj_data_t *)interface->data;
+
+ struct sockaddr_storage addr;
+
+ mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from);
+ const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ? "answer" :
+ ((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional");
+
+ switch(type) {
+ case MDNS_RECORDTYPE_A:
+ {
+ ip_address_t ip_address;
+ mdns_record_parse_a(data, size, offset, length, (struct sockaddr_in*)&addr);
+ ip_address_set_sockaddr(&ip_address, (struct sockaddr *)&addr);
+
+ mdns_string_t addrstr = ipv4_address_to_string(namebuffer, sizeof(namebuffer), (struct sockaddr_in *)&addr);
+ DEBUG("%.*s : %s A %.*s",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(addrstr));
+
+ facelet_t * facelet = facelet_create();
+ facelet_set_netdevice(facelet, bj_data->cfg.netdevice);
+ facelet_set_family(facelet, AF_INET);
+ facelet_set_remote_addr(facelet, ip_address);
+ //facelet_set_remote_port(facelet, ((struct sockaddr_in*)&addr)->sin_port);
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ interface_raise_event(interface, facelet);
+ break;
+ }
+
+ case MDNS_RECORDTYPE_AAAA:
+ {
+ ip_address_t ip_address;
+ mdns_record_parse_aaaa(data, size, offset, length, (struct sockaddr_in6*)&addr);
+ ip_address_set_sockaddr(&ip_address, (struct sockaddr *)&addr);
+
+ mdns_string_t addrstr = ipv6_address_to_string(namebuffer,
+ sizeof(namebuffer), (struct sockaddr_in6*)&addr);
+ DEBUG("%.*s : %s AAAA %.*s",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(addrstr));
+
+ facelet_t * facelet = facelet_create();
+ facelet_set_netdevice(facelet, bj_data->cfg.netdevice);
+ facelet_set_family(facelet, AF_INET6);
+ facelet_set_remote_addr(facelet, ip_address);
+ //facelet_set_remote_port(facelet, ((struct sockaddr_in6*)&addr)->sin6_port);
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ interface_raise_event(interface, facelet);
+ break;
+ }
+
+ case MDNS_RECORDTYPE_SRV: /* same port for both v4 and v6 */
+ {
+ mdns_record_srv_t srv = mdns_record_parse_srv(data, size, offset, length,
+ namebuffer, sizeof(namebuffer));
+
+ DEBUG("%.*s : %s SRV %.*s priority %d weight %d port %d",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
+
+ /* We raise both v4 and v6
+ *
+ * Unless we choose whether we query A and/or AAAA, this might leave
+ * us with an unused pending facelet, eg. we might not have an IPv6
+ * but we raise an IPv6 bonjour event...
+ */
+
+ facelet_t * facelet = facelet_create();
+ facelet_set_netdevice(facelet, bj_data->cfg.netdevice);
+ facelet_set_family(facelet, AF_INET);
+ facelet_set_remote_port(facelet, srv.port);
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ interface_raise_event(interface, facelet);
+
+ facelet = facelet_create();
+ facelet_set_netdevice(facelet, bj_data->cfg.netdevice);
+ facelet_set_family(facelet, AF_INET6);
+ facelet_set_remote_port(facelet, srv.port);
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ interface_raise_event(interface, facelet);
+ break;
+ }
+
+ case MDNS_RECORDTYPE_PTR:
+ {
+ mdns_string_t namestr = mdns_record_parse_ptr(data, size, offset, length,
+ namebuffer, sizeof(namebuffer));
+ DEBUG("%.*s : %s PTR %.*s type %u rclass 0x%x ttl %u length %d",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(namestr), type, rclass, ttl, (int)length);
+ break;
+ }
+
+ case MDNS_RECORDTYPE_TXT:
+ {
+ size_t parsed = mdns_record_parse_txt(data, size, offset, length,
+ txtbuffer, sizeof(txtbuffer) / sizeof(mdns_record_txt_t));
+ for (size_t itxt = 0; itxt < parsed; ++itxt) {
+ if (txtbuffer[itxt].value.length) {
+ DEBUG("%.*s : %s TXT %.*s = %.*s",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key),
+ MDNS_STRING_FORMAT(txtbuffer[itxt].value));
+ }
+ else {
+ DEBUG("%.*s : %s TXT %.*s",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key));
+ }
+ }
+ break;
+ }
+
+ default:
+ /* Silently ignore the received record */
+ DEBUG("%.*s : %s type %u rclass 0x%x ttl %u length %d",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ type, rclass, ttl, (int)length);
+ return 0;
+ }
+ return 0;
+
+}
+
+/*
+ * The fact we use a single fd does not allow us to get user_data associated to
+ * the query.
+ */
+int bj_callback(interface_t * interface, int fd, void * unused)
+{
+ bj_data_t * data = (bj_data_t*)interface->data;
+ DEBUG("Got an mDNS reply");
+ /* size_t records = */ mdns_query_recv(data->sock, data->buffer, data->buffer_size, callback, interface, 1);
+
+ return 0;
+}
+
+int bj_finalize(interface_t * interface)
+{
+ bj_data_t * data = (bj_data_t*)interface->data;
+
+ free(data->buffer);
+ mdns_socket_close(data->sock);
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ return 0;
+
+}
+
+const interface_ops_t bonjour_ops = {
+ .type = "bonjour",
+ .initialize = bj_initialize,
+ .on_event = bj_on_event,
+ .callback = bj_callback,
+ .finalize = bj_finalize,
+ // .on_event = NULL,
+};
diff --git a/ctrl/facemgr/src/interfaces/bonjour/bonjour.h b/ctrl/facemgr/src/interfaces/bonjour/bonjour.h
new file mode 100644
index 000000000..fe053079d
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/bonjour.h
@@ -0,0 +1,35 @@
+/*
+ * 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 interfaces/bonjour/bonjour.h
+ * \brief Bonjour interface
+ *
+ * NOTES:
+ * - shall we support multiple service names, or instanciate multiple instances
+ * of the interface ?
+ * - interface list ?
+ * - ideally we should register here events that will trigger bonjour
+ * queries...
+ */
+
+#include <hicn/ctrl/face.h> /* netdevice_t */
+
+typedef struct {
+ netdevice_t netdevice;
+ char * service_name;
+ char * service_protocol;
+ char * service_domain;
+} bonjour_cfg_t;
diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE b/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE
new file mode 100644
index 000000000..cf1ab25da
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>
diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md b/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md
new file mode 100644
index 000000000..1bee49c08
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md
@@ -0,0 +1,9 @@
+# Public domain mDNS/DNS-SD library in C
+
+This library provides a cross-platform mDNS and DNS-DS library in C. The latest source code is always available at
+
+https://github.com/mjansson/mdns
+
+This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+
+Created by Mattias Jansson ([@maniccoder](https://twitter.com/maniccoder))
diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c
new file mode 100644
index 000000000..a8e97e8e0
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c
@@ -0,0 +1,192 @@
+
+#ifdef _WIN32
+# define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include "mdns.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef _WIN32
+# define sleep(x) Sleep(x * 1000)
+#else
+# include <netdb.h>
+#endif
+
+static char addrbuffer[64];
+static char namebuffer[256];
+static mdns_record_txt_t txtbuffer[128];
+
+static mdns_string_t
+ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in),
+ host, NI_MAXHOST, service, NI_MAXSERV,
+ NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin_port != 0)
+ len = snprintf(buffer, capacity, "%s:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str = {buffer, len};
+ return str;
+}
+
+static mdns_string_t
+ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in6),
+ host, NI_MAXHOST, service, NI_MAXSERV,
+ NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin6_port != 0)
+ len = snprintf(buffer, capacity, "[%s]:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str = {buffer, len};
+ return str;
+}
+
+static mdns_string_t
+ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr) {
+ if (addr->sa_family == AF_INET6)
+ return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr);
+ return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr);
+}
+
+static int
+callback(const struct sockaddr* from,
+ mdns_entry_type_t entry, uint16_t type,
+ uint16_t rclass, uint32_t ttl,
+ const void* data, size_t size, size_t offset, size_t length,
+ void* user_data) {
+ mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from);
+ const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ? "answer" :
+ ((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional");
+ if (type == MDNS_RECORDTYPE_PTR) {
+ mdns_string_t namestr = mdns_record_parse_ptr(data, size, offset, length,
+ namebuffer, sizeof(namebuffer));
+ INFO("%.*s : %s PTR %.*s type %u rclass 0x%x ttl %u length %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(namestr), type, rclass, ttl, (int)length);
+ }
+ else if (type == MDNS_RECORDTYPE_SRV) {
+ mdns_record_srv_t srv = mdns_record_parse_srv(data, size, offset, length,
+ namebuffer, sizeof(namebuffer));
+ INFO("%.*s : %s SRV %.*s priority %d weight %d port %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
+ }
+ else if (type == MDNS_RECORDTYPE_A) {
+ struct sockaddr_in addr;
+ mdns_record_parse_a(data, size, offset, length, &addr);
+ mdns_string_t addrstr = ipv4_address_to_string(namebuffer, sizeof(namebuffer), &addr);
+ INFO("%.*s : %s A %.*s\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(addrstr));
+ }
+ else if (type == MDNS_RECORDTYPE_AAAA) {
+ struct sockaddr_in6 addr;
+ mdns_record_parse_aaaa(data, size, offset, length, &addr);
+ mdns_string_t addrstr = ipv6_address_to_string(namebuffer, sizeof(namebuffer), &addr);
+ INFO("%.*s : %s AAAA %.*s\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(addrstr));
+ }
+ else if (type == MDNS_RECORDTYPE_TXT) {
+ size_t parsed = mdns_record_parse_txt(data, size, offset, length,
+ txtbuffer, sizeof(txtbuffer) / sizeof(mdns_record_txt_t));
+ for (size_t itxt = 0; itxt < parsed; ++itxt) {
+ if (txtbuffer[itxt].value.length) {
+ INFO("%.*s : %s TXT %.*s = %.*s\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key),
+ MDNS_STRING_FORMAT(txtbuffer[itxt].value));
+ }
+ else {
+ INFO("%.*s : %s TXT %.*s\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key));
+ }
+ }
+ }
+ else {
+ INFO("%.*s : %s type %u rclass 0x%x ttl %u length %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ type, rclass, ttl, (int)length);
+ }
+ return 0;
+}
+
+int
+main() {
+ size_t capacity = 2048;
+ void* buffer = 0;
+ void* user_data = 0;
+ size_t records;
+
+#ifdef _WIN32
+ WORD versionWanted = MAKEWORD(1, 1);
+ WSADATA wsaData;
+ WSAStartup(versionWanted, &wsaData);
+#endif
+
+ int sock = mdns_socket_open_ipv4();
+ if (sock < 0) {
+ INFO("Failed to open socket: %s\n", strerror(errno));
+ return -1;
+ }
+ INFO("Opened IPv4 socket for mDNS/DNS-SD\n");
+ buffer = malloc(capacity);
+/*
+ INFO("Sending DNS-SD discovery\n");
+ if (mdns_discovery_send(sock)) {
+ INFO("Failed to send DNS-DS discovery: %s\n", strerror(errno));
+ goto quit;
+ }
+
+ INFO("Reading DNS-SD replies\n");
+ for (int i = 0; i < 10; ++i) {
+ records = mdns_discovery_recv(sock, buffer, capacity, callback,
+ user_data);
+ sleep(1);
+ }
+ */
+
+ INFO("Sending mDNS query\n");
+ if (mdns_query_send(sock, MDNS_RECORDTYPE_PTR,
+ MDNS_STRING_CONST("_hicn._udp.local."),
+ buffer, capacity)) {
+ INFO("Failed to send mDNS query: %s\n", strerror(errno));
+ goto quit;
+ }
+
+ INFO("Reading mDNS replies\n");
+ for (int i = 0; i < 10; ++i) {
+ records = mdns_query_recv(sock, buffer, capacity, callback, user_data, 1);
+ sleep(1);
+ }
+
+quit:
+ free(buffer);
+
+ mdns_socket_close(sock);
+ INFO("Closed socket\n");
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ return 0;
+}
diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h
new file mode 100644
index 000000000..ff04b5d72
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h
@@ -0,0 +1,879 @@
+/* mdns.h - mDNS/DNS-SD library - Public Domain - 2017 Mattias Jansson
+ *
+ * This library provides a cross-platform mDNS and DNS-SD library in C.
+ * The implementation is based on RFC 6762 and RFC 6763.
+ *
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/mdns
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#ifdef _WIN32
+#include <Winsock2.h>
+#include <Ws2tcpip.h>
+#define strncasecmp _strnicmp
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#define MDNS_INVALID_POS ((size_t)-1)
+
+#define MDNS_STRING_CONST(s) (s), (sizeof((s))-1)
+#define MDNS_STRING_FORMAT(s) (int)((s).length), s.str
+
+enum mdns_record_type {
+ MDNS_RECORDTYPE_IGNORE = 0,
+ //Address
+ MDNS_RECORDTYPE_A = 1,
+ //Domain Name pointer
+ MDNS_RECORDTYPE_PTR = 12,
+ //Arbitrary text string
+ MDNS_RECORDTYPE_TXT = 16,
+ //IP6 Address [Thomson]
+ MDNS_RECORDTYPE_AAAA = 28,
+ //Server Selection [RFC2782]
+ MDNS_RECORDTYPE_SRV = 33
+};
+
+enum mdns_entry_type {
+ MDNS_ENTRYTYPE_ANSWER = 1,
+ MDNS_ENTRYTYPE_AUTHORITY = 2,
+ MDNS_ENTRYTYPE_ADDITIONAL = 3
+};
+
+enum mdns_class {
+ MDNS_CLASS_IN = 1
+};
+
+typedef enum mdns_record_type mdns_record_type_t;
+typedef enum mdns_entry_type mdns_entry_type_t;
+typedef enum mdns_class mdns_class_t;
+
+typedef int (* mdns_record_callback_fn)(const struct sockaddr* from,
+ mdns_entry_type_t entry, uint16_t type,
+ uint16_t rclass, uint32_t ttl,
+ const void* data, size_t size, size_t offset, size_t length,
+ void* user_data);
+
+typedef struct mdns_string_t mdns_string_t;
+typedef struct mdns_string_pair_t mdns_string_pair_t;
+typedef struct mdns_record_srv_t mdns_record_srv_t;
+typedef struct mdns_record_txt_t mdns_record_txt_t;
+
+struct mdns_string_t {
+ const char* str;
+ size_t length;
+};
+
+struct mdns_string_pair_t {
+ size_t offset;
+ size_t length;
+ int ref;
+};
+
+struct mdns_record_srv_t {
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ mdns_string_t name;
+};
+
+struct mdns_record_txt_t {
+ mdns_string_t key;
+ mdns_string_t value;
+};
+
+static int
+mdns_socket_open_ipv4(void);
+
+static int
+mdns_socket_setup_ipv4(int sock);
+
+#if 0
+static int
+mdns_socket_open_ipv6(void);
+
+
+
+static int
+mdns_socket_setup_ipv6(int sock);
+#endif
+
+static void
+mdns_socket_close(int sock);
+
+#if 0
+static int
+mdns_discovery_send(int sock);
+
+
+static size_t
+mdns_discovery_recv(int sock, void* buffer, size_t capacity,
+ mdns_record_callback_fn callback, void* user_data);
+#endif
+
+static int
+mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length,
+ void* buffer, size_t capacity);
+
+static size_t
+mdns_query_recv(int sock, void* buffer, size_t capacity,
+ mdns_record_callback_fn callback, void* user_data,
+ uint8_t one_shot);
+
+static mdns_string_t
+mdns_string_extract(const void* buffer, size_t size, size_t* offset,
+ char* str, size_t capacity);
+
+static int
+mdns_string_skip(const void* buffer, size_t size, size_t* offset);
+
+#if 0
+static int
+mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs,
+ const void* buffer_rhs, size_t size_rhs, size_t* ofs_rhs);
+#endif
+
+static void*
+mdns_string_make(void* data, size_t capacity, const char* name, size_t length);
+
+static mdns_string_t
+mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity);
+
+static mdns_record_srv_t
+mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity);
+
+static struct sockaddr_in*
+mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in* addr);
+
+static struct sockaddr_in6*
+mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in6* addr);
+
+static size_t
+mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length,
+ mdns_record_txt_t* records, size_t capacity);
+
+// Implementations
+
+static int
+mdns_socket_open_ipv4(void) {
+ int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ return -1;
+ if (mdns_socket_setup_ipv4(sock)) {
+ mdns_socket_close(sock);
+ return -1;
+ }
+ return sock;
+}
+
+static int
+mdns_socket_setup_ipv4(int sock) {
+ struct sockaddr_in saddr;
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = INADDR_ANY;
+#ifdef __APPLE__
+ saddr.sin_len = sizeof(saddr);
+#endif
+
+ if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)))
+ return -1;
+
+#ifdef _WIN32
+ unsigned long param = 1;
+ ioctlsocket(sock, FIONBIO, &param);
+#else
+ const int flags = fcntl(sock, F_GETFL, 0);
+ fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+#endif
+
+ unsigned char ttl = 1;
+ unsigned char loopback = 1;
+ struct ip_mreq req;
+
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl));
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback));
+
+ memset(&req, 0, sizeof(req));
+ req.imr_multiaddr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
+ req.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&req, sizeof(req)))
+ return -1;
+
+ return 0;
+}
+
+#if 0
+static int
+mdns_socket_open_ipv6(void) {
+ int sock = (int)socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ return -1;
+ if (mdns_socket_setup_ipv6(sock)) {
+ mdns_socket_close(sock);
+ return -1;
+ }
+ return sock;
+}
+
+
+static int
+mdns_socket_setup_ipv6(int sock) {
+ struct sockaddr_in6 saddr;
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin6_family = AF_INET6;
+ saddr.sin6_addr = in6addr_any;
+#ifdef __APPLE__
+ saddr.sin6_len = sizeof(saddr);
+#endif
+
+ if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)))
+ return -1;
+
+#ifdef _WIN32
+ unsigned long param = 1;
+ ioctlsocket(sock, FIONBIO, &param);
+#else
+ const int flags = fcntl(sock, F_GETFL, 0);
+ fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+#endif
+
+ int hops = 1;
+ unsigned int loopback = 1;
+ struct ipv6_mreq req;
+
+ setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&hops, sizeof(hops));
+ setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback));
+
+ memset(&req, 0, sizeof(req));
+ req.ipv6mr_multiaddr.s6_addr[0] = 0xFF;
+ req.ipv6mr_multiaddr.s6_addr[1] = 0x02;
+ req.ipv6mr_multiaddr.s6_addr[15] = 0xFB;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&req, sizeof(req)))
+ return -1;
+
+ return 0;
+}
+#endif
+
+static void
+mdns_socket_close(int sock) {
+#ifdef _WIN32
+ closesocket(sock);
+#else
+ close(sock);
+#endif
+}
+
+static int
+mdns_is_string_ref(uint8_t val) {
+ return (0xC0 == (val & 0xC0));
+}
+
+static mdns_string_pair_t
+mdns_get_next_substring(const void* rawdata, size_t size, size_t offset) {
+ const uint8_t* buffer = rawdata;
+ mdns_string_pair_t pair = {MDNS_INVALID_POS, 0, 0};
+ if (!buffer[offset]) {
+ pair.offset = offset;
+ return pair;
+ }
+ if (mdns_is_string_ref(buffer[offset])) {
+ if (size < offset + 2)
+ return pair;
+
+ offset = (((size_t)(0x3f & buffer[offset]) << 8) | (size_t)buffer[offset + 1]);
+ if (offset >= size)
+ return pair;
+
+ pair.ref = 1;
+ }
+
+ size_t length = (size_t)buffer[offset++];
+ if (size < offset + length)
+ return pair;
+
+ pair.offset = offset;
+ pair.length = length;
+
+ return pair;
+}
+
+static int
+mdns_string_skip(const void* buffer, size_t size, size_t* offset) {
+ size_t cur = *offset;
+ mdns_string_pair_t substr;
+ do {
+ substr = mdns_get_next_substring(buffer, size, cur);
+ if (substr.offset == MDNS_INVALID_POS)
+ return 0;
+ if (substr.ref) {
+ *offset = cur + 2;
+ return 1;
+ }
+ cur = substr.offset + substr.length;
+ }
+ while (substr.length);
+
+ *offset = cur + 1;
+ return 1;
+}
+
+#if 0
+static int
+mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs,
+ const void* buffer_rhs, size_t size_rhs, size_t* ofs_rhs) {
+ size_t lhs_cur = *ofs_lhs;
+ size_t rhs_cur = *ofs_rhs;
+ size_t lhs_end = MDNS_INVALID_POS;
+ size_t rhs_end = MDNS_INVALID_POS;
+ mdns_string_pair_t lhs_substr;
+ mdns_string_pair_t rhs_substr;
+ do {
+ lhs_substr = mdns_get_next_substring(buffer_lhs, size_lhs, lhs_cur);
+ rhs_substr = mdns_get_next_substring(buffer_rhs, size_rhs, rhs_cur);
+ if ((lhs_substr.offset == MDNS_INVALID_POS) || (rhs_substr.offset == MDNS_INVALID_POS))
+ return 0;
+ if (lhs_substr.length != rhs_substr.length)
+ return 0;
+ if (strncasecmp((const char*)buffer_rhs + rhs_substr.offset,
+ (const char*)buffer_lhs + lhs_substr.offset, rhs_substr.length))
+ return 0;
+ if (lhs_substr.ref && (lhs_end == MDNS_INVALID_POS))
+ lhs_end = lhs_cur + 2;
+ if (rhs_substr.ref && (rhs_end == MDNS_INVALID_POS))
+ rhs_end = rhs_cur + 2;
+ lhs_cur = lhs_substr.offset + lhs_substr.length;
+ rhs_cur = rhs_substr.offset + rhs_substr.length;
+ }
+ while (lhs_substr.length);
+
+ if (lhs_end == MDNS_INVALID_POS)
+ lhs_end = lhs_cur + 1;
+ *ofs_lhs = lhs_end;
+
+ if (rhs_end == MDNS_INVALID_POS)
+ rhs_end = rhs_cur + 1;
+ *ofs_rhs = rhs_end;
+
+ return 1;
+}
+#endif
+
+static mdns_string_t
+mdns_string_extract(const void* buffer, size_t size, size_t* offset,
+ char* str, size_t capacity) {
+ size_t cur = *offset;
+ size_t end = MDNS_INVALID_POS;
+ mdns_string_pair_t substr;
+ mdns_string_t result = {str, 0};
+ char* dst = str;
+ size_t remain = capacity;
+ do {
+ substr = mdns_get_next_substring(buffer, size, cur);
+ if (substr.offset == MDNS_INVALID_POS)
+ return result;
+ if (substr.ref && (end == MDNS_INVALID_POS))
+ end = cur + 2;
+ if (substr.length) {
+ size_t to_copy = (substr.length < remain) ? substr.length : remain;
+ memcpy(dst, (const char*)buffer + substr.offset, to_copy);
+ dst += to_copy;
+ remain -= to_copy;
+ if (remain) {
+ *dst++ = '.';
+ --remain;
+ }
+ }
+ cur = substr.offset + substr.length;
+ }
+ while (substr.length);
+
+ if (end == MDNS_INVALID_POS)
+ end = cur + 1;
+ *offset = end;
+
+ result.length = capacity - remain;
+ return result;
+}
+
+static size_t
+mdns_string_find(const char* str, size_t length, char c, size_t offset) {
+ const void* found;
+ if (offset >= length)
+ return MDNS_INVALID_POS;
+ found = memchr(str + offset, c, length - offset);
+ if (found)
+ return (size_t)((const char*)found - str);
+ return MDNS_INVALID_POS;
+}
+
+static void*
+mdns_string_make(void* data, size_t capacity, const char* name, size_t length) {
+ size_t pos = 0;
+ size_t last_pos = 0;
+ size_t remain = capacity;
+ unsigned char* dest = data;
+ while ((last_pos < length) && ((pos = mdns_string_find(name, length, '.', last_pos)) != MDNS_INVALID_POS)) {
+ size_t sublength = pos - last_pos;
+ if (sublength < remain) {
+ *dest = (unsigned char)sublength;
+ memcpy(dest + 1, name + last_pos, sublength);
+ dest += sublength + 1;
+ remain -= sublength + 1;
+ }
+ else {
+ return 0;
+ }
+ last_pos = pos + 1;
+ }
+ if (last_pos < length) {
+ size_t sublength = length - last_pos;
+ if (sublength < capacity) {
+ *dest = (unsigned char)sublength;
+ memcpy(dest + 1, name + last_pos, sublength);
+ dest += sublength + 1;
+ remain -= sublength + 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ if (!remain)
+ return 0;
+ *dest++ = 0;
+ return dest;
+}
+
+static size_t
+mdns_records_parse(const struct sockaddr* from, const void* buffer, size_t size, size_t* offset,
+ mdns_entry_type_t type, size_t records, mdns_record_callback_fn callback,
+ void* user_data) {
+ size_t parsed = 0;
+ int do_callback = 1;
+ for (size_t i = 0; i < records; ++i) {
+ mdns_string_skip(buffer, size, offset);
+ const uint16_t* data = (const uint16_t*)((const char*)buffer + (*offset));
+
+ uint16_t rtype = ntohs(*data++);
+ uint16_t rclass = ntohs(*data++);
+ uint32_t ttl = ntohs(*(const uint32_t*)(const void*)data); data += 2;
+ uint16_t length = ntohs(*data++);
+
+ *offset += 10;
+
+ if (do_callback) {
+ ++parsed;
+ if (callback(from, type, rtype, rclass, ttl, buffer, size, *offset, length,
+ user_data))
+ do_callback = 0;
+ }
+
+ *offset += length;
+ }
+ return parsed;
+}
+
+static const uint8_t mdns_services_query[] = {
+ // Transaction ID
+ 0x00, 0x00,
+ // Flags
+ 0x00, 0x00,
+ // 1 question
+ 0x00, 0x01,
+ // No answer, authority or additional RRs
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ // _services._dns-sd._udp.local.
+ 0x09, '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's',
+ 0x07, '_', 'd', 'n', 's', '-', 's', 'd',
+ 0x04, '_', 'u', 'd', 'p',
+ 0x05, 'l', 'o', 'c', 'a', 'l',
+ 0x00,
+ // PTR record
+ 0x00, MDNS_RECORDTYPE_PTR,
+ // QU (unicast response) and class IN
+ 0x80, MDNS_CLASS_IN
+};
+
+#if 0
+static int
+mdns_discovery_send(int sock) {
+ struct sockaddr_storage addr_storage;
+ struct sockaddr_in addr;
+ struct sockaddr_in6 addr6;
+ struct sockaddr* saddr = (struct sockaddr*)&addr_storage;
+ socklen_t saddrlen = sizeof(struct sockaddr_storage);
+ if (getsockname(sock, saddr, &saddrlen))
+ return -1;
+ if (saddr->sa_family == AF_INET6) {
+ memset(&addr6, 0, sizeof(struct sockaddr_in6));
+ addr6.sin6_family = AF_INET6;
+#ifdef __APPLE__
+ addr6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ addr6.sin6_addr.s6_addr[0] = 0xFF;
+ addr6.sin6_addr.s6_addr[1] = 0x02;
+ addr6.sin6_addr.s6_addr[15] = 0xFB;
+ addr6.sin6_port = htons((unsigned short)5353);
+ saddr = (struct sockaddr*)&addr6;
+ saddrlen = sizeof(struct sockaddr_in6);
+ }
+ else {
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+#ifdef __APPLE__
+ addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+ addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
+ addr.sin_port = htons((unsigned short)5353);
+ saddr = (struct sockaddr*)&addr;
+ saddrlen = sizeof(struct sockaddr_in);
+ }
+
+ if (sendto(sock, mdns_services_query, sizeof(mdns_services_query), 0,
+ saddr, saddrlen) < 0)
+ return -1;
+ return 0;
+}
+
+static size_t
+mdns_discovery_recv(int sock, void* buffer, size_t capacity,
+ mdns_record_callback_fn callback, void* user_data) {
+ struct sockaddr_in6 addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ memset(&addr, 0, sizeof(addr));
+ saddr->sa_family = AF_INET;
+#ifdef __APPLE__
+ saddr->sa_len = sizeof(addr);
+#endif
+ socklen_t addrlen = sizeof(addr);
+ int ret = recvfrom(sock, buffer, capacity, 0,
+ saddr, &addrlen);
+ if (ret <= 0)
+ return 0;
+
+ size_t data_size = (size_t)ret;
+ size_t records = 0;
+ uint16_t* data = (uint16_t*)buffer;
+
+ uint16_t transaction_id = ntohs(*data++);
+ uint16_t flags = ntohs(*data++);
+ uint16_t questions = ntohs(*data++);
+ uint16_t answer_rrs = ntohs(*data++);
+ uint16_t authority_rrs = ntohs(*data++);
+ uint16_t additional_rrs = ntohs(*data++);
+
+ if (transaction_id || (flags != 0x8400))
+ return 0; //Not a reply to our question
+
+ if (questions > 1)
+ return 0;
+
+ int i;
+ for (i = 0; i < questions; ++i) {
+ size_t ofs = (size_t)((char*)data - (char*)buffer);
+ size_t verify_ofs = 12;
+ //Verify it's our question, _services._dns-sd._udp.local.
+ if (!mdns_string_equal(buffer, data_size, &ofs,
+ mdns_services_query, sizeof(mdns_services_query), &verify_ofs))
+ return 0;
+ data = (uint16_t*)((char*)buffer + ofs);
+
+ uint16_t type = ntohs(*data++);
+ uint16_t rclass = ntohs(*data++);
+
+ //Make sure we get a reply based on our PTR question for class IN
+ if ((type != MDNS_RECORDTYPE_PTR) || ((rclass & 0x7FFF) != MDNS_CLASS_IN))
+ return 0;
+ }
+
+ int do_callback = 1;
+ for (i = 0; i < answer_rrs; ++i) {
+ size_t ofs = (size_t)((char*)data - (char*)buffer);
+ size_t verify_ofs = 12;
+ //Verify it's an answer to our question, _services._dns-sd._udp.local.
+ int is_answer = mdns_string_equal(buffer, data_size, &ofs,
+ mdns_services_query, sizeof(mdns_services_query), &verify_ofs);
+ data = (uint16_t*)((char*)buffer + ofs);
+
+ uint16_t type = ntohs(*data++);
+ uint16_t rclass = ntohs(*data++);
+ uint32_t ttl = ntohl(*(uint32_t*)(void*)data); data += 2;
+ uint16_t length = ntohs(*data++);
+
+ if (is_answer && do_callback) {
+ ++records;
+ if (callback(saddr, MDNS_ENTRYTYPE_ANSWER, type, rclass, ttl, buffer,
+ data_size, (size_t)((char*)data - (char*)buffer), length,
+ user_data))
+ do_callback = 0;
+ }
+ data = (void*)((char*)data + length);
+ }
+
+ size_t offset = (size_t)((char*)data - (char*)buffer);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_AUTHORITY, authority_rrs,
+ callback, user_data);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ADDITIONAL, additional_rrs,
+ callback, user_data);
+
+ return records;
+}
+#endif
+
+static uint16_t mdns_transaction_id = 0;
+
+static int
+mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length,
+ void* buffer, size_t capacity) {
+ if (capacity < (17 + length))
+ return -1;
+
+ uint16_t* data = buffer;
+ //Transaction ID
+ *data++ = htons(++mdns_transaction_id);
+ //Flags
+ *data++ = 0;
+ //Questions
+ *data++ = htons(1);
+ //No answer, authority or additional RRs
+ *data++ = 0;
+ *data++ = 0;
+ *data++ = 0;
+ //Name string
+ data = mdns_string_make(data, capacity - 17, name, length);
+ if (!data)
+ return -1;
+ //Record type
+ *data++ = htons(type);
+ //! Unicast response, class IN
+ *data++ = htons(0x8000U | MDNS_CLASS_IN);
+
+ struct sockaddr_storage addr_storage;
+ struct sockaddr_in addr;
+ struct sockaddr_in6 addr6;
+ struct sockaddr* saddr = (struct sockaddr*)&addr_storage;
+ socklen_t saddrlen = sizeof(struct sockaddr_storage);
+ if (getsockname(sock, saddr, &saddrlen))
+ return -1;
+ if (saddr->sa_family == AF_INET6) {
+ memset(&addr6, 0, sizeof(struct sockaddr_in6));
+ addr6.sin6_family = AF_INET6;
+#ifdef __APPLE__
+ addr6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ addr6.sin6_addr.s6_addr[0] = 0xFF;
+ addr6.sin6_addr.s6_addr[1] = 0x02;
+ addr6.sin6_addr.s6_addr[15] = 0xFB;
+ addr6.sin6_port = htons((unsigned short)5353);
+ saddr = (struct sockaddr*)&addr6;
+ saddrlen = sizeof(struct sockaddr_in6);
+ }
+ else {
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+#ifdef __APPLE__
+ addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+ addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
+ addr.sin_port = htons((unsigned short)5353);
+ saddr = (struct sockaddr*)&addr;
+ saddrlen = sizeof(struct sockaddr_in);
+ }
+
+ if (sendto(sock, buffer, (char*)data - (char*)buffer, 0,
+ saddr, saddrlen) < 0)
+ return -1;
+ return 0;
+}
+
+static size_t
+mdns_query_recv(int sock, void* buffer, size_t capacity,
+ mdns_record_callback_fn callback, void* user_data,
+ uint8_t one_shot) {
+ struct sockaddr_in6 addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ memset(&addr, 0, sizeof(addr));
+ saddr->sa_family = AF_INET;
+#ifdef __APPLE__
+ saddr->sa_len = sizeof(addr);
+#endif
+ socklen_t addrlen = sizeof(addr);
+ int ret = recvfrom(sock, buffer, capacity, 0,
+ saddr, &addrlen);
+ if (ret <= 0)
+ return 0;
+
+ size_t data_size = (size_t)ret;
+ uint16_t* data = (uint16_t*)buffer;
+
+ uint16_t transaction_id = ntohs(*data++);
+ ++data;// uint16_t flags = ntohs(*data++);
+ uint16_t questions = ntohs(*data++);
+ uint16_t answer_rrs = ntohs(*data++);
+ uint16_t authority_rrs = ntohs(*data++);
+ uint16_t additional_rrs = ntohs(*data++);
+
+ if (one_shot && transaction_id != mdns_transaction_id)// || (flags != 0x8400))
+ return 0; //Not a reply to our last question
+
+ if (questions > 1)
+ return 0;
+
+ //Skip questions part
+ int i;
+ for (i = 0; i < questions; ++i) {
+ size_t ofs = (size_t)((char*)data - (char*)buffer);
+ if (!mdns_string_skip(buffer, data_size, &ofs))
+ return 0;
+ data = (void*)((char*)buffer + ofs);
+ ++data;
+ ++data;
+ }
+
+ size_t records = 0;
+ size_t offset = (size_t)((char*)data - (char*)buffer);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ANSWER, answer_rrs,
+ callback, user_data);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_AUTHORITY, authority_rrs,
+ callback, user_data);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ADDITIONAL, additional_rrs,
+ callback, user_data);
+ return records;
+}
+
+static mdns_string_t
+mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity) {
+ //PTR record is just a string
+ if ((size >= offset + length) && (length >= 2))
+ return mdns_string_extract(buffer, size, &offset, strbuffer, capacity);
+ mdns_string_t empty = {0, 0};
+ return empty;
+}
+
+static mdns_record_srv_t
+mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity) {
+ mdns_record_srv_t srv;
+ memset(&srv, 0, sizeof(mdns_record_srv_t));
+ // Read the priority, weight, port number and the discovery name
+ // SRV record format (http://www.ietf.org/rfc/rfc2782.txt):
+ // 2 bytes network-order unsigned priority
+ // 2 bytes network-order unsigned weight
+ // 2 bytes network-order unsigned port
+ // string: discovery (domain) name, minimum 2 bytes when compressed
+ if ((size >= offset + length) && (length >= 8)) {
+ const uint16_t* recorddata = (const uint16_t*)((const char*)buffer + offset);
+ srv.priority = ntohs(*recorddata++);
+ srv.weight = ntohs(*recorddata++);
+ srv.port = ntohs(*recorddata++);
+ offset += 6;
+ srv.name = mdns_string_extract(buffer, size, &offset, strbuffer, capacity);
+ }
+ return srv;
+}
+
+static struct sockaddr_in*
+mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in* addr) {
+ memset(addr, 0, sizeof(struct sockaddr_in));
+ addr->sin_family = AF_INET;
+#ifdef __APPLE__
+ addr->sin_len = sizeof(struct sockaddr_in);
+#endif
+ if ((size >= offset + length) && (length == 4))
+ addr->sin_addr.s_addr = *(const uint32_t*)((const char*)buffer + offset);
+ return addr;
+}
+
+static struct sockaddr_in6*
+mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in6* addr) {
+ memset(addr, 0, sizeof(struct sockaddr_in6));
+ addr->sin6_family = AF_INET6;
+#ifdef __APPLE__
+ addr->sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ if ((size >= offset + length) && (length == 16))
+ addr->sin6_addr = *(const struct in6_addr*)((const char*)buffer + offset);
+ return addr;
+}
+
+static size_t
+mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length,
+ mdns_record_txt_t* records, size_t capacity) {
+ size_t parsed = 0;
+ const char* strdata;
+ size_t separator, sublength;
+ size_t end = offset + length;
+
+ if (size < end)
+ end = size;
+
+ while ((offset < end) && (parsed < capacity)) {
+ strdata = (const char*)buffer + offset;
+ sublength = *(const unsigned char*)strdata;
+
+ ++strdata;
+ offset += sublength + 1;
+
+ separator = 0;
+ for (size_t c = 0; c < sublength; ++c) {
+ //DNS-SD TXT record keys MUST be printable US-ASCII, [0x20, 0x7E]
+ if ((strdata[c] < 0x20) || (strdata[c] > 0x7E))
+ break;
+ if (strdata[c] == '=') {
+ separator = c;
+ break;
+ }
+ }
+
+ if (!separator)
+ continue;
+
+ if (separator < sublength) {
+ records[parsed].key.str = strdata;
+ records[parsed].key.length = separator;
+ records[parsed].value.str = strdata + separator + 1;
+ records[parsed].value.length = sublength - (separator + 1);
+ }
+ else {
+ records[parsed].key.str = strdata;
+ records[parsed].key.length = sublength;
+ }
+
+ ++parsed;
+ }
+
+ return parsed;
+}
+
+#ifdef _WIN32
+#undef strncasecmp
+#endif
diff --git a/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt b/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt
index 1af3b4b2a..05276bc5a 100644
--- a/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt
+++ b/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt
@@ -12,6 +12,7 @@
# limitations under the License.
list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/dummy.h
)
list(APPEND SOURCE_FILES
diff --git a/ctrl/facemgr/src/interfaces/dummy/dummy.c b/ctrl/facemgr/src/interfaces/dummy/dummy.c
index b0c558388..6a21792a2 100644
--- a/ctrl/facemgr/src/interfaces/dummy/dummy.c
+++ b/ctrl/facemgr/src/interfaces/dummy/dummy.c
@@ -19,31 +19,101 @@
*/
#include <stdlib.h>
+#include <unistd.h> // close
+
+#include <hicn/facemgr.h>
-#include "../../interface.h"
#include "../../common.h"
-#include "../../event.h"
-#include "../../face.h"
-#include "../../facemgr.h"
+#include "../../facelet.h"
+#include "../../interface.h"
+
+#include "dummy.h"
#define DEFAULT_PORT 9695
-int dummy_initialize(interface_t * interface, face_rules_t * rules, void **pdata) {
- ip_address_t local = IPV4_LOOPBACK;
- ip_address_t remote = IPV4_LOOPBACK;
- face_t * face = face_create_udp(&local, DEFAULT_PORT, &remote, DEFAULT_PORT, AF_INET);
- event_raise(EVENT_TYPE_CREATE, face, interface);
- return FACEMGR_SUCCESS;
+#define UNUSED(x) ((void)x)
+
+/*
+ * Internal data
+ */
+typedef struct {
+ /* The configuration data will likely be allocated on the stack (or should
+ * be freed) by the caller, we recommend to make a copy of this data.
+ * This copy can further be altered with default values.
+ */
+ dummy_cfg_t cfg;
+
+ /* ... */
+
+ int fd; /* Sample internal data: file descriptor */
+} dummy_data_t;
+
+int dummy_initialize(interface_t * interface, void * cfg)
+{
+ dummy_data_t * data = malloc(sizeof(dummy_data_t));
+ if (!data)
+ goto ERR_MALLOC;
+ interface->data = data;
+
+ /* Use default values for unspecified configuration parameters */
+ if (cfg) {
+ data->cfg = *(dummy_cfg_t *)cfg;
+ } else {
+ memset(&data->cfg, 0, sizeof(data->cfg));
+ }
+
+ /* ... */
+
+ data->fd = 0;
+
+ /* ... */
+
+ /*
+ * We should return a negative value in case of error, and a positive value
+ * otherwise:
+ * - a file descriptor (>0) will be added to the event loop; or
+ * - 0 if we don't use any file descriptor
+ */
+ return data->fd;
+
+ERR_MALLOC:
+ return -1;
+}
+
+int dummy_finalize(interface_t * interface)
+{
+ dummy_data_t * data = (dummy_data_t*)interface->data;
+
+ if (data->fd > 0)
+ close(data->fd);
+
+ return 0;
}
-int dummy_finalize(interface_t * interface) {
- return FACEMGR_SUCCESS;
+int dummy_callback(interface_t * interface)
+{
+ dummy_data_t * data = (dummy_data_t*)interface->data;
+ UNUSED(data);
+
+ /* ... */
+
+ return 0;
+}
+
+int dummy_on_event(interface_t * interface, const facelet_t * facelet)
+{
+ dummy_data_t * data = (dummy_data_t*)interface->data;
+ UNUSED(data);
+
+ /* ... */
+
+ return 0;
}
interface_ops_t dummy_ops = {
.type = "dummy",
- .is_singleton = true,
.initialize = dummy_initialize,
.finalize = dummy_finalize,
- .on_event = NULL,
+ .callback = dummy_callback,
+ .on_event = dummy_on_event,
};
diff --git a/ctrl/facemgr/src/interface_ops_map.h b/ctrl/facemgr/src/interfaces/dummy/dummy.h
index 2d590390a..22fe5d1a6 100644
--- a/ctrl/facemgr/src/interface_ops_map.h
+++ b/ctrl/facemgr/src/interfaces/dummy/dummy.h
@@ -13,12 +13,22 @@
* limitations under the License.
*/
-#ifndef INTERFACE_OPS_MAP_H
-#define INTERFACE_OPS_MAP_H
+/**
+ * \file dummy.h
+ * \brief Dummy interface
+ *
+ * This class serves as a template to implement new face maanger interfaces, and
+ * can be used for test purposes.
+ */
-#include "interface.h"
-#include "util/map.h"
+#ifndef FACEMGR_INTERFACE_DUMMY_H
+#define FACEMGR_INTERFACE_DUMMY_H
-TYPEDEF_MAP_H(interface_ops_map, const char *, interface_ops_t *);
+/*
+ * Configuration data
+ */
+typedef struct {
+ /* ... */
+} dummy_cfg_t;
-#endif /* INTERFACE_OPS_MAP_H */
+#endif /* FACEMGR_INTERFACE_DUMMY_H */
diff --git a/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c b/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c
index 85694573d..1f20177c2 100644
--- a/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c
+++ b/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c
@@ -17,96 +17,265 @@
* \file interfaces/hicn_light/hicn_light.c
* \brief hICN light interface
*/
+#include <assert.h>
#include <stdbool.h>
-#include <stdlib.h> // arc4random [random, rand]
#include <stdio.h> // snprintf
#include <time.h> // time
#include <hicn/ctrl.h>
+#include <hicn/facemgr.h>
+#include <hicn/util/ip_address.h>
+#include <hicn/util/log.h>
-#include "../../facemgr.h"
+#include "../../facelet.h"
#include "../../interface.h"
-#include "../../util/ip_address.h"
-#include "../../util/log.h"
#include "../../util/map.h"
-#include "../../event.h"
#define DEFAULT_ROUTE_COST 0
+#define INTERVAL_MS 1000
+
+typedef enum {
+ HL_STATE_UNDEFINED,
+ HL_STATE_CONNECTING,
+ HL_STATE_FACES_SENT,
+ HL_STATE_DONE,
+} hl_state_t;
+
typedef struct {
- hc_sock_t * s;
- bool busy;
+ hc_sock_t * s; /* NULL means no active socket */
+ hl_state_t state;
+ int timer_fd; /* 0 means no active timer */
} hl_data_t;
-int hl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
+/* Forward declarations */
+int hl_timeout(interface_t * interface, int fd, void * unused);
+
+int hl_process_state(interface_t * interface)
{
- hl_data_t * data = malloc(sizeof(hl_data_t));
- if (!data) {
- ERROR("[hicn_light] Out of memory!");
- goto ERR_MALLOC;
+ hl_data_t * data = (hl_data_t *)interface->data;
+
+#if 0
+ char buf[MAXSZ_FACE];
+#endif
+
+ switch(data->state)
+ {
+ case HL_STATE_UNDEFINED: // FIXME
+ case HL_STATE_CONNECTING: // FIXME
+ if (hc_face_list_async(data->s) < 0) {
+ /* Blocking call */
+ printf("Could not retrieve face list\n");
+ return -1;
+ }
+ break;
+#if 0
+ foreach_face(f, faces) {
+#if 0
+ hc_face_snprintf(buf, MAXSZ_FACE, f);
+ printf("Face: %s\n", buf);
+#endif
+ facelet_t * facelet = facelet_create_from_face(&f->face);
+ facelet_set_event(facelet, FACELET_EVENT_GET);
+ interface_raise_event(interface, facelet);
+ }
+ break;
+#endif
+
+ case HL_STATE_FACES_SENT:
+ break;
+
+ default: /* HL_STATE_DONE never called */
+ break;
+ }
+
+ return 0;
+}
+
+
+int
+hl_after_connect(interface_t * interface)
+{
+ hl_data_t * data = interface->data;
+ // XXX cancel timer
+
+ /* File descriptor for control socket operations */
+ if (interface_register_fd(interface, hc_sock_get_fd(data->s), NULL) < 0) {
+ ERROR("[hc_connect] Error registering fd");
+ goto ERR_FD;
}
+ data->state = HL_STATE_UNDEFINED;
+
+ hl_process_state(interface);
+
+ return 0;
+
+ //interface_unregister_fd(interface, hc_sock_get_fd(data->s));
+ERR_FD:
+ return -1;
+}
+
+int _hl_connect(interface_t * interface);
+
+int
+hl_connect_timeout(interface_t * interface, int fd, void * unused)
+{
+ int rc = _hl_connect(interface);
+ if (rc < 0) {
+ ERROR("[hl_initialize] Error during connection reattempt; next attempt in %ds", INTERVAL_MS / 1000);
+ return -1;
+ }
+
+ if (interface_unregister_timer(interface, fd) < 0) {
+ ERROR("[hl_connect_timeout] Could not cancel timer after successful connect");
+ }
+
+ /* Connect success */
+ return hl_after_connect(interface);
+}
+
+
+int
+_hl_connect(interface_t * interface)
+{
+ hl_data_t * data = interface->data;
+ assert(!data->s);
+
data->s = hc_sock_create();
if (data->s <= 0) {
- ERROR("[hicn_light] Could not create control socket");
+ ERROR("[hc_connect] Could not create control socket");
goto ERR_SOCK;
}
if (hc_sock_connect(data->s) < 0) {
- ERROR("[hicn_light] Could not connect control socket");
+ ERROR("[hc_connect] Could not connect control socket");
goto ERR_CONNECT;
}
- data->busy = false;
-
- *pdata = data;
-
- return FACEMGR_SUCCESS;
+ return hl_after_connect(interface);
ERR_CONNECT:
hc_sock_free(data->s);
+ data->s = NULL;
ERR_SOCK:
+ return -1;
+
+}
+
+int hl_disconnect(interface_t * interface)
+{
+ hl_data_t * data = (hl_data_t *) interface->data;
+ if (data->timer_fd > 0)
+ interface_unregister_timer(interface, data->timer_fd);
+
+ if (data->s) {
+ interface_unregister_fd(interface, hc_sock_get_fd(data->s));
+ hc_sock_free(data->s);
+ }
+
+ return 0;
+}
+
+int
+hl_connect(interface_t * interface)
+{
+ hl_data_t * data = interface->data;
+
+ if (_hl_connect(interface) >= 0)
+ return 0;
+
+ /* Timer for managing the connection to the forwarder */
+ DEBUG("Connection to forwarder failed... next retry in %ds", INTERVAL_MS / 1000);
+ data->timer_fd = interface_register_timer(interface, INTERVAL_MS, hl_connect_timeout, NULL);
+ if (data->timer_fd < 0) {
+ ERROR("[hc_connect] Could not initialize reattempt timer");
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+hl_initialize(interface_t * interface, void * cfg)
+{
+ hl_data_t * data = malloc(sizeof(hl_data_t));
+ if (!data) {
+ ERROR("[hicn_light] Out of memory!");
+ goto ERR_MALLOC;
+ }
+
+ data->s = NULL;
+ data->timer_fd = 0;
+
+ interface->data = data;
+
+ if (hl_connect(interface) < 0) {
+ ERROR("[hl_initialize] Error during connection to forwarder");
+ goto ERR_CONNECT;
+ }
+
+ return 0;
+
+ERR_CONNECT:
free(data);
ERR_MALLOC:
- return FACEMGR_FAILURE;
+ return -1;
}
int hl_finalize(interface_t * interface)
{
- //hc_data_t * data = interface->data;
- //hc_sock_close(data->s);
- return FACEMGR_SUCCESS;
+ hl_data_t * data = (hl_data_t *) interface->data;
+
+ hl_disconnect(interface);
+
+ free(data);
+
+ return 0;
}
-int hl_on_event(interface_t * interface, const event_t * event)
+int hl_on_event(interface_t * interface, const facelet_t * facelet)
{
- hc_face_t face;
+ hc_face_t hc_face;
hc_route_t route;
int rc;
hl_data_t * data = (hl_data_t *)interface->data;
- /* XXX We need a queue or a socket pool to process concurrent events */
- if (data->busy) {
- ERROR("[hicn_light] Busy !");
- return FACEMGR_FAILURE;
+ face_t * face = NULL;
+
+ /* NOTE
+ * - One example where this fails (and it is normal) is when we delete a
+ * face that was not completely created, because for instance bonjour did
+ * not give any data
+ */
+ if (facelet_get_face(facelet, &face) < 0) {
+ ERROR("Could not retrieve face from facelet");
+ return -1;
}
- switch(event->type) {
- case EVENT_TYPE_CREATE:
+ if (!data->s) {
+ /* We are not connected to the forwarder */
+ return -1;
+
+ }
+
+ switch(facelet_get_event(facelet)) {
+
+ case FACELET_EVENT_CREATE:
/* Create face */
- face.face = *event->face;
- rc = hc_face_create(data->s, &face);
+ hc_face.face = *face;
+ rc = hc_face_create(data->s, &hc_face);
if (rc < 0) {
ERROR("Failed to create face\n");
goto ERR;
}
- DEBUG("Created face id=%d\n", face.id);
+ INFO("Created face id=%d\n", hc_face.id);
-#if 0
- /* Add default route v4 */
+ /* Adding default routs e*/
+#if 1
route = (hc_route_t) {
- .face_id = face.id,
+ .face_id = hc_face.id,
.family = AF_INET,
.remote_addr = IPV4_ANY,
.len = 0,
@@ -117,12 +286,9 @@ int hl_on_event(interface_t * interface, const event_t * event)
ERROR("Failed to create default hICN/IPv4 route");
goto ERR;
}
- INFO("Successfully created default hICN/IPv4 route.");
-#endif
-#if 0
route = (hc_route_t) {
- .face_id = face.id,
+ .face_id = hc_face.id,
.family = AF_INET6,
.remote_addr = IPV6_ANY,
.len = 0,
@@ -132,91 +298,130 @@ int hl_on_event(interface_t * interface, const event_t * event)
ERROR("Failed to create default hICN/IPv6 route");
goto ERR;
}
+
+#else
+ route = (hc_route_t) {
+ .face_id = hc_face.id,
+ .family = AF_INET6,
+ .len = 0,
+ .cost = DEFAULT_ROUTE_COST,
+ };
+ if (ip_address_pton("::", &route.remote_addr) < 0) {
+ ERROR("Failed to convert prefix");
+ goto ERR;
+ }
+ if (hc_route_create(data->s, &route) < 0) {
+ ERROR("Failed to create hICN/IPv6 route");
+ goto ERR;
+ }
#endif
+ INFO("Successfully created default route(s).");
-#if 1
- /* We add routes based on face tags */
-
- if (policy_tags_has(event->face->tags, POLICY_TAG_TRUSTED)) {
- route = (hc_route_t) {
- .face_id = face.id,
- .family = AF_INET6,
- .len = 16,
- .cost = DEFAULT_ROUTE_COST,
- };
- if (ip_address_pton("b001::", &route.remote_addr) < 0) {
- ERROR("Failed to convert prefix");
- goto ERR;
- }
- if (hc_route_create(data->s, &route) < 0) {
- ERROR("Failed to create hICN/IPv6 route");
- goto ERR;
- }
+ break;
+
+ case FACELET_EVENT_DELETE:
+ /* Removing a face should also remove associated routes */
+ /* Create face */
+ hc_face.face = *face;
+ rc = hc_face_delete(data->s, &hc_face);
+ if (rc < 0) {
+ ERROR("Failed to delete face\n");
+ goto ERR;
+ }
+ break;
+
+ case FACELET_EVENT_UPDATE:
+ /* Currently, only admin_state is supported */
+ if (facelet_get_admin_state_status(facelet) == FACELET_ATTR_STATUS_DIRTY) {
+ hc_face.face = *face;
+ hc_face_t * face_found;
- route = (hc_route_t) {
- .face_id = face.id,
- .family = AF_INET6,
- .len = 16,
- .cost = DEFAULT_ROUTE_COST,
- };
- if (ip_address_pton("d001::", &route.remote_addr) < 0) {
- ERROR("Failed to convert prefix");
+ printf("hc_face_get\n");
+ rc = hc_face_get(data->s, &hc_face, &face_found);
+ if (rc < 0) {
+ ERROR("Failed to find face\n");
goto ERR;
}
- if (hc_route_create(data->s, &route) < 0) {
- ERROR("Failed to create hICN/IPv6 route");
+ if (!face_found) {
+ ERROR("Face to update has not been found");
goto ERR;
}
+ char conn_id_or_name[SYMBOLIC_NAME_LEN];
+ snprintf(conn_id_or_name, SYMBOLIC_NAME_LEN, "%d", face_found->id);
+ free(face_found);
- } else {
-
- route = (hc_route_t) {
- .face_id = face.id,
- .family = AF_INET6,
- .len = 16,
- .cost = DEFAULT_ROUTE_COST,
- };
- if (ip_address_pton("c001::", &route.remote_addr) < 0) {
- ERROR("Failed to convert prefix");
+ face_state_t admin_state;
+ if (facelet_get_admin_state(facelet, &admin_state) < 0) {
+ ERROR("Failed to retrieve facelet admin state");
goto ERR;
}
- if (hc_route_create(data->s, &route) < 0) {
- ERROR("Failed to create hICN/IPv6 route");
+
+ printf("Setting admin state");
+ printf("hc_connection_set_admin_state\n");
+ if (hc_connection_set_admin_state(data->s, conn_id_or_name, admin_state) < 0) {
+ ERROR("Failed to update admin state");
goto ERR;
}
+ INFO("Admin state updated");
}
-#endif
-
- break;
-
- case EVENT_TYPE_DELETE:
- /* Removing a face should also remove associated routes */
- /* Create face */
- face.face = *event->face;
- rc = hc_face_delete(data->s, &face);
- if (rc < 0) {
- ERROR("Failed to delete face\n");
- goto ERR;
- }
- INFO("Deleted face id=%d\n", face.id);
break;
default:
- ERROR("Unknown event %s\n", event_type_str[event->type]);
+ ERROR("Unknown event %s\n", facelet_event_str[facelet_get_event(facelet)]);
/* Unsupported events */
goto ERR;
}
- return FACEMGR_SUCCESS;
+ face_free(face);
+ return 0;
ERR:
- return FACEMGR_FAILURE;
+ face_free(face);
+ return -1;
+}
+
+int hl_callback(interface_t * interface, int fd, void * unused)
+{
+ hl_data_t * data = (hl_data_t*)interface->data;
+
+ hc_data_t * faces;
+ if (hc_sock_callback(data->s, &faces) < 0){
+ DEBUG("Closing socket... reconnecting...");
+ if (interface_unregister_fd(interface, hc_sock_get_fd(data->s)) < 0) {
+ ERROR("[hl_initialize] Error registering fd");
+ }
+ hc_sock_free(data->s);
+ data->s = NULL;
+ hl_connect(interface);
+ return 0;
+ }
+
+ if (faces->complete) {
+ foreach_face(f, faces) {
+#if 1
+ char buf[MAXSZ_FACE];
+ hc_face_snprintf(buf, MAXSZ_FACE, f);
+ printf("Face: %s\n", buf);
+#else
+ facelet_t * facelet = facelet_create_from_face(&f->face);
+ facelet_set_event(facelet, FACELET_EVENT_GET);
+ interface_raise_event(interface, facelet);
+#endif
+ }
+ }
+ hc_data_free(faces);
+
+ /* XXX how do we know what object we get back */
+
+ /* We have a queue of pending data elements per active query */
+
+ return 0;
}
const interface_ops_t hicn_light_ops = {
.type = "hicn_light",
- .is_singleton = false,
.initialize = hl_initialize,
.finalize = hl_finalize,
.on_event = hl_on_event,
+ .callback = hl_callback,
};
diff --git a/ctrl/facemgr/src/interfaces/netlink/netlink.c b/ctrl/facemgr/src/interfaces/netlink/netlink.c
index 5bf0baf9f..babf1c305 100644
--- a/ctrl/facemgr/src/interfaces/netlink/netlink.c
+++ b/ctrl/facemgr/src/interfaces/netlink/netlink.c
@@ -18,34 +18,123 @@
* \brief Netlink interface
*/
+#include <assert.h>
#include <linux/rtnetlink.h>
+#include <net/if_arp.h> // ARPHRD_LOOPBACK
#include <sys/types.h> // getpid
#include <unistd.h> // getpid
-#include "../../event.h"
-#include "../../facemgr.h"
+#include <hicn/facemgr.h>
+#include <hicn/util/ip_address.h>
+#include <hicn/util/log.h>
+
+#include "../../common.h"
+#include "../../facelet.h"
#include "../../interface.h"
+typedef enum {
+ NL_STATE_UNDEFINED,
+ NL_STATE_LINK_SENT,
+ NL_STATE_ADDR_SENT,
+ NL_STATE_DONE,
+} nl_state_t;
+
/* Internal data storage */
typedef struct {
int fd;
+ nl_state_t state;
} nl_data_t;
-// little helper to parsing message using netlink macroses
-void parseRtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+static inline void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len,
+ unsigned short flags)
{
+ unsigned short type;
+
memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
+ while (RTA_OK(rta, len)) {
+ type = rta->rta_type & ~flags;
+ if (type <= max)
+ tb[type] = rta;
+ rta = RTA_NEXT(rta, len);
+ }
+}
- while (RTA_OK(rta, len)) { // while not end of the message
- if (rta->rta_type <= max) {
- tb[rta->rta_type] = rta; // read attr
+int nl_process_state(interface_t * interface)
+{
+ nl_data_t * data = (nl_data_t*)interface->data;
+ int rc;
+
+ switch(data->state) {
+ case NL_STATE_UNDEFINED:
+ {
+ DEBUG("[nl_process_state] UNDEFINED->LINK_SENT");
+ struct {
+ struct nlmsghdr header;
+ struct rtgenmsg payload;
+ } msg2 = {
+ .header = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ .nlmsg_type = RTM_GETLINK,
+ .nlmsg_pid = getpid(),
+ .nlmsg_seq = 3,
+ },
+ .payload = {
+ .rtgen_family = AF_PACKET,
+ }
+ };
+
+ rc = send(data->fd, &msg2, msg2.header.nlmsg_len, 0);
+ if (rc < 0)
+ printf("E: Error sending netlink query\n");
+
+ data->state = NL_STATE_LINK_SENT;
+ break;
}
- rta = RTA_NEXT(rta,len); // get next attr
+
+ case NL_STATE_LINK_SENT:
+ {
+ DEBUG("[nl_process_state] LINK_SENT->ADDR_SENT");
+ /* Issue a first query to receive static state */
+ struct {
+ struct nlmsghdr header;
+ struct ifaddrmsg payload;
+ } msg = {
+ .header = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ .nlmsg_type = RTM_GETADDR,
+ .nlmsg_pid = getpid(),
+ .nlmsg_seq = 7,
+ },
+ .payload = {
+ .ifa_family = AF_INET,
+ }
+ };
+
+ rc = send(data->fd, &msg, msg.header.nlmsg_len, 0);
+ if (rc < 0)
+ printf("E: Error sending netlink query\n");
+
+ data->state = NL_STATE_ADDR_SENT;
+ break;
+ }
+
+ case NL_STATE_ADDR_SENT:
+ {
+ DEBUG("[nl_process_state] ADDR_SENT->DONE");
+ data->state = NL_STATE_DONE;
+ break;
+ }
+
+ default: /* NL_STATE_DONE never called */
+ break;
}
-}
+ return 0;
+}
-int nl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
+int nl_initialize(interface_t * interface, void * cfg)
{
nl_data_t * data = malloc(sizeof(nl_data_t));
if (!data)
@@ -57,34 +146,207 @@ int nl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
goto ERR_SOCKET;
}
+ data->state = NL_STATE_UNDEFINED;
+
struct sockaddr_nl local; // local addr struct
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK; // set protocol family
- local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; // set groups we interested in
+ // NOTE: RTNLGRP_LINK replaces obsolete RTMGRP_LINK, etc
+ local.nl_groups = 0
+ | RTMGRP_LINK
+ | RTMGRP_IPV4_IFADDR
+ | RTMGRP_IPV6_IFADDR
+#if 0
+ | RTMGRP_IPV4_ROUTE;
+ | RTMGRP_IPV6_ROUTE;
+#endif
+ ;
local.nl_pid = getpid(); // set out id using current process id
-
if (bind(data->fd, (struct sockaddr*)&local, sizeof(local)) < 0) { // bind socket
printf("Failed to bind netlink socket: %s\n", (char*)strerror(errno));
goto ERR_BIND;
}
- /* Issue a first query to receive static state */
+ interface->data = data;
+
+ interface_register_fd(interface, data->fd, NULL);
+#if 1
+ nl_process_state(interface);
+#endif
- *pdata = data;
- return data->fd; // FACEMGR_SUCCESS;
+ return 0;
ERR_BIND:
close(data->fd);
ERR_SOCKET:
free(data);
ERR_MALLOC:
- *pdata = NULL;
- return FACEMGR_FAILURE;
+ return -1;
+}
+
+int parse_link(struct nlmsghdr * h, facelet_t ** facelet,
+ char * interface_name, size_t interface_name_size,
+ bool * up, bool * running)
+{
+ struct ifinfomsg *ifi; // structure for network interface info
+ struct rtattr *tb[IFLA_MAX + 1];
+
+ assert(facelet);
+
+ ifi = (struct ifinfomsg*) NLMSG_DATA(h); // get information about changed network interface
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(h), 1<<15);
+
+ if (interface_name) {
+ assert(tb[IFLA_IFNAME]);
+ snprintf(interface_name, interface_name_size, "%s", (char*)RTA_DATA(tb[IFLA_IFNAME]));
+ }
+
+ if (up)
+ *up = ifi->ifi_flags & IFF_UP;
+ if (running)
+ *running = ifi->ifi_flags & IFF_RUNNING;
+
+
+ *facelet = facelet_create();
+ netdevice_t * netdevice = netdevice_create_from_name(interface_name);
+ if (!netdevice)
+ goto ERROR_ND;
+ int rc = facelet_set_netdevice(*facelet, *netdevice);
+ if (rc < 0)
+ goto ERROR;
+
+// FIXME Tags
+#if 0
+ /* This is the only opportunity to identify a loopback interface on both
+ * linux _and_ android, as NetworkCapabilities does not have a flag for
+ * LOOPBACK... */
+ if (ifi->ifi_type==ARPHRD_LOOPBACK) {
+ DEBUG("loopback");
+ }
+
+#ifdef IFLA_WIRELESS
+ /*
+ * This signals a wirless event, but it typically occurs _after_ a face is
+ * created... we might need to update an existing face by setting a tag...
+ * or find a way to exploit this flag before actually creating the face...
+ */
+ if (tb[IFLA_WIRELESS])
+ DEBUG("wireless!!!");
+#else
+#warning "IFLA_WIRELESS not supported on this platform"
+#endif /* IFLA_WIRELESS */
+
+#endif
+
+ // TODO
+ // - ifi_change
+ // - IFLA_PROTINFO
+
+ netdevice_free(netdevice);
+ return 0;
+
+ERROR:
+ netdevice_free(netdevice);
+ERROR_ND:
+ facelet_free(*facelet);
+ *facelet = NULL;
+
+ return -1;
}
-int nl_callback(interface_t * interface)
+int parse_addr(struct nlmsghdr * h, facelet_t ** facelet,
+ char * interface_name, size_t interface_name_size,
+ char * interface_address, size_t interface_address_size)
+{
+ ip_address_t local_addr = IP_ADDRESS_EMPTY;
+ struct ifaddrmsg *ifa; // structure for network interface data
+ struct rtattr *tba[IFA_MAX+1];
+
+ assert(facelet);
+
+ ifa = (struct ifaddrmsg*)NLMSG_DATA(h); // get data from the network interface
+
+ parse_rtattr(tba, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h), 0);
+
+ /* FIXME
+ *
+ * IFA_LOCAL ok for v4, not there for v6
+ *
+ * IFA_ADDRESS seems to work for both but with the following precaution
+ *
+ * IFA_ADDRESS is prefix address, rather than local interface address.
+ * It makes no difference for normally configured broadcast interfaces,
+ * but for point-to-point IFA_ADDRESS is DESTINATION address,
+ * local address is supplied in IFA_LOCAL attribute.
+ */
+ if (!tba[IFA_ADDRESS]) {
+ ERROR("[netlink.parse_addr] No local address");
+ return -1;
+ }
+
+ switch(ifa->ifa_family) {
+ case AF_INET:
+ local_addr.v4.as_inaddr = *(struct in_addr*)RTA_DATA(tba[IFA_ADDRESS]);
+ break;
+ case AF_INET6:
+ local_addr.v6.as_in6addr = *(struct in6_addr*)RTA_DATA(tba[IFA_ADDRESS]);
+ break;
+ default:
+ return 0;
+ }
+
+#if 0 /* Not working for v6 */
+ if (interface_name) {
+ assert(tba[IFLA_IFNAME]);
+ snprintf(interface_name, interface_name_size, "%s", (char*)RTA_DATA(tba[IFLA_IFNAME]));
+ }
+#endif
+
+ /* See comment in parse_link */
+ if (interface_address) {
+ assert(tba[IFA_ADDRESS]);
+ ip_address_snprintf(interface_address, interface_address_size, &local_addr, ifa->ifa_family);
+ }
+
+ netdevice_t * netdevice = netdevice_create_from_index(ifa->ifa_index);
+ if (!netdevice) {
+ ERROR("[netlink.parse_addr] error creating netdevice '%s'", interface_name);
+ goto ERROR_ND;
+ }
+
+ if (interface_name) {
+ snprintf(interface_name, interface_name_size, "%s", netdevice->name);
+ }
+
+ *facelet = facelet_create();
+ if (facelet_set_netdevice(*facelet, *netdevice) < 0) {
+ ERROR("[netlink.parse_addr] error setting netdevice");
+ goto ERROR;
+ }
+ if (facelet_set_family(*facelet, ifa->ifa_family) < 0) {
+ ERROR("[netlink.parse_addr] error setting family");
+ goto ERROR;
+ }
+ if (facelet_set_local_addr(*facelet, local_addr) < 0) {
+ ERROR("[netlink.parse_addr] error setting local address");
+ goto ERROR;
+ }
+
+ netdevice_free(netdevice);
+ return 0;
+
+ERROR:
+ netdevice_free(netdevice);
+ERROR_ND:
+ facelet_free(*facelet);
+ *facelet = NULL;
+
+ return -1;
+}
+
+int nl_callback(interface_t * interface, int fd, void * unused)
{
nl_data_t * data = (nl_data_t*)interface->data;
@@ -97,13 +359,12 @@ int nl_callback(interface_t * interface)
iov.iov_len = sizeof(buf); // set size
// initialize protocol message header
- struct msghdr msg;
- {
- msg.msg_name = &local; // local address
- msg.msg_namelen = sizeof(local); // address size
- msg.msg_iov = &iov; // io vector
- msg.msg_iovlen = 1; // io size
- }
+ struct msghdr msg = {
+ .msg_name = &local, // local address
+ .msg_namelen = sizeof(local), // address size
+ .msg_iov = &iov, // io vector
+ .msg_iovlen = 1, // io size
+ };
ssize_t status = recvmsg(data->fd, &msg, 0);
@@ -115,12 +376,12 @@ int nl_callback(interface_t * interface)
*/
printf("Failed to read netlink: %s", (char*)strerror(errno));
- return FACEMGR_FAILURE;
+ return -1;
}
if (msg.msg_namelen != sizeof(local)) { // check message length, just in case
printf("Invalid length of the sender address struct\n");
- return FACEMGR_FAILURE;
+ return -1;
}
// message parser
@@ -129,103 +390,131 @@ int nl_callback(interface_t * interface)
for (h = (struct nlmsghdr*)buf; status >= (ssize_t)sizeof(*h); ) { // read all messagess headers
int len = h->nlmsg_len;
int l = len - sizeof(*h);
- char *ifName = NULL;
if ((l < 0) || (len > status)) {
printf("Invalid message length: %i\n", len);
continue;
}
- // now we can check message type
- if ((h->nlmsg_type == RTM_NEWROUTE) || (h->nlmsg_type == RTM_DELROUTE)) { // some changes in routing table
- printf("Routing table was changed\n");
- } else { // in other case we need to go deeper
- char *ifUpp;
- char *ifRunn;
- struct ifinfomsg *ifi; // structure for network interface info
- struct rtattr *tb[IFLA_MAX + 1];
+ switch(h->nlmsg_type) {
+#if 0
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ DEBUG("Routing table was changed");
+ break;
+#endif
+
+ case RTM_DELADDR:
+ {
+ facelet_t * facelet = NULL;
+ char interface_name[IFNAMSIZ];
+ char interface_address[MAXSZ_IP_ADDRESS] = {0};
+
+ if (parse_addr(h, &facelet, interface_name, IFNAMSIZ,
+ interface_address, MAXSZ_IP_ADDRESS) < 0) {
+ ERROR("Error parsing address message");
+ break;
+ }
- ifi = (struct ifinfomsg*) NLMSG_DATA(h); // get information about changed network interface
+ //DEBUG("Interface %s: address was removed", interface_name);
+ if (facelet) {
+ facelet_set_event(facelet, FACELET_EVENT_DELETE);
+ interface_raise_event(interface, facelet);
+ }
+ break;
+ }
- parseRtattr(tb, IFLA_MAX, IFLA_RTA(ifi), h->nlmsg_len); // get attributes
+ case RTM_NEWADDR:
+ {
+ facelet_t * facelet = NULL;
+ char interface_name[IFNAMSIZ];
+ char interface_address[MAXSZ_IP_ADDRESS] = {0};
- if (tb[IFLA_IFNAME]) { // validation
- ifName = (char*)RTA_DATA(tb[IFLA_IFNAME]); // get network interface name
- }
+ if (parse_addr(h, &facelet, interface_name, IFNAMSIZ,
+ interface_address, MAXSZ_IP_ADDRESS) < 0) {
+ ERROR("Error parsing address message");
+ break;
+ }
- if (ifi->ifi_flags & IFF_UP) { // get UP flag of the network interface
- ifUpp = (char*)"UP";
- } else {
- ifUpp = (char*)"DOWN";
- }
+ //DEBUG("Interface %s: new address was assigned: %s", interface_name, interface_address);
- if (ifi->ifi_flags & IFF_RUNNING) { // get RUNNING flag of the network interface
- ifRunn = (char*)"RUNNING";
- } else {
- ifRunn = (char*)"NOT RUNNING";
+ if (facelet) {
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ interface_raise_event(interface, facelet);
+ }
+ break;
}
- char ifAddress[256] = {0}; // network addr
- struct ifaddrmsg *ifa; // structure for network interface data
- struct rtattr *tba[IFA_MAX+1];
+ case RTM_DELLINK:
+ {
+ facelet_t * facelet = NULL;
+ char interface_name[IFNAMSIZ];
+ if (parse_link(h, &facelet, interface_name, IFNAMSIZ,
+ NULL, NULL) < 0) {
+ ERROR("Error parsing link message");
+ break;
+ }
+
+ //DEBUG("Network interface %s was removed", interface_name);
- ifa = (struct ifaddrmsg*)NLMSG_DATA(h); // get data from the network interface
+ if (!facelet)
+ break;
- parseRtattr(tba, IFA_MAX, IFA_RTA(ifa), h->nlmsg_len);
+ facelet_set_event(facelet, FACELET_EVENT_DELETE);
+ interface_raise_event(interface, facelet);
- if (tba[IFA_LOCAL]) {
- inet_ntop(AF_INET, RTA_DATA(tba[IFA_LOCAL]), ifAddress, sizeof(ifAddress)); // get IP addr
+ break;
}
- face_t * face;
+ case RTM_NEWLINK:
+ {
+ facelet_t * facelet = NULL;
+ char interface_name[IFNAMSIZ];
+ bool up, running;
- if (tba[IFA_LOCAL]) {
- ip_address_t local_addr = IP_ADDRESS_EMPTY;
- switch(ifa->ifa_family) {
- case AF_INET:
- local_addr.v4.as_inaddr = *(struct in_addr*)RTA_DATA(tba[IFA_LOCAL]);
- break;
- case AF_INET6:
- local_addr.v6.as_in6addr = *(struct in6_addr*)RTA_DATA(tba[IFA_LOCAL]);
- break;
- default:
- continue;
+ if (parse_link(h, &facelet, interface_name, IFNAMSIZ, &up, &running) < 0) {
+ ERROR("Error parsing link message");
+ break;
}
- face = face_create_udp(&local_addr, 0, &IP_ADDRESS_EMPTY, 0, ifa->ifa_family);
- } else {
- face = NULL;
- }
- switch (h->nlmsg_type) {
- case RTM_DELADDR:
- // DOES NOT SEEM TO BE TRIGGERED
- printf("Interface %s: address was removed\n", ifName);
- if (face)
- event_raise(EVENT_TYPE_DELETE, face, interface);
- break;
+ // UP RUNNING
+ // UP NOT RUNNING
+ // DOWN NOT RUNNING
+#if 0
+ DEBUG("New network interface %s, state: %s %s", interface_name,
+ up ? "UP" : "DOWN",
+ running ? "RUNNING" : "NOT_RUNNING");
+#endif
- case RTM_DELLINK:
- printf("Network interface %s was removed\n", ifName);
+ if (!facelet)
break;
-
- case RTM_NEWLINK:
- printf("New network interface %s, state: %s %s\n", ifName, ifUpp, ifRunn);
- // UP RUNNING
- // UP NOT RUNNING
- // DOWN NOT RUNNING
- if (!(ifi->ifi_flags & IFF_UP) || (!(ifi->ifi_flags & IFF_RUNNING))) {
- if(face)
- event_raise(EVENT_TYPE_DELETE, face, interface);
+ if (up && running) {
+ facelet_set_event(facelet, FACELET_EVENT_CREATE);
+ facelet_t * facelet6 = facelet_dup(facelet);
+ if (!facelet6) {
+ ERROR("Could not duplicate face for v6");
+ break;
}
- break;
- case RTM_NEWADDR:
- printf("Interface %s: new address was assigned: %s\n", ifName, ifAddress);
- printf("NEW FACE\n");
- if (face)
- event_raise(EVENT_TYPE_CREATE, face, interface);
- break;
+ facelet_set_family(facelet, AF_INET);
+ interface_raise_event(interface, facelet);
+
+ facelet_set_family(facelet6, AF_INET6);
+ interface_raise_event(interface, facelet6);
+ } else {
+ facelet_free(facelet);
+ }
+ break;
}
+
+ case NLMSG_ERROR:
+ break;
+ case NLMSG_DONE:
+ nl_process_state(interface);
+ break;
+ default:
+ break;
+
}
status -= NLMSG_ALIGN(len); // align offsets by the message length, this is important
@@ -233,20 +522,20 @@ int nl_callback(interface_t * interface)
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); // get next message
}
- return FACEMGR_SUCCESS;
+ return 0;
}
int nl_finalize(interface_t * interface)
{
nl_data_t * data = (nl_data_t*)interface->data;
close(data->fd);
- return FACEMGR_SUCCESS;
+ free(interface->data);
+ return 0;
}
const interface_ops_t netlink_ops = {
.type = "netlink",
- .is_singleton = true,
.initialize = nl_initialize,
.callback = nl_callback,
.finalize = nl_finalize,
diff --git a/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt b/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt
index ca6659342..e8b0144b1 100644
--- a/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt
+++ b/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt
@@ -17,6 +17,7 @@ if (NOT NETWORK_LIBRARY)
endif()
list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/network_framework.h
)
list(APPEND SOURCE_FILES
diff --git a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c
index 8a33129b4..f438d34d5 100644
--- a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c
+++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c
@@ -18,20 +18,30 @@
* \brief Implementation of Network framework interface
*/
+#include "Availability.h"
+
#include <sys/socket.h>
#include <arpa/inet.h>
#include <Network/Network.h>
#include <err.h>
+#include <hicn/facemgr.h>
+#include <hicn/util/token.h>
+#include <hicn/util/log.h>
+
#include "../../common.h"
-#include "../../event.h"
-#include "../../face.h"
-#include "../../facemgr.h"
+#include <hicn/ctrl/face.h>
+#include "../../facelet.h"
#include "../../interface.h"
#include "../../util/map.h"
-#include "../../util/token.h"
-#include "../../util/log.h"
+
+#include "network_framework.h"
+
+#if !defined(MAC_OS_X_VERSION_10_14)
+#error "Network frameork requires MacOSX 10.14+"
+#endif /* !defined(MAC_OS_X_VERSION_10_14) */
+
/*
* Bonjour service discovery for hICN forwarder
@@ -56,7 +66,7 @@
#define BONJOUR_PROTOCOL udp
#define BONJOUR_SERVICE_DOMAIN "local"
-#define BONJOUR_SERVICE_NAME "hicn"
+#define BONJOUR_SERVICE_NAME "hicn node"
/* Generated variables */
#define BONJOUR_SERVICE_TYPE "_hicn._" STRINGIZE(BONJOUR_PROTOCOL)
@@ -77,7 +87,7 @@ const char * interface_type_str[] = {
"OTHER", "WIFI", "CELLULAR", "WIRED", "LOOPBACK",
};
-#if 0
+#if 1
typedef enum {
PATH_STATUS_INVALID,
PATH_STATUS_SATISTIED,
@@ -107,7 +117,7 @@ cmp_iface(const nw_interface_t iface1, const nw_interface_t iface2)
//TYPEDEF_MAP(map_cnx, nw_interface_t, nw_connection_t, cmp_iface);
typedef struct {
- face_rules_t * rules; /**< Face creation rules */
+ network_framework_cfg_t cfg;
nw_path_monitor_t pm; /**< Main path monitor */
// map_cnx_t map_cnx; /**< Map: interface -> connection for face status */
} nf_data_t;
@@ -209,104 +219,119 @@ dump_connection(nw_connection_t connection, int indent)
nw_release(path);
}
-face_t *
-face_create_from_connection(nw_connection_t connection, face_rules_t * rules)
+#if defined(MAC_OS_X_VERSION_10_15)
+void
+dump_browse_result(nw_browse_result_t result, int indent)
{
- face_t * face;
- struct sockaddr_in * sin;
- struct sockaddr_in6 * sin6;
+ /* Endpoint */
+ nw_endpoint_t browse_endpoint = nw_browse_result_copy_endpoint(result);
+ if (!bendpoint) {
+ ERROR("[network_framework.dump_result] Failed to retrieve endpoint from Bonjour browse result");
+ return;
+ }
+ printfi(indent + 1, "Endpoint:")
+ dump_endpoint(browse_endpoint, indent + 2);
+
+ /* Interfaces */
+ printfi(indent + 1, "Interfaces:")
+ nw_browse_result_enumerate_interfaces(result, ^(nw_interface_t interface) {
+ dump_interface(interface, index + 2);
+ return true;
+ });
+}
+#endif /* defined(MAC_OS_X_VERSION_10_15) */
+
+facelet_t *
+facelet_create_from_connection(nw_connection_t connection)
+{
+ facelet_t * facelet;
+ ip_address_t local_addr, remote_addr;
+ uint16_t remote_port;
nw_path_t path = nw_connection_copy_current_path(connection);
nw_endpoint_t local = nw_path_copy_effective_local_endpoint(path);
nw_endpoint_t remote = nw_path_copy_effective_remote_endpoint(path);
__block nw_interface_t interface;
- const struct sockaddr * local_addr = nw_endpoint_get_address(local);
- const struct sockaddr * remote_addr = nw_endpoint_get_address(remote);
+ const struct sockaddr * local_sa = nw_endpoint_get_address(local);
+ const struct sockaddr * remote_sa = nw_endpoint_get_address(remote);
- assert (local_addr->sa_family == remote_addr->sa_family);
- switch(local_addr->sa_family) {
+ assert (local_sa->sa_family == remote_sa->sa_family);
+ switch(local_sa->sa_family) {
case AF_INET:
- sin = (struct sockaddr_in *)local_addr;
- sin->sin_port = htons(DEFAULT_PORT);
- sin = (struct sockaddr_in *)remote_addr;
- sin->sin_port = htons(DEFAULT_PORT);
+ local_addr.v4.as_inaddr = ((struct sockaddr_in *)local_sa)->sin_addr;
+ remote_addr.v4.as_inaddr = ((struct sockaddr_in *)remote_sa)->sin_addr;
+ remote_port = ((struct sockaddr_in *)remote_sa)->sin_port;
break;
case AF_INET6:
- sin6 = (struct sockaddr_in6 *)local_addr;
- sin6->sin6_port = htons(DEFAULT_PORT);
- sin6 = (struct sockaddr_in6 *)remote_addr;
- sin6->sin6_port = htons(DEFAULT_PORT);
+ local_addr.v6.as_in6addr = ((struct sockaddr_in6 *)local_sa)->sin6_addr;
+ remote_addr.v6.as_in6addr = ((struct sockaddr_in6 *)remote_sa)->sin6_addr;
+ remote_port = ((struct sockaddr_in6 *)remote_sa)->sin6_port;
break;
default:
- ERROR("Unsupported address family: %d\n", local_addr->sa_family);
+ ERROR("Unsupported address family: %d\n", local_sa->sa_family);
return NULL;
}
- face = face_create_udp_sa(local_addr, remote_addr);
/* Retrieving path interface type (a single one expected */
nw_path_enumerate_interfaces(path, (nw_path_enumerate_interfaces_block_t)^(nw_interface_t path_interface) {
interface = path_interface;
return false;
});
- nw_interface_type_t type = nw_interface_get_type(interface);
- const char * name = nw_interface_get_name(interface);
-
- policy_tags_t tags = POLICY_TAGS_EMPTY;
- if (rules) {
- if (!FACEMGR_IS_ERROR(face_rules_get(rules, name, &tags)))
- goto SET_TAGS;
+ const char * name = nw_interface_get_name(interface);
+ netdevice_t netdevice;
+ snprintf(netdevice.name, IFNAMSIZ, "%s", name);
+ netdevice_update_index(&netdevice);
- char tags[MAXSZ_POLICY_TAGS];
- policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags);
- }
+ netdevice_type_t netdevice_type;
+ nw_interface_type_t type = nw_interface_get_type(interface);
switch(type) {
case INTERFACE_TYPE_OTHER:
- policy_tags_add(&tags, POLICY_TAG_WIFI);
- policy_tags_add(&tags, POLICY_TAG_TRUSTED);
+ netdevice_type = NETDEVICE_TYPE_UNDEFINED;
break;
case INTERFACE_TYPE_WIFI:
- // XXX disambuiguate on interface name for now.
- policy_tags_add(&tags, POLICY_TAG_WIFI);
- policy_tags_add(&tags, POLICY_TAG_TRUSTED);
+ netdevice_type = NETDEVICE_TYPE_WIFI;
break;
case INTERFACE_TYPE_CELLULAR:
- policy_tags_add(&tags, POLICY_TAG_CELLULAR);
+ netdevice_type = NETDEVICE_TYPE_CELLULAR;
break;
case INTERFACE_TYPE_WIRED:
- /* Both VPN and USB WiFi are not well detected on MacOS. For USB
- * WiFi, we currently have no solution. For VPN, until we have
- * proper support of AnyC APIs, we need to have heuristics to
- * determine VPN interfaces. */
- policy_tags_add(&tags, POLICY_TAG_WIRED);
- policy_tags_add(&tags, POLICY_TAG_TRUSTED);
+ netdevice_type = NETDEVICE_TYPE_WIRED;
break;
case INTERFACE_TYPE_LOOPBACK:
- tags = POLICY_TAGS_EMPTY;
+ netdevice_type = NETDEVICE_TYPE_LOOPBACK;
break;
default:
break;
}
-SET_TAGS:
- face_set_tags(face, tags);
-
nw_release(local);
nw_release(remote);
nw_release(path);
- return face;
+ facelet = facelet_create();
+ if (!facelet)
+ return NULL;
+
+ facelet_set_netdevice(facelet, netdevice);
+ facelet_set_netdevice_type(facelet, netdevice_type);
+ facelet_set_family(facelet, local_sa->sa_family);
+ facelet_set_local_addr(facelet, local_addr);
+ facelet_set_remote_addr(facelet, remote_addr);
+ facelet_set_remote_port(facelet, remote_port);
+
+ return facelet;
}
void
on_connection_state_event(interface_t * interface, nw_interface_t iface,
nw_connection_t cnx, nw_connection_state_t state, nw_error_t error)
{
-#if 0
+#if 1
DEBUG("Connection [new state = %s]:\n", connection_state_str[state]);
nw_path_t path = nw_connection_copy_current_path(cnx);
nw_path_enumerate_interfaces(path, (nw_path_enumerate_interfaces_block_t)^(nw_interface_t interface) {
@@ -335,14 +360,18 @@ on_connection_state_event(interface_t * interface, nw_interface_t iface,
case nw_connection_state_ready:
{
-#if 0
+ printf("info:\n");
+ warn("connection ready");
+#if 1
WITH_DEBUG({
dump_connection(cnx, 1);
});
#endif
- nf_data_t * data = (nf_data_t*)interface->data;
- face_t * face = face_create_from_connection(cnx, data->rules);
- event_raise(EVENT_TYPE_CREATE, face, interface);
+ facelet_t * facelet = facelet_create_from_connection(cnx);
+ if (!facelet)
+ return;
+ facelet_set_event(facelet, FACELET_EVENT_CREATE);
+ interface_raise_event(interface, facelet);
break;
}
case nw_connection_state_failed:
@@ -373,10 +402,10 @@ void
on_connection_path_event(interface_t * interface, nw_interface_t iface,
nw_connection_t cnx, nw_path_t path)
{
-#if 0
+#if 1
DEBUG("Connection [path changed]:\n");
WITH_DEBUG({
- //dump_connection(cnx, 1);
+ dump_connection(cnx, 1);
});
#endif
/* redundant *//*
@@ -420,15 +449,7 @@ void on_interface_event(interface_t * interface, nw_interface_t iface)
* time, if none is discovered, we cannot do any tunnel face.
*/
- nw_endpoint_t endpoint;
-
- endpoint = nw_endpoint_create_bonjour_service(
- BONJOUR_SERVICE_NAME,
- BONJOUR_SERVICE_TYPE,
- BONJOUR_SERVICE_DOMAIN);
-
- if (!endpoint)
- goto ERR;
+ // OLD CODE
/* nw_parameters_create_secure_{udp,tcp} */
nw_parameters_t parameters = nw_parameters_create_fn(
@@ -436,14 +457,93 @@ void on_interface_event(interface_t * interface, nw_interface_t iface)
NW_PARAMETERS_DEFAULT_CONFIGURATION /* default udp/tcp */);
if (!parameters)
- goto ERR;
+ goto ERR_PARAMETERS;
nw_parameters_require_interface(parameters, iface);
nw_parameters_set_reuse_local_address(parameters, true);
+#if defined(MAC_OS_X_VERSION_10_15)
+ /*
+ * Before being able to create a bonjour endpoint, we need to browse for
+ * available services on the local network using the parameters specified
+ * before.
+ */
+ nw_browse_descriptor_t descriptor = nw_browse_descriptor_create_bonjour_service(BONJOUR_SERVICE_TYPE, BONJOUR_SERVICE_DOMAIN);
+ if (!descriptor) {
+ ERROR("[network_framework.on_interface_event] Failed to create a bonjour browse descriptor");
+ goto ERR_DESCRIPTOR;
+ }
+
+ nw_browser_t browser = nw_browser_create(descriptor, parameters);
+ nw_browser_set_queue(browser, dispatch_get_main_queue());
+ nw_browser_set_browse_results_changed_handler(browser, ^(nw_browse_result_t result, nw_browse_result_t result2, bool flag) {
+ /* Dump result */
+ printfi(0, "NEW BROWSE RESULT");
+ printfi(1, "Result:");
+ dump_browse_result(result, 2);
+ printfi(1, "Result2:");
+ dump_browse_result(result2, 2);
+ printfi("Flag: %s\n", flag?"ON":"OFF");
+
+ /* Changes */
+ nw_browse_result_change_t change = nw_browse_result_get_changes(result, result2);
+ switch(change) {
+ case nw_browse_result_change_identical:
+ printfi("The compared services are identical.");
+ break;
+ case nw_browse_result_change_result_added:
+ printfi(2, "A new service was discovered.");
+ break;
+
+ case nw_browse_result_change_result_removed:
+ printfi(2, "A previously discovered service was removed.");
+ break;
+
+ case nw_browse_result_change_txt_record_changed:
+ printfi(2, "The service's associated TXT record changed.");
+ break;
+
+ case nw_browse_result_change_interface_added:
+ printfi(2, "The service was discovered over a new interface.");
+ break;
+
+nw_browse_result_change_interface_removed
+ printfi(2, "The service was no longer discovered over a certain interface.");
+ break;
+ }
+ });
+
+ browser.browseResultsChangedHandler = { browseResults, _ in
+ for browseResult in browseResults {
+ print("Discovered \(browseResult.endpoint) over \(browseResult.interfaces)")
+ }
+ }
+ nw_browser_start(browser);
+//#else
+//#warning "Bonjour discovery only available in MacOS 10.15+"
+#endif /* defined(MAC_OS_X_VERSION_10_15) */
+
+ /*
+ * Now that we have resolve the name of a bonjour remote, we can create a
+ * connection to the corresponding endpoint identified by its name.
+ */
+ nw_endpoint_t endpoint;
+
+ DEBUG("Creating bonjour service towards NAME=%s TYPE=%s DOMAIN=%s",
+ BONJOUR_SERVICE_NAME, BONJOUR_SERVICE_TYPE, BONJOUR_SERVICE_DOMAIN);
+ endpoint = nw_endpoint_create_bonjour_service(
+ BONJOUR_SERVICE_NAME,
+ BONJOUR_SERVICE_TYPE,
+ BONJOUR_SERVICE_DOMAIN);
+
+ if (!endpoint) {
+ ERROR("[network_framework.on_interface_event] Failed to create bound Bonjour connection");
+ goto ERR_ENDPOINT;
+ }
+
nw_connection_t connection = nw_connection_create(endpoint, parameters);
if (!connection)
- goto ERR;
+ goto ERR_CONNECTION;
nw_release(endpoint);
nw_release(parameters);
@@ -462,7 +562,7 @@ void on_interface_event(interface_t * interface, nw_interface_t iface)
});
nw_connection_set_better_path_available_handler(connection, ^(bool value) {
-#if 0
+#if 1
DEBUG("Connection [better path = %s]\n", (value ? "true" : "false"));
WITH_DEBUG({
dump_connection(connection, 1);
@@ -471,7 +571,7 @@ void on_interface_event(interface_t * interface, nw_interface_t iface)
});
nw_connection_set_viability_changed_handler(connection, ^(bool value) {
-#if 0
+#if 1
DEBUG("Connection [viable = %s]\n", (value ? "true" : "false"));
WITH_DEBUG({
//dump_connection(connection, 1);
@@ -482,14 +582,11 @@ void on_interface_event(interface_t * interface, nw_interface_t iface)
* This is the first time we have a connection with address and port
* and thus the full identification of an hICN face
*/
- nf_data_t * data = (nf_data_t*)interface->data;
- face_t * face = face_create_from_connection(connection, data->rules);
- //event_raise(value ? EVENT_TYPE_SET_UP : EVENT_TYPE_SET_DOWN, face, interface);
- if(value) {
- event_raise(EVENT_TYPE_CREATE, face, interface);
- } else {
- event_raise(EVENT_TYPE_DELETE, face, interface);
- }
+ facelet_t * facelet = facelet_create_from_connection(connection);
+ if (!facelet)
+ return;
+ facelet_set_event(facelet, value ? FACELET_EVENT_CREATE : FACELET_EVENT_DELETE);
+ interface_raise_event(interface, facelet);
});
@@ -498,14 +595,26 @@ void on_interface_event(interface_t * interface, nw_interface_t iface)
nw_connection_set_queue(connection, dispatch_get_main_queue());
nw_retain(connection); // Hold a reference until cancelled
-#if 0
- DEBUG("Created Bonjour cnx on interface:\n");
+#if 1
+ DEBUG("Created Bonjour cnx on interface:");
WITH_DEBUG({
dump_interface(iface, 1);
});
#endif
-ERR:
+ return;
+
+ nw_release(connection);
+ERR_CONNECTION:
+ nw_release(endpoint);
+ERR_ENDPOINT:
+#if defined(MAC_OS_X_VERSION_10_15)
+ nw_release(descriptor);
+ERR_DESCRIPTOR:
+#endif /* defined(MAC_OS_X_VERSION_10_15) */
+ nw_release(parameters);
+
+ERR_PARAMETERS:
return;
}
@@ -514,7 +623,7 @@ void on_path_event(interface_t * interface, nw_path_t path)
/* Simplification: we handle path event only once.
* Ideally, test whether we discover new interfaces or not
*/
-#if 0
+#if 1
DEBUG("Path [event]:\n");
WITH_DEBUG({
dump_path(path, 1);
@@ -528,13 +637,14 @@ void on_path_event(interface_t * interface, nw_path_t path)
}
-int nf_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
+int nf_initialize(interface_t * interface, void * cfg)
{
nf_data_t * data = malloc(sizeof(nf_data_t));
if (!data)
goto ERR_MALLOC;
- data->rules = rules;
+ if (cfg)
+ data->cfg = * (network_framework_cfg_t *)cfg;
data->pm = nw_path_monitor_create();
if (!data->pm)
@@ -552,14 +662,13 @@ int nf_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
DEBUG("Starting network path monitor");
nw_path_monitor_start(data->pm);
- *pdata = data;
- return FACEMGR_SUCCESS;
+ interface->data = data;
+ return 0;
ERR_PM:
free(data);
ERR_MALLOC:
- *pdata = NULL;
- return FACEMGR_FAILURE;
+ return -1;
}
int nf_finalize(interface_t * interface)
@@ -569,12 +678,11 @@ int nf_finalize(interface_t * interface)
nw_path_monitor_cancel(data->pm);
data->pm = NULL;
}
- return FACEMGR_SUCCESS;
+ return 0;
}
const interface_ops_t network_framework_ops = {
.type = "network_framework",
- .is_singleton = true,
.initialize = nf_initialize,
.finalize = nf_finalize,
.on_event = NULL,
diff --git a/ctrl/facemgr/src/face_cache.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.h
index bee36af30..edb35e904 100644
--- a/ctrl/facemgr/src/face_cache.c
+++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.h
@@ -13,9 +13,10 @@
* limitations under the License.
*/
-#include "face_cache.h"
-
-#include "face.h"
-#include "util/set.h"
+/**
+ * \file network_framework.h
+ * \brief Network framework interface
+ */
-TYPEDEF_SET(face_cache, face_t *, face_cmp, face_snprintf);
+typedef struct {
+} network_framework_cfg_t;
diff --git a/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt b/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt
new file mode 100644
index 000000000..e5fd2167e
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt
@@ -0,0 +1,31 @@
+# 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.
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/updown.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/updown.c
+)
+
+list(APPEND INCLUDE_DIRS
+)
+
+list(APPEND LIBRARIES
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
+set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
+set(LIBRARIES ${LIBRARIES} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/interfaces/updown/updown.c b/ctrl/facemgr/src/interfaces/updown/updown.c
new file mode 100644
index 000000000..c864c8c04
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/updown/updown.c
@@ -0,0 +1,138 @@
+/*
+ * 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 updown.c
+ * \brief Implementation of Example updown interface
+ */
+
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hicn/facemgr.h>
+
+#include "../../common.h"
+#include "../../facelet.h"
+#include "../../interface.h"
+
+/**
+ * \brief Default unix socket path (the leading \0 means using the abstract
+ * namespace instead of the filesystem).
+ */
+#define UNIX_PATH "\0updownsrv"
+
+typedef struct {
+ int fd; /* Unix client socket */
+} updown_data_t;
+
+int updown_initialize(interface_t * interface, void * cfg)
+{
+ struct sockaddr_un addr;
+ char * socket_path = UNIX_PATH;
+
+ updown_data_t * data = malloc(sizeof(updown_data_t));
+ if (!data)
+ goto ERR_MALLOC;
+ interface->data = data;
+
+ data->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (data->fd == -1) {
+ perror("socket error");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ if (*socket_path == '\0') {
+ *addr.sun_path = '\0';
+ strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
+ } else {
+ strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
+ }
+
+ if (connect(data->fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ perror("connect error");
+ return -1;
+ }
+
+ return data->fd;
+
+ERR_MALLOC:
+ return -1;
+}
+
+int updown_finalize(interface_t * interface)
+{
+ updown_data_t * data = (updown_data_t*)interface->data;
+
+ if (data->fd > 0)
+ close(data->fd);
+
+ return 0;
+}
+
+int updown_callback(interface_t * interface)
+{
+ updown_data_t * data = (updown_data_t*)interface->data;
+ char buf[100];
+ int rc;
+
+ rc = read(data->fd, buf, sizeof(buf));
+ if (rc < 0)
+ return -1;
+
+ /*
+ * If the process is paused (eg. in a debugger, we might have more than one
+ * read.
+ * XXX how big is the buffer
+ * XXX shall we drain the queue if it exceeds buffer size ?
+ */
+ //assert(rc == 1);
+
+ /* Raise facelet update event */
+ facelet_t * facelet = facelet_create();
+ facelet_set_netdevice_type(facelet, NETDEVICE_TYPE_WIFI); //CELLULAR);
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ switch(buf[0]) {
+ case '\0':
+ facelet_set_admin_state(facelet, FACE_STATE_DOWN);
+ break;
+ case '\1':
+ facelet_set_admin_state(facelet, FACE_STATE_UP);
+ break;
+ break;
+ default:
+ ERROR("Invalid data received from updown server. Ignoring...");
+ facelet_free(facelet);
+ return -1;
+ }
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+
+ interface_raise_event(interface, facelet);
+
+ return 0;
+}
+
+interface_ops_t updown_ops = {
+ .type = "updown",
+ .initialize = updown_initialize,
+ .finalize = updown_finalize,
+ .callback = updown_callback,
+};
diff --git a/ctrl/facemgr/src/loop_dispatcher.c b/ctrl/facemgr/src/loop_dispatcher.c
new file mode 100644
index 000000000..7e7f9d667
--- /dev/null
+++ b/ctrl/facemgr/src/loop_dispatcher.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file loop_dispatcher.c
+ * \brief Implementation of facemgr main loop using Apple Dispatcher framework
+ */
+
+#ifndef __APPLE__
+#error "This implementation only supports Apple platforms"
+#endif /* __APPLE__ */
+
+#ifdef WITH_THREAD
+#error "Multithreaded implementation is not (yet) supported on Apple platforms"
+#endif /* WITH_THREAD */
+
+#include <stdlib.h>
+
+#include <Dispatch/Dispatch.h>
+
+#include <hicn/facemgr/loop.h>
+#include <hicn/util/log.h>
+
+struct loop_s {
+};
+
+loop_t *
+loop_create()
+{
+ /* Nothing to do */
+ return NULL;
+}
+
+void
+loop_free(loop_t * loop)
+{
+ /* Nothing to do */
+}
+
+void
+loop_dispatch(loop_t * loop)
+{
+ dispatch_main();
+}
+
+void
+loop_undispatch(loop_t * loop)
+{
+ /* Nothing to do */
+}
+
+void
+loop_break(loop_t * loop)
+{
+ exit(0);
+}
+
+int
+loop_callback(loop_t * loop, facemgr_cb_type_t type, void * data)
+{
+ INFO("loop_callback not (yet) implemented");
+ return 0;
+}
diff --git a/ctrl/facemgr/src/loop_libevent.c b/ctrl/facemgr/src/loop_libevent.c
new file mode 100644
index 000000000..4042c717a
--- /dev/null
+++ b/ctrl/facemgr/src/loop_libevent.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file loop_libevent.c
+ * \brief Implementation of facemgr main loop using libevent
+ */
+
+#ifndef __linux__
+#error "Only linux is supported"
+#endif /* __linux__ */
+
+#include <assert.h>
+#include <event2/event.h>
+#include <event2/thread.h>
+#include <fcntl.h> // fcntl
+#ifdef WITH_THREAD
+#include <pthread.h>
+#endif /* WITH_THREAD */
+#include <stdlib.h>
+#include <sys/timerfd.h>
+#include <unistd.h> // fcntl
+
+#include <hicn/facemgr/api.h>
+#include <hicn/util/log.h>
+
+#include <hicn/facemgr/loop.h>
+#include "util/map.h"
+
+/**
+ * \brief Holds all callback parameters
+ */
+typedef struct {
+ void * owner;
+ fd_callback_t callback;
+ void * data;
+} cb_wrapper_args_t;
+
+TYPEDEF_MAP_H(event_map, int, struct event *);
+TYPEDEF_MAP(event_map, int, struct event *, int_cmp, int_snprintf, generic_snprintf);
+
+/* Map that associates timer fds with their associated cb_wrapper_args_t */
+TYPEDEF_MAP_H(timer_fd_map, int, cb_wrapper_args_t *);
+TYPEDEF_MAP(timer_fd_map, int, cb_wrapper_args_t *, int_cmp, int_snprintf, generic_snprintf);
+
+struct loop_s {
+ struct event_base * event_base;
+ event_map_t * event_map;
+ timer_fd_map_t * timer_fd_map;
+#ifdef WITH_THREAD
+ pthread_t thread;
+#endif /* WITH_THREAD */
+};
+
+/* Forward declarations */
+int _loop_unregister_fd(loop_t * loop, int fd);
+int _loop_unregister_timer(loop_t * loop, int fd);
+
+loop_t *
+loop_create()
+{
+ loop_t * loop = malloc(sizeof(loop_t));
+ if (!loop) {
+ ERROR("[loop_create] Failed to allocate memory");
+ goto ERR_MALLOC;
+ }
+
+#ifdef WITH_THREAD
+ evthread_use_pthreads();
+#endif /* WITH_THREAD */
+
+ loop->event_base = event_base_new();
+ if (!loop)
+ goto ERR_EVENT;
+
+ loop->event_map = event_map_create();
+ if (!loop->event_map) {
+ ERROR("[loop_create] Failed to create event_map");
+ goto ERR_EVENT_MAP;
+ }
+
+ loop->timer_fd_map = timer_fd_map_create();
+ if (!loop->timer_fd_map) {
+ ERROR("[loop_create] Failed to create timer_fd_map");
+ goto ERR_TIMER_FD_MAP;
+ }
+
+ event_set_log_callback(NULL);
+
+ return loop;
+
+ timer_fd_map_free(loop->timer_fd_map);
+ERR_TIMER_FD_MAP:
+ event_map_free(loop->event_map);
+ERR_EVENT_MAP:
+ event_base_free(loop->event_base);
+ERR_EVENT:
+ free(loop);
+ERR_MALLOC:
+ return NULL;
+}
+
+void
+loop_free(loop_t * loop)
+{
+ /*
+ * Release all timer cb_wrapper_args_t
+ *
+ * We need to stop all timers, this should release associated fd events at
+ * the same time... for that reason, this code has to be called before
+ * releasing events
+ */
+
+ int * timer_fd_map_array;
+ int n = timer_fd_map_get_key_array(loop->timer_fd_map, &timer_fd_map_array);
+ if (n < 0) {
+ ERROR("[loop_free] Could not get event map array");
+ } else {
+ for (unsigned i = 0; i < n; i++) {
+ int fd = timer_fd_map_array[i];
+ if (_loop_unregister_timer(loop, fd) < 0) {
+ ERROR("[loop_free] Could not unregister timer");
+ }
+ }
+ free(timer_fd_map_array);
+ }
+ timer_fd_map_free(loop->timer_fd_map);
+
+ /* Release all events */
+
+ int * event_map_array;
+ n = event_map_get_key_array(loop->event_map, &event_map_array);
+ if (n < 0) {
+ ERROR("[loop_free] Could not get event map array");
+ } else {
+ for (unsigned i = 0; i < n; i++) {
+ int fd = event_map_array[i];
+ if (_loop_unregister_fd(loop, fd) < 0) {
+ ERROR("[loop_free] Could not unregister fd");
+ }
+ }
+ free(event_map_array);
+ }
+ event_map_free(loop->event_map);
+
+ event_base_free(loop->event_base);
+
+ free(loop);
+}
+
+void
+loop_dispatch(loop_t * loop)
+{
+#ifdef WITH_THREAD
+ if (pthread_create(loop->thread, NULL, start_dispatch, loop)) {
+ fprintf(stderr, "Error creating thread\n");
+ return EXIT_FAILURE;
+ }
+#else
+ event_base_dispatch(loop->event_base);
+#endif /* WITH_THREAD */
+}
+
+void
+loop_undispatch(loop_t * loop)
+{
+#ifdef WITH_THREAD
+ DEBUG("Waiting for loop to terminate...");
+ if(pthread_join(loop->thread, NULL)) {
+ fprintf(stderr, "Error joining thread\n");
+ return EXIT_FAILURE;
+ }
+ DEBUG("Loop terminated !");
+#endif /* WITH_THREAD */
+}
+
+void
+loop_break(loop_t * loop)
+{
+ event_base_loopbreak(loop->event_base);
+}
+
+void cb_wrapper(evutil_socket_t fd, short what, void * arg) {
+ cb_wrapper_args_t * cb_wrapper_args = arg;
+ cb_wrapper_args->callback(cb_wrapper_args->owner, fd, cb_wrapper_args->data);
+}
+
+/**
+ * \brief Registers a new file descriptor to the event loop
+ * \param [in] fd - File descriptor to register
+ * \param [in] callback_owner - Pointer to the owner of the callack (first
+ * parameter of callback function)
+ * \param [in] callback - Callback function
+ * \param [in] callback_data - User data to pass alongside callback invocation
+ * \return 0 in case of success, -1 otherwise
+ */
+int
+_loop_register_fd(loop_t * loop, int fd, void * callback_owner,
+ fd_callback_t callback, void * callback_data)
+{
+ /* This will be freed with the event */
+ cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t));
+ *cb_wrapper_args = (cb_wrapper_args_t) {
+ .owner = callback_owner,
+ .callback = callback,
+ .data = callback_data,
+ };
+
+ evutil_make_socket_nonblocking(fd);
+ struct event * event = event_new(loop->event_base, fd, EV_READ | EV_PERSIST, cb_wrapper, cb_wrapper_args);
+ if (!event)
+ goto ERR_EVENT_NEW;
+
+ if (event_add(event, NULL) < 0)
+ goto ERR_EVENT_ADD;
+
+ if (event_map_add(loop->event_map, fd, event) < 0)
+ goto ERR_EVENT_MAP;
+
+ return 0;
+
+ERR_EVENT_MAP:
+ERR_EVENT_ADD:
+ event_free(event);
+ERR_EVENT_NEW:
+ return -1;
+}
+
+/**
+ * \brief Unregisters a file descriptor from the event loop
+ * \param [in] fd - File descriptor to unregister
+ * \return 0 in case of success, -1 otherwise
+ */
+int
+_loop_unregister_fd(loop_t * loop, int fd)
+{
+ struct event * event = NULL;
+
+ if (event_map_remove(loop->event_map, fd, &event) < 0) {
+ ERROR("[loop_unregister_fd] Error removing event associated to fd");
+ return -1;
+ }
+
+ assert(event);
+
+ cb_wrapper_args_t * cb_wrapper_args = event_get_callback_arg(event);
+ free(cb_wrapper_args);
+
+ event_del(event);
+ event_free(event);
+
+ return 0;
+}
+
+int
+loop_timer_callback(loop_t * loop, int fd, void * data)
+{
+ char buf[1024]; /* size is not important */
+ cb_wrapper_args_t * cb_wrapper_args = data;
+ while (read(fd, &buf, sizeof(buf)) > 0)
+ ;
+
+ int rc = cb_wrapper_args->callback(cb_wrapper_args->owner, fd,
+ cb_wrapper_args->data);
+
+ return rc;
+}
+
+int
+_loop_register_timer(loop_t * loop, timer_callback_data_t * timer_callback_data)
+{
+ int fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (fd == -1) {
+ perror("timerfd_create");
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ perror("fcntl");
+ return -1;
+ }
+
+ struct itimerspec ts = {
+ .it_interval = {
+ .tv_sec = 1, //timer_callback_data->delay_ms / 1000,
+ .tv_nsec = (timer_callback_data->delay_ms % 1000) * 1000000,
+ },
+ .it_value = {
+ .tv_sec = 1, //timer_callback_data->delay_ms / 1000,
+ .tv_nsec = (timer_callback_data->delay_ms % 1000) * 1000000,
+ }
+ };
+
+ if (timerfd_settime(fd, 0, &ts, NULL) == -1) {
+ perror("timerfd_settime");
+ return -1;
+ }
+
+ /* This should be freed together with the timer release */
+ cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t));
+ *cb_wrapper_args = (cb_wrapper_args_t) {
+ .owner = timer_callback_data->owner,
+ .callback = timer_callback_data->callback,
+ .data = timer_callback_data->data,
+ };
+
+ if (timer_fd_map_add(loop->timer_fd_map, fd, cb_wrapper_args) < 0) {
+ ERROR("[loop_callback] Could not add cb_wrapper to timer map");
+ return -1;
+ }
+
+ if (_loop_register_fd(loop, fd, loop,
+ (fd_callback_t) loop_timer_callback, cb_wrapper_args) < 0) {
+ ERROR("[loop_callback] Error registering fd to event loop");
+ return -1;
+ }
+
+ return fd;
+}
+
+int
+_loop_unregister_timer(loop_t * loop, int fd)
+{
+ struct itimerspec ts = {
+ .it_interval = {
+ .tv_sec = 0,
+ .tv_nsec = 0,
+ },
+ .it_value = { /* This value disables the timer */
+ .tv_sec = 0,
+ .tv_nsec = 0,
+ }
+ };
+ ts.it_value.tv_sec = 0;
+
+ if (timerfd_settime(fd, 0, &ts, NULL) == -1) {
+ perror("timerfd_settime");
+ return -1;
+ }
+
+ cb_wrapper_args_t * cb_wrapper_args;
+ if (timer_fd_map_remove(loop->timer_fd_map, fd, &cb_wrapper_args) < 0) {
+ ERROR("[loop_callback] Could not remove cb_wrapper from timer map");
+ return -1;
+ }
+ assert(cb_wrapper_args);
+ free(cb_wrapper_args);
+
+ if (_loop_unregister_fd(loop, fd) < 0) {
+ ERROR("[loop_callback] Error unregistering fd from event loop");
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+loop_callback(loop_t * loop, facemgr_cb_type_t type, void * data)
+{
+ switch(type) {
+ case FACEMGR_CB_TYPE_REGISTER_FD:
+ {
+ fd_callback_data_t * fd_callback_data = (fd_callback_data_t *)data;
+ if (_loop_register_fd(loop, fd_callback_data->fd,
+ fd_callback_data->owner,
+ fd_callback_data->callback,
+ fd_callback_data->data) < 0) {
+
+ ERROR("[loop_callback] Error registering fd to event loop");
+ return -1;
+ }
+ break;
+ }
+
+ case FACEMGR_CB_TYPE_UNREGISTER_FD:
+ {
+ int fd = *(int*)data;
+ /* We need a map to associate fd and events */
+ if (_loop_unregister_fd(loop, fd) < 0) {
+ ERROR("[loop_callback] Error registering fd to event loop");
+ return -1;
+ }
+ break;
+ }
+
+ case FACEMGR_CB_TYPE_REGISTER_TIMER:
+ {
+ timer_callback_data_t * timer_callback_data = (timer_callback_data_t *)data;
+
+ int fd = _loop_register_timer(loop, timer_callback_data);
+ if (fd < 0) {
+ ERROR("[loop_callback] Error registering timer to event loop");
+ return -1;
+ }
+ return fd;
+
+ }
+
+ case FACEMGR_CB_TYPE_UNREGISTER_TIMER:
+ {
+ int fd = *(int*)data;
+
+ if (_loop_unregister_timer(loop, fd) < 0) {
+ ERROR("[loop_callback] Error unregistering timer from event loop");
+ return -1;
+ }
+ return 0;
+
+ }
+ }
+ return 0;
+}
+
diff --git a/ctrl/facemgr/src/main.c b/ctrl/facemgr/src/main.c
index 6a80d806b..be5ff3c68 100644
--- a/ctrl/facemgr/src/main.c
+++ b/ctrl/facemgr/src/main.c
@@ -20,27 +20,29 @@
#include <getopt.h>
#include <limits.h>
+#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <unistd.h> // faccess
-#include <libconfig.h>
+#include <hicn/facemgr.h>
+#include <hicn/policy.h>
-#include "util/log.h"
-#include "util/policy.h"
+#include <hicn/util/ip_address.h>
+#include <hicn/util/log.h>
-#ifdef __APPLE__
-#include <Dispatch/Dispatch.h>
-#else
-// Note: we might want to use libevent on Apple too
-#include <event2/event.h>
-#endif
+#include <hicn/facemgr/cfg.h>
+#include <hicn/facemgr/loop.h>
-#include "facemgr.h"
+#include "cfg_file.h"
+#include "util/map.h"
#define FACEMGR_TIMEOUT 3
+#if 0
+static struct event_base * loop;
+#endif
+static loop_t * loop = NULL;
static struct option long_options[] =
{
@@ -52,13 +54,6 @@ typedef struct {
char * cfgfile;
} facemgr_options_t;
-static const char * DEFAULT_CFGFILES[] = {
- "/etc/facemgr.conf",
- "~/facemgr.conf",
-};
-
-#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x))
-
void usage(const char * progname)
{
printf("%s: Face manager daemon\n", progname);
@@ -70,16 +65,11 @@ void usage(const char * progname)
printf("\n");
}
-int probe_cfgfile(char * f)
-{
- for (unsigned i = 0; i < ARRAYSIZE(DEFAULT_CFGFILES); i++) {
- if (access(DEFAULT_CFGFILES[i], F_OK ) != -1) {
- if (!realpath(DEFAULT_CFGFILES[i], f))
- continue;
- return 0;
- }
+void facemgr_signal_handler(int signal) {
+ fprintf(stderr, "Received ^C... quitting !\n");
+ if (loop) {
+ loop_break(loop);
}
- return -1;
}
int parse_cmdline(int argc, char ** argv, facemgr_options_t * opts)
@@ -88,7 +78,7 @@ int parse_cmdline(int argc, char ** argv, facemgr_options_t * opts)
while ((c = getopt_long(argc, argv, "c:", long_options, NULL)) != -1) {
switch(c) {
case 'c':
- opts->cfgfile = strdup(optarg);
+ opts->cfgfile = optarg;
break;
case ':':
case '?':
@@ -101,149 +91,20 @@ int parse_cmdline(int argc, char ** argv, facemgr_options_t * opts)
return 0;
}
-int parse_config_file(const char * cfgpath, facemgr_t * facemgr)
-{
- /* Reading configuration file */
- config_t cfg;
- config_setting_t *setting;
-
- config_init(&cfg);
-
- /* Read the file. If there is an error, report it and exit. */
- if(!config_read_file(&cfg, cfgpath))
- goto ERR_FILE;
-
- setting = config_lookup(&cfg, "log");
- if (setting) {
- const char *log_level_str;
- if (config_setting_lookup_string(setting, "log_level", &log_level_str)) {
- if (strcmp(log_level_str, "FATAL") == 0) {
- log_conf.log_level = LOG_FATAL;
- } else
- if (strcmp(log_level_str, "ERROR") == 0) {
- log_conf.log_level = LOG_ERROR;
- } else
- if (strcmp(log_level_str, "WARN") == 0) {
- log_conf.log_level = LOG_WARN;
- } else
- if (strcmp(log_level_str, "INFO") == 0) {
- log_conf.log_level = LOG_INFO;
- } else
- if (strcmp(log_level_str, "DEBUG") == 0) {
- log_conf.log_level = LOG_DEBUG;
- } else
- if (strcmp(log_level_str, "TRACE") == 0) {
- log_conf.log_level = LOG_TRACE;
- } else {
- printf("Ignored unknown log level\n");
- }
- }
- }
-
- setting = config_lookup(&cfg, "faces.overlay.ipv4");
- if (setting) {
- const char * ip_address;
- int local_port, remote_port;
- if (config_setting_lookup_int(setting, "local_port", &local_port)) {
- if ((local_port < 0) || (local_port > MAX_PORT))
- goto ERR;
- facemgr->overlay_v4_local_port = (uint16_t)local_port;
- }
-
- if (config_setting_lookup_int(setting, "remote_port", &remote_port)) {
- if ((remote_port < 0) || (remote_port > MAX_PORT))
- goto ERR;
- facemgr->overlay_v4_remote_port = (uint16_t)remote_port;
- }
-
- if (config_setting_lookup_string(setting, "remote_addr", &ip_address)) {
- ip_address_pton(ip_address, &facemgr->overlay_v4_remote_addr);
- printf("got v4 remote addr\n");
- }
- }
-
- setting = config_lookup(&cfg, "faces.overlay.ipv6");
- if (setting) {
- const char * ip_address;
- int local_port, remote_port;
- if (config_setting_lookup_int(setting, "local_port", &local_port)) {
- if ((local_port < 0) || (local_port > MAX_PORT))
- goto ERR;
- facemgr->overlay_v6_local_port = (uint16_t)local_port;
- }
-
- if (config_setting_lookup_int(setting, "remote_port", &remote_port)) {
- if ((remote_port < 0) || (remote_port > MAX_PORT))
- goto ERR;
- facemgr->overlay_v6_remote_port = (uint16_t)remote_port;
- }
-
- if (config_setting_lookup_string(setting, "remote_addr", &ip_address))
- ip_address_pton(ip_address, &facemgr->overlay_v6_remote_addr);
- }
-
- setting = config_lookup(&cfg, "faces.rules");
- if (setting) {
- int count = config_setting_length(setting);
- for(unsigned i = 0; i < count; ++i) {
- const char *interface_name;
- policy_tags_t tags = POLICY_TAGS_EMPTY;
-
- config_setting_t *rule = config_setting_get_elem(setting, i);
-
- /* Interface name */
- if(!(config_setting_lookup_string(rule, "name", &interface_name)))
- continue;
-
- /* Associated tags */
- config_setting_t *tag_settings = config_setting_get_member(rule, "tags");
- if (!tag_settings)
- goto ERR;
-
-
- for (unsigned j = 0; j < config_setting_length(tag_settings); j++) {
- const char * tag_str = config_setting_get_string_elem(tag_settings, j);
- policy_tag_t tag = policy_tag_from_str(tag_str);
- if (tag == POLICY_TAG_N)
- goto ERR;
- policy_tags_add(&tags, tag);
- }
-
- /* debug */
- char tags_str[MAXSZ_POLICY_TAGS];
- policy_tags_snprintf(tags_str, MAXSZ_POLICY_TAGS, tags);
- printf("Rule #%d interface_name=%s, tags=%s\n", i, interface_name, tags_str);
- face_rules_add(&facemgr->rules, strdup(interface_name), tags);
- }
- }
-
- config_destroy(&cfg);
- return 0;
-
-ERR_FILE:
- printf("Could not read configuration file %s\n", cfgpath);
- fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
- config_error_line(&cfg), config_error_text(&cfg));
- config_destroy(&cfg);
- exit(EXIT_FAILURE);
- return -1;
-ERR:
- fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
- config_error_line(&cfg), config_error_text(&cfg));
- config_destroy(&cfg);
- return -1;
-}
-
-#ifndef APPLE
-void dummy_handler(int fd, short event, void *arg) { }
-#endif /* APPLE */
+#ifdef __linux__
+#endif /* __linux__ */
-int main(int argc, char **argv)
+int main(int argc, char ** argv)
{
- facemgr_t * facemgr = facemgr_create();
- if (!facemgr)
- goto ERR_FACEMGR;
+ facemgr_cfg_t * cfg = NULL;
+ facemgr_t * facemgr;
+
+ struct sigaction sigIntHandler;
+ sigIntHandler.sa_handler = facemgr_signal_handler;
+ sigemptyset(&sigIntHandler.sa_mask);
+ sigIntHandler.sa_flags = 0;
+ sigaction(SIGINT, &sigIntHandler, NULL);
char cfgfile[PATH_MAX];
@@ -252,7 +113,7 @@ int main(int argc, char **argv)
/* Commandline */
facemgr_options_t cmdline_opts = {0};
if (parse_cmdline(argc, argv, &cmdline_opts) < 0) {
- ERROR("Error parsing commandline\n");
+ ERROR("Error parsing commandline");
goto ERR_CMDLINE;
}
@@ -260,7 +121,7 @@ int main(int argc, char **argv)
//facemgr_options_t cfgfile_opts;
if (cmdline_opts.cfgfile) {
- if (strcmp(cmdline_opts.cfgfile, "none") == 0)
+ if (strcasecmp(cmdline_opts.cfgfile, "none") == 0)
goto NO_CFGFILE;
if (!realpath(cmdline_opts.cfgfile, (char*)&cfgfile))
@@ -274,76 +135,84 @@ int main(int argc, char **argv)
if (probe_cfgfile(cfgfile) < 0)
goto NO_CFGFILE;
- printf("Using configuration file %s\n", cfgfile);
-
PARSE_CFGFILE:
- if (parse_config_file(cfgfile, facemgr) < 0) {
- ERROR("Error parsing configuration file %s\n", cfgfile);
+ DEBUG("Using configuration file %s", cfgfile);
+ cfg = facemgr_cfg_create();
+ if (!cfg)
+ goto ERR_FACEMGR_CFG;
+
+ if (parse_config_file(cfgfile, cfg) < 0) {
+ ERROR("Error parsing configuration file %s", cfgfile);
goto ERR_PARSE;
}
+ facemgr = facemgr_create_with_config(cfg);
+ if (!facemgr)
+ goto ERR_FACEMGR_CONFIG;
+
+ goto MAIN_LOOP;
+
NO_CFGFILE:
+ facemgr = facemgr_create();
+ if (!facemgr)
+ goto ERR_FACEMGR;
+
+MAIN_LOOP:
+
+ /* Main loop */
+ loop = loop_create();
#ifdef __linux__
- facemgr->loop = event_base_new();
- if (!facemgr->loop)
- fatal("Could not create an event base");
-
- /* Main loop
- *
- * To avoid the loop to exit when empty, we might either rely on an option
- * introduced from versions 2.1.x:
- * event_base_loop(loop->base, EVLOOP_NO_EXIT_ON_EMPTY);
- * or use this workaround:
- * http://archives.seul.org/libevent/users/Sep-2012/msg00056.html
- *
- * TODO:
- * - HUP should interrupt the main loop
- */
- {
- struct event *ev;
- struct timeval tv;
- tv.tv_sec = FACEMGR_TIMEOUT;
- tv.tv_usec = 0;
-
- ev = event_new(facemgr->loop, fileno(stdin), EV_TIMEOUT | EV_PERSIST, dummy_handler, NULL);
- event_add(ev, &tv);
- }
+ facemgr_set_callback(facemgr, loop, (void*)loop_callback);
#endif /* __linux__ */
- DEBUG("Bootstrap...\n");
+#ifdef __ANDROID__
+ facemgr_set_jvm(facemgr, NULL, NULL); // FIXME
+#endif /* __ ANDROID__ */
+
+ DEBUG("Bootstrap...");
+
if (facemgr_bootstrap(facemgr) < 0 )
goto ERR_BOOTSTRAP;
-#ifdef __linux__
- event_set_log_callback(NULL);
- event_base_dispatch(facemgr->loop);
+ loop_dispatch(loop);
- event_base_free(facemgr->loop);
+#ifdef __linux__
+#ifdef WITH_THREAD
+ for(;;) {
+ facemgr_list_faces(facemgr, NULL, NULL);
+ sleep(5);
+ }
+#endif /* WITH_THREAD */
#endif /* __linux__ */
-#ifdef __APPLE__
- /* Main loop */
- facemgr->loop = NULL;
- dispatch_main();
-#endif /* __APPLE__ */
-
- /* Clean up */
- //interface_delete_all();
+ facemgr_stop(facemgr);
+ loop_undispatch(loop);
facemgr_free(facemgr);
+ if (cfg)
+ facemgr_cfg_free(cfg);
+
+ loop_free(loop);
+
return EXIT_SUCCESS;
ERR_BOOTSTRAP:
+
+ facemgr_free(facemgr);
+ERR_FACEMGR_CONFIG:
+ERR_FACEMGR:
ERR_PARSE:
+ if (cfg)
+ facemgr_cfg_free(cfg);
+ERR_FACEMGR_CFG:
+
ERR_PATH:
ERR_CMDLINE:
- facemgr_free(facemgr);
-ERR_FACEMGR:
return EXIT_FAILURE;
-}
+}
diff --git a/ctrl/facemgr/src/netdevice.h b/ctrl/facemgr/src/netdevice.h
deleted file mode 100644
index b64ad0f9a..000000000
--- a/ctrl/facemgr/src/netdevice.h
+++ /dev/null
@@ -1,52 +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 netdevice.h
- * \brief Netdevice abstraction
- */
-#ifndef FACEMGR_NETDEVICE_H
-#define FACEMGR_NETDEVICE_H
-
-#include <net/if.h> // IFNAMSIZ
-
-#include "common.h"
-
-#define foreach_netdevice_type \
- _(UNDEFINED) \
- _(WIRED) \
- _(WIFI) \
- _(CELLULAR) \
- _(VPN) \
- _(N)
-
-#define MAXSZ_NETDEVICE_TYPE 9
-#define MAXSZ_NETDEVICE_TYPE_ MAXSZ_NETDEVICE_TYPE
-
-typedef enum {
-#define _(x) x,
-foreach_netdevice_type
-#undef _
-} netdevice_type_t;
-
-extern const char * netdevice_type_str[];
-
-
-typedef struct {
- u32 index;
- char name[IFNAMSIZ];
-} netdevice_t;
-
-#endif /* FACEMGR_NETDEVICE_H */
diff --git a/ctrl/facemgr/src/util/log.c b/ctrl/facemgr/src/util/log.c
index 54943cf45..c1fc999ad 100644
--- a/ctrl/facemgr/src/util/log.c
+++ b/ctrl/facemgr/src/util/log.c
@@ -13,12 +13,16 @@
* limitations under the License.
*/
-#include "log.h"
+#include <hicn/util/log.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+
log_conf_t log_conf = DEFAULT_LOG_CONF;
#define FMT_DATETIME "%02d-%02d-%04d %02d:%02d:%02d"
@@ -43,48 +47,96 @@ static char *timestamp(void)
}
void _log_va(int level, const char *fmt, va_list ap)
-{
- char *prefix;
- FILE *f = log_conf.log_file ? log_conf.log_file : stdout;
+{
#if 0
if (!conf.log_system)
return;
#endif
+ char *prefix;
+
+#ifdef __ANDROID__
+ int prio = -1;
if (level > log_conf.log_level)
return;
switch (level) {
case LOG_FATAL:
+ prio = ANDROID_LOG_FATAL;
prefix = "FATAL: ";
break;
case LOG_ERROR:
+ prio = ANDROID_LOG_ERROR;
prefix = "ERROR: ";
break;
case LOG_WARN:
+ prio = ANDROID_LOG_WARN;
prefix = "WARNING: ";
break;
case LOG_INFO:
+ prio = ANDROID_LOG_INFO;
prefix = "";
break;
case LOG_DEBUG:
+ prio = ANDROID_LOG_DEBUG;
prefix = "DEBUG: ";
break;
case LOG_TRACE:
+ prio = ANDROID_LOG_DEBUG;
prefix = "TRACE: ";
break;
default:
+ prio = ANDROID_LOG_INFO;
prefix = "";
break;
}
+ if (log_conf.log_file) {
+ FILE *f = log_conf.log_file;
+ fprintf(f, "%s %s", timestamp(), prefix);
+ vfprintf(f, fmt, ap);
+ fprintf(f, "\n");
+ } else {
+ __android_log_vprint(ANDROID_LOG_INFO, "HICN FACEMGR", fmt, ap);
+ }
+
+#else
+
+ if (level > log_conf.log_level)
+ return;
+
+ switch (level) {
+ case LOG_FATAL:
+ prefix = "FATAL: ";
+ break;
+ case LOG_ERROR:
+ prefix = "ERROR: ";
+ break;
+ case LOG_WARN:
+ prefix = "WARNING: ";
+ break;
+ case LOG_INFO:
+ prefix = "";
+ break;
+ case LOG_DEBUG:
+ prefix = "DEBUG: ";
+ break;
+ case LOG_TRACE:
+ prefix = "TRACE: ";
+ break;
+ default:
+ prefix = "";
+ break;
+ }
+ FILE *f = log_conf.log_file ? log_conf.log_file : stdout;
fprintf(f, "%s %s", timestamp(), prefix);
vfprintf(f, fmt, ap);
fprintf(f, "\n");
#ifdef DEBUG
fflush(f);
#endif
+#endif
}
void _log(int level, const char *fmt, ...)
diff --git a/ctrl/facemgr/src/util/map.h b/ctrl/facemgr/src/util/map.h
index 2694de2a7..b113954a6 100644
--- a/ctrl/facemgr/src/util/map.h
+++ b/ctrl/facemgr/src/util/map.h
@@ -18,7 +18,6 @@
#include <stdlib.h>
-#include "../common.h"
#include "set.h"
#define ERR_MAP_EXISTS -2
@@ -31,6 +30,10 @@ typedef struct {
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 *) \
@@ -47,7 +50,7 @@ NAME ## _t * NAME ## _create();
\
void NAME ## _free(NAME ## _t * map); \
\
-int NAME ## _add(NAME ## _t * map, KEY_T key, const VAL_T value); \
+int NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value); \
\
int NAME ## _remove(NAME ## _t * map, KEY_T key, VAL_T * value); \
\
@@ -60,6 +63,24 @@ 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) \
{ \
@@ -72,7 +93,7 @@ NAME ## _pair_snprintf(char * buf, size_t size, const NAME ## _pair_t * pair) {
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); \
+ rc = VALUE_SNPRINTF(buf+rc, BUFSIZE/2, (VAL_T)pair->value); \
return rc; \
} \
\
@@ -90,60 +111,124 @@ NAME ## _finalize(NAME ## _t * map)
return NAME ## _pair_set_finalize(&map->pair_set); \
} \
\
-AUTOGENERATE_CREATE_FREE(NAME) \
+NAME ## _t * \
+NAME ## _create() \
+{ \
+ NAME ## _t * map = malloc(sizeof(NAME ## _t)); \
+ if (!map) \
+ goto ERR_MALLOC; \
+ \
+ if (NAME ## _initialize(map) < 0) \
+ goto ERR_INITIALIZE; \
+ \
+ return map; \
+ \
+ERR_INITIALIZE: \
+ free(map); \
+ERR_MALLOC: \
+ return NULL; \
+} \
+ \
+void \
+NAME ## _free(NAME ## _t * map) \
+{ \
+ NAME ## _finalize(map); \
+ free(map); \
+} \
\
int \
-NAME ## _add(NAME ## _t * map, KEY_T key, const VAL_T value) \
+NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value) \
{ \
int rc; \
+ NAME ## _pair_t * found = NULL; \
\
- /* Create pair */ \
- NAME ## _pair_t * pair = malloc(sizeof(NAME ## _pair_t)); \
+ NAME ## _pair_t * pair = NAME ## _pair_create(key, value); \
if (!pair) \
- return FACEMGR_FAILURE; \
+ return -1; \
\
- pair->key = key; \
- pair->value = (VAL_T)value; \
- \
- rc = NAME ## _pair_set_get(&map->pair_set, pair, NULL); \
- if (!FACEMGR_IS_ERROR(rc)) { \
- free(pair); \
+ 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 (FACEMGR_IS_ERROR(rc)) { \
- free(pair); \
- return FACEMGR_FAILURE; \
+ if (rc < 0) { \
+ NAME ## _pair_free(pair); \
+ return -1; \
} \
- return FACEMGR_SUCCESS; \
+ return 0; \
} \
\
int \
NAME ## _remove(NAME ## _t * map, KEY_T key, VAL_T * value) \
{ \
- NAME ## _pair_t * found, search = { .key = key }; \
+ NAME ## _pair_t * found = NULL; \
+ NAME ## _pair_t search = { .key = key }; \
int rc = NAME ## _pair_set_remove(&map->pair_set, &search, &found); \
- if (FACEMGR_IS_ERROR(rc)) \
+ if (rc < 0) \
return ERR_MAP_NOT_FOUND; \
- *value = found->value; \
- return FACEMGR_SUCCESS; \
+ 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, search = { .key = key }; \
+ NAME ## _pair_t * found = NULL, search = { .key = key }; \
int rc = NAME ## _pair_set_get(&map->pair_set, &search, &found); \
- if (FACEMGR_IS_ERROR(rc)) \
- return ERR_MAP_NOT_FOUND; \
- *value = found->value; \
- return FACEMGR_SUCCESS; \
+ 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/facemgr/src/util/policy.c b/ctrl/facemgr/src/util/policy.c
deleted file mode 100644
index 6c8651ee3..000000000
--- a/ctrl/facemgr/src/util/policy.c
+++ /dev/null
@@ -1,59 +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, y) [POLICY_TAG_ ## x] = STRINGIZE(x),
- foreach_policy_tag
- #undef _
-};
-
-const char policy_tag_short_str[] = {
- #define _(x, y) [POLICY_TAG_ ## x] = y,
- 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/facemgr/src/util/set.h b/ctrl/facemgr/src/util/set.h
index 47a6eeaff..0dad17423 100644
--- a/ctrl/facemgr/src/util/set.h
+++ b/ctrl/facemgr/src/util/set.h
@@ -16,15 +16,33 @@
#ifndef UTIL_SET_H
#define UTIL_SET_H
+#include <hicn/util/log.h>
#include <search.h>
#include <string.h>
-#include "token.h"
-#include "../common.h"
+//#if !defined(__ANDROID__) && !defined(__APPLE__)
+//#include <threads.h>
+//#else
+#define thread_local _Thread_local
+//#endif /* ! __ANDROID__ */
#define ERR_SET_EXISTS -2
#define ERR_SET_NOT_FOUND -3
-#define BUFSIZE 80
+/* 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
@@ -34,10 +52,12 @@ string_snprintf(char * buf, size_t size, const char * s) {
static inline
int
-generic_snprintf(char * buf, size_t size, void * value) {
+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 { \
@@ -57,7 +77,9 @@ int NAME ## _add(NAME ## _t * set, const T element); \
\
int NAME ## _remove(NAME ## _t * set, const T search, T * element); \
\
-int NAME ## _get(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);
@@ -70,58 +92,122 @@ NAME ## _initialize(NAME ## _t * set) \
{ \
set->root = NULL; \
set->size = 0; \
- return FACEMGR_SUCCESS; \
+ return 0; \
} \
\
-NO_FINALIZE(NAME); \
-AUTOGENERATE_CREATE_FREE(NAME); \
+int \
+NAME ## _finalize(NAME ## _t * set) { return 0; } \
+ \
+NAME ## _t * \
+NAME ## _create() \
+{ \
+ NAME ## _t * set = malloc(sizeof(NAME ## _t)); \
+ if (!set) \
+ goto ERR_MALLOC; \
+ \
+ if (NAME ## _initialize(set) < 0) \
+ goto ERR_INITIALIZE; \
+ \
+ return set; \
+ \
+ERR_INITIALIZE: \
+ free(set); \
+ERR_MALLOC: \
+ return NULL; \
+} \
+ \
+void \
+NAME ## _free(NAME ## _t * set) \
+{ \
+ NAME ## _finalize(set); \
+ free(set); \
+} \
\
int \
NAME ## _add(NAME ## _t * set, const T element) \
{ \
- return tsearch(element, &set->root, (cmp_t)CMP) \
- ? FACEMGR_SUCCESS : FACEMGR_FAILURE; \
+ 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 = tdelete(search, &set->root, (cmp_t)CMP); \
- if (found && element) \
+ T * found = tfind(search, &set->root, (cmp_t)CMP); \
+ if (!found) \
+ return ERR_SET_NOT_FOUND; \
+ if (element) \
*element = *found; \
- return found ? FACEMGR_SUCCESS : ERR_SET_NOT_FOUND; \
+ tdelete(search, &set->root, (cmp_t)CMP); \
+ set->size--; \
+ return 0; \
} \
\
int \
-NAME ## _get(NAME ## _t * set, const T search, T * element) \
+NAME ## _get(const NAME ## _t * set, const T search, T * element) \
{ \
T * found = tfind(search, &set->root, (cmp_t)CMP); \
- if (found && element) \
- *element = *found; \
- return found ? FACEMGR_SUCCESS : ERR_SET_NOT_FOUND; \
+ if (element) \
+ *element = found ? *found : NULL; \
+ return 0; \
} \
\
-void \
-__ ## NAME ## _dump_node(const void *nodep, const VISIT which, const int depth) \
+static void \
+NAME ## _dump_node(const void *nodep, const VISIT which, \
+ const int depth) \
{ \
char buf[BUFSIZE]; \
switch (which) { \
case preorder: \
- break; \
- case postorder: \
- break; \
case endorder: \
break; \
+ case postorder: \
case leaf: \
SNPRINTF(buf, BUFSIZE, *(T*)nodep); \
- printf("%s\n", buf); \
+ INFO("%s", buf); \
break; \
} \
} \
\
void \
NAME ## _dump(NAME ## _t * set) { \
- twalk(set->root, __ ## NAME ## _dump_node); \
+ 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/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 */
diff --git a/ctrl/sysrepo-plugins/README.md b/ctrl/sysrepo-plugins/README.md
index 3f0ed2e34..0940fff67 100644
--- a/ctrl/sysrepo-plugins/README.md
+++ b/ctrl/sysrepo-plugins/README.md
@@ -1,6 +1,8 @@
# Sysrepo plugin for hicn-plugin (2019)
-These plugins serve as a data management agent. They provide yang models via NETCONF to allow the management of hicn-light, and hicn-plugin which runs in VPP instance from out-of-box.
+These plugins serve as a data management agent. They provide yang models via
+NETCONF to allow the management of hicn-light, and hicn-plugin which runs in VPP
+instance from out-of-box.
## Software Requirement
@@ -15,7 +17,7 @@ These plugins serve as a data management agent. They provide yang models via NET
## hICN yang model
You can install the yang model using the following bash script:
-
+```
EXIT_CODE=0
command -v sysrepoctl > /dev/null
if [ $? != 0 ]; then
@@ -24,53 +26,21 @@ if [ $? != 0 ]; then
else
sysrepoctl --install --yang=path_to_hicn_yang_model
fi
-
-hicn.yang can be found in the yang-model. It consists of two container nodes: hicn-conf and hicn-state. One is used to hold the configuration data (i.e., hicn-conf) and one for providing the state data (i.e., hicn-state). The hicn-conf has one node, params, which contains the hICN configuration parameters. Controler can configure these parameters through the edit-config RPC call. This node can be used to enable and to initialize the hicn-plugin in VPP instance. Hicn-state container is used to provide the state data to the controler. It consists of state, strategy, strategies, route, and face-ip-params nodes with the coresponding leaves. In hicn model variety of RPCs are provided to allow controler to communicate with hicn-plugin as well as update the state data in hicn-state. Here you can find the schematic view of the described hicn model:
-
-
-module: hicn
- +--rw hicn-conf
- | +--rw params
- | +--rw enable_disable? boolean
- | +--rw pit_max_size? int32
- | +--rw cs_max_size? int32
- | +--rw cs_reserved_app? int32
- | +--rw pit_dflt_lifetime_sec? float
- | +--rw pit_max_lifetime_sec? float
- | +--rw pit_min_lifetime_sec? float
- +--ro hicn-state
- +--ro states
- | +--ro pkts_processed? uint64
- | +--ro pkts_interest_count? uint64
- | +--ro pkts_data_count? uint64
- | +--ro pkts_from_cache_count? uint64
- | +--ro pkts_no_pit_count? uint64
- | +--ro pit_expired_count? uint64
- | +--ro cs_expired_count? uint64
- | +--ro cs_lru_count? uint64
- | +--ro pkts_drop_no_buf? uint64
- | +--ro interests_aggregated? uint64
- | +--ro interests_retx? uint64
- | +--ro interests_hash_collision? uint64
- | +--ro pit_entries_count? uint64
- | +--ro cs_entries_count? uint64
- | +--ro cs_entries_ntw_count? uint64
- +--ro strategy
- | +--ro description? uint8
- +--ro route
- | +--ro faceids? uint16
- | +--ro strategy_id? uint32
- +--ro strategies
- | +--ro n_strategies? uint8
- | +--ro strategy_id? uint32
- +--ro face-ip-params
- +--ro nh_addr? uint64
- +--ro swif? uint32
- +--ro flags? uint32
-
+```
+hicn.yang can be found in the yang-model. It consists of two container nodes:
+hicn-conf and hicn-state. One is used to hold the configuration data (i.e.,
+hicn-conf) and one for providing the state data (i.e., hicn-state). The
+hicn-conf has one node, params, which contains the hICN configuration
+parameters. A controller can configure these parameters through the edit-config RPC
+call. This node can be used to enable and to initialize the hicn-plugin in VPP
+instance. Hicn-state container is used to provide the state data to the
+controller. It consists of state, strategy, strategies, route, and face-ip-params
+nodes with the corresponding leaves. In the hicn model a variety of RPCs are provided
+to allow controller to communicate with the hicn-plugin as well as update the state
+data in hicn-state.
To setup the startup configuration you can use the following script:
-
+```
EXIT_CODE=0
command -v sysrepocfg > /dev/null
if [ $? != 0 ]; then
@@ -79,10 +49,10 @@ if [ $? != 0 ]; then
else
sysrepocfg -d startup -i path_to_startup_xml -f xml hicn
fi
-
+```
startup.xml is placed in the yang-model. Here you can find the content:
-
+```
<hicn-conf xmlns="urn:sysrepo:hicn">
<params>
<enable_disable>false</enable_disable>
@@ -94,81 +64,17 @@ startup.xml is placed in the yang-model. Here you can find the content:
<pit_min_lifetime_sec>-1</pit_min_lifetime_sec>
</params>
</hicn-conf>
-
-As can be seen, it contains the leaves of the params in hicn-conf node which is used as the startup configuration. This configuration can be changed through the controler by subscribing which changes the target to the running state. hicn yang model provides a list of RPCs which allows controler to communicate directly with the hicn-plugin. This RPCs may also cause the modification in state data. Here you can find the list of RPCs:
-
- rpcs:
- +---x node-params-set
- | +---w input
- | +---w enable_disable? boolean
- | +---w pit_max_size? int32
- | +---w cs_max_size? int32
- | +---w cs_reserved_app? int32
- | +---w pit_dflt_lifetime_sec? float
- | +---w pit_max_lifetime_sec? float
- | +---w pit_min_lifetime_sec? float
- +---x node-params-get
- +---x node-stat-get
- +---x strategy-get
- | +---w input
- | +---w strategy_id? uint32
- +---x strategies-get
- +---x route-get
- | +---w input
- | +---w prefix0? uint64
- | +---w prefix1? uint64
- | +---w len? uint8
- +---x route-del
- | +---w input
- | +---w prefix0? uint64
- | +---w prefix1? uint64
- | +---w len? uint8
- +---x route-nhops-add
- | +---w input
- | +---w prefix0? uint64
- | +---w prefix1? uint64
- | +---w len? uint8
- | +---w face_ids0? uint32
- | +---w face_ids1? uint32
- | +---w face_ids2? uint32
- | +---w face_ids3? uint32
- | +---w face_ids4? uint32
- | +---w face_ids5? uint32
- | +---w face_ids6? uint32
- | +---w n_faces? uint8
- +---x route-nhops-del
- | +---w input
- | +---w prefix0? uint64
- | +---w prefix1? uint64
- | +---w len? uint8
- | +---w faceid? uint16
- +---x face-ip-params-get
- | +---w input
- | +---w faceid? uint16
- +---x face-ip-add
- | +---w input
- | +---w nh_addr0? uint64
- | +---w nh_addr1? uint64
- | +---w swif? uint32
- +---x face-ip-del
- | +---w input
- | +---w faceid? uint16
- +---x punting-add
- | +---w input
- | +---w prefix0? uint64
- | +---w prefix1? uint64
- | +---w len? uint8
- | +---w swif? uint32
- +---x punting-del
- +---w input
- +---w prefix0? uint64
- +---w prefix1? uint64
- +---w len? uint8
- +---w swif? uint32
-
-
-In order to run different RPCs from controler you can use the examples in the controler_rpcs_instances.xml in the yang-model. Here you can find the content:
-
+```
+As can be seen, it contains the leaves of the params in hicn-conf node which is
+used as the startup configuration. This configuration can be changed through the
+controller by subscribing which changes the target to the running state. hicn
+yang model provides a list of RPCs which allows controller to communicate
+directly with the hicn-plugin. This RPCs may also cause the modification in
+state data.
+
+In order to run different RPCs from controller you can use the examples in the
+controler_rpcs_instances.xml in the yang-model. Here you can find the content:
+```
<node-params-get xmlns="urn:sysrepo:hicn"/>
<node-stat-get xmlns="urn:sysrepo:hicn"/>
@@ -179,7 +85,6 @@ In order to run different RPCs from controler you can use the examples in the co
<strategies-get xmlns="urn:sysrepo:hicn"/>
-
<route-get xmlns="urn:sysrepo:hicn">
<prefix0>10</prefix0>
<prefix1>20</prefix1>
@@ -213,7 +118,6 @@ In order to run different RPCs from controler you can use the examples in the co
<faceid>40</faceid>
</route-nhops-del>
-
<face-ip-params-get xmlns="urn:sysrepo:hicn">
<faceid>10</faceid>
</face-ip-params-get>
@@ -235,27 +139,33 @@ In order to run different RPCs from controler you can use the examples in the co
<swif>40</swif>
</punting-add>
-
<punting-del xmlns="urn:sysrepo:hicn">
<prefix0>10</prefix0>
<prefix1>20</prefix1>
<len>30</len>
<swif>40</swif>
</punting-del>
-
+```
## Run the plugin
-Firstly, verify the plugin and binary libraries are located correctly, then run the vpp through (service vpp start). Next, run the sysrepo daemon (sysrepod), for debug mode: sysrepo -d -l 4 which runs with high verbosity. Then, run the sysrepo plugin (sysrepo-plugind), for debug mode: sysrep-plugind -d -l 4 which runs with high verbosity. Now, the hicn sysrepo plugin is loaded. Then, run the netopeer2-server which serves as NETCONF server.
+Firstly, verify the plugin and binary libraries are located correctly, then run
+the vpp through (service vpp start). Next, run the sysrepo daemon (sysrepod),
+for debug mode: sysrepo -d -l 4 which runs with high verbosity. Then, run the
+sysrepo plugin (sysrepo-plugind), for debug mode: sysrep-plugind -d -l 4 which
+runs with high verbosity. Now, the hicn sysrepo plugin is loaded. Then, run the
+netopeer2-server which serves as NETCONF server.
## Connect from netopeer2-cli
In order to connect through the netopeer client run the netopeer2-cli. Then, follow these steps:
-connect --host XXX --login XXX
---> get (you can get the configuration and operational data)
---> get-config (you can get the configuratoin data)
---> edit-config --target running --config (you can modify the configuration but it needs an xml configuration input. For example,
+- connect --host XXX --login XXX
+- get (you can get the configuration and operational data)
+- get-config (you can get the configuration data)
+- edit-config --target running --config
+ you can modify the configuration but it needs an xml configuration input
+```
<hicn-conf xmlns="urn:sysrepo:hicn">
<params>
<enable_disable>false</enable_disable>
@@ -267,15 +177,16 @@ connect --host XXX --login XXX
<pit_min_lifetime_sec>-1</pit_min_lifetime_sec>
</params>
</hicn-conf>
-)
---> user-rpc (you can call one of the rpc proposed by hicn model but it needs an xml input, you can pick one in controler_rpcs_instances.xml)
+```
+- user-rpc (you can call one of the rpc proposed by hicn model but it needs an xml input)
-## Connect from OpenDayligh (ODL) controller
+## Connect from OpenDaylight (ODL) controller
-In order to connect througt the OpenDaylight follow these procedure:
+In order to connect through the OpenDaylight follow these procedure:
- run karaf distribution (./opendayligh_installation_folder/bin/karaf)
-- install the required feature list in DOL (feature:install odl-netconf-server odl-netconf-connector odl-restconf-all odl-netconf-topology or
+- install the required feature list in DOL (feature:install odl-netconf-server
+ odl-netconf-connector odl-restconf-all odl-netconf-topology or
odl-netconf-clustered-topology)
- run a rest client program (e.g., postman or RESTClient)
- mount the remote netopeer2-server to the OpenDaylight by the following REST API:
@@ -283,7 +194,7 @@ In order to connect througt the OpenDaylight follow these procedure:
PUT http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/hicn-node
with the following body
-
+```
<node xmlns="urn:TBD:params:xml:ns:yang:network-topology">
<node-id>hicn-node</node-id>
<host xmlns="urn:opendaylight:netconf-node-topology">Remote_NETCONF_SERVER_IP</host>
@@ -293,8 +204,8 @@ with the following body
<tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only>
<keepalive-delay xmlns="urn:opendaylight:netconf-node-topology">1</keepalive-delay>
</node>
-
-Note that the header files must be set to Content-Type: application/xml, Accept: application/xml. There are more options which can be set but for simplicity we keep a short configuration to mount the remote node.
+```
+Note that the header files must be set to Content-Type: application/xml, Accept: application/xml.
- send the operation through the following REST API:
@@ -304,7 +215,9 @@ The body can be used the same as edit-config in netopeer2-cli.
## Connect from Network Services Orchestrator (NSO)
-To connect NSO to the netopeer2-server, first, you need to write a NED package for your device. The procudeure to create NED for hicn is explaned in the following:
+To connect NSO to the netopeer2-server, first, you need to write a NED package
+for your device. The procedure to create NED for hicn is explained in the
+following:
Place hicn.yang model in a folder called hicn-yang-model, and follow these steps:
@@ -323,7 +236,6 @@ Place hicn.yang model in a folder called hicn-yang-model, and follow these steps
At this point, we are able to connect to the remote device.
-
## Release note
-The current version is compatible with the 19.01 VPP stable and sysrepo 0.7.7.
+The current version is compatible with the 19.01 VPP stable and sysrepo 0.7.7. \ No newline at end of file
diff --git a/hicn-light/CMakeLists.txt b/hicn-light/CMakeLists.txt
index 39fce8c1f..a632380fc 100644
--- a/hicn-light/CMakeLists.txt
+++ b/hicn-light/CMakeLists.txt
@@ -40,7 +40,7 @@ else ()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996")
endif ()
-if(ANDROID_API)
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
message("############ Detected cross compile for $ENV{CMAKE_SYSTEM_NAME}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS}")
endif()
@@ -58,7 +58,7 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(HICN_LIGHT_CONTROL ${HICN_LIGHT}-control)
set(HICN_LIGHT_DAEMON ${HICN_LIGHT}-daemon)
else()
- if (ANDROID_API)
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
set(HICN_LIBRARIES ${LIBHICN_STATIC})
list(APPEND DEPENDENCIES
${LIBHICN_STATIC}
@@ -71,7 +71,7 @@ else()
endif ()
endif()
-include( Packaging )
+include(Packaging)
find_package(Threads REQUIRED)
@@ -107,3 +107,10 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
endif()
add_subdirectory(src/hicn)
+
+# Install service file in linux systems
+include(ServiceScript)
+install_service_script(
+ ${CMAKE_CURRENT_SOURCE_DIR}/config/hicn-light.service
+ COMPONENT ${HICN_LIGHT}
+) \ No newline at end of file
diff --git a/hicn-light/src/hicn/CMakeLists.txt b/hicn-light/src/hicn/CMakeLists.txt
index 9129cba17..64b0ff2a0 100644
--- a/hicn-light/src/hicn/CMakeLists.txt
+++ b/hicn-light/src/hicn/CMakeLists.txt
@@ -14,8 +14,7 @@ list(APPEND COMPILER_DEFINITIONS
"-DWITH_POLICY"
)
-
-if(NOT ANDROID_API AND NOT COMPILE_FOR_IOS)
+if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android" AND NOT COMPILE_FOR_IOS)
add_subdirectory(command_line)
endif ()
@@ -43,7 +42,7 @@ list(APPEND TO_INSTALL_HEADER_FILES
${CMAKE_CURRENT_BINARY_DIR}/hicn-light/config.h
)
-if (ANDROID_API)
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
build_library(${LIBHICN_LIGHT}
STATIC
SOURCES ${SOURCE_FILES}
diff --git a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c b/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c
index f704d237e..ab0e0e6d8 100644
--- a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c
+++ b/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c
@@ -63,6 +63,7 @@ static int payloadLengthController[LAST_COMMAND_VALUE] = {
sizeof(add_route_command),
sizeof(list_routes_command), // needed when get response from FWD
sizeof(remove_connection_command),
+ sizeof(remove_listener_command),
sizeof(remove_route_command),
sizeof(cache_store_command),
sizeof(cache_serve_command),
diff --git a/hicn-light/src/hicn/config/CMakeLists.txt b/hicn-light/src/hicn/config/CMakeLists.txt
index b1e475aee..45f36e8ff 100644
--- a/hicn-light/src/hicn/config/CMakeLists.txt
+++ b/hicn-light/src/hicn/config/CMakeLists.txt
@@ -35,6 +35,7 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/controlListPolicies.h
${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.h
${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveListener.h
${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.h
${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.h
${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePolicy.h
@@ -78,6 +79,7 @@ list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/controlListPolicies.c
${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.c
${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveListener.c
${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.c
${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.c
${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePolicy.c
diff --git a/hicn-light/src/hicn/config/configuration.c b/hicn-light/src/hicn/config/configuration.c
index 182c2fdc1..4771c4073 100644
--- a/hicn-light/src/hicn/config/configuration.c
+++ b/hicn-light/src/hicn/config/configuration.c
@@ -346,7 +346,6 @@ static void configuration_SendResponse(Configuration *config, struct iovec *msg,
if (conn == NULL) {
return;
}
-
connection_SendIOVBuffer(conn, msg, 2);
}
@@ -363,30 +362,32 @@ struct iovec *configuration_ProcessCreateTunnel(Configuration *config,
Address *source = NULL;
Address *destination = NULL;
- if (!symbolicNameTable_Exists(config->symbolicNameTable, symbolicName)) {
- if (control->ipType == ADDR_INET) {
- source =
- addressFromInaddr4Port(&control->localIp.ipv4, &control->localPort);
- destination =
- addressFromInaddr4Port(&control->remoteIp.ipv4, &control->remotePort);
- } else if (control->ipType == ADDR_INET6) {
- source =
- addressFromInaddr6Port(&control->localIp.ipv6, &control->localPort);
- destination =
- addressFromInaddr6Port(&control->remoteIp.ipv6, &control->remotePort);
- } else {
- printf("Invalid IP type.\n"); // will generate a Nack
- }
-
- AddressPair *pair = addressPair_Create(source, destination);
- conn = (Connection *)connectionTable_FindByAddressPair(
- forwarder_GetConnectionTable(config->forwarder), pair);
+ if (symbolicNameTable_Exists(config->symbolicNameTable, symbolicName)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+ __func__, "Listener symbolic name already exists");
+ goto ERR;
+ }
- addressPair_Release(&pair);
+ if (control->ipType == ADDR_INET) {
+ source =
+ addressFromInaddr4Port(&control->localIp.ipv4, &control->localPort);
+ destination =
+ addressFromInaddr4Port(&control->remoteIp.ipv4, &control->remotePort);
+ } else if (control->ipType == ADDR_INET6) {
+ source =
+ addressFromInaddr6Port(&control->localIp.ipv6, &control->localPort);
+ destination =
+ addressFromInaddr6Port(&control->remoteIp.ipv6, &control->remotePort);
} else {
- conn = NULL;
+ printf("Invalid IP type.\n"); // will generate a Nack
}
+ AddressPair *pair = addressPair_Create(source, destination);
+ conn = (Connection *)connectionTable_FindByAddressPair(
+ forwarder_GetConnectionTable(config->forwarder), pair);
+
+ addressPair_Release(&pair);
+
if (!conn) {
IoOperations *ops = NULL;
switch (control->connectionType) {
@@ -448,6 +449,10 @@ struct iovec *configuration_ProcessCreateTunnel(Configuration *config,
/* Hook: new connection created through the control protocol */
forwarder_onConnectionEvent(config->forwarder, conn, CONNECTION_EVENT_UPDATE);
#endif /* WITH_MAPME */
+ if (source)
+ addressDestroy(&source);
+ if (destination)
+ addressDestroy(&destination);
success = true;
#else
@@ -460,13 +465,80 @@ struct iovec *configuration_ProcessCreateTunnel(Configuration *config,
if (destination)
addressDestroy(&destination);
+ if (!success)
+ goto ERR;
+
+ // ACK
+ return utils_CreateAck(header, control, sizeof(add_connection_command));
+
+ERR:
+ return utils_CreateNack(header, control, sizeof(add_connection_command));
+}
+
+struct iovec *configuration_ProcessRemoveListener(Configuration *config,
+ struct iovec *request,
+ unsigned ingressId) {
+ header_control_message *header = request[0].iov_base;
+ remove_listener_command *control = request[1].iov_base;
+
+ bool success = false;
+
+ const char *symbolicOrListenerid = control->symbolicOrListenerid;
+ int listenerId = -1;
+ ListenerSet *listenerSet = forwarder_GetListenerSet(config->forwarder);
+ if (utils_IsNumber(symbolicOrListenerid)) {
+ // case for connid as input
+ listenerId = (unsigned)strtold(symbolicOrListenerid, NULL);
+ } else {
+ listenerId = listenerSet_FindIdByListenerName(listenerSet, symbolicOrListenerid);
+ }
+
+ if (listenerId >= 0) {
+
+ ConnectionTable *connTable = forwarder_GetConnectionTable(config->forwarder);
+ ListenerOps *listenerOps = listenerSet_FindById(listenerSet, listenerId);
+ if (listenerOps) {
+ ConnectionList *connectionList =connectionTable_GetEntries(connTable);
+ for (size_t i =0; i < connectionList_Length(connectionList); i++) {
+ Connection *connection = connectionList_Get(connectionList, i);
+ const AddressPair *addressPair = connection_GetAddressPair(connection);
+ const Address *address = addressPair_GetLocal(addressPair);
+ if (addressEquals(listenerOps->getListenAddress(listenerOps),address)) {
+ // case for connid as input
+ unsigned connid = connection_GetConnectionId(connection);
+ // remove connection from the FIB
+ forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid);
+ // remove connection
+ connectionTable_RemoveById(connTable, connid);
+ const char *symbolicConnection = symbolicNameTable_GetNameByIndex(config->symbolicNameTable,connid);
+ symbolicNameTable_Remove(config->symbolicNameTable, symbolicConnection);
+ }
+ }
+ // remove listener
+ listenerSet_RemoveById(listenerSet, listenerId);
+ success = true;
+ } else {
+ logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error, __func__,
+ "Listener Id not found, check list listeners");
+ }
+ }
+
+ // generate ACK/NACK
+ struct iovec *response;
+
if (success) { // ACK
- return utils_CreateAck(header, control, sizeof(add_connection_command));
+ response =
+ utils_CreateAck(header, control, sizeof(remove_listener_command));
} else { // NACK
- return utils_CreateNack(header, control, sizeof(add_connection_command));
+ response =
+ utils_CreateNack(header, control, sizeof(remove_connection_command));
}
+
+ return response;
}
+
/**
* Add an IP-based tunnel.
*
@@ -488,7 +560,6 @@ struct iovec *configuration_ProcessRemoveTunnel(Configuration *config,
const char *symbolicOrConnid = control->symbolicOrConnid;
ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
-
if (strcmp(symbolicOrConnid, "SELF") == 0) {
forwarder_RemoveConnectionIdFromRoutes(config->forwarder, ingressId);
connectionTable_RemoveById(table, ingressId);
@@ -510,6 +581,9 @@ struct iovec *configuration_ProcessRemoveTunnel(Configuration *config,
forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid);
// remove connection
connectionTable_RemoveById(table, connid);
+ // remove connection from symbolicNameTable
+ const char *symbolicConnection = symbolicNameTable_GetNameByIndex(config->symbolicNameTable,connid);
+ symbolicNameTable_Remove(config->symbolicNameTable, symbolicConnection);
#ifdef WITH_MAPME
/* Hook: new connection created through the control protocol */
@@ -563,6 +637,8 @@ struct iovec *configuration_ProcessRemoveTunnel(Configuration *config,
}
}
+
+
// generate ACK/NACK
struct iovec *response;
@@ -577,6 +653,13 @@ struct iovec *configuration_ProcessRemoveTunnel(Configuration *config,
return response;
}
+void _strlwr(char *string) {
+ char *p = string;
+ while ((*p = tolower(*p))) {
+ p++;
+ }
+}
+
struct iovec *configuration_ProcessConnectionList(Configuration *config,
struct iovec *request) {
ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
@@ -600,11 +683,20 @@ struct iovec *configuration_ProcessConnectionList(Configuration *config,
list_connections_command *listConnectionsCommand =
(list_connections_command *)(payloadResponse +
(i * sizeof(list_connections_command)));
-
// set structure fields
+
listConnectionsCommand->connid = connection_GetConnectionId(original);
+
+ const char *connectionName = symbolicNameTable_GetNameByIndex(config->symbolicNameTable, connection_GetConnectionId(original));
+ snprintf(listConnectionsCommand->connectionName, SYMBOLIC_NAME_LEN, "%s", connectionName);
+ _strlwr(listConnectionsCommand->connectionName);
+
+ snprintf(listConnectionsCommand->interfaceName, SYMBOLIC_NAME_LEN, "%s", ioOperations_GetInterfaceName(connection_GetIoOperations(original)));
+
listConnectionsCommand->state =
connection_IsUp(original) ? IFACE_UP : IFACE_DOWN;
+ listConnectionsCommand->admin_state =
+ (connection_GetAdminState(original) == CONNECTION_STATE_UP) ? IFACE_UP : IFACE_DOWN;
listConnectionsCommand->connectionData.connectionType =
ioOperations_GetConnectionType(connection_GetIoOperations(original));
@@ -707,6 +799,14 @@ struct iovec *configuration_ProcessListenersList(Configuration *config,
listListenersCommand->address.ipv6 = tmpAddr6.sin6_addr;
listListenersCommand->port = tmpAddr6.sin6_port;
}
+
+ const char * listenerName = listenerEntry->getListenerName(listenerEntry);
+ snprintf(listListenersCommand->listenerName, SYMBOLIC_NAME_LEN, "%s", listenerName);
+ if (listenerEntry->getEncapType(listenerEntry) == ENCAP_TCP ||
+ listenerEntry->getEncapType(listenerEntry) == ENCAP_UDP) {
+ const char * interfaceName = listenerEntry->getInterfaceName(listenerEntry);
+ snprintf(listListenersCommand->interfaceName, SYMBOLIC_NAME_LEN, "%s", interfaceName);
+ }
}
// send response
@@ -1173,7 +1273,6 @@ struct iovec *configuration_DispatchCommand(Configuration *config,
struct iovec *control,
unsigned ingressId) {
struct iovec *response = NULL;
-
switch (command) {
case ADD_LISTENER:
response = configurationListeners_Add(config, control, ingressId);
@@ -1200,6 +1299,10 @@ struct iovec *configuration_DispatchCommand(Configuration *config,
response = configuration_ProcessRemoveTunnel(config, control, ingressId);
break;
+ case REMOVE_LISTENER:
+ response = configuration_ProcessRemoveListener(config, control, ingressId);
+ break;
+
case REMOVE_ROUTE:
response = configuration_ProcessUnregisterHicnPrefix(config, control);
break;
diff --git a/hicn-light/src/hicn/config/configurationListeners.c b/hicn-light/src/hicn/config/configurationListeners.c
index 97e7dbb87..8abbeb781 100644
--- a/hicn-light/src/hicn/config/configurationListeners.c
+++ b/hicn-light/src/hicn/config/configurationListeners.c
@@ -211,32 +211,21 @@ static bool _addEther(Configuration *config, add_listener_command *control,
return false;
}
-#ifdef __linux__
/*
* Create a new IPV4/TCP listener.
*
* @param [in,out] forwarder The hicn-light forwarder instance
+ * @param [in] listenerName The name of the listener
* @param [in] addr4 The ipv4 address in network byte order
* @param [in] port The port number in network byte order
* @param [in] interfaceName The name of the interface to bind the socket
*
* return true if success, false otherwise
*/
-static bool _setupTcpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
- uint16_t *port, const char *interfaceName) {
-#else
-/*
- * Create a new IPV4/TCP listener.
- *
- * @param [in,out] forwarder The hicn-light forwarder instance
- * @param [in] addr4 The ipv4 address in network byte order
- * @param [in] port The port number in network byte order
- *
- * return true if success, false otherwise
- */
-static bool _setupTcpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
- uint16_t *port) {
-#endif
+static bool _setupTcpListenerOnInet(Forwarder *forwarder, char *listenerName, ipv4_addr_t *addr4,
+ uint16_t *port, char *interfaceName) {
+ parcAssertNotNull(listenerName, "Parameter listenerName must be non-null");
+
bool success = false;
struct sockaddr_in addr;
@@ -245,42 +234,31 @@ static bool _setupTcpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
addr.sin_port = *port;
addr.sin_addr.s_addr = *addr4;
- ListenerOps *ops = tcpListener_CreateInet(forwarder, addr);
+ ListenerOps *ops = tcpListener_CreateInet(forwarder, listenerName, addr, interfaceName);
if (ops) {
success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+#if 0
parcAssertTrue(success, "Failed to add TCP listener on %s to ListenerSet",
addressToString(ops->getListenAddress(ops)));
+#endif
}
return success;
}
-#ifdef __linux__
/*
* Create a new IPV4/UDP listener.
*
* @param [in,out] forwarder The hicn-light forwarder instance
+ * @param [in] listenerName The name of the listener
* @param [in] addr4 The ipv4 address in network byte order
* @param [in] port The port number in network byte order
* @param [in] interfaceName The name of the interface to bind the socket
*
* return true if success, false otherwise
*/
-static bool _setupUdpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
+static bool _setupUdpListenerOnInet(Forwarder *forwarder, char *listenerName, ipv4_addr_t *addr4,
uint16_t *port, char *interfaceName) {
-#else
-/*
- * Create a new IPV4/UDP listener.
- *
- * @param [in,out] forwarder The hicn-light forwarder instance
- * @param [in] addr4 The ipv4 address in network byte order
- * @param [in] port The port number in network byte order
- *
- * return true if success, false otherwise
- */
-static bool _setupUdpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
- uint16_t *port) {
-#endif
bool success = false;
struct sockaddr_in addr;
@@ -289,21 +267,18 @@ static bool _setupUdpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
addr.sin_port = *port;
addr.sin_addr.s_addr = *addr4;
-#ifdef __linux__
- ListenerOps *ops = udpListener_CreateInet(forwarder, addr, interfaceName);
-#else
- ListenerOps *ops = udpListener_CreateInet(forwarder, addr);
-#endif
+ ListenerOps *ops = udpListener_CreateInet(forwarder, listenerName, addr, interfaceName);
if (ops) {
success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+#if 0
parcAssertTrue(success, "Failed to add UDP listener on %s to ListenerSet",
addressToString(ops->getListenAddress(ops)));
+#endif
}
return success;
}
-#ifdef __linux__
/*
* Create a new IPV6/TCP listener.
*
@@ -314,23 +289,9 @@ static bool _setupUdpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
*
* return true if success, false otherwise
*/
-static bool _setupTcpListenerOnInet6Light(Forwarder *forwarder,
+static bool _setupTcpListenerOnInet6Light(Forwarder *forwarder, char *listenerName,
ipv6_addr_t *addr6, uint16_t *port, char *interfaceName,
uint32_t scopeId) {
-#else
-/*
- * Create a new IPV6/TCP listener.
- *
- * @param [in,out] forwarder The hicn-light forwarder instance
- * @param [in] addr6 The ipv6 address in network byte order
- * @param [in] port The port number in network byte order
- *
- * return true if success, false otherwise
- */
-static bool _setupTcpListenerOnInet6Light(Forwarder *forwarder,
- ipv6_addr_t *addr6, uint16_t *port,
- uint32_t scopeId) {
-#endif
bool success = false;
struct sockaddr_in6 addr;
@@ -340,42 +301,31 @@ static bool _setupTcpListenerOnInet6Light(Forwarder *forwarder,
addr.sin6_addr = *addr6;
addr.sin6_scope_id = scopeId;
- ListenerOps *ops = tcpListener_CreateInet6(forwarder, addr);
+ ListenerOps *ops = tcpListener_CreateInet6(forwarder, listenerName, addr, interfaceName);
if (ops) {
success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+#if 0
parcAssertTrue(success, "Failed to add TCP6 listener on %s to ListenerSet",
addressToString(ops->getListenAddress(ops)));
+#endif
}
return success;
}
-#ifdef __linux__
/*
* Create a new IPV6/UDP listener.
*
* @param [in,out] forwarder The hicn-light forwarder instance
+ * @param [in] listenerName The name of the listener
* @param [in] addr6 The ipv6 address in network byte order
* @param [in] port The port number in network byte order
* @param [in] interfaceName The name of the interface to bind the socket
*
* return true if success, false otherwise
*/
-static bool _setupUdpListenerOnInet6Light(Forwarder *forwarder,
+static bool _setupUdpListenerOnInet6Light(Forwarder *forwarder, char *listenerName,
ipv6_addr_t *addr6, uint16_t *port, char *interfaceName) {
-#else
-/*
- * Create a new IPV6/UDP listener.
- *
- * @param [in,out] forwarder The hicn-light forwarder instance
- * @param [in] addr6 The ipv6 address in network byte order
- * @param [in] port The port number in network byte order
- *
- * return true if success, false otherwise
- */
-static bool _setupUdpListenerOnInet6Light(Forwarder *forwarder,
- ipv6_addr_t *addr6, uint16_t *port) {
-#endif
bool success = false;
struct sockaddr_in6 addr;
@@ -385,15 +335,13 @@ static bool _setupUdpListenerOnInet6Light(Forwarder *forwarder,
addr.sin6_addr = *addr6;
addr.sin6_scope_id = 0;
-#ifdef __linux__
- ListenerOps *ops = udpListener_CreateInet6(forwarder, addr, interfaceName);
-#else
- ListenerOps *ops = udpListener_CreateInet6(forwarder, addr);
-#endif
+ ListenerOps *ops = udpListener_CreateInet6(forwarder, listenerName, addr, interfaceName);
if (ops) {
success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+#if 0
parcAssertTrue(success, "Failed to add UDP6 listener on %s to ListenerSet",
addressToString(ops->getListenAddress(ops)));
+#endif
}
return success;
}
@@ -460,56 +408,33 @@ bool _addHicn(Configuration *config, add_listener_command *control,
bool _addIP(Configuration *config, add_listener_command *control,
unsigned ingressId) {
bool success = false;
+ char *symbolic = control->symbolic;
switch (control->addressType) {
case ADDR_INET: {
-#ifdef __linux__
if (control->connectionType == UDP_CONN) {
success =
- _setupUdpListenerOnInet(configuration_GetForwarder(config),
+ _setupUdpListenerOnInet(configuration_GetForwarder(config), symbolic,
&control->address.ipv4, &control->port, control->interfaceName);
} else if (control->connectionType == TCP_CONN) {
success =
- _setupTcpListenerOnInet(configuration_GetForwarder(config),
+ _setupTcpListenerOnInet(configuration_GetForwarder(config), symbolic,
&control->address.ipv4, &control->port, control->interfaceName);
}
-#else
- if (control->connectionType == UDP_CONN) {
- success =
- _setupUdpListenerOnInet(configuration_GetForwarder(config),
- &control->address.ipv4, &control->port);
- } else if (control->connectionType == TCP_CONN) {
- success =
- _setupTcpListenerOnInet(configuration_GetForwarder(config),
- &control->address.ipv4, &control->port);
- }
-#endif
break;
}
case ADDR_INET6: {
-#ifdef __linux__
if (control->connectionType == UDP_CONN) {
success = _setupUdpListenerOnInet6Light(
- configuration_GetForwarder(config), &control->address.ipv6,
+ configuration_GetForwarder(config), symbolic, &control->address.ipv6,
&control->port, control->interfaceName);
} else if (control->connectionType == TCP_CONN) {
success = _setupTcpListenerOnInet6Light(
- configuration_GetForwarder(config), &control->address.ipv6,
+ configuration_GetForwarder(config), symbolic, &control->address.ipv6,
&control->port, control->interfaceName, 0);
}
-#else
- if (control->connectionType == UDP_CONN) {
- success = _setupUdpListenerOnInet6Light(
- configuration_GetForwarder(config), &control->address.ipv6,
- &control->port);
- } else if (control->connectionType == TCP_CONN) {
- success = _setupTcpListenerOnInet6Light(
- configuration_GetForwarder(config), &control->address.ipv6,
- &control->port, 0);
- }
-#endif
break;
}
@@ -551,20 +476,25 @@ struct iovec *configurationListeners_Add(Configuration *config,
bool success = false;
- if (control->listenerMode == ETHER_MODE) {
- parcTrapNotImplemented("Add Ethernet Listener is not supported");
- success = _addEther(config, control, ingressId);
- // it is a failure
- } else if (control->listenerMode == IP_MODE) {
- success = _addIP(config, control, ingressId);
- } else if (control->listenerMode == HICN_MODE) {
- success = _addHicn(config, control, ingressId);
- } else {
- Logger *logger = configuration_GetLogger(config);
- if (logger_IsLoggable(logger, LoggerFacility_Config,
- PARCLogLevel_Warning)) {
- logger_Log(logger, LoggerFacility_Config, PARCLogLevel_Warning, __func__,
- "Unsupported encapsulation mode (ingress id %u)", ingressId);
+ ListenerSet *listenerSet = forwarder_GetListenerSet(configuration_GetForwarder(config));
+ int listenerId = listenerSet_FindIdByListenerName(listenerSet, control->symbolic);
+
+ if (listenerId < 0) {
+ if (control->listenerMode == ETHER_MODE) {
+ parcTrapNotImplemented("Add Ethernet Listener is not supported");
+ success = _addEther(config, control, ingressId);
+ // it is a failure
+ } else if (control->listenerMode == IP_MODE) {
+ success = _addIP(config, control, ingressId);
+ } else if (control->listenerMode == HICN_MODE) {
+ success = _addHicn(config, control, ingressId);
+ } else {
+ Logger *logger = configuration_GetLogger(config);
+ if (logger_IsLoggable(logger, LoggerFacility_Config,
+ PARCLogLevel_Warning)) {
+ logger_Log(logger, LoggerFacility_Config, PARCLogLevel_Warning, __func__,
+ "Unsupported encapsulation mode (ingress id %u)", ingressId);
+ }
}
}
@@ -619,7 +549,7 @@ struct iovec *configurationListeners_AddPunting(Configuration *config,
//=========================== INITIAL LISTENERS ====================
-static void _setupListenersOnAddress(Forwarder *forwarder,
+static void _setupListenersOnAddress(Forwarder *forwarder, char *listenerName,
const Address *address, uint16_t port,
char *interfaceName) {
address_type type = addressGetType(address);
@@ -627,24 +557,15 @@ static void _setupListenersOnAddress(Forwarder *forwarder,
case ADDR_INET: {
struct sockaddr_in tmp;
addressGetInet(address, &tmp);
-#ifdef __linux__
- _setupTcpListenerOnInet(forwarder, &tmp.sin_addr.s_addr, &port, interfaceName);
-#else
- _setupTcpListenerOnInet(forwarder, &tmp.sin_addr.s_addr, &port);
-#endif
+ _setupTcpListenerOnInet(forwarder, listenerName, &tmp.sin_addr.s_addr, &port, interfaceName);
break;
}
case ADDR_INET6: {
struct sockaddr_in6 tmp;
addressGetInet6(address, &tmp);
-#ifdef __linux__
- _setupTcpListenerOnInet6Light(forwarder, &tmp.sin6_addr, &port, interfaceName,
+ _setupTcpListenerOnInet6Light(forwarder, listenerName, &tmp.sin6_addr, &port, interfaceName,
tmp.sin6_scope_id);
-#else
- _setupTcpListenerOnInet6Light(forwarder, &tmp.sin6_addr, &port,
- tmp.sin6_scope_id);
-#endif
break;
}
@@ -674,8 +595,14 @@ void configurationListeners_SetupAll(const Configuration *config, uint16_t port,
const Address *address = addressListGetItem(addresses, j);
// Do not start on link address
+ char listenerName[SYMBOLIC_NAME_LEN];
+#ifdef __ANDROID__
+ snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%zu", i);
+#else
+ snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%ld", i);
+#endif
if (addressGetType(address) != ADDR_LINK) {
- _setupListenersOnAddress(forwarder, address, port,
+ _setupListenersOnAddress(forwarder, listenerName, address, port,
(char *)interfaceGetName(iface));
}
}
@@ -689,16 +616,12 @@ void configurationListeners_SetutpLocalIPv4(const Configuration *config,
Forwarder *forwarder = configuration_GetForwarder(config);
in_addr_t addr = inet_addr("127.0.0.1");
uint16_t network_byte_order_port = htons(port);
-#ifdef __linux__
+
+ char listenerNameUdp[SYMBOLIC_NAME_LEN] = "lo_udp";
+ char listenerNameTcp[SYMBOLIC_NAME_LEN] = "lo_tcp";
char *loopback_interface = "lo";
- _setupUdpListenerOnInet(forwarder, (ipv4_addr_t *)&(addr),
+ _setupUdpListenerOnInet(forwarder, listenerNameUdp,(ipv4_addr_t *)&(addr),
&network_byte_order_port, loopback_interface);
- _setupTcpListenerOnInet(forwarder, (ipv4_addr_t *)&(addr),
+ _setupTcpListenerOnInet(forwarder, listenerNameTcp, (ipv4_addr_t *)&(addr),
&network_byte_order_port, loopback_interface);
-#else
- _setupUdpListenerOnInet(forwarder, (ipv4_addr_t *)&(addr),
- &network_byte_order_port);
- _setupTcpListenerOnInet(forwarder, (ipv4_addr_t *)&(addr),
- &network_byte_order_port);
-#endif
}
diff --git a/hicn-light/src/hicn/config/controlAddConnection.c b/hicn-light/src/hicn/config/controlAddConnection.c
index e09b61b37..eaa680bde 100644
--- a/hicn-light/src/hicn/config/controlAddConnection.c
+++ b/hicn-light/src/hicn/config/controlAddConnection.c
@@ -42,11 +42,13 @@ static CommandReturn _controlAddConnection_Execute(CommandParser *parser,
// ===================================================
+#ifdef __linux__
static CommandReturn _controlAddConnection_HicnHelpExecute(
CommandParser *parser, CommandOps *ops, PARCList *args);
static CommandReturn _controlAddConnection_HicnExecute(CommandParser *parser,
CommandOps *ops,
PARCList *args);
+#endif
static CommandReturn _controlAddConnection_UdpHelpExecute(CommandParser *parser,
CommandOps *ops,
@@ -65,11 +67,15 @@ static CommandReturn _controlAddConnection_TcpExecute(CommandParser *parser,
// ===================================================
static const char *_commandAddConnection = "add connection";
+#ifdef __linux__
static const char *_commandAddConnectionHicn = "add connection hicn";
+#endif
static const char *_commandAddConnectionUdp = "add connection udp";
static const char *_commandAddConnectionTcp = "add connection tcp";
static const char *_commandAddConnectionHelp = "help add connection";
+#ifdef __linux__
static const char *_commandAddConnectionHicnHelp = "help add connection hicn";
+#endif
static const char *_commandAddConnectionUdpHelp = "help add connection udp";
static const char *_commandAddConnectionTcpHelp = "help add connection tcp";
@@ -89,11 +95,13 @@ CommandOps *controlAddConnection_HelpCreate(ControlState *state) {
// ===================================================
+#ifdef __linux__
static CommandOps *_controlAddConnection_HicnCreate(ControlState *state) {
return commandOps_Create(state, _commandAddConnectionHicn, NULL,
_controlAddConnection_HicnExecute,
commandOps_Destroy);
}
+#endif
static CommandOps *_controlAddConnection_UdpCreate(ControlState *state) {
return commandOps_Create(state, _commandAddConnectionUdp, NULL,
@@ -108,12 +116,13 @@ static CommandOps *_controlAddConnection_TcpCreate(ControlState *state) {
}
// ===================================================
-
+#ifdef __linux__
static CommandOps *_controlAddConnection_HicnHelpCreate(ControlState *state) {
return commandOps_Create(state, _commandAddConnectionHicnHelp, NULL,
_controlAddConnection_HicnHelpExecute,
commandOps_Destroy);
}
+#endif
static CommandOps *_controlAddConnection_UdpHelpCreate(ControlState *state) {
return commandOps_Create(state, _commandAddConnectionUdpHelp, NULL,
@@ -133,7 +142,9 @@ static CommandReturn _controlAddConnection_HelpExecute(CommandParser *parser,
CommandOps *ops,
PARCList *args) {
printf("Available commands:\n");
+#ifdef __linux__
printf(" %s\n", _commandAddConnectionHicn);
+#endif
printf(" %s\n", _commandAddConnectionUdp);
printf(" %s\n", _commandAddConnectionTcp);
printf("\n");
@@ -142,14 +153,17 @@ static CommandReturn _controlAddConnection_HelpExecute(CommandParser *parser,
static void _controlAddConnection_Init(CommandParser *parser, CommandOps *ops) {
ControlState *state = ops->closure;
+#ifdef __linux__
controlState_RegisterCommand(state,
_controlAddConnection_HicnHelpCreate(state));
+#endif
controlState_RegisterCommand(state,
_controlAddConnection_UdpHelpCreate(state));
controlState_RegisterCommand(state,
_controlAddConnection_TcpHelpCreate(state));
-
+#ifdef __linux__
controlState_RegisterCommand(state, _controlAddConnection_HicnCreate(state));
+#endif
controlState_RegisterCommand(state, _controlAddConnection_UdpCreate(state));
controlState_RegisterCommand(state, _controlAddConnection_TcpCreate(state));
}
@@ -255,7 +269,9 @@ static CommandReturn _controlAddConnection_IpHelp(CommandParser *parser,
CommandOps *ops,
PARCList *args,
const char *protocol) {
+#ifdef __linux__
printf("add connection hicn <symbolic> <remote_ip> <local_ip>\n");
+#endif
printf(
"add connection udp <symbolic> <remote_ip> <port> <local_ip> <port>\n");
printf(
@@ -268,6 +284,7 @@ static CommandReturn _controlAddConnection_IpHelp(CommandParser *parser,
return CommandReturn_Success;
}
+#ifdef __linux__
static CommandReturn _controlAddConnection_HicnHelpExecute(
CommandParser *parser, CommandOps *ops, PARCList *args) {
_controlAddConnection_IpHelp(parser, ops, args, "hicn");
@@ -303,6 +320,7 @@ static CommandReturn _controlAddConnection_HicnExecute(CommandParser *parser,
return _controlAddConnection_CreateTunnel(
parser, ops, local_ip, port, remote_ip, port, HICN_CONN, symbolic);
}
+#endif
static CommandReturn _controlAddConnection_UdpHelpExecute(CommandParser *parser,
CommandOps *ops,
diff --git a/hicn-light/src/hicn/config/controlAddListener.c b/hicn-light/src/hicn/config/controlAddListener.c
index c9253425a..1a94ff252 100644
--- a/hicn-light/src/hicn/config/controlAddListener.c
+++ b/hicn-light/src/hicn/config/controlAddListener.c
@@ -58,27 +58,26 @@ static const int _indexProtocol = 2;
static const int _indexSymbolic = 3;
static const int _indexAddress = 4;
static const int _indexPort = 5;
-#ifdef __linux__
static const int _indexInterfaceName = 6;
-#endif
static CommandReturn _controlAddListener_HelpExecute(CommandParser *parser,
CommandOps *ops,
PARCList *args) {
printf("commands:\n");
- printf(" add listener hicn <symbolic> <localAddress> \n");
#ifdef __linux__
+ printf(" add listener hicn <symbolic> <localAddress> \n");
+#endif
printf(" add listener udp <symbolic> <localAddress> <port> <interface>\n");
printf(" add listener tcp <symbolic> <localAddress> <port> <interface>\n");
-#else
- printf(" add listener udp <symbolic> <localAddress> <port>\n");
- printf(" add listener tcp <symbolic> <localAddress> <port>\n");
-#endif
printf("\n");
printf(
" symbolic: User defined name for listener, must start with "
"alpha and be alphanum\n");
+#ifdef __linux__
printf(" protocol: hicn | udp\n");
+#else
+ printf(" protocol: udp\n");
+#endif
printf(
" localAddress: IPv4 or IPv6 address (or prefix protocol = hicn) "
"assigend to the local interface\n");
@@ -88,23 +87,18 @@ static CommandReturn _controlAddListener_HelpExecute(CommandParser *parser,
printf("\n");
printf("Notes:\n");
printf(" The symblic name must be unique or the source will reject it.\n");
+#ifdef __linux__
printf(
- " If protocol = hinc: the address 0::0 indicates the main listern, "
+ " If protocol = hicn: the address 0::0 indicates the main listern, "
"for which we can set punting rules.\n");
+#endif
return CommandReturn_Success;
}
-#ifdef __linux__
-static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops,
- const char *symbolic, const char *addr,
- const char *port, const char *interfaceName, listener_mode mode,
- connection_type type) {
-#else
static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops,
const char *symbolic, const char *addr,
- const char *port, listener_mode mode,
+ const char *port, char *interfaceName, listener_mode mode,
connection_type type) {
-#endif
ControlState *state = ops->closure;
// allocate command payload
@@ -126,9 +120,7 @@ static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops,
}
// Fill remaining payload fields
-#ifdef __linux__
- memcpy(addListenerCommand->interfaceName, interfaceName, 16);
-#endif
+ memcpy(addListenerCommand->interfaceName, interfaceName, SYMBOLIC_NAME_LEN);
addListenerCommand->listenerMode = mode;
addListenerCommand->connectionType = type;
addListenerCommand->port = htons((uint16_t)atoi(port));
@@ -149,11 +141,7 @@ static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops,
static CommandReturn _controlAddListener_Execute(CommandParser *parser,
CommandOps *ops,
PARCList *args) {
-#ifdef __linux__
if (parcList_Size(args) != 5 && parcList_Size(args) != 7) {
-#else
- if (parcList_Size(args) != 5 && parcList_Size(args) != 6) {
-#endif
_controlAddListener_HelpExecute(parser, ops, args);
return CommandReturn_Failure;
}
@@ -169,45 +157,26 @@ static CommandReturn _controlAddListener_Execute(CommandParser *parser,
return result;
}
- const char *host = parcList_GetAtIndex(args, _indexAddress);
-#ifdef __linux__
- const char *interfaceName = parcList_GetAtIndex(args, _indexInterfaceName);
-#endif
const char *protocol = parcList_GetAtIndex(args, _indexProtocol);
-
+ const char *host = parcList_GetAtIndex(args, _indexAddress);
+ char *interfaceName = parcList_GetAtIndex(args, _indexInterfaceName);
if ((strcasecmp("hicn", protocol) == 0)) {
const char *port =
"1234"; // this is a random port number that will be ignored
// here we discard the prefix len if it exists, since we don't use it in
// code but we let libhicn to find the right ip address.
-#ifdef __linux__
return _CreateListener(parser, ops, symbolic, host, port, "hicn", HICN_MODE,
HICN_CONN);
-#else
- return _CreateListener(parser, ops, symbolic, host, port, HICN_MODE,
- HICN_CONN);
-#endif
}
-
const char *port = parcList_GetAtIndex(args, _indexPort);
if ((strcasecmp("udp", protocol) == 0)) {
-#ifdef __linux__
return _CreateListener(parser, ops, symbolic, host, port, interfaceName, IP_MODE,
UDP_CONN);
-#else
- return _CreateListener(parser, ops, symbolic, host, port, IP_MODE,
- UDP_CONN);
-#endif
} else if ((strcasecmp("tcp", protocol) == 0)) {
-#ifdef __linux__
return _CreateListener(parser, ops, symbolic, host, port, interfaceName, IP_MODE,
TCP_CONN);
-#else
- return _CreateListener(parser, ops, symbolic, host, port, IP_MODE,
- TCP_CONN);
-#endif
} else {
_controlAddListener_HelpExecute(parser, ops, args);
return CommandReturn_Failure;
diff --git a/hicn-light/src/hicn/config/controlListConnections.c b/hicn-light/src/hicn/config/controlListConnections.c
index 0eb6392ea..0e8e2c30b 100644
--- a/hicn-light/src/hicn/config/controlListConnections.c
+++ b/hicn-light/src/hicn/config/controlListConnections.c
@@ -83,7 +83,7 @@ static CommandReturn _controlListConnections_Execute(CommandParser *parser,
return CommandReturn_Failure;
}
#ifdef WITH_POLICY
- char flags_str[POLICY_TAG_N];
+ char flags_str[POLICY_TAG_N+1];
char *s;
#endif /* WITH_POLICY */
@@ -113,7 +113,14 @@ static CommandReturn _controlListConnections_Execute(CommandParser *parser,
}
}
+#ifdef WITH_POLICY
+ printf("%5s %10s %12s %6s %40s %40s %5s %s\n", "id", "name", "admin_state", "state", "source", "destination", "type", "flags");
+#else
+ printf("%5s %10s %12s %6s %40s %40s %5s\n", "id", "name", "admin_state", "state", "source", "destination", "type");
+#endif /* WITH_POLICY */
+
// Process/Print payload
+
for (int i = 0; i < receivedHeader->length; i++) {
list_connections_command *listConnectionsCommand =
(list_connections_command *)(receivedPayload +
@@ -140,7 +147,8 @@ foreach_policy_tag
*s = '\0';
parcBufferComposer_Format(
- composer, "%5d %4s %s %s %s [%s]", listConnectionsCommand->connid,
+ composer, "%5d %10s %12s %6s %40s %40s %5s [%s]", listConnectionsCommand->connid, listConnectionsCommand->connectionName,
+ stateString[listConnectionsCommand->admin_state],
stateString[listConnectionsCommand->state], sourceString,
destinationString,
connTypeString[listConnectionsCommand->connectionData.connectionType],
@@ -148,7 +156,8 @@ foreach_policy_tag
#else
parcBufferComposer_Format(
- composer, "%5d %4s %s %s %s", listConnectionsCommand->connid,
+ composer, "%5d %10s %12s %6s %40s %40s %5s", listConnectionsCommand->connid, listConnectionsCommand->connectionName,
+ stateString[listConnectionsCommand->admin_state],
stateString[listConnectionsCommand->state], sourceString,
destinationString,
connTypeString[listConnectionsCommand->connectionData.connectionType]);
diff --git a/hicn-light/src/hicn/config/controlListListeners.c b/hicn-light/src/hicn/config/controlListListeners.c
index 1f4ad7f2c..1489470a8 100644
--- a/hicn-light/src/hicn/config/controlListListeners.c
+++ b/hicn-light/src/hicn/config/controlListListeners.c
@@ -95,7 +95,8 @@ static CommandReturn _controlListListeners_Execute(CommandParser *parser,
char *addrString = NULL;
if (receivedHeader->length > 0) {
- printf("%6.6s %50.70s %s\n", "iface", "address", "type");
+ printf("%6.6s %.*s %50.70s %6s %10s\n", "iface", SYMBOLIC_NAME_LEN, "name", "address", "type", "interface");
+
} else {
printf(" --- No entry in the list \n");
}
@@ -111,16 +112,28 @@ static CommandReturn _controlListListeners_Execute(CommandParser *parser,
PARCBufferComposer *composer = parcBufferComposer_Create();
- parcBufferComposer_Format(composer, "%6u %50.70s %3s",
- listListenersCommand->connid, addrString,
- listenerType[listListenersCommand->encapType]);
+ if (strcmp(listenerType[listListenersCommand->encapType], "UDP") == 0 ||
+ strcmp(listenerType[listListenersCommand->encapType], "TCP") == 0) {
+ parcBufferComposer_Format(composer, "%6u %.*s %50.70s %6s %10s",
+ listListenersCommand->connid,
+ SYMBOLIC_NAME_LEN, listListenersCommand->listenerName,
+ addrString,
+ listenerType[listListenersCommand->encapType],
+ listListenersCommand->interfaceName);
+ } else {
+ parcBufferComposer_Format(composer, "%6u %.*s %50.70s %6s",
+ listListenersCommand->connid,
+ SYMBOLIC_NAME_LEN, listListenersCommand->listenerName,
+ addrString,
+ listenerType[listListenersCommand->encapType]);
+ }
PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
char *result = parcBuffer_ToString(tempBuffer);
parcBuffer_Release(&tempBuffer);
if (!controlState_IsInteractive(state)) {
- strcpy(commandOutputMain[i], result);
+ strncpy(commandOutputMain[i], result, 128);
}
puts(result);
diff --git a/hicn-light/src/hicn/config/controlRemove.c b/hicn-light/src/hicn/config/controlRemove.c
index af833dc8b..ef0c15934 100644
--- a/hicn-light/src/hicn/config/controlRemove.c
+++ b/hicn-light/src/hicn/config/controlRemove.c
@@ -27,6 +27,7 @@
#include <parc/algol/parc_Memory.h>
#include <hicn/config/controlRemove.h>
+#include <hicn/config/controlRemoveListener.h>
#include <hicn/config/controlRemoveConnection.h>
#include <hicn/config/controlRemovePunting.h>
#include <hicn/config/controlRemoveRoute.h>
@@ -62,6 +63,7 @@ static CommandReturn _controlRemove_HelpExecute(CommandParser *parser,
CommandOps *ops,
PARCList *args) {
CommandOps *ops_remove_connection = controlRemoveConnection_Create(NULL);
+ CommandOps *ops_remove_listener = controlRemoveListener_Create(NULL);
CommandOps *ops_remove_route = controlRemoveRoute_Create(NULL);
CommandOps *ops_remove_punting = controlRemovePunting_Create(NULL);
#ifdef WITH_POLICY
@@ -70,6 +72,7 @@ static CommandReturn _controlRemove_HelpExecute(CommandParser *parser,
printf("Available commands:\n");
printf(" %s\n", ops_remove_connection->command);
+ printf(" %s\n", ops_remove_listener->command);
printf(" %s\n", ops_remove_route->command);
printf(" %s\n", ops_remove_punting->command);
#ifdef WITH_POLICY
@@ -78,6 +81,7 @@ static CommandReturn _controlRemove_HelpExecute(CommandParser *parser,
printf("\n");
commandOps_Destroy(&ops_remove_connection);
+ commandOps_Destroy(&ops_remove_listener);
commandOps_Destroy(&ops_remove_route);
commandOps_Destroy(&ops_remove_punting);
#ifdef WITH_POLICY
@@ -90,8 +94,11 @@ static void _controlRemove_Init(CommandParser *parser, CommandOps *ops) {
ControlState *state = ops->closure;
controlState_RegisterCommand(state,
controlRemoveConnection_HelpCreate(state));
+ controlState_RegisterCommand(state,
+ controlRemoveListener_HelpCreate(state));
controlState_RegisterCommand(state, controlRemoveRoute_HelpCreate(state));
controlState_RegisterCommand(state, controlRemoveConnection_Create(state));
+ controlState_RegisterCommand(state, controlRemoveListener_Create(state));
controlState_RegisterCommand(state, controlRemoveRoute_Create(state));
controlState_RegisterCommand(state, controlRemovePunting_Create(state));
controlState_RegisterCommand(state, controlRemovePunting_HelpCreate(state));
diff --git a/hicn-light/src/hicn/config/controlRemoveListener.c b/hicn-light/src/hicn/config/controlRemoveListener.c
new file mode 100644
index 000000000..545e189c0
--- /dev/null
+++ b/hicn-light/src/hicn/config/controlRemoveListener.c
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#include <hicn/hicn-light/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <hicn/utils/address.h>
+
+#include <hicn/config/controlRemoveListener.h>
+
+#include <hicn/utils/commands.h>
+#include <hicn/utils/utils.h>
+
+static CommandReturn _controlRemoveListener_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlRemoveListener_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+// ===================================================
+
+static const char *_commandRemoveListener = "remove listener";
+static const char *_commandRemoveListenerHelp = "help remove listener";
+
+// ====================================================
+
+CommandOps *controlRemoveListener_Create(ControlState *state) {
+ return commandOps_Create(state, _commandRemoveListener, NULL,
+ _controlRemoveListener_Execute,
+ commandOps_Destroy);
+}
+
+CommandOps *controlRemoveListener_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandRemoveListenerHelp, NULL,
+ _controlRemoveListener_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlRemoveListener_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("command:\n");
+ printf(" remove listener <symbolic|id>\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlRemoveListener_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ ControlState *state = ops->closure;
+
+ if (parcList_Size(args) != 3) {
+ _controlRemoveListener_HelpExecute(parser, ops, args);
+ return false;
+ }
+
+ if ((strcmp(parcList_GetAtIndex(args, 0), "remove") != 0) ||
+ (strcmp(parcList_GetAtIndex(args, 1), "listener") != 0)) {
+ _controlRemoveListener_HelpExecute(parser, ops, args);
+ return false;
+ }
+
+ const char *listenerId = parcList_GetAtIndex(args, 2);
+
+if (!utils_ValidateSymbolicName(listenerId) &&
+ !utils_IsNumber(listenerId)) {
+ printf(
+ "ERROR: Invalid symbolic or listenerId:\nsymbolic name must begin with an "
+ "alpha followed by alphanum;\nlistenerId must be an integer\n");
+ return CommandReturn_Failure;
+ }
+
+ // allocate command payload
+ remove_listener_command *removeListenerCommand =
+ parcMemory_AllocateAndClear(sizeof(remove_listener_command));
+ // fill payload
+ //removeListenerCommand->listenerId = atoi(listenerId);
+ snprintf(removeListenerCommand->symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%s", listenerId);
+
+ // send message and receive response
+ struct iovec *response =
+ utils_SendRequest(state, REMOVE_LISTENER, removeListenerCommand,
+ sizeof(remove_listener_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/ctrl/facemgr/src/face_rules.h b/hicn-light/src/hicn/config/controlRemoveListener.h
index 28f5391a0..794d1e1a9 100644
--- a/ctrl/facemgr/src/face_rules.h
+++ b/hicn-light/src/hicn/config/controlRemoveListener.h
@@ -13,19 +13,19 @@
* limitations under the License.
*/
-#ifndef FACE_RULES_H
-#define FACE_RULES_H
-
-#include "util/map.h"
-#include "util/policy.h"
-
-/*
- * Face creation rules
+/**
+ * @file control_RemoveConnection.h
+ * @brief Remove a connection from the connection table
+ *
+ * Implements the "remove connection" and "help remove connection" nodes of the
+ * CLI tree
*
- * For now, face creations rules are very simple and consist in a map between
- * the physical interface name, and the associated list of tags that will
- * preempt those assigned by the system.
*/
-TYPEDEF_MAP_H(face_rules, const char *, policy_tags_t);
-#endif /* FACE_RULES_H */
+#ifndef Control_RemoveListener_h
+#define Control_RemoveListener_h
+
+#include <hicn/config/controlState.h>
+CommandOps *controlRemoveListener_Create(ControlState *state);
+CommandOps *controlRemoveListener_HelpCreate(ControlState *state);
+#endif // Control_RemoveListener_h
diff --git a/hicn-light/src/hicn/config/controlUpdateConnection.c b/hicn-light/src/hicn/config/controlUpdateConnection.c
index 3e573d41d..ff834522e 100644
--- a/hicn-light/src/hicn/config/controlUpdateConnection.c
+++ b/hicn-light/src/hicn/config/controlUpdateConnection.c
@@ -31,9 +31,9 @@
#include <hicn/config/controlUpdateConnection.h>
+#include <hicn/policy.h>
#include <hicn/utils/commands.h>
#include <hicn/utils/utils.h>
-#include <hicn/utils/policy.h>
static CommandReturn _controlUpdateConnection_Execute(CommandParser *parser,
CommandOps *ops,
diff --git a/hicn-light/src/hicn/config/symbolicNameTable.c b/hicn-light/src/hicn/config/symbolicNameTable.c
index 746c4e647..723039fae 100644
--- a/hicn-light/src/hicn/config/symbolicNameTable.c
+++ b/hicn-light/src/hicn/config/symbolicNameTable.c
@@ -127,19 +127,36 @@ bool symbolicNameTable_Add(SymbolicNameTable *table, const char *symbolicName,
parcAssertTrue(connid < UINT32_MAX, "Parameter connid must be less than %u",
UINT32_MAX);
- char *key = _createKey(symbolicName);
+ char *key1 = _createKey(symbolicName);
- uint32_t *value = parcMemory_Allocate(sizeof(uint32_t));
- *value = connid;
+ uint32_t *value1 = parcMemory_Allocate(sizeof(uint32_t));
+ *value1 = connid;
- bool success = parcHashCodeTable_Add(table->symbolicNameTable, key, value);
- success = parcHashCodeTable_Add(table->indexToNameTable, value, key);
- if (!success) {
- parcMemory_Deallocate((void **)&key);
- parcMemory_Deallocate((void **)&value);
- }
+ bool success = parcHashCodeTable_Add(table->symbolicNameTable, key1, value1);
+ if (!success)
+ goto ERR_NAME;
+
+ char *key2 = _createKey(symbolicName);
+
+ uint32_t *value2 = parcMemory_Allocate(sizeof(uint32_t));
+ *value2 = connid;
+ success = parcHashCodeTable_Add(table->indexToNameTable, value2, key2);
+ if (!success)
+ goto ERR_INDEX;
+
+ goto END;
+
+ERR_INDEX:
+ parcMemory_Deallocate((void **)&key2);
+ parcMemory_Deallocate((void **)&value2);
+ parcHashCodeTable_Del(table->symbolicNameTable, key1);
+ERR_NAME:
+ parcMemory_Deallocate((void **)&key1);
+ parcMemory_Deallocate((void **)&value1);
+END:
return success;
+
}
unsigned symbolicNameTable_Get(SymbolicNameTable *table,
@@ -152,9 +169,8 @@ unsigned symbolicNameTable_Get(SymbolicNameTable *table,
char *key = _createKey(symbolicName);
uint32_t *value = parcHashCodeTable_Get(table->symbolicNameTable, key);
- if (value) {
+ if (value)
connid = *value;
- }
parcMemory_Deallocate((void **)&key);
return connid;
diff --git a/hicn-light/src/hicn/core/connection.c b/hicn-light/src/hicn/core/connection.c
index 2f50dbf7f..fb43d4a1e 100644
--- a/hicn-light/src/hicn/core/connection.c
+++ b/hicn-light/src/hicn/core/connection.c
@@ -28,10 +28,11 @@
#include <parc/algol/parc_Memory.h>
#include <parc/assert/parc_Assert.h>
#ifdef WITH_POLICY
-#include <hicn/utils/policy.h>
+#include <hicn/policy.h>
#endif /* WITH_POLICY */
struct connection {
+
const AddressPair *addressPair;
IoOperations *ops;
@@ -329,6 +330,14 @@ void connection_SetAdminState(Connection *conn, connection_state_t admin_state)
ioOperations_SetAdminState(conn->ops, admin_state);
}
+const char * connection_GetInterfaceName(const Connection * conn)
+{
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ if (!conn->ops)
+ return NULL;
+ return ioOperations_GetInterfaceName(conn->ops);
+}
+
#ifdef WITH_POLICY
void connection_AddTag(Connection *conn, policy_tag_t tag)
diff --git a/hicn-light/src/hicn/core/connection.h b/hicn-light/src/hicn/core/connection.h
index c007a1a26..b7b5e3c91 100644
--- a/hicn-light/src/hicn/core/connection.h
+++ b/hicn-light/src/hicn/core/connection.h
@@ -41,7 +41,7 @@ typedef enum {
#endif /* WITH_MAPME */
#ifdef WITH_POLICY
-#include <hicn/utils/policy.h>
+#include <hicn/policy.h>
#endif /* WITH_POLICY */
// packet types for probing
@@ -183,6 +183,8 @@ connection_state_t connection_GetAdminState(const Connection *conn);
void connection_SetAdminState(Connection *conn, connection_state_t admin_state);
+const char * connection_GetInterfaceName(const Connection * conn);
+
#ifdef WITH_POLICY
void connection_AddTag(Connection *conn, policy_tag_t tag);
void connection_RemoveTag(Connection *conn, policy_tag_t tag);
diff --git a/hicn-light/src/hicn/core/mapMe.c b/hicn-light/src/hicn/core/mapMe.c
index 0f86dfd7e..2b621387b 100644
--- a/hicn-light/src/hicn/core/mapMe.c
+++ b/hicn-light/src/hicn/core/mapMe.c
@@ -207,11 +207,11 @@ static PARCIterator *mapMeTFIB_CreateKeyIterator(const MapMeTFIB *tfib) {
int hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix) {
NameBitvector *bv = name_GetContentName(name);
- ip_address_t ip_address;
- nameBitvector_ToIPAddress(bv, &ip_address);
+ ip_prefix_t ip_prefix;
+ nameBitvector_ToIPAddress(bv, &ip_prefix);
/* The name length will be equal to ip address' prefix length */
- return hicn_prefix_create_from_ip_address(&ip_address, prefix);
+ return hicn_prefix_create_from_ip_prefix(&ip_prefix, prefix);
}
static Message *mapMe_createMessage(const MapMe *mapme, const Name *name,
diff --git a/hicn-light/src/hicn/core/nameBitvector.c b/hicn-light/src/hicn/core/nameBitvector.c
index ad6884d02..9a734359c 100644
--- a/hicn-light/src/hicn/core/nameBitvector.c
+++ b/hicn-light/src/hicn/core/nameBitvector.c
@@ -264,11 +264,11 @@ void nameBitvector_clear(NameBitvector *a, uint8_t start_from){
}
int nameBitvector_ToIPAddress(const NameBitvector *name,
- ip_address_t *ip_address) {
+ ip_prefix_t *prefix) {
if (name->IPversion == IPv4_TYPE) {
- struct in_addr *addr = (struct in_addr *)(&ip_address->buffer);
- ip_address->family = AF_INET;
- ip_address->prefix_len = IPV4_ADDR_LEN_BITS;
+ struct in_addr *addr = (struct in_addr *)(&prefix->address.buffer);
+ prefix->family = AF_INET;
+ prefix->len = IPV4_ADDR_LEN_BITS;
uint32_t tmp_addr = name->bits[0] >> 32ULL;
uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
@@ -283,9 +283,9 @@ int nameBitvector_ToIPAddress(const NameBitvector *name,
addr->s_addr = (addr->s_addr | addr_1);
} else {
- struct in6_addr *addr = (struct in6_addr *)(&ip_address->buffer);
- ip_address->family = AF_INET6;
- ip_address->prefix_len = name->len; // IPV6_ADDR_LEN_BITS;
+ struct in6_addr *addr = (struct in6_addr *)(&prefix->address.buffer);
+ prefix->family = AF_INET6;
+ prefix->len = name->len; // IPV6_ADDR_LEN_BITS;
for (int i = 0; i < 8; i++) {
addr->s6_addr[i] = (uint8_t)((name->bits[0] >> 8 * (7 - i)) & 0xFF);
diff --git a/hicn-light/src/hicn/core/nameBitvector.h b/hicn-light/src/hicn/core/nameBitvector.h
index 44cc45662..19944778c 100644
--- a/hicn-light/src/hicn/core/nameBitvector.h
+++ b/hicn-light/src/hicn/core/nameBitvector.h
@@ -48,8 +48,7 @@ uint32_t nameBitvector_lpm(const NameBitvector *a, const NameBitvector *b);
void nameBitvector_clear(NameBitvector *a, uint8_t start_from);
-int nameBitvector_ToIPAddress(const NameBitvector *name,
- ip_address_t *ip_address);
+int nameBitvector_ToIPAddress(const NameBitvector *name, ip_prefix_t *prefix);
void nameBitvector_setLen(NameBitvector *name, uint8_t len);
Address *nameBitvector_ToAddress(const NameBitvector *name);
diff --git a/hicn-light/src/hicn/io/hicnConnection.c b/hicn-light/src/hicn/io/hicnConnection.c
index 124885b33..d56231c38 100644
--- a/hicn-light/src/hicn/io/hicnConnection.c
+++ b/hicn-light/src/hicn/io/hicnConnection.c
@@ -40,6 +40,7 @@
typedef struct hicn_state {
Forwarder *forwarder;
+ char * interfaceName;
Logger *logger;
// the hicn listener socket we receive packets on
@@ -96,6 +97,7 @@ static connection_state_t _getState(const IoOperations *ops);
static void _setState(IoOperations *ops, connection_state_t state);
static connection_state_t _getAdminState(const IoOperations *ops);
static void _setAdminState(IoOperations *ops, connection_state_t admin_state);
+static const char * _getInterfaceName(const IoOperations *ops);
/*
* This assigns a unique pointer to the void * which we use
@@ -127,6 +129,7 @@ static IoOperations _template = {
.setState = &_setState,
.getAdminState = &_getAdminState,
.setAdminState = &_setAdminState,
+ .getInterfaceName = &_getInterfaceName,
};
// =================================================================
@@ -136,7 +139,7 @@ static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair);
static void _refreshProbeDestAddress(_HicnState *hicnConnState,
const uint8_t *message);
-IoOperations *hicnConnection_Create(Forwarder *forwarder, int fd,
+IoOperations *hicnConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd,
const AddressPair *pair, bool isLocal) {
IoOperations *io_ops = NULL;
@@ -146,6 +149,7 @@ IoOperations *hicnConnection_Create(Forwarder *forwarder, int fd,
sizeof(_HicnState));
hicnConnState->forwarder = forwarder;
+ hicnConnState->interfaceName = strdup(interfaceName);
hicnConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder));
bool saved = _saveSockaddr(hicnConnState, pair);
@@ -183,6 +187,7 @@ IoOperations *hicnConnection_Create(Forwarder *forwarder, int fd,
// _saveSockaddr will already log an error, no need for extra log message
// here
logger_Release(&hicnConnState->logger);
+ free(hicnConnState->interfaceName);
parcMemory_Deallocate((void **)&hicnConnState);
}
@@ -223,6 +228,7 @@ static void _destroy(IoOperations **opsPtr) {
// should I say something to libhicn?
logger_Release(&hicnConnState->logger);
+ free(hicnConnState->interfaceName);
parcMemory_Deallocate((void **)&hicnConnState);
parcMemory_Deallocate((void **)&ops);
@@ -585,3 +591,11 @@ static void _setAdminState(IoOperations *ops, connection_state_t admin_state) {
(_HicnState *)ioOperations_GetClosure(ops);
hicnConnState->admin_state = admin_state;
}
+
+static const char * _getInterfaceName(const IoOperations *ops)
+{
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ _HicnState *hicnConnState =
+ (_HicnState *)ioOperations_GetClosure(ops);
+ return hicnConnState->interfaceName;
+}
diff --git a/hicn-light/src/hicn/io/hicnConnection.h b/hicn-light/src/hicn/io/hicnConnection.h
index a14024a4e..fec18e1bd 100644
--- a/hicn-light/src/hicn/io/hicnConnection.h
+++ b/hicn-light/src/hicn/io/hicnConnection.h
@@ -48,6 +48,6 @@
* <#example#>
* @endcode
*/
-IoOperations *hicnConnection_Create(Forwarder *forwarder, int fd,
+IoOperations *hicnConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd,
const AddressPair *pair, bool isLocal);
#endif // hicnConnection_h
diff --git a/hicn-light/src/hicn/io/hicnListener.c b/hicn-light/src/hicn/io/hicnListener.c
index d13dc5b4d..a60c4dd12 100644
--- a/hicn-light/src/hicn/io/hicnListener.c
+++ b/hicn-light/src/hicn/io/hicnListener.c
@@ -42,6 +42,9 @@
#define MAX_HICN_RETRY 5
struct hicn_listener {
+
+ char *listenerName;
+
Forwarder *forwarder;
Logger *logger;
@@ -71,12 +74,20 @@ struct hicn_listener {
};
static void _destroy(ListenerOps **listenerOpsPtr);
+static const char *_getListenerName(const ListenerOps *ops);
+static const char *_getInterfaceName(const ListenerOps *ops);
static unsigned _getInterfaceIndex(const ListenerOps *ops);
static const Address *_getListenAddress(const ListenerOps *ops);
static EncapType _getEncapType(const ListenerOps *ops);
static int _getSocket(const ListenerOps *ops);
static unsigned _createNewConnection(ListenerOps *listener, int fd, const AddressPair *pair);
static const Connection * _lookupConnection(ListenerOps * listener, const AddressPair *pair);
+static Message *_readMessage(ListenerOps * listener, int fd, uint8_t *msgBuffer);
+static void _hicnListener_readcb(int fd, PARCEventType what, void *listener_void);
+static Address *_createAddressFromPacket(uint8_t *msgBuffer);
+static void _handleProbeMessage(ListenerOps * listener, uint8_t *msgBuffer);
+static void _handleWldrNotification(ListenerOps *listener, uint8_t *msgBuffer);
+static void _readFrameToDiscard(HicnListener *hicn, int fd);
static ListenerOps _hicnTemplate = {
.context = NULL,
@@ -85,12 +96,12 @@ static ListenerOps _hicnTemplate = {
.getListenAddress = &_getListenAddress,
.getEncapType = &_getEncapType,
.getSocket = &_getSocket,
+ .getInterfaceName = &_getInterfaceName,
+ .getListenerName = &_getListenerName,
.createConnection = &_createNewConnection,
.lookupConnection = &_lookupConnection,
};
-static void _hicnListener_readcb(int fd, PARCEventType what, void *hicnVoid);
-
static bool _isEmptyAddressIPv6(Address *address) {
struct sockaddr_in6 *addr6 =
parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
@@ -111,6 +122,100 @@ static bool _isEmptyAddressIPv6(Address *address) {
return res;
}
+static Message *_readMessage(ListenerOps * listener, int fd, uint8_t *msgBuffer) {
+ HicnListener * hicn = (HicnListener*)listener->context;
+ Message *message = NULL;
+
+ ssize_t readLength = read(fd, msgBuffer, MTU_SIZE);
+
+ if (readLength < 0) {
+ printf("read failed %d: (%d) %s\n", fd, errno, strerror(errno));
+ return message;
+ }
+
+ size_t packetLength = messageHandler_GetTotalPacketLength(msgBuffer);
+
+ if (readLength != packetLength) {
+ parcMemory_Deallocate((void **)&msgBuffer);
+ return message;
+ }
+
+ if (messageHandler_IsTCP(msgBuffer)) {
+ MessagePacketType pktType;
+ unsigned connid = 0;
+ if (messageHandler_IsData(msgBuffer)) {
+ pktType = MessagePacketType_ContentObject;
+ if (hicn->connection_id == -1) {
+ parcMemory_Deallocate((void **)&msgBuffer);
+ return message;
+ } else {
+ connid = hicn->connection_id;
+ }
+ } else if (messageHandler_IsInterest(msgBuffer)) {
+ // notice that the connections for the interest (the one that we create at
+ // run time) uses as a local address 0::0, so the main tun
+ pktType = MessagePacketType_Interest;
+ Address *packetAddr = _createAddressFromPacket(msgBuffer);
+
+ AddressPair *pair_find = addressPair_Create(packetAddr, /* dummy */ hicn->localAddress);
+ const Connection *conn = _lookupConnection(listener, pair_find);
+ addressPair_Release(&pair_find);
+ if (conn == NULL) {
+ AddressPair *pair = addressPair_Create(hicn->localAddress, packetAddr);
+ connid = _createNewConnection(listener, fd, pair);
+ addressPair_Release(&pair);
+ } else {
+ connid = connection_GetConnectionId(conn);
+ }
+ addressDestroy(&packetAddr);
+ } else {
+ printf("Got a packet that is not a data nor an interest, drop it!\n");
+ parcMemory_Deallocate((void **)&msgBuffer);
+ return message;
+ }
+
+ message = message_CreateFromByteArray(connid, msgBuffer, pktType,
+ forwarder_GetTicks(hicn->forwarder),
+ forwarder_GetLogger(hicn->forwarder));
+ if (message == NULL) {
+ parcMemory_Deallocate((void **)&msgBuffer);
+ }
+ } else if (messageHandler_IsWldrNotification(msgBuffer)) {
+ _handleWldrNotification(listener, msgBuffer);
+ } else if (messageHandler_IsLoadBalancerProbe(msgBuffer)) {
+ _handleProbeMessage(listener, msgBuffer);
+ } else {
+ messageHandler_handleHooks(hicn->forwarder, msgBuffer, listener, fd, NULL);
+ parcMemory_Deallocate((void **)&msgBuffer);
+ }
+
+ return message;
+}
+
+static void _receivePacket(ListenerOps * listener, int fd) {
+ HicnListener * hicn = (HicnListener*)listener->context;
+ Message *msg = NULL;
+ uint8_t *msgBuffer = parcMemory_AllocateAndClear(MTU_SIZE);
+ msg = _readMessage(listener, fd, msgBuffer);
+
+ if (msg) {
+ forwarder_Receive(hicn->forwarder, msg);
+ }
+}
+
+static void _hicnListener_readcb(int fd, PARCEventType what, void *listener_void) {
+ ListenerOps * listener = (ListenerOps *)listener_void;
+ HicnListener *hicn = (HicnListener *)listener->context;
+
+ if (hicn->inetFamily == IPv4 || hicn->inetFamily == IPv6) {
+ if (what & PARCEventType_Read) {
+ _receivePacket(listener, fd);
+ }
+ } else {
+ _readFrameToDiscard(hicn, fd);
+ }
+}
+
static bool _isEmptyAddressIPv4(Address *address) {
bool res = false;
@@ -125,11 +230,9 @@ ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic,
sizeof(HicnListener));
hicn->forwarder = forwarder;
- hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ hicn->listenerName = parcMemory_StringDuplicate(symbolic, strlen(symbolic));
hicn->conn_id = forwarder_GetNextConnectionId(forwarder);
- hicn->localAddress = addressCopy(address);
-
hicn->inetFamily = IPv4;
hicn->connection_id = -1;
@@ -164,6 +267,7 @@ ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic,
}
logger_Release(&hicn->logger);
addressDestroy(&hicn->localAddress);
+ parcMemory_Deallocate((void **)&hicn->listenerName);
parcMemory_Deallocate((void **)&hicn);
return NULL;
}
@@ -206,6 +310,7 @@ ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic,
sizeof(HicnListener));
hicn->forwarder = forwarder;
+ hicn->listenerName = parcMemory_StringDuplicate(symbolic, strlen(symbolic));
hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder));
hicn->conn_id = forwarder_GetNextConnectionId(forwarder);
@@ -255,6 +360,7 @@ ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic,
}
logger_Release(&hicn->logger);
addressDestroy(&hicn->localAddress);
+ parcMemory_Deallocate((void **)&hicn->listenerName);
parcMemory_Deallocate((void **)&hicn);
return NULL;
}
@@ -309,7 +415,7 @@ bool _hicnListener_BindInet6(ListenerOps *ops, const Address *remoteAddress) {
if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
PARCLogLevel_Debug)) {
logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
- "hicn_bild failed %d %s", res, hicn_socket_strerror(res));
+ "hicn_bind failed %d %s", res, hicn_socket_strerror(res));
}
} else {
result = true;
@@ -341,7 +447,7 @@ bool _hicnListener_BindInet(ListenerOps *ops, const Address *remoteAddress) {
if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
PARCLogLevel_Debug)) {
logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
- "hicn_bild failed %d %s", res, hicn_socket_strerror(res));
+ "hicn_bind failed %d %s", res, hicn_socket_strerror(res));
}
} else {
result = true;
@@ -421,6 +527,16 @@ static void _destroy(ListenerOps **listenerOpsPtr) {
*listenerOpsPtr = NULL;
}
+static const char *_getListenerName(const ListenerOps *ops) {
+ HicnListener *hicn = (HicnListener *)ops->context;
+ return hicn->listenerName;
+}
+
+static const char *_getInterfaceName(const ListenerOps *ops) {
+ const char *interfaceName = "";
+ return interfaceName;
+}
+
static unsigned _getInterfaceIndex(const ListenerOps *ops) {
HicnListener *hicn = (HicnListener *)ops->context;
return hicn->conn_id;
@@ -468,7 +584,7 @@ static unsigned _createNewConnection(ListenerOps * listener, int fd,
bool isLocal = false;
// udpConnection_Create takes ownership of the pair
- IoOperations *ops = hicnConnection_Create(hicn->forwarder, fd, pair, isLocal);
+ IoOperations *ops = hicnConnection_Create(hicn->forwarder, listener->getInterfaceName(listener), fd, pair, isLocal);
Connection *conn = connection_Create(ops);
connectionTable_Add(forwarder_GetConnectionTable(hicn->forwarder), conn);
@@ -579,96 +695,6 @@ static void _handleWldrNotification(ListenerOps *listener, uint8_t *msgBuffer) {
}
-static Message *_readMessage(ListenerOps * listener, int fd, uint8_t *msgBuffer) {
- HicnListener * hicn = (HicnListener*)listener->context;
- Message *message = NULL;
- ssize_t readLength = read(fd, msgBuffer, MTU_SIZE);
- if (readLength < 0) {
- printf("read failed %d: (%d) %s\n", fd, errno, strerror(errno));
- return message;
- }
-
- size_t packetLength = messageHandler_GetTotalPacketLength(msgBuffer);
-
- if (readLength != packetLength) {
- parcMemory_Deallocate((void **)&msgBuffer);
- return message;
- }
- if (messageHandler_IsTCP(msgBuffer)) {
- MessagePacketType pktType;
- unsigned connid = 0;
- if (messageHandler_IsData(msgBuffer)) {
- pktType = MessagePacketType_ContentObject;
- if (hicn->connection_id == -1) {
- parcMemory_Deallocate((void **)&msgBuffer);
- return message;
- } else {
- connid = hicn->connection_id;
- }
- } else if (messageHandler_IsInterest(msgBuffer)) {
- // notice that the connections for the interest (the one that we create at
- // run time) uses as a local address 0::0, so the main tun
- pktType = MessagePacketType_Interest;
- Address *packetAddr = _createAddressFromPacket(msgBuffer);
-
- AddressPair *pair_find = addressPair_Create(packetAddr, /* dummy */ hicn->localAddress);
- const Connection *conn = _lookupConnection(listener, pair_find);
- addressPair_Release(&pair_find);
- if (conn == NULL) {
- AddressPair *pair = addressPair_Create(hicn->localAddress, packetAddr);
- connid = _createNewConnection(listener, fd, pair);
- addressPair_Release(&pair);
- } else {
- connid = connection_GetConnectionId(conn);
- }
- addressDestroy(&packetAddr);
- } else {
- printf("Got a packet that is not a data nor an interest, drop it!\n");
- parcMemory_Deallocate((void **)&msgBuffer);
- return message;
- }
-
- message = message_CreateFromByteArray(connid, msgBuffer, pktType,
- forwarder_GetTicks(hicn->forwarder),
- forwarder_GetLogger(hicn->forwarder));
- if (message == NULL) {
- parcMemory_Deallocate((void **)&msgBuffer);
- }
- } else if (messageHandler_IsWldrNotification(msgBuffer)) {
- _handleWldrNotification(listener, msgBuffer);
- } else if (messageHandler_IsLoadBalancerProbe(msgBuffer)) {
- _handleProbeMessage(listener, msgBuffer);
- } else {
- messageHandler_handleHooks(hicn->forwarder, msgBuffer, listener, fd, NULL);
- parcMemory_Deallocate((void **)&msgBuffer);
- }
-
- return message;
-}
-
-static void _receivePacket(ListenerOps * listener, int fd) {
- HicnListener * hicn = (HicnListener*)listener->context;
- Message *msg = NULL;
- uint8_t *msgBuffer = parcMemory_AllocateAndClear(MTU_SIZE);
- msg = _readMessage(listener, fd, msgBuffer);
-
- if (msg) {
- forwarder_Receive(hicn->forwarder, msg);
- }
-}
-
-static void _hicnListener_readcb(int fd, PARCEventType what, void *listener_void) {
- ListenerOps * listener = (ListenerOps *)listener_void;
- HicnListener *hicn = (HicnListener *)listener->context;
-
- if (hicn->inetFamily == IPv4 || hicn->inetFamily == IPv6) {
- if (what & PARCEventType_Read) {
- _receivePacket(listener, fd);
- }
- } else {
- _readFrameToDiscard(hicn, fd);
- }
-}
diff --git a/hicn-light/src/hicn/io/hicnTunnel.c b/hicn-light/src/hicn/io/hicnTunnel.c
index baf10c637..fd5acc680 100644
--- a/hicn-light/src/hicn/io/hicnTunnel.c
+++ b/hicn-light/src/hicn/io/hicnTunnel.c
@@ -56,7 +56,7 @@ IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder,
AddressPair *pair = addressPair_Create(localAddress, remoteAddress);
bool isLocal = false;
int fd = localListener->getSocket(localListener);
- ops = hicnConnection_Create(forwarder, fd, pair, isLocal);
+ ops = hicnConnection_Create(forwarder, localListener->getInterfaceName(localListener), fd, pair, isLocal);
addressPair_Release(&pair);
} else {
diff --git a/hicn-light/src/hicn/io/ioOperations.c b/hicn-light/src/hicn/io/ioOperations.c
index bbcea41f8..b2d346ed8 100644
--- a/hicn-light/src/hicn/io/ioOperations.c
+++ b/hicn-light/src/hicn/io/ioOperations.c
@@ -41,6 +41,8 @@ const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops) {
return ops->getAddressPair(ops);
}
+
+
bool ioOperations_IsUp(const IoOperations *ops) { return ops->isUp(ops); }
bool ioOperations_IsLocal(const IoOperations *ops) { return ops->isLocal(ops); }
@@ -83,3 +85,7 @@ connection_state_t ioOperations_GetAdminState(const IoOperations *ops) {
void ioOperations_SetAdminState(IoOperations *ops, connection_state_t admin_state) {
ops->setAdminState(ops, admin_state);
}
+
+const char * ioOperations_GetInterfaceName(const IoOperations *ops) {
+ return ops->getInterfaceName(ops);
+}
diff --git a/hicn-light/src/hicn/io/ioOperations.h b/hicn-light/src/hicn/io/ioOperations.h
index 7a48b7e3e..c8a107199 100644
--- a/hicn-light/src/hicn/io/ioOperations.h
+++ b/hicn-light/src/hicn/io/ioOperations.h
@@ -67,6 +67,8 @@ typedef struct io_ops IoOperations;
* state).
* @constant setAdminState Allows to set the administrative state of a
* connection.
+ * @constant getInterfaceName Returns the interface name associated to a
+ * connection.
* @discussion <#Discussion#>
*/
struct io_ops {
@@ -87,6 +89,7 @@ struct io_ops {
void (*setState)(IoOperations *ops, connection_state_t state);
connection_state_t (*getAdminState)(const IoOperations *ops);
void (*setAdminState)(IoOperations *ops, connection_state_t admin_state);
+ const char * (*getInterfaceName)(const IoOperations *ops);
};
/**
@@ -413,4 +416,12 @@ connection_state_t ioOperations_GetAdminState(const IoOperations *ops);
*/
void ioOperations_SetAdminState(IoOperations *ops, connection_state_t admin_state);
+/**
+ * Sets the interface name associated to the connection.
+ *
+ * @param [in] ops The connection implementation.
+ * @return the name associated to the connection (const char *)
+ */
+const char * ioOperations_GetInterfaceName(const IoOperations *ops);
+
#endif // io_h
diff --git a/hicn-light/src/hicn/io/listener.h b/hicn-light/src/hicn/io/listener.h
index ef1955b12..1b473be59 100644
--- a/hicn-light/src/hicn/io/listener.h
+++ b/hicn-light/src/hicn/io/listener.h
@@ -55,6 +55,15 @@ struct listener_ops {
void (*destroy)(ListenerOps **listenerOpsPtr);
/**
+ * Returns the listener name of the listener.
+ *
+ * @param [in] ops Pointer to this structure
+ *
+ * @return the listener name of the listener
+ */
+ const char *(*getListenerName)(const ListenerOps *ops);
+
+ /**
* Returns the interface index of the listener.
*
* @param [in] ops Pointer to this structure
@@ -82,6 +91,15 @@ struct listener_ops {
EncapType (*getEncapType)(const ListenerOps *ops);
/**
+ * Returns the interface name of the listener.
+ *
+ * @param [in] ops Pointer to this structure
+ *
+ * @return the interface name of the listener
+ */
+ const char *(*getInterfaceName)(const ListenerOps *ops);
+
+ /**
* Returns the underlying socket associated with the listener
*
* Not all listeners are capable of returning a useful socket. In those
diff --git a/hicn-light/src/hicn/io/listenerSet.c b/hicn-light/src/hicn/io/listenerSet.c
index 982373b63..45dbe887a 100644
--- a/hicn-light/src/hicn/io/listenerSet.c
+++ b/hicn-light/src/hicn/io/listenerSet.c
@@ -130,3 +130,53 @@ ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType,
return match;
}
+
+ListenerOps *listenerSet_FindById(const ListenerSet *set, unsigned id) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+
+ ListenerOps *match = NULL;
+
+ for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match;
+ i++) {
+ ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i);
+ parcAssertNotNull(ops, "Got null listener ops at index %zu", i);
+ if (ops->getInterfaceIndex(ops) == id) {
+ match = ops;
+ }
+ }
+
+ return match;
+}
+
+int listenerSet_FindIdByListenerName(const ListenerSet *set, const char *listenerName ) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ parcAssertNotNull(listenerName, "Parameter listenerName must be non-null");
+
+ ListenerOps *match = NULL;
+ int index = -1;
+ for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match;
+ i++) {
+ ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i);
+ parcAssertNotNull(ops, "Got null listener ops at index %zu", i);
+ if (ops->getListenerName(ops) && strcmp(ops->getListenerName(ops), listenerName) == 0) {
+ index = ops->getInterfaceIndex(ops);
+ break;
+ }
+ }
+
+ return index;
+}
+
+void listenerSet_RemoveById(const ListenerSet *set, unsigned id) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+
+ for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners);
+ i++) {
+ ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i);
+ parcAssertNotNull(ops, "Got null listener ops at index %zu", i);
+ if (ops->getInterfaceIndex(ops) == id) {
+ parcArrayList_RemoveAtIndex(set->listOfListeners, i);
+ break;
+ }
+ }
+}
diff --git a/hicn-light/src/hicn/io/listenerSet.h b/hicn-light/src/hicn/io/listenerSet.h
index 8d15a2736..5779d2af4 100644
--- a/hicn-light/src/hicn/io/listenerSet.h
+++ b/hicn-light/src/hicn/io/listenerSet.h
@@ -134,4 +134,55 @@ ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index);
*/
ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType,
const Address *localAddress);
+
+/**
+ * Looks up a listener by its id
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] id of the listener
+ *
+ * @retval non-null The listener matching the query
+ * @retval null Does not exist
+ *
+ * Example:
+ * @code
+ *
+ * @endcode
+ */
+ListenerOps *listenerSet_FindById(const ListenerSet *set, unsigned id);
+
+/**
+ * Looks up a listener by its id
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] name of the listener
+ *
+ * @retval greater or equal to 0 The listener matching the query
+ * @retval -1 Does not exist
+ *
+ * Example:
+ * @code
+ *
+ * @endcode
+ */
+int listenerSet_FindIdByListenerName(const ListenerSet *set, const char *listenerName);
+
+/**
+ * Remove up a listener by its id
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] id of the listener
+ *
+ * Example:
+ * @code
+ *
+ * @endcode
+ */
+void listenerSet_RemoveById(const ListenerSet *set, unsigned id);
#endif
diff --git a/hicn-light/src/hicn/io/streamConnection.c b/hicn-light/src/hicn/io/streamConnection.c
index ce2341cb8..08ff728d6 100644
--- a/hicn-light/src/hicn/io/streamConnection.c
+++ b/hicn-light/src/hicn/io/streamConnection.c
@@ -47,6 +47,7 @@ static void _conn_eventcb(PARCEventQueue *bufferEventVector,
typedef struct stream_state {
Forwarder *forwarder;
+ char * interfaceName;
Logger *logger;
int fd;
@@ -90,6 +91,7 @@ static connection_state_t _streamConnection_getState(const IoOperations *ops);
static void _streamConnection_setState(IoOperations *ops, connection_state_t state);
static connection_state_t _streamConnection_getAdminState(const IoOperations *ops);
static void _streamConnection_setAdminState(IoOperations *ops, connection_state_t admin_state);
+static const char * _streamConnection_getInterfaceName(const IoOperations *ops);
/*
* This assigns a unique pointer to the void * which we use
@@ -121,6 +123,7 @@ static IoOperations _template = {
.setState = &_streamConnection_setState,
.getAdminState = &_streamConnection_getAdminState,
.setAdminState = &_streamConnection_setAdminState,
+ .getInterfaceName = &_streamConnection_getInterfaceName,
};
IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd,
@@ -137,6 +140,7 @@ IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd,
PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks);
stream->forwarder = forwarder;
+ stream->interfaceName = NULL;
stream->logger = logger_Acquire(forwarder_GetLogger(forwarder));
stream->fd = fd;
stream->id = forwarder_GetNextConnectionId(forwarder);
@@ -191,6 +195,7 @@ IoOperations *streamConnection_OpenConnection(Forwarder *forwarder,
sizeof(_StreamState));
stream->forwarder = forwarder;
+ stream->interfaceName = NULL;
stream->logger = logger_Acquire(forwarder_GetLogger(forwarder));
stream->fd = parcEventQueue_GetFileDescriptor(bufferEventVector);
stream->bufferEventVector = bufferEventVector;
@@ -584,6 +589,7 @@ static void _conn_readcb(PARCEventQueue *event, PARCEventType type,
// kind of packets
while (parcEventBuffer_GetLength(input) >= sizeof(header_control_message) &&
parcEventBuffer_GetLength(input) >= stream->nextMessageLength) {
+
if ((command = _isACommand(input)) != LAST_COMMAND_VALUE) {
struct iovec *rx;
// Get message from the stream and set the stream->nextMessageLength
@@ -606,7 +612,7 @@ static void _conn_readcb(PARCEventQueue *event, PARCEventType type,
} else {
parcAssertTrue(false,
- "(Local stream connection) malformend packet received");
+ "(Local stream connection) malformed packet received");
}
}
@@ -728,3 +734,11 @@ static void _streamConnection_setAdminState(IoOperations *ops, connection_state_
(_StreamState *)ioOperations_GetClosure(ops);
stream->admin_state = admin_state;
}
+
+static const char * _streamConnection_getInterfaceName(const IoOperations *ops)
+{
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ _StreamState *stream =
+ (_StreamState *)ioOperations_GetClosure(ops);
+ return stream->interfaceName;
+}
diff --git a/hicn-light/src/hicn/io/tcpListener.c b/hicn-light/src/hicn/io/tcpListener.c
index cc6fdbba8..e2b80c215 100644
--- a/hicn-light/src/hicn/io/tcpListener.c
+++ b/hicn-light/src/hicn/io/tcpListener.c
@@ -30,6 +30,7 @@
#include <parc/assert/parc_Assert.h>
typedef struct tcp_listener {
+ char *listenerName;
Forwarder *forwarder;
Logger *logger;
@@ -38,6 +39,7 @@ typedef struct tcp_listener {
Address *localAddress;
unsigned id;
+ char *interfaceName;
// is the localAddress as 127.0.0.0 address?
bool isLocalAddressLocal;
@@ -46,30 +48,42 @@ typedef struct tcp_listener {
static void _tcpListener_Destroy(_TcpListener **listenerPtr);
static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr);
+
+static const char *_tcpListener_ListenerName(const ListenerOps *ops);
+
static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops);
+
static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops);
+
+static const char *_tcpListener_InterfaceName(const ListenerOps *ops);
+
static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops);
static ListenerOps _tcpTemplate = {
.context = NULL,
.destroy = &_tcpListener_OpsDestroy,
+ .getListenerName = &_tcpListener_ListenerName,
.getInterfaceIndex = &_tcpListener_OpsGetInterfaceIndex,
.getListenAddress = &_tcpListener_OpsGetListenAddress,
.getEncapType = &_tcpListener_OpsGetEncapType,
+ .getInterfaceName = &_tcpListener_InterfaceName,
.getSocket = NULL};
// STREAM daemon listener callback
static void _tcpListener_Listen(int, struct sockaddr *, int socklen,
void *tcpVoid);
-ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder,
- struct sockaddr_in6 sin6) {
+ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder, char *listenerName,
+ struct sockaddr_in6 sin6, char *interfaceName) {
+
_TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener));
parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL",
sizeof(_TcpListener));
tcp->forwarder = forwarder;
+ tcp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName));
tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ tcp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName));
tcp->listener = dispatcher_CreateListener(
forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1,
@@ -107,14 +121,17 @@ ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder,
return ops;
}
-ListenerOps *tcpListener_CreateInet(Forwarder *forwarder,
- struct sockaddr_in sin) {
+ListenerOps *tcpListener_CreateInet(Forwarder *forwarder, char *listenerName,
+ struct sockaddr_in sin, char *interfaceName) {
_TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener));
parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL",
sizeof(_TcpListener));
tcp->forwarder = forwarder;
+ tcp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName));
tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ tcp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName));
+
tcp->listener = dispatcher_CreateListener(
forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1,
(struct sockaddr *)&sin, sizeof(sin));
@@ -164,6 +181,8 @@ static void _tcpListener_Destroy(_TcpListener **listenerPtr) {
parcMemory_Deallocate((void **)&str);
}
+ parcMemory_Deallocate((void **)&tcp->listenerName);
+ parcMemory_Deallocate((void **)&tcp->interfaceName);
logger_Release(&tcp->logger);
dispatcher_DestroyListener(forwarder_GetDispatcher(tcp->forwarder),
&tcp->listener);
@@ -174,6 +193,16 @@ static void _tcpListener_Destroy(_TcpListener **listenerPtr) {
// ==================================================
+static const char *_tcpListener_ListenerName(const ListenerOps *ops) {
+ _TcpListener *tcp = (_TcpListener *)ops->context;
+ return tcp->listenerName;
+}
+
+static const char *_tcpListener_InterfaceName(const ListenerOps *ops) {
+ _TcpListener *tcp = (_TcpListener *)ops->context;
+ return tcp->interfaceName;
+}
+
static void _tcpListener_Listen(int fd, struct sockaddr *sa, int socklen,
void *tcpVoid) {
_TcpListener *tcp = (_TcpListener *)tcpVoid;
diff --git a/hicn-light/src/hicn/io/tcpListener.h b/hicn-light/src/hicn/io/tcpListener.h
index df0bbea1e..a841738e5 100644
--- a/hicn-light/src/hicn/io/tcpListener.h
+++ b/hicn-light/src/hicn/io/tcpListener.h
@@ -33,8 +33,8 @@
#include <hicn/io/listener.h>
#include <stdlib.h>
-ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder,
- struct sockaddr_in6 sin6);
-ListenerOps *tcpListener_CreateInet(Forwarder *forwarder,
- struct sockaddr_in sin);
+ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder, char *listenerName,
+ struct sockaddr_in6 sin6, char *interfaceName);
+ListenerOps *tcpListener_CreateInet(Forwarder *forwarder, char *listenerName,
+ struct sockaddr_in sin, char *interfaceName);
#endif // tcpListener_h
diff --git a/hicn-light/src/hicn/io/udpConnection.c b/hicn-light/src/hicn/io/udpConnection.c
index 78157f01f..9ad70403f 100644
--- a/hicn-light/src/hicn/io/udpConnection.c
+++ b/hicn-light/src/hicn/io/udpConnection.c
@@ -40,6 +40,7 @@
typedef struct udp_state {
Forwarder *forwarder;
+ char * interfaceName;
Logger *logger;
// the udp listener socket we receive packets on
@@ -81,6 +82,7 @@ static connection_state_t _getState(const IoOperations *ops);
static void _setState(IoOperations *ops, connection_state_t state);
static connection_state_t _getAdminState(const IoOperations *ops);
static void _setAdminState(IoOperations *ops, connection_state_t admin_state);
+static const char * _getInterfaceName(const IoOperations *ops);
/*
* This assigns a unique pointer to the void * which we use
@@ -112,6 +114,7 @@ static IoOperations _template = {
.setState = &_setState,
.getAdminState = &_getAdminState,
.setAdminState = &_setAdminState,
+ .getInterfaceName = &_getInterfaceName,
};
// =================================================================
@@ -119,7 +122,7 @@ static IoOperations _template = {
static void _setConnectionState(_UdpState *Udp, bool isUp);
static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair);
-IoOperations *udpConnection_Create(Forwarder *forwarder, int fd,
+IoOperations *udpConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd,
const AddressPair *pair, bool isLocal) {
IoOperations *io_ops = NULL;
@@ -129,6 +132,7 @@ IoOperations *udpConnection_Create(Forwarder *forwarder, int fd,
sizeof(_UdpState));
udpConnState->forwarder = forwarder;
+ udpConnState->interfaceName = strdup(interfaceName);
udpConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder));
bool saved = _saveSockaddr(udpConnState, pair);
@@ -166,6 +170,8 @@ IoOperations *udpConnection_Create(Forwarder *forwarder, int fd,
// _saveSockaddr will already log an error, no need for extra log message
// here
logger_Release(&udpConnState->logger);
+
+ free(udpConnState->interfaceName);
parcMemory_Deallocate((void **)&udpConnState);
}
@@ -202,6 +208,7 @@ static void _destroy(IoOperations **opsPtr) {
// that when its done
logger_Release(&udpConnState->logger);
+ free(udpConnState->interfaceName);
parcMemory_Deallocate((void **)&udpConnState);
parcMemory_Deallocate((void **)&ops);
@@ -435,3 +442,11 @@ static void _setAdminState(IoOperations *ops, connection_state_t admin_state) {
(_UdpState *)ioOperations_GetClosure(ops);
udpConnState->admin_state = admin_state;
}
+
+static const char * _getInterfaceName(const IoOperations *ops)
+{
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ _UdpState *udpConnState =
+ (_UdpState *)ioOperations_GetClosure(ops);
+ return udpConnState->interfaceName;
+}
diff --git a/hicn-light/src/hicn/io/udpConnection.h b/hicn-light/src/hicn/io/udpConnection.h
index 07c4da9bd..9fbc5348b 100644
--- a/hicn-light/src/hicn/io/udpConnection.h
+++ b/hicn-light/src/hicn/io/udpConnection.h
@@ -48,6 +48,6 @@
* <#example#>
* @endcode
*/
-IoOperations *udpConnection_Create(Forwarder *forwarder, int fd,
+IoOperations *udpConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd,
const AddressPair *pair, bool isLocal);
#endif // udpConnection_h
diff --git a/hicn-light/src/hicn/io/udpListener.c b/hicn-light/src/hicn/io/udpListener.c
index f6b434fed..f43756a11 100644
--- a/hicn-light/src/hicn/io/udpListener.c
+++ b/hicn-light/src/hicn/io/udpListener.c
@@ -40,6 +40,7 @@
#define IPv6 6
struct udp_listener {
+ char *listenerName;
Forwarder *forwarder;
Logger *logger;
@@ -48,13 +49,16 @@ struct udp_listener {
uint16_t port;
unsigned id;
+ char *interfaceName;
Address *localAddress;
};
static void _destroy(ListenerOps **listenerOpsPtr);
+static const char *_getListenerName(const ListenerOps *ops);
static unsigned _getInterfaceIndex(const ListenerOps *ops);
static const Address *_getListenAddress(const ListenerOps *ops);
static EncapType _getEncapType(const ListenerOps *ops);
+static const char *_getInterfaceName(const ListenerOps *ops);
static int _getSocket(const ListenerOps *ops);
static unsigned _createNewConnection(ListenerOps *listener, int fd, const AddressPair *pair);
static const Connection * _lookupConnection(ListenerOps * listener, const AddressPair *pair);
@@ -66,29 +70,29 @@ static ListenerOps udpTemplate = {
.getListenAddress = &_getListenAddress,
.getEncapType = &_getEncapType,
.getSocket = &_getSocket,
+ .getListenerName = &_getListenerName,
.createConnection = &_createNewConnection,
.lookupConnection = &_lookupConnection,
+ .getInterfaceName = &_getInterfaceName,
};
+
static void _readcb(int fd, PARCEventType what, void * listener_void);
#ifdef __ANDROID__
extern int bindSocket(int sock, const char* ifname);
#endif
-#ifdef __linux__
-ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
+ListenerOps *udpListener_CreateInet6(Forwarder *forwarder, char *listenerName,
struct sockaddr_in6 sin6, const char *interfaceName) {
-#else
-ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
- struct sockaddr_in6 sin6) {
-#endif
ListenerOps *ops = NULL;
UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener));
parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL",
sizeof(UdpListener));
udp->forwarder = forwarder;
+ udp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName));
+ udp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName));
udp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
udp->localAddress = addressCreateFromInet6(&sin6);
udp->id = forwarder_GetNextConnectionId(forwarder);
@@ -172,6 +176,8 @@ ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
myerrno, strerror(myerrno));
parcMemory_Deallocate((void **)&str);
}
+ parcMemory_Deallocate((void **)&udp->listenerName);
+ parcMemory_Deallocate((void **)&udp->interfaceName);
#ifndef _WIN32
close(udp->udp_socket);
#else
@@ -185,19 +191,16 @@ ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
return ops;
}
-#ifdef __linux__
-ListenerOps *udpListener_CreateInet(Forwarder *forwarder,
+ListenerOps *udpListener_CreateInet(Forwarder *forwarder, char *listenerName,
struct sockaddr_in sin, const char *interfaceName) {
-#else
-ListenerOps *udpListener_CreateInet(Forwarder *forwarder,
- struct sockaddr_in sin) {
-#endif
ListenerOps *ops = NULL;
UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener));
parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL",
sizeof(UdpListener));
udp->forwarder = forwarder;
+ udp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName));
+ udp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName));
udp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
udp->localAddress = addressCreateFromInet(&sin);
udp->id = forwarder_GetNextConnectionId(forwarder);
@@ -315,6 +318,16 @@ static void udpListener_Destroy(UdpListener **listenerPtr) {
*listenerPtr = NULL;
}
+static const char *_getListenerName(const ListenerOps *ops) {
+ UdpListener *udp = (UdpListener *)ops->context;
+ return udp->listenerName;
+}
+
+static const char *_getInterfaceName(const ListenerOps *ops) {
+ UdpListener *udp = (UdpListener *)ops->context;
+ return udp->interfaceName;
+}
+
static void _destroy(ListenerOps **listenerOpsPtr) {
ListenerOps *ops = *listenerOpsPtr;
UdpListener *udp = (UdpListener *)ops->context;
@@ -420,7 +433,7 @@ static unsigned _createNewConnection(ListenerOps * listener, int fd,
}
// metisUdpConnection_Create takes ownership of the pair
- IoOperations *ops = udpConnection_Create(udp->forwarder, fd, pair, isLocal);
+ IoOperations *ops = udpConnection_Create(udp->forwarder, udp->interfaceName, fd, pair, isLocal);
Connection *conn = connection_Create(ops);
// connection_AllowWldrAutoStart(conn);
diff --git a/hicn-light/src/hicn/io/udpListener.h b/hicn-light/src/hicn/io/udpListener.h
index 81d191eab..62c09e4db 100644
--- a/hicn-light/src/hicn/io/udpListener.h
+++ b/hicn-light/src/hicn/io/udpListener.h
@@ -27,16 +27,9 @@
struct udp_listener;
typedef struct udp_listener UdpListener;
-#ifdef __linux__
-ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
+ListenerOps *udpListener_CreateInet6(Forwarder *forwarder, char *listenerName,
struct sockaddr_in6 sin6, const char *if_bind);
-ListenerOps *udpListener_CreateInet(Forwarder *forwarder,
+ListenerOps *udpListener_CreateInet(Forwarder *forwarder, char *listenerName,
struct sockaddr_in sin, const char *if_bind);
-#else
-ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
- struct sockaddr_in6 sin6);
-ListenerOps *udpListener_CreateInet(Forwarder *forwarder,
- struct sockaddr_in sin);
-#endif
// void udpListener_SetPacketType(ListenerOps *ops, MessagePacketType type);
#endif // udpListener_h
diff --git a/hicn-light/src/hicn/io/udpTunnel.c b/hicn-light/src/hicn/io/udpTunnel.c
index 2f2f84105..9f5249e3c 100644
--- a/hicn-light/src/hicn/io/udpTunnel.c
+++ b/hicn-light/src/hicn/io/udpTunnel.c
@@ -60,7 +60,7 @@ IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder,
int fd = localListener->getSocket(localListener);
// udpListener_SetPacketType(localListener,
// MessagePacketType_ContentObject);
- ops = udpConnection_Create(forwarder, fd, pair, isLocal);
+ ops = udpConnection_Create(forwarder, localListener->getInterfaceName(localListener), fd, pair, isLocal);
addressPair_Release(&pair);
} else {
diff --git a/hicn-light/src/hicn/processor/fib.c b/hicn-light/src/hicn/processor/fib.c
index 6489e59e2..6bb29c404 100644
--- a/hicn-light/src/hicn/processor/fib.c
+++ b/hicn-light/src/hicn/processor/fib.c
@@ -452,6 +452,8 @@ void fib_RemoveConnectionId(FIB *fib, unsigned connectionId) {
for (int i = 0; i < fibEntryList_Length(list); i++) {
_removeNode(fib, fibEntry_GetPrefix(fibEntryList_Get(list, i)));
}
+
+ fibEntryList_Destroy(&list);
}
size_t fib_Length(const FIB *fib) {
diff --git a/hicn-light/src/hicn/processor/fibEntry.c b/hicn-light/src/hicn/processor/fibEntry.c
index 9d82b086e..f12dd506b 100644
--- a/hicn-light/src/hicn/processor/fibEntry.c
+++ b/hicn-light/src/hicn/processor/fibEntry.c
@@ -39,7 +39,7 @@
#ifdef WITH_POLICY
#include <hicn/core/forwarder.h>
-#include <hicn/utils/policy.h>
+#include <hicn/policy.h>
#ifdef WITH_MAPME
#include <hicn/core/mapMe.h>
@@ -201,6 +201,7 @@ NumberSet *
fibEntry_GetAvailableNextHops(const FibEntry *fibEntry, unsigned in_connection) {
ConnectionTable * table = forwarder_GetConnectionTable(fibEntry->forwarder);
NumberSet * nexthops;
+ bool dealloc_nexthops = false;
policy_t policy = fibEntry_GetPolicy(fibEntry);
/* Reset available next hops and start filtering */
@@ -214,17 +215,20 @@ fibEntry_GetAvailableNextHops(const FibEntry *fibEntry, unsigned in_connection)
if (in_connection == ~0) {
/* We might advertise among all available up connections */
nexthops = numberSet_Create();
+ dealloc_nexthops = true;
ConnectionList * list = connectionTable_GetEntries(table);
for (size_t i = 0; i < connectionList_Length(list); i++) {
Connection *conn = connectionList_Get(list, i);
+ if (connection_GetAdminState(conn) == CONNECTION_STATE_DOWN)
+ continue;
if (connection_GetState(conn) == CONNECTION_STATE_DOWN)
continue;
if (connection_IsLocal(conn))
continue;
numberSet_Add(nexthops, connection_GetConnectionId(conn));
}
-
+ connectionList_Destroy(&list);
} else {
nexthops = (NumberSet*)fibEntry_GetNexthops(fibEntry);
for (size_t k = 0; k < numberSet_Length(nexthops); k++) {
@@ -236,6 +240,8 @@ fibEntry_GetAvailableNextHops(const FibEntry *fibEntry, unsigned in_connection)
const Connection * conn = connectionTable_FindById(table, conn_id);
if (!conn)
continue;
+ if (connection_GetAdminState(conn) == CONNECTION_STATE_DOWN)
+ continue;
if (connection_GetState(conn) == CONNECTION_STATE_DOWN)
continue;
if (!connection_IsLocal(conn))
@@ -243,8 +249,12 @@ fibEntry_GetAvailableNextHops(const FibEntry *fibEntry, unsigned in_connection)
numberSet_Add(available_nexthops, conn_id);
}
- if (numberSet_Length(available_nexthops) > 0)
+ if (numberSet_Length(available_nexthops) > 0){
+ if(dealloc_nexthops){
+ numberSet_Release(&nexthops);
+ }
return available_nexthops;
+ }
}
for (size_t k = 0; k < numberSet_Length(nexthops); k++) {
@@ -259,6 +269,8 @@ fibEntry_GetAvailableNextHops(const FibEntry *fibEntry, unsigned in_connection)
conn = connectionTable_FindById(table, conn_id);
if (!conn)
continue;
+ if (connection_GetAdminState(conn) == CONNECTION_STATE_DOWN)
+ continue;
if (connection_GetState(conn) == CONNECTION_STATE_DOWN)
continue;
@@ -291,6 +303,9 @@ fibEntry_GetAvailableNextHops(const FibEntry *fibEntry, unsigned in_connection)
numberSet_Add(available_nexthops, conn_id);
}
+ if(dealloc_nexthops)
+ numberSet_Release(&nexthops);
+
if (numberSet_Length(available_nexthops) == 0)
return available_nexthops;
diff --git a/hicn-light/src/hicn/processor/messageProcessor.c b/hicn-light/src/hicn/processor/messageProcessor.c
index 456618269..6598b9035 100644
--- a/hicn-light/src/hicn/processor/messageProcessor.c
+++ b/hicn-light/src/hicn/processor/messageProcessor.c
@@ -131,16 +131,18 @@ static void messageProcessor_ForwardToInterfaceId(MessageProcessor *processor,
static void
messageProcessor_Tick(int fd, PARCEventType type, void *user_data)
{
- MessageProcessor *processor = (MessageProcessor*)user_data;
- uint64_t now = (uint64_t)forwarder_GetTicks(processor->forwarder);
+ MessageProcessor *processor = (MessageProcessor*)user_data;
+ uint64_t now = (uint64_t)forwarder_GetTicks(processor->forwarder);
- /* Loop over FIB entries to compute statistics from counters */
- FibEntryList *fibList = forwarder_GetFibEntries(processor->forwarder);
+ /* Loop over FIB entries to compute statistics from counters */
+ FibEntryList *fibList = forwarder_GetFibEntries(processor->forwarder);
- for (size_t i = 0; i < fibEntryList_Length(fibList); i++) {
- FibEntry *entry = (FibEntry *)fibEntryList_Get(fibList, i);
- fibEntry_UpdateStats(entry, now);
- }
+ for (size_t i = 0; i < fibEntryList_Length(fibList); i++) {
+ FibEntry *entry = (FibEntry *)fibEntryList_Get(fibList, i);
+ fibEntry_UpdateStats(entry, now);
+ }
+
+ fibEntryList_Destroy(&fibList);
}
#endif /* WITH_POLICY */
@@ -298,7 +300,7 @@ bool messageProcessor_AddOrUpdateRoute(MessageProcessor *processor,
unsigned ifidx) {
Configuration *config = forwarder_GetConfiguration(processor->forwarder);
- const char *prefixStr = utils_PrefixLenToString(
+ char *prefixStr = (char *) utils_PrefixLenToString(
control->addressType, &control->address, &control->len);
strategy_type fwdStrategy =
configuration_GetForwardingStrategy(config, prefixStr);
@@ -323,6 +325,7 @@ bool messageProcessor_AddOrUpdateRoute(MessageProcessor *processor,
fib_Add(processor->fib, entry);
}
+ free(prefixStr);
name_Release(&prefix);
/* For policy implementation, we need access to the ConnectionTable in all
diff --git a/hicn-light/src/hicn/socket/api.c b/hicn-light/src/hicn/socket/api.c
index 213163675..a3d5a3cfe 100644
--- a/hicn-light/src/hicn/socket/api.c
+++ b/hicn-light/src/hicn/socket/api.c
@@ -39,7 +39,7 @@ static hicn_conf_t hicn_default_conf = {
struct ip_rule_state_ {
char tun_name[IF_NAMESIZE];
- ip_address_t ip_address;
+ ip_prefix_t prefix;
uint32_t table_id;
uint8_t priority;
uint8_t address_family;
@@ -160,7 +160,7 @@ void hicn_destroy() {
}
} else {
rc = ops.del_prio_rule(
- &rules_to_remove[i].ip_address, rules_to_remove[i].address_family,
+ &rules_to_remove[i].prefix, rules_to_remove[i].address_family,
rules_to_remove[i].priority, rules_to_remove[i].table_id);
if (rc < 0) {
goto ERR;
@@ -204,7 +204,7 @@ int hicn_socket_cmp(hicn_socket_t *a, hicn_socket_t *b) {
return b->fd - a->fd;
}
-ip_address_t *hicn_socket_get_src_ip(hicn_socket_t *socket) {
+ip_prefix_t *hicn_socket_get_src_ip(hicn_socket_t *socket) {
if (socket->type != HS_CONNECTION) {
return NULL;
}
@@ -252,7 +252,7 @@ int hicn_set_local_endpoint(hicn_socket_t *socket, const char *local_ip_address,
*/
/* Copy the local IP address inside the connection */
- rc = hicn_ip_pton(local_ip_address, &socket->connection.tun_ip_address);
+ rc = ip_prefix_pton(local_ip_address, &socket->connection.tun_ip_address);
if (rc < 0) {
rc = HICN_SOCKET_ERROR_SOCKET_LOCAL_REPR;
goto end;
@@ -262,13 +262,13 @@ end:
return rc;
}
-int hicn_get_local_address(const ip_address_t *remote_address,
- ip_address_t *local_address) {
+int hicn_get_local_address(const ip_prefix_t *remote_address,
+ ip_prefix_t *local_address) {
int rc = 0;
uint32_t interface_id;
- char remote_address_str[INET_MAX_ADDRSTRLEN];
+ char remote_address_str[INET_MAX_ADDRSTRLEN + 4 ];
- rc = hicn_ip_ntop(remote_address, remote_address_str,
+ rc = ip_prefix_ntop_short(remote_address, remote_address_str,
sizeof(remote_address_str));
if (rc < 0) {
rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR;
@@ -300,7 +300,7 @@ ERR:
int hicn_set_remote_endpoint(hicn_socket_t *socket,
const char *remote_ip_address) {
int af, rc = HICN_SOCKET_ERROR_NONE;
- ip_address_t addr;
+ ip_prefix_t addr;
af = get_addr_family(remote_ip_address);
if ((af != AF_INET6) && (af != AF_INET)) {
@@ -308,8 +308,8 @@ int hicn_set_remote_endpoint(hicn_socket_t *socket,
}
/* Bind local endpoint if not done yet */
- if (ip_address_empty(&socket->connection.tun_ip_address)) {
- char local_ip_address[INET_MAX_ADDRSTRLEN];
+ if (ip_prefix_empty(&socket->connection.tun_ip_address)) {
+ char local_ip_address[INET_MAX_ADDRSTRLEN + 4];
/* Local interface id */
// INFO("Getting interface_id from gateway IP address %s",
@@ -338,7 +338,7 @@ int hicn_set_remote_endpoint(hicn_socket_t *socket,
/////
/* Convert to representation format */
- rc = hicn_ip_ntop(&addr, local_ip_address, sizeof(local_ip_address));
+ rc = ip_prefix_ntop_short(&addr, local_ip_address, sizeof(local_ip_address));
if (rc < 0) {
rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR;
goto ERR;
@@ -455,8 +455,8 @@ int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix) {
return rc;
}
- ip_address_t ip_address;
- rc = hicn_ip_pton(prefix, &ip_address);
+ ip_prefix_t ip_prefix;
+ rc = ip_prefix_pton(prefix, &ip_prefix);
if (rc < 0) {
return rc;
}
@@ -467,7 +467,7 @@ int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix) {
if (punting_table_id == -1) punting_table_id = socket->connection.table_id;
- rc = ops.add_prio_rule(&ip_address, ip_address.family, 0,
+ rc = ops.add_prio_rule(&ip_prefix, ip_prefix.family, 0,
socket->connection.table_id);
if (rc < 0) {
return rc;
@@ -475,8 +475,8 @@ int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix) {
strcpy(rules_to_remove[rules_counter].tun_name, "NONE");
- rules_to_remove[rules_counter].ip_address = ip_address;
- rules_to_remove[rules_counter].address_family = ip_address.family;
+ rules_to_remove[rules_counter].prefix = ip_prefix;
+ rules_to_remove[rules_counter].address_family = ip_prefix.family;
rules_to_remove[rules_counter].table_id = socket->connection.table_id;
rules_to_remove[rules_counter].priority = 0;
++rules_counter;
diff --git a/hicn-light/src/hicn/socket/api.h b/hicn-light/src/hicn/socket/api.h
index 283065fc7..1a7f5c700 100644
--- a/hicn-light/src/hicn/socket/api.h
+++ b/hicn-light/src/hicn/socket/api.h
@@ -84,7 +84,7 @@ typedef struct hicn_socket_s {
union {
struct {
- ip_address_t tun_ip_address;
+ ip_prefix_t tun_ip_address;
uint32_t interface_id;
/* ID of the corresponding table : avoid default values of 0, 32766 and
@@ -163,8 +163,8 @@ void hicn_free(hicn_socket_helper_t *hicn);
*
* @return 0 in case of success, -1 otherwise.
*/
-int hicn_get_local_address(const ip_address_t *remote_address,
- ip_address_t *local_address);
+int hicn_get_local_address(const ip_prefix_t *remote_address,
+ ip_prefix_t *local_address);
/* hICN socket */
diff --git a/hicn-light/src/hicn/socket/ops.h b/hicn-light/src/hicn/socket/ops.h
index 249caf87a..1bee7c6f6 100644
--- a/hicn-light/src/hicn/socket/ops.h
+++ b/hicn-light/src/hicn/socket/ops.h
@@ -17,10 +17,10 @@ typedef struct {
int (*get_output_ifid)(const char *ip_address, uint8_t address_family,
uint32_t *interface_id);
int (*get_ip_addr)(uint32_t interface_id, uint8_t address_family,
- ip_address_t *ip_address);
- int (*set_ip_addr)(uint32_t interface_id, ip_address_t *ip_address);
+ ip_prefix_t *ip_address);
+ int (*set_ip_addr)(uint32_t interface_id, ip_prefix_t *ip_address);
int (*up_if)(uint32_t interface_id);
- int (*add_in_route_table)(const ip_address_t *prefix,
+ int (*add_in_route_table)(const ip_prefix_t *prefix,
const uint32_t interface_id,
const uint8_t table_id);
int (*add_in_route_table_s)(const char *prefix, const uint32_t interface_id,
@@ -30,23 +30,23 @@ typedef struct {
const uint8_t table_id, int default_route);
int (*del_out_route)(const char *gateway, const uint8_t address_family,
const uint8_t table_id);
- int (*del_lo_route)(const ip_address_t *ip_address);
+ int (*del_lo_route)(const ip_prefix_t *ip_address);
int (*add_rule)(const char *interface_name, const uint8_t address_family,
const uint8_t table_id);
int (*del_rule)(const char *interface_name, const uint8_t address_family,
const uint8_t table_id);
- int (*add_neigh_proxy)(const ip_address_t *ip_address,
+ int (*add_neigh_proxy)(const ip_prefix_t *ip_address,
const uint32_t interface_id);
- int (*add_prio_rule)(const ip_address_t *ip_address,
+ int (*add_prio_rule)(const ip_prefix_t *ip_address,
const uint8_t address_family, const uint32_t priority,
const uint8_t table_id);
- int (*add_lo_prio_rule)(const ip_address_t *ip_address,
+ int (*add_lo_prio_rule)(const ip_prefix_t *ip_address,
const uint8_t address_family,
const uint32_t priority);
- int (*del_prio_rule)(const ip_address_t *ip_address,
+ int (*del_prio_rule)(const ip_prefix_t *ip_address,
const uint8_t address_family, const uint32_t priority,
const uint8_t table_id);
- int (*del_lo_prio_rule)(const ip_address_t *ip_address,
+ int (*del_lo_prio_rule)(const ip_prefix_t *ip_address,
const uint8_t address_family,
const uint32_t priority);
} hicn_socket_ops_t;
diff --git a/hicn-light/src/hicn/socket/ops_linux.c b/hicn-light/src/hicn/socket/ops_linux.c
index 0b1c6b817..af41f400f 100644
--- a/hicn-light/src/hicn/socket/ops_linux.c
+++ b/hicn-light/src/hicn/socket/ops_linux.c
@@ -60,13 +60,13 @@ int _nl_get_output_ifid(const char *ip_address, uint8_t address_family,
* @see getifaddrs
*/
int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family,
- ip_address_t *ip_address);
+ ip_prefix_t *ip_address);
-int _nl_set_ip_addr(uint32_t interface_id, ip_address_t *ip_address);
+int _nl_set_ip_addr(uint32_t interface_id, ip_prefix_t *ip_address);
int _nl_up_if(uint32_t interface_id);
-int _nl_add_in_route_table(const ip_address_t *prefix,
+int _nl_add_in_route_table(const ip_prefix_t *prefix,
const uint32_t interface_id, const uint8_t table_id);
int _nl_add_in_route_table_s(const char *prefix, const uint32_t interface_id,
const uint8_t table_id);
@@ -77,25 +77,25 @@ int _nl_add_out_route(const char *gateway, const uint8_t address_family,
int _nl_del_out_route(const char *gateway, const uint8_t address_family,
const uint8_t table_id);
-int _nl_del_lo_route(const ip_address_t *ip_address);
+int _nl_del_lo_route(const ip_prefix_t *ip_address);
int _nl_add_rule(const char *interface_name, const uint8_t address_family,
const uint8_t table_id);
int _nl_del_rule(const char *interface_name, const uint8_t address_family,
const uint8_t table_id);
-int _nl_add_neigh_proxy(const ip_address_t *ip_address,
+int _nl_add_neigh_proxy(const ip_prefix_t *ip_address,
const uint32_t interface_id);
-int _nl_add_prio_rule(const ip_address_t *ip_address,
+int _nl_add_prio_rule(const ip_prefix_t *ip_address,
const uint8_t address_family, const uint32_t priority,
const uint8_t table_id);
-int _nl_add_lo_prio_rule(const ip_address_t *ip_address,
+int _nl_add_lo_prio_rule(const ip_prefix_t *ip_address,
const uint8_t address_family, const uint32_t priority);
-int _nl_del_prio_rule(const ip_address_t *ip_address,
+int _nl_del_prio_rule(const ip_prefix_t *ip_address,
const uint8_t address_family, const uint32_t priority,
const uint8_t table_id);
-int _nl_del_lo_prio_rule(const ip_address_t *ip_address,
+int _nl_del_lo_prio_rule(const ip_prefix_t *ip_address,
const uint8_t address_family, const uint32_t priority);
#endif /* HICN_NETLINK_H */
@@ -530,7 +530,7 @@ ERR:
}
int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family,
- ip_address_t *ip_address) {
+ ip_prefix_t *prefix) {
char buffer[BUFSIZE];
struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
size_t n;
@@ -574,21 +574,17 @@ int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family,
if (address_family == AF_INET6) {
if ((payload->ifa_index == interface_id) &&
(payload->ifa_prefixlen < IPV6_ADDR_LEN * 8)) {
- printf("got ip address\n");
- memcpy(ip_address->buffer, RTA_DATA(payload + 1), IPV6_ADDR_LEN);
- ip_address->family = AF_INET6;
- ip_address->prefix_len = IPV6_ADDR_LEN_BITS;
- printf("returning %d\n", HICN_SOCKET_ERROR_NONE);
+ memcpy(prefix->address.buffer, RTA_DATA(payload + 1), IPV6_ADDR_LEN);
+ prefix->family = AF_INET6;
+ prefix->len = IPV6_ADDR_LEN_BITS;
return HICN_SOCKET_ERROR_NONE;
}
} else if (address_family == AF_INET) {
if ((payload->ifa_index == interface_id) &&
(payload->ifa_prefixlen < IPV4_ADDR_LEN * 8)) {
- printf("got ip address\n");
- memcpy(ip_address->buffer, RTA_DATA(payload + 1), IPV4_ADDR_LEN);
- ip_address->family = AF_INET;
- ip_address->prefix_len = IPV4_ADDR_LEN_BITS;
- printf("returning %d\n", HICN_SOCKET_ERROR_NONE);
+ memcpy(prefix->address.buffer, RTA_DATA(payload + 1), IPV4_ADDR_LEN);
+ prefix->family = AF_INET;
+ prefix->len = IPV4_ADDR_LEN_BITS;
return HICN_SOCKET_ERROR_NONE;
}
} else {
@@ -600,11 +596,10 @@ ERR_NL:
ERR_RECV:
ERR_SEND:
ERR_SOCKET:
- printf("error getting ip address\n");
return HICN_SOCKET_ERROR_UNSPEC;
}
-int _nl_set_ip_addr(uint32_t interface_id, ip_address_t *ip_address) {
+int _nl_set_ip_addr(uint32_t interface_id, ip_prefix_t *prefix) {
char buffer[BUFSIZE];
struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
size_t n;
@@ -617,19 +612,19 @@ int _nl_set_ip_addr(uint32_t interface_id, ip_address_t *ip_address) {
.hdr.nlmsg_type = RTM_NEWADDR,
.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC,
.hdr.nlmsg_seq = seq++,
- .payload.ifa_family = ip_address->family,
- .payload.ifa_prefixlen = ip_address->prefix_len,
+ .payload.ifa_family = prefix->family,
+ .payload.ifa_prefixlen = prefix->len,
.payload.ifa_flags = 0,
.payload.ifa_scope = RT_SCOPE_UNIVERSE,
.payload.ifa_index = interface_id};
/* Set attributes = length/type/value */
- struct rtattr ifa_address = {RTA_LENGTH(ip_address_len(ip_address)),
+ struct rtattr ifa_address = {RTA_LENGTH(ip_address_len(&prefix->address, prefix->family)),
IFA_ADDRESS};
struct iovec iov[] = {
{&msg, sizeof(msg)},
{&ifa_address, sizeof(ifa_address)},
- {(void *)&ip_address->buffer, sizeof(ip_address->buffer)},
+ {(void *)&prefix->address.buffer, sizeof(prefix->address.buffer)},
};
msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
@@ -966,7 +961,7 @@ ERR_SOCKET:
* ip route del 1:2::2 dev lo table local
*
*/
-int _nl_del_lo_route(const ip_address_t *ip_address) {
+int _nl_del_lo_route(const ip_prefix_t *prefix) {
char buffer[BUFSIZE];
struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
size_t n;
@@ -979,8 +974,8 @@ int _nl_del_lo_route(const ip_address_t *ip_address) {
.hdr.nlmsg_type = RTM_DELROUTE,
.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
.hdr.nlmsg_seq = seq++,
- .payload.rtm_family = ip_address->family,
- .payload.rtm_dst_len = ip_address->prefix_len,
+ .payload.rtm_family = prefix->family,
+ .payload.rtm_dst_len = prefix->len,
.payload.rtm_src_len = 0,
.payload.rtm_tos = 0,
.payload.rtm_table = RT_TABLE_LOCAL,
@@ -992,13 +987,13 @@ int _nl_del_lo_route(const ip_address_t *ip_address) {
/* Set attribute = length/type/value */
uint32_t one = 1;
- struct rtattr a_dst = {RTA_LENGTH(ip_address_len(ip_address)), RTA_DST};
+ struct rtattr a_dst = {RTA_LENGTH(ip_address_len(&prefix->address, prefix->family)), RTA_DST};
struct rtattr a_ifid_lo = {RTA_LENGTH(sizeof(uint32_t)), RTA_OIF};
struct iovec iov[] = {
{&msg, sizeof(msg)},
/* Ip address */
{&a_dst, sizeof(a_dst)},
- {(void *)&ip_address->buffer, ip_address_len(ip_address)},
+ {(void *)&prefix->address.buffer, ip_address_len(&prefix->address, prefix->family)},
/* Interface id */
{&a_ifid_lo, sizeof(a_ifid_lo)},
{&one, sizeof(one)}};
@@ -1129,7 +1124,7 @@ ERR_SOCKET:
* ip -6 neigh add proxy 1:2::2 dev hicnc-cons-eth0 2>&1 | grep nei
*
*/
-int _nl_add_neigh_proxy(const ip_address_t *ip_address,
+int _nl_add_neigh_proxy(const ip_prefix_t *prefix,
const uint32_t interface_id) {
/* Buffer for holding the response, with appropriate casting on the header */
char buffer[BUFSIZE];
@@ -1147,21 +1142,21 @@ int _nl_add_neigh_proxy(const ip_address_t *ip_address,
.hdr.nlmsg_type = RTM_NEWNEIGH,
.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL,
.hdr.nlmsg_seq = seq++,
- .payload.ndm_family = ip_address->family,
+ .payload.ndm_family = prefix->family,
.payload.ndm_ifindex = interface_id,
.payload.ndm_state = NUD_PERMANENT,
.payload.ndm_flags = NTF_PROXY,
};
/* Message attributes = length/type/value */
- struct rtattr a_dst = {RTA_LENGTH(ip_address_len(ip_address)), NDA_DST};
+ struct rtattr a_dst = {RTA_LENGTH(ip_address_len(&prefix->address, prefix->family)), NDA_DST};
/* Iovec describing the packets */
struct iovec iov[] = {
{&msg, sizeof(msg)},
/* Ip address */
{&a_dst, sizeof(a_dst)},
- {(void *)&ip_address->buffer, sizeof(ip_address->buffer)},
+ {(void *)&prefix->address.buffer, sizeof(prefix->address.buffer)},
};
msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
@@ -1199,7 +1194,7 @@ ERR:
/* ip -6 route add 0:1::/64 dev hicn-if0 table 100 */
/* ip -6 route add 0:2::/64 dev hicn-if1 table 100 */
-int _nl_add_in_route_table(const ip_address_t *prefix,
+int _nl_add_in_route_table(const ip_prefix_t *prefix,
const uint32_t interface_id,
const uint8_t table_id) {
/* Buffer for holding the response, with appropriate casting on the header */
@@ -1219,7 +1214,7 @@ int _nl_add_in_route_table(const ip_address_t *prefix,
.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL,
.hdr.nlmsg_seq = seq++,
.payload.rtm_family = prefix->family,
- .payload.rtm_dst_len = prefix->prefix_len,
+ .payload.rtm_dst_len = prefix->len,
.payload.rtm_src_len = 0,
.payload.rtm_tos = 0,
.payload.rtm_table = table_id, /* RT_TABLE_MAIN, etc. */
@@ -1231,7 +1226,7 @@ int _nl_add_in_route_table(const ip_address_t *prefix,
};
/* Message attributes = length/type/value */
- struct rtattr a_dst = {RTA_LENGTH(ip_address_len(prefix)), RTA_DST};
+ struct rtattr a_dst = {RTA_LENGTH(ip_address_len(&prefix->address, prefix->family)), RTA_DST};
struct rtattr a_oif = {RTA_LENGTH(sizeof(uint32_t)), RTA_OIF};
/* Iovec describing the packets */
@@ -1239,7 +1234,7 @@ int _nl_add_in_route_table(const ip_address_t *prefix,
{&msg, sizeof(msg)},
/* Destination prefix / ip address */
{&a_dst, sizeof(a_dst)},
- {(void *)&prefix->buffer, ip_address_len(prefix)},
+ {(void *)&prefix->address.buffer, ip_address_len(&prefix->address, prefix->family)},
/* Output interface */
{&a_oif, sizeof(a_oif)},
{(void *)&interface_id, sizeof(uint32_t)},
@@ -1283,9 +1278,9 @@ ERR:
int _nl_add_in_route_table_s(const char *prefix, const uint32_t interface_id,
const uint8_t table_id) {
int rc;
- ip_address_t ip_address;
+ ip_prefix_t ip_address;
- rc = hicn_ip_pton(prefix, &ip_address);
+ rc = ip_prefix_pton(prefix, &ip_address);
if (rc < 0) {
return rc;
}
@@ -1298,7 +1293,7 @@ int _nl_add_in_route_s(const char *prefix, const uint32_t interface_id) {
}
/* ip -6 rule add from b001::/16 prio 0 table 100 */
-int _nl_add_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+int _nl_add_prio_rule(const ip_prefix_t *prefix, uint8_t address_family,
const uint32_t priority, const uint8_t table_id) {
/* Buffer for holding the response, with appropriate casting on the header */
char buffer[BUFSIZE];
@@ -1318,7 +1313,7 @@ int _nl_add_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
.hdr.nlmsg_seq = seq++,
.payload.family = address_family,
//.payload.dst_len = ,
- .payload.src_len = ip_address ? ip_address->prefix_len : 0,
+ .payload.src_len = prefix ? prefix->len : 0,
.payload.tos = 0,
.payload.table = table_id,
.payload.action = FR_ACT_TO_TBL,
@@ -1331,17 +1326,17 @@ int _nl_add_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
goto ERR;
}
- if (ip_address) {
+ if (prefix) {
/* Message attributes = length/type/value */
- struct rtattr a_src = {RTA_LENGTH(ip_address_len(ip_address)), FRA_SRC};
+ struct rtattr a_src = {RTA_LENGTH(ip_address_len(&prefix->address, prefix->family)), FRA_SRC};
struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY};
/* Iovec describing the packets */
struct iovec iov[] = {
{&msg, sizeof(msg)},
- /* Source prefix / ip_address */
+ /* Source prefix / prefix */
{&a_src, sizeof(a_src)},
- {(void *)&ip_address->buffer, ip_address_len(ip_address)},
+ {(void *)&prefix->address.buffer, ip_address_len(&prefix->address, prefix->family)},
/* Priority */
{&a_prio, sizeof(a_prio)},
{(void *)&priority, sizeof(uint32_t)},
@@ -1392,14 +1387,14 @@ ERR:
return HICN_SOCKET_ERROR_UNSPEC;
}
-int _nl_add_lo_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+int _nl_add_lo_prio_rule(const ip_prefix_t *prefix, uint8_t address_family,
const uint32_t priority) {
- return _nl_add_prio_rule(ip_address, address_family, priority,
+ return _nl_add_prio_rule(prefix, address_family, priority,
RT_TABLE_LOCAL);
}
/* ip -6 rule del from all prio 0 table local */
-int _nl_del_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+int _nl_del_prio_rule(const ip_prefix_t *prefix, uint8_t address_family,
const uint32_t priority, const uint8_t table_id) {
/* Buffer for holding the response, with appropriate casting on the header */
char buffer[BUFSIZE];
@@ -1419,7 +1414,7 @@ int _nl_del_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
.hdr.nlmsg_seq = seq++,
.payload.family = address_family,
//.payload.dst_len = ,
- .payload.src_len = ip_address ? ip_address->prefix_len : 0,
+ .payload.src_len = prefix ? prefix->len : 0,
.payload.tos = 0,
.payload.table = table_id,
.payload.action = FR_ACT_TO_TBL,
@@ -1433,16 +1428,16 @@ int _nl_del_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
}
/* Message attributes = length/type/value */
- if (ip_address) {
- struct rtattr a_src = {RTA_LENGTH(ip_address_len(ip_address)), FRA_SRC};
+ if (prefix) {
+ struct rtattr a_src = {RTA_LENGTH(ip_address_len(&prefix->address, prefix->family)), FRA_SRC};
struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY};
/* Iovec describing the packets */
struct iovec iov[] = {
{&msg, sizeof(msg)},
- /* Source prefix / ip_address */
+ /* Source prefix / prefix */
{&a_src, sizeof(a_src)},
- {(void *)&ip_address->buffer, ip_address_len(ip_address)},
+ {(void *)&prefix->address.buffer, ip_address_len(&prefix->address, prefix->family)},
/* Priority */
{&a_prio, sizeof(a_prio)},
{(void *)&priority, sizeof(uint32_t)},
@@ -1495,7 +1490,7 @@ ERR:
return HICN_SOCKET_ERROR_UNSPEC;
}
-int _nl_del_lo_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+int _nl_del_lo_prio_rule(const ip_prefix_t *ip_address, uint8_t address_family,
const uint32_t priority) {
return _nl_del_prio_rule(ip_address, address_family, priority,
RT_TABLE_LOCAL);
diff --git a/hicn-light/src/hicn/strategies/loadBalancer.c b/hicn-light/src/hicn/strategies/loadBalancer.c
index b66de217e..ca9d34289 100644
--- a/hicn-light/src/hicn/strategies/loadBalancer.c
+++ b/hicn-light/src/hicn/strategies/loadBalancer.c
@@ -201,6 +201,7 @@ static NumberSet *_strategyLoadBalancer_LookupNexthop(
PARCUnsigned *cid = parcUnsigned_Create(numberSet_GetItem(nexthops, i));
const StrategyNexthopState *elem =
parcHashMap_Get(lb->strategy_state, cid);
+ parcUnsigned_Release(&cid);
if (!elem)
continue;
sum += strategyNexthopState_GetWeight(elem);
@@ -213,12 +214,15 @@ static NumberSet *_strategyLoadBalancer_LookupNexthop(
PARCUnsigned *cid = parcUnsigned_Create(numberSet_GetItem(nexthops, i));
const StrategyNexthopState *state =
parcHashMap_Get(lb->strategy_state, cid);
- if (!state)
- continue;
+ if (!state){
+ parcUnsigned_Release(&cid);
+ continue;
+ }
distance -= strategyNexthopState_GetWeight(state);
if (distance < 0) {
numberSet_Add(outList, parcUnsigned_GetUnsigned(cid));
_update_Stats(lb, (StrategyNexthopState *)state, true);
+ parcUnsigned_Release(&cid);
break;
}
}
@@ -296,19 +300,20 @@ static void _strategyLoadBalancer_resetState(StrategyImpl *strategy) {
static void _strategyLoadBalancer_AddNexthop(StrategyImpl *strategy,
unsigned connectionId) {
- StrategyNexthopState *state = strategyNexthopState_Create();
PARCUnsigned *cid = parcUnsigned_Create(connectionId);
StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
if (!parcHashMap_Contains(lb->strategy_state, cid)) {
+ StrategyNexthopState *state = strategyNexthopState_Create();
parcHashMap_Put(lb->strategy_state, cid, state);
#ifndef WITH_POLICY
numberSet_Add(lb->nexthops, connectionId);
#endif /* WITH_POLICY */
_strategyLoadBalancer_resetState(strategy);
}
+ parcUnsigned_Release(&cid);
}
static void _strategyLoadBalancer_RemoveNexthop(StrategyImpl *strategy,
diff --git a/hicn-light/src/hicn/utils/CMakeLists.txt b/hicn-light/src/hicn/utils/CMakeLists.txt
index dd9e12c15..1ab38deba 100644
--- a/hicn-light/src/hicn/utils/CMakeLists.txt
+++ b/hicn-light/src/hicn/utils/CMakeLists.txt
@@ -19,7 +19,6 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/commands.h
${CMAKE_CURRENT_SOURCE_DIR}/interface.h
${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.h
- ${CMAKE_CURRENT_SOURCE_DIR}/policy.h
${CMAKE_CURRENT_SOURCE_DIR}/punting.h
${CMAKE_CURRENT_SOURCE_DIR}/token.h
${CMAKE_CURRENT_SOURCE_DIR}/utils.h
@@ -30,7 +29,6 @@ list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/addressList.c
${CMAKE_CURRENT_SOURCE_DIR}/interface.c
${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.c
- ${CMAKE_CURRENT_SOURCE_DIR}/policy.c
${CMAKE_CURRENT_SOURCE_DIR}/punting.c
${CMAKE_CURRENT_SOURCE_DIR}/utils.c
)
diff --git a/hicn-light/src/hicn/utils/commands.h b/hicn-light/src/hicn/utils/commands.h
index 223bbffaa..60d4cd5fa 100644
--- a/hicn-light/src/hicn/utils/commands.h
+++ b/hicn-light/src/hicn/utils/commands.h
@@ -31,7 +31,11 @@
#include <stdint.h>
#include <stdlib.h>
-#include <hicn/utils/policy.h>
+#ifdef WITH_POLICY
+#include <hicn/policy.h>
+#endif /* WITH_POLICY */
+
+#define SYMBOLIC_NAME_LEN 16
typedef struct in6_addr ipv6_addr_t;
typedef uint32_t ipv4_addr_t;
@@ -56,6 +60,7 @@ typedef enum {
ADD_ROUTE,
LIST_ROUTES,
REMOVE_CONNECTION,
+ REMOVE_LISTENER,
REMOVE_ROUTE,
CACHE_STORE,
CACHE_SERVE,
@@ -112,10 +117,8 @@ typedef struct {
typedef enum { ETHER_MODE, IP_MODE, HICN_MODE } listener_mode;
typedef struct {
- char symbolic[16];
-#ifdef __linux__
- char interfaceName[16];
-#endif
+ char symbolic[SYMBOLIC_NAME_LEN];
+ char interfaceName[SYMBOLIC_NAME_LEN];
union commandAddr address;
uint16_t port;
// uint16_t etherType;
@@ -124,12 +127,13 @@ typedef struct {
uint8_t connectionType;
} add_listener_command;
-// SIZE=40
+// SIZE=56
//========== [01] ADD CONNECTION ==========
typedef struct {
- char symbolic[16];
+ char symbolic[SYMBOLIC_NAME_LEN];
+ //char interfaceName[SYMBOLIC_NAME_LEN];
union commandAddr remoteIp;
union commandAddr localIp;
uint16_t remotePort;
@@ -165,14 +169,17 @@ typedef struct {
add_connection_command connectionData;
uint32_t connid;
uint8_t state;
+ uint8_t admin_state;
+ char interfaceName[SYMBOLIC_NAME_LEN];
+ char connectionName[SYMBOLIC_NAME_LEN];
} list_connections_command;
-// SIZE=64
+// SIZE=80
//========== [03] ADD ROUTE ==========
typedef struct {
- char symbolicOrConnid[16];
+ char symbolicOrConnid[SYMBOLIC_NAME_LEN];
union commandAddr address;
uint16_t cost;
uint8_t addressType;
@@ -194,17 +201,21 @@ typedef struct {
// SIZE=24
//========== [05] REMOVE CONNECTION ==========
-
typedef struct {
- char symbolicOrConnid[16];
+ char symbolicOrConnid[SYMBOLIC_NAME_LEN];
} remove_connection_command;
+//========== [06] REMOVE LISTENER ==========
+typedef struct {
+ char symbolicOrListenerid[SYMBOLIC_NAME_LEN];
+} remove_listener_command;
+
// SIZE=16
-//========== [06] REMOVE ROUTE ==========
+//========== [07] REMOVE ROUTE ==========
typedef struct {
- char symbolicOrConnid[16];
+ char symbolicOrConnid[SYMBOLIC_NAME_LEN];
union commandAddr address;
uint8_t addressType;
uint8_t len;
@@ -212,7 +223,7 @@ typedef struct {
// SIZE=36
-//========== [07] CACHE STORE ==========
+//========== [08] CACHE STORE ==========
typedef struct {
uint8_t activate;
@@ -220,7 +231,7 @@ typedef struct {
// SIZE=1
-//========== [08] CACHE SERVE ==========
+//========== [09] CACHE SERVE ==========
typedef struct {
uint8_t activate;
@@ -228,15 +239,13 @@ typedef struct {
// SIZE=1
-//========== [09] SET STRATEGY ==========
+//========== [10] SET STRATEGY ==========
typedef enum {
SET_STRATEGY_LOADBALANCER,
SET_STRATEGY_RANDOM,
SET_STRATEGY_RANDOM_PER_DASH_SEGMENT,
SET_STRATEGY_LOADBALANCER_WITH_DELAY,
- SET_STRATEGY_LOADBALANCER_BY_RATE,
- SET_STRATEGY_LOADBALANCER_BEST_ROUTE,
LAST_STRATEGY_VALUE
} strategy_type;
@@ -252,7 +261,7 @@ typedef struct {
//========== [11] SET WLDR ==========
typedef struct {
- char symbolicOrConnid[16];
+ char symbolicOrConnid[SYMBOLIC_NAME_LEN];
uint8_t activate;
} set_wldr_command;
@@ -261,7 +270,7 @@ typedef struct {
//========== [12] ADD PUNTING ==========
typedef struct {
- char symbolicOrConnid[16];
+ char symbolicOrConnid[SYMBOLIC_NAME_LEN];
union commandAddr address;
uint8_t addressType;
uint8_t len;
@@ -273,13 +282,15 @@ typedef struct {
typedef struct {
union commandAddr address;
+ char listenerName[SYMBOLIC_NAME_LEN];
+ char interfaceName[SYMBOLIC_NAME_LEN];
uint32_t connid;
uint16_t port;
uint8_t addressType;
uint8_t encapType;
} list_listeners_command;
-// SIZE=24
+// SIZE=56
//========== [14] MAPME ==========
@@ -298,8 +309,9 @@ typedef struct {
// SIZE=1
typedef struct {
- char symbolicOrConnid[16];
+ char symbolicOrConnid[SYMBOLIC_NAME_LEN];
uint8_t admin_state;
+ uint16_t pad16;
} connection_set_admin_state_command;
#ifdef WITH_POLICY
@@ -325,7 +337,7 @@ typedef struct {
} remove_policy_command;
typedef struct {
- char symbolicOrConnid[16];
+ char symbolicOrConnid[SYMBOLIC_NAME_LEN];
uint8_t admin_state;
policy_tags_t tags;
} update_connection_command;
@@ -346,9 +358,11 @@ static inline int payloadLengthDaemon(command_id id) {
case ADD_ROUTE:
return sizeof(add_route_command);
case LIST_ROUTES:
- return 0; // list routes: payload always 0
+ return 0; // list rout`es: payload always 0
case REMOVE_CONNECTION:
return sizeof(remove_connection_command);
+ case REMOVE_LISTENER:
+ return sizeof(remove_listener_command);
case REMOVE_ROUTE:
return sizeof(remove_route_command);
case CACHE_STORE:
diff --git a/hicn-light/src/hicn/utils/policy.h b/hicn-light/src/hicn/utils/policy.h
deleted file mode 100644
index 993fdca44..000000000
--- a/hicn-light/src/hicn/utils/policy.h
+++ /dev/null
@@ -1,232 +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 <string.h> // strcasecmp
-#include "token.h"
-
-/* POLICY TAG */
-
-#define foreach_policy_tag \
- /* Interface type */ \
- _(WIRED, 'E') \
- _(WIFI, 'W') \
- _(CELLULAR, 'C') \
- /* QoS */ \
- _(BEST_EFFORT, 'b') \
- _(REALTIME, 'r') \
- _(MULTIPATH, 'M') \
- /* Security */ \
- _(TRUSTED, 'T')
-
-typedef enum {
-#define _(x, y) 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[];
-extern const char policy_tag_short_str[];
-
-static inline
-policy_tag_t
-policy_tag_from_str(const char * str)
-{
-#define _(x, y) if (strcasecmp(str, policy_tag_str[POLICY_TAG_ ## x] ) == 0) { return POLICY_TAG_ ## x; } else
-foreach_policy_tag
-#undef _
- return POLICY_TAG_N;
-}
-
-/* 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
-
-static inline
-int
-policy_tags_snprintf(char * s, size_t size, policy_tags_t tags)
-{
-#define _(x, y) s[POLICY_TAG_ ## x] = policy_tags_has(tags, POLICY_TAG_ ## x) ? y : '.';
-foreach_policy_tag
-#undef _
- s[POLICY_TAG_N] = '\0';
- return POLICY_TAG_N + 1;
-}
-
-#define MAXSZ_POLICY_TAGS_ POLICY_TAG_N
-#define MAXSZ_POLICY_TAGS MAXSZ_POLICY_TAGS_ + 1
-
-/* POLICY STATE */
-
-#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, y) [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;
-
-#endif /* HICN_POLICY_H */
diff --git a/hicn-light/src/hicn/utils/utils.c b/hicn-light/src/hicn/utils/utils.c
index 61ff9a904..93a3efd81 100644
--- a/hicn-light/src/hicn/utils/utils.c
+++ b/hicn-light/src/hicn/utils/utils.c
@@ -90,7 +90,6 @@ struct iovec *utils_CreateNack(header_control_message *header, void *payload,
parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
header->messageType = NACK_LIGHT;
-
response[0].iov_base = header;
response[0].iov_len = sizeof(header_control_message);
response[1].iov_base = payload;
diff --git a/hicn-plugin/CMakeLists.txt b/hicn-plugin/CMakeLists.txt
index 0da096e22..8425a5cf3 100644
--- a/hicn-plugin/CMakeLists.txt
+++ b/hicn-plugin/CMakeLists.txt
@@ -55,25 +55,31 @@ set(LIBHICN_FILES
)
set(LIBHICN_HEADER_FILES_SRC
- ../lib/src/hicn.h
- ../lib/src/base.h
- ../lib/src/common.h
- ../lib/src/error.h
- ../lib/src/header.h
- ../lib/src/name.h
- ../lib/src/protocol.h
- ../lib/src/ops.h
- ../lib/src/mapme.h
+ ../lib/includes/hicn/hicn.h
+ ../lib/includes/hicn/base.h
+ ../lib/includes/hicn/common.h
+ ../lib/includes/hicn/error.h
+ ../lib/includes/hicn/header.h
+ ../lib/includes/hicn/name.h
+ ../lib/includes/hicn/protocol.h
+ ../lib/includes/hicn/ops.h
+ ../lib/includes/hicn/mapme.h
)
set(LIBHICN_HEADER_FILES_PROTOCOL
- ../lib/src/protocol/ah.h
- ../lib/src/protocol/icmp.h
- ../lib/src/protocol/icmprd.h
- ../lib/src/protocol/ipv4.h
- ../lib/src/protocol/ipv6.h
- ../lib/src/protocol/tcp.h
- ../lib/src/protocol/udp.h
+ ../lib/includes/hicn/protocol/ah.h
+ ../lib/includes/hicn/protocol/icmp.h
+ ../lib/includes/hicn/protocol/icmprd.h
+ ../lib/includes/hicn/protocol/ipv4.h
+ ../lib/includes/hicn/protocol/ipv6.h
+ ../lib/includes/hicn/protocol/tcp.h
+ ../lib/includes/hicn/protocol/udp.h
+)
+
+set(LIBHICN_HEADER_FILES_UTIL
+ ../lib/includes/hicn/util/ip_address.h
+ ../lib/includes/hicn/util/token.h
+ ../lib/includes/hicn/util/types.h
)
set(HICN_PLUGIN_SOURCE_FILES
@@ -262,6 +268,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}/vpp_plugins)
file(COPY ${LIBHICN_HEADER_FILES_SRC} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/hicn)
file(COPY ${LIBHICN_HEADER_FILES_PROTOCOL} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/hicn/protocol)
+file(COPY ${LIBHICN_HEADER_FILES_UTIL} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/hicn/util)
add_library(hicn_api_test_plugin SHARED
${HICN_API_TEST_SOURCE_FILES}
@@ -300,6 +307,10 @@ install(FILES ${HICN_API_HEADER_FILES} ${HICN_API_GENERATED_FILES}
DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/vpp_plugins/hicn
COMPONENT ${HICN_PLUGIN}-dev)
+install(FILES ${HICN_API_GENERATED_FILES}
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/vpp_plugins/hicn
+ COMPONENT ${HICN_PLUGIN_DEV})
+
install(FILES ${HICN_VAPI_GENERATED_FILES}
DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/vapi
COMPONENT ${HICN_PLUGIN}-dev)
diff --git a/hicn-plugin/scripts/post b/hicn-plugin/scripts/post
index 3cde599ca..dd0a9fbf5 100644
--- a/hicn-plugin/scripts/post
+++ b/hicn-plugin/scripts/post
@@ -1,7 +1,8 @@
#!/bin/bash
if [ -e /etc/vpp/startup.conf ]; then
- if ! grep -q "hicn" /etc/vpp/startup.conf; then
+ RESULTS=$(sed -n '/hicn[ ]*{/p' /etc/vpp/startup.conf | wc -l)
+ if [[ $RESULTS = 0 ]]; then
printf '\n hicn {
## Set PIT size. Default is 131 072 entries
# pit-size 500000
diff --git a/hicn-plugin/scripts/postinst b/hicn-plugin/scripts/postinst
index 012fc3571..d6d48509c 100644
--- a/hicn-plugin/scripts/postinst
+++ b/hicn-plugin/scripts/postinst
@@ -1,7 +1,8 @@
#!/bin/bash
if [ -e /etc/vpp/startup.conf ]; then
- if ! grep -q "hicn" /etc/vpp/startup.conf; then
+ RESULTS=$(sed -n '/hicn[ ]*{/p' /etc/vpp/startup.conf | wc -l)
+ if [[ $RESULTS = 0 ]]; then
printf '\n hicn {
## Set PIT size. Default is 131 072 entries
# pit-size 500000
diff --git a/hicn-plugin/src/data_fwd_node.c b/hicn-plugin/src/data_fwd_node.c
index 53308a49d..ca3baaa0d 100644
--- a/hicn-plugin/src/data_fwd_node.c
+++ b/hicn-plugin/src/data_fwd_node.c
@@ -176,6 +176,7 @@ hicn_data_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
hicn_pcs_delete (pitcs, &pitp, &node0, vm, hash_entry0,
dpo_vft0, &hicn_dpo_id0);
+#if HICN_FEATURE_CS
if (hicnb0->flags & HICN_BUFFER_FLAGS_FACE_IS_APP)
{
push_in_cache (vm, bi0, &n_left_to_next, &next0, &to_next,
@@ -186,6 +187,10 @@ hicn_data_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
drop_packet (vm, bi0, &n_left_to_next, &next0, &to_next,
&next_index, node);
}
+#else
+ drop_packet (vm, bi0, &n_left_to_next, &next0, &to_next,
+ &next_index, node);
+#endif
stats.pit_expired_count++;
if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
diff --git a/hicn-plugin/src/data_pcslookup_node.c b/hicn-plugin/src/data_pcslookup_node.c
index aeb8c2276..1ae36202f 100644
--- a/hicn-plugin/src/data_pcslookup_node.c
+++ b/hicn-plugin/src/data_pcslookup_node.c
@@ -14,12 +14,12 @@
*/
#include "data_pcslookup.h"
+#include "infra.h"
#include "mgmt.h"
#include "parser.h"
-#include "infra.h"
+#include "state.h"
#include "strategy.h"
#include "strategy_dpo_manager.h"
-#include "state.h"
/* Stats string values */
static char *hicn_data_pcslookup_error_strings[] = {
@@ -37,10 +37,9 @@ vlib_node_registration_t hicn_data_pcslookup_node;
* hICN node for handling data. It performs a lookup in the PIT.
*/
static uword
-hicn_data_pcslookup_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+hicn_data_pcslookup_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
{
-
u32 n_left_from, *from, *to_next;
hicn_data_pcslookup_next_t next_index;
hicn_data_pcslookup_runtime_t *rt;
@@ -87,7 +86,8 @@ hicn_data_pcslookup_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
{
vlib_buffer_t *b1;
b1 = vlib_get_buffer (vm, from[1]);
- //Prefetch two cache lines-- 128 byte-- so that we load the hicn_buffer_t as well
+ // Prefetch two cache lines-- 128 byte-- so that we load the
+ // hicn_buffer_t as well
CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, STORE);
CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, LOAD);
}
@@ -99,47 +99,35 @@ hicn_data_pcslookup_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
to_next += 1;
n_left_to_next -= 1;
-
b0 = vlib_get_buffer (vm, bi0);
hb0 = hicn_get_buffer (b0);
+ next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP;
/* Incr packet counter */
stats.pkts_processed += 1;
ret0 = hicn_data_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
-
- if (PREDICT_TRUE (ret0 == HICN_ERROR_NONE))
- {
- next0 =
- isv6 ? HICN_DATA_PCSLOOKUP_NEXT_V6_LOOKUP :
- HICN_DATA_PCSLOOKUP_NEXT_V4_LOOKUP;
- }
nameptr = (u8 *) (&name);
- if (PREDICT_FALSE
- (ret0 != HICN_ERROR_NONE
- || hicn_hashtb_fullhash (nameptr, namelen,
- &name_hash) != HICN_ERROR_NONE))
- {
- next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP;
- }
- else
+
+ if (PREDICT_TRUE (ret0 == HICN_ERROR_NONE &&
+ hicn_hashtb_fullhash (nameptr, namelen,
+ &name_hash) ==
+ HICN_ERROR_NONE))
{
int res =
hicn_hashtb_lookup_node (rt->pitcs->pcs_table, nameptr,
namelen, name_hash,
- !(hb0->flags &
- HICN_BUFFER_FLAGS_FACE_IS_APP)
- /* take lock */ ,
+ 1 /*is_data. Do not take lock if hit CS */ ,
&node_id0, &dpo_ctx_id0, &vft_id0,
- &is_cs0,
- &hash_entry_id, &bucket_id,
+ &is_cs0, &hash_entry_id, &bucket_id,
&bucket_is_overflown);
stats.pkts_data_count += 1;
- if ((res == HICN_ERROR_HASHTB_HASH_NOT_FOUND
- || (res == HICN_ERROR_NONE && is_cs0))
- && (hb0->flags & HICN_BUFFER_FLAGS_FACE_IS_APP))
+#if HICN_FEATURE_CS
+ if ((res == HICN_ERROR_HASHTB_HASH_NOT_FOUND ||
+ (res == HICN_ERROR_NONE && is_cs0)) &&
+ ((hb0->flags & HICN_BUFFER_FLAGS_FACE_IS_APP)))
{
next0 = HICN_DATA_PCSLOOKUP_NEXT_STORE_DATA;
}
@@ -153,6 +141,18 @@ hicn_data_pcslookup_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
next0 = HICN_DATA_PCSLOOKUP_NEXT_DATA_FWD + is_cs0;
}
}
+#else
+ if (res == HICN_ERROR_NONE)
+ {
+ /*
+ * In case the result of the lookup
+ * is a CS entry, the packet is
+ * dropped
+ */
+ next0 = HICN_DATA_PCSLOOKUP_NEXT_DATA_FWD + is_cs0;
+ }
+ }
+#endif
hicn_store_internal_state (b0, name_hash, node_id0, dpo_ctx_id0,
vft_id0, hash_entry_id, bucket_id,
@@ -166,9 +166,8 @@ hicn_data_pcslookup_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
* Fix in case of a wrong speculation. Needed to
* clone the data in the right frame
*/
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, next0);
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, next0);
/* Maybe trace */
if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
@@ -214,24 +213,22 @@ hicn_data_pcslookup_format_trace (u8 * s, va_list * args)
return (s);
}
-
/*
* Node registration for the data forwarder node
*/
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (hicn_data_pcslookup_node) =
+VLIB_REGISTER_NODE(hicn_data_pcslookup_node) =
{
.function = hicn_data_pcslookup_node_fn,
.name = "hicn-data-pcslookup",
- .vector_size = sizeof (u32),
- .runtime_data_bytes = sizeof (hicn_data_pcslookup_runtime_t),
+ .vector_size = sizeof(u32),
+ .runtime_data_bytes = sizeof(hicn_data_pcslookup_runtime_t),
.format_trace = hicn_data_pcslookup_format_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
- .n_errors = ARRAY_LEN (hicn_data_pcslookup_error_strings),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN(hicn_data_pcslookup_error_strings),
.error_strings = hicn_data_pcslookup_error_strings,
.n_next_nodes = HICN_DATA_PCSLOOKUP_N_NEXT,
- .next_nodes =
- {
+ .next_nodes = {
[HICN_DATA_PCSLOOKUP_NEXT_V4_LOOKUP] = "ip4-lookup",
[HICN_DATA_PCSLOOKUP_NEXT_V6_LOOKUP] = "ip6-lookup",
[HICN_DATA_PCSLOOKUP_NEXT_STORE_DATA] = "hicn-data-push",
diff --git a/hicn-plugin/src/faces/app/face_prod.c b/hicn-plugin/src/faces/app/face_prod.c
index 7e6117b84..bbcc7fa6e 100644
--- a/hicn-plugin/src/faces/app/face_prod.c
+++ b/hicn-plugin/src/faces/app/face_prod.c
@@ -218,7 +218,7 @@ hicn_face_prod_add (hicn_prefix_t * prefix, u32 sw_if, u32 * cs_reserved,
remote_app_ip = to_ip46 ( /* isv6 */ 0, remote_app_ip4.as_u8);
ret =
- hicn_face_ip_add (&local_app_ip, &remote_app_ip, sw_if, faceid);
+ hicn_face_ip_add (&local_app_ip, &remote_app_ip, sw_if, faceid, HICN_FACE_FLAGS_APPFACE_PROD);
}
else
{
@@ -238,7 +238,7 @@ hicn_face_prod_add (hicn_prefix_t * prefix, u32 sw_if, u32 * cs_reserved,
remote_app_ip = to_ip46 ( /* isv6 */ 1, remote_app_ip6.as_u8);
ret =
- hicn_face_ip_add (&local_app_ip, &remote_app_ip, sw_if, faceid);
+ hicn_face_ip_add (&local_app_ip, &remote_app_ip, sw_if, faceid, HICN_FACE_FLAGS_APPFACE_PROD);
}
face = hicn_dpoi_get_from_idx (*faceid);
diff --git a/hicn-plugin/src/faces/ip/dpo_ip.c b/hicn-plugin/src/faces/ip/dpo_ip.c
index de71f1b01..d05fec1a0 100644
--- a/hicn-plugin/src/faces/ip/dpo_ip.c
+++ b/hicn-plugin/src/faces/ip/dpo_ip.c
@@ -19,6 +19,8 @@ mhash_t hicn_face_ip_local_hashtb;
mhash_t hicn_face_ip_remote_hashtb;
dpo_type_t hicn_face_ip_type;
+hicn_face_ip_vec_t * hicn_vec_pool;
+
const static char *const hicn_face_ip4dpoi_nodes[] = {
"hicn-face-ip4-input",
"hicn-face-ip4-output",
@@ -51,12 +53,14 @@ void
hicn_dpo_ip_module_init (void)
{
mhash_init (&hicn_face_ip_local_hashtb,
- sizeof (hicn_face_id_t) /* value */ ,
+ sizeof (hicn_face_ip_input_faces_t) /* value */ ,
sizeof (hicn_face_ip_key_t) /* key */ );
mhash_init (&hicn_face_ip_remote_hashtb,
sizeof (hicn_face_id_t) /* value */ ,
sizeof (hicn_face_ip_key_t) /* key */ );
+ pool_alloc(hicn_vec_pool, 100);
+
/*
* How much useful is the following registration?
* So far it seems that we need it only for setting the dpo_type.
@@ -65,106 +69,6 @@ hicn_dpo_ip_module_init (void)
dpo_register_new_type (&hicn_face_ip_vft, hicn_ip_nodes);
}
-
-int
-hicn_dpo_ip4_create (dpo_id_t * dpo,
- const ip4_address_t * local_addr,
- const ip4_address_t * remote_addr,
- u32 sw_if,
- adj_index_t adj,
- u32 node_index,
- hicn_face_flags_t flags, hicn_face_id_t * face_id)
-{
- /* If local matches the dpoi is a face */
- hicn_face_t *face =
- hicn_face_ip4_get (local_addr, sw_if, &hicn_face_ip_local_hashtb);
- u8 hicnb_flags;
-
- if (face != NULL)
- return HICN_ERROR_FACE_ALREADY_CREATED;
-
- face = hicn_face_ip4_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb);
-
- if (face == NULL)
- {
- hicn_dpo_ip4_add_and_lock_from_remote (dpo, &hicnb_flags, local_addr,
- remote_addr, sw_if, node_index);
- *face_id = (hicn_face_id_t) dpo->dpoi_index;
- face = hicn_dpoi_get_from_idx (*face_id);
- }
- else
- {
- *face_id = hicn_dpoi_get_index (face);
- dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, *face_id);
- dpo->dpoi_next_node = node_index;
- }
-
-
- hicn_face_ip_key_t key;
- hicn_face_ip4_get_key (local_addr, sw_if, &key);
-
- mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) face_id, 0);
-
- hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
- ip46_address_set_ip4 (&ip_face->local_addr, local_addr);
- ip46_address_set_ip4 (&ip_face->remote_addr, remote_addr);
- face->shared.flags = flags;
- face->shared.adj = adj;
-
- return HICN_ERROR_NONE;
-}
-
-int
-hicn_dpo_ip6_create (dpo_id_t * dpo,
- const ip6_address_t * local_addr,
- const ip6_address_t * remote_addr,
- u32 sw_if,
- adj_index_t adj,
- u32 node_index,
- hicn_face_flags_t flags, hicn_face_id_t * face_id)
-{
- /* If local matches the dpoi is a face */
- hicn_face_t *face =
- hicn_face_ip6_get (local_addr, sw_if, &hicn_face_ip_local_hashtb);
-
- u8 hicnb_flags;
-
- if (face != NULL)
- return HICN_ERROR_FACE_ALREADY_CREATED;
-
- face = hicn_face_ip6_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb);
-
- /* If remote matches the dpoi is a iface */
- if (face == NULL)
- {
- hicn_dpo_ip6_add_and_lock_from_remote (dpo, &hicnb_flags, local_addr,
- remote_addr, sw_if, node_index);
- *face_id = (hicn_face_id_t) dpo->dpoi_index;
- face = hicn_dpoi_get_from_idx (*face_id);
- }
- else
- {
- *face_id = hicn_dpoi_get_index (face);
- dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, *face_id);
- dpo->dpoi_next_node = node_index;
- }
-
- hicn_face_ip_key_t key;
- hicn_face_ip6_get_key (local_addr, sw_if, &key);
-
- mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) face_id, 0);
-
- hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
- clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip6_address_t));
- clib_memcpy (&ip_face->remote_addr, remote_addr, sizeof (ip6_address_t));
- face->shared.sw_if = sw_if;
- face->shared.flags = flags;
- face->shared.adj = adj;
-
-
- return HICN_ERROR_NONE;
-}
-
void
hicn_dpo_ip_create_from_face (hicn_face_t * face, dpo_id_t * dpo,
u16 dpoi_next_node)
diff --git a/hicn-plugin/src/faces/ip/dpo_ip.h b/hicn-plugin/src/faces/ip/dpo_ip.h
index 164931a06..d6b4f5f7e 100644
--- a/hicn-plugin/src/faces/ip/dpo_ip.h
+++ b/hicn-plugin/src/faces/ip/dpo_ip.h
@@ -29,10 +29,9 @@ void hicn_dpo_ip_module_init (void);
/**
- * @brief Retrieve a face from the ip4 local address and returns its dpo. This
- * method adds a lock on the face state.
+ * @brief Retrieve a vector of faces from the ip4 local address and returns its index.
*
- * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL
+ * @param vec: Result of the lookup. If no face exists for the local address vec = NULL
* @param hicnb_flags: Flags that indicate whether the face is an application
* face or not
* @param local_addr: Ip v4 local address of the face
@@ -42,22 +41,25 @@ void hicn_dpo_ip_module_init (void);
*/
always_inline int
hicn_dpo_ip4_lock_from_local (dpo_id_t * dpo,
+ u32 * in_faces_vec_id,
u8 * hicnb_flags,
const ip4_address_t * local_addr, u32 sw_if)
{
- hicn_face_t *face =
- hicn_face_ip4_get (local_addr, sw_if, &hicn_face_ip_local_hashtb);
+ hicn_face_ip_input_faces_t * in_faces_vec =
+ hicn_face_ip4_get_vec (local_addr, sw_if, &hicn_face_ip_local_hashtb);
- if (PREDICT_FALSE (face == NULL))
+ if (PREDICT_FALSE (in_faces_vec == NULL))
return HICN_ERROR_FACE_NOT_FOUND;
+ *in_faces_vec_id = in_faces_vec->vec_id;
+ hicn_face_t *face = hicn_dpoi_get_from_idx (in_faces_vec->face_id);
+
*hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT;
*hicnb_flags |=
(face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD) >>
HICN_FACE_FLAGS_APPFACE_PROD_BIT;
- hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
- dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index);
+ dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, in_faces_vec->face_id);
dpo->dpoi_next_node = ~0;
dpo_lock (dpo);
@@ -78,22 +80,25 @@ hicn_dpo_ip4_lock_from_local (dpo_id_t * dpo,
*/
always_inline int
hicn_dpo_ip6_lock_from_local (dpo_id_t * dpo,
+ u32 * in_faces_vec_id,
u8 * hicnb_flags,
const ip6_address_t * local_addr, u32 sw_if)
{
- hicn_face_t *face =
- hicn_face_ip6_get (local_addr, sw_if, &hicn_face_ip_local_hashtb);
+ hicn_face_ip_input_faces_t * in_faces_vec =
+ hicn_face_ip6_get_vec (local_addr, sw_if, &hicn_face_ip_local_hashtb);
- if (PREDICT_FALSE (face == NULL))
+ if (PREDICT_FALSE (in_faces_vec == NULL))
return HICN_ERROR_FACE_NOT_FOUND;
+ *in_faces_vec_id = in_faces_vec->vec_id;
+ hicn_face_t *face = hicn_dpoi_get_from_idx (in_faces_vec->face_id);
+
*hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT;
*hicnb_flags |=
(face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD) >>
HICN_FACE_FLAGS_APPFACE_PROD_BIT;
- hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
- dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, dpoi_index);
+ dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, in_faces_vec->face_id);
dpo->dpoi_next_node = ~0;
dpo_lock (dpo);
@@ -210,49 +215,49 @@ hicn_dpo_ip6_add_and_lock_from_remote (dpo_id_t * dpo,
}
-/**
- * @brief Create an ip face and its corresponding dpo. Meant to be used for the
- * control plane.
- *
- * @param dpo: Data plane object that point to the face created.
- * @param local_addr: Ip v4 local address of the face
- * @param remote_addr: Ip v4 remote address of the face
- * @param sw_if: software interface id of the face
- * @param adj: Ip adjacency corresponding to the remote address in the face
- * @param node_index: vlib edge index to use in the packet processing
- * @param flags: Flags of the face
- * @param face_id: Identifier for the face (dpoi_index)
- * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE
- */
-int hicn_dpo_ip4_create (dpo_id_t * dpo,
- const ip4_address_t * local_addr,
- const ip4_address_t * remote_addr,
- u32 sw_if,
- adj_index_t adj,
- u32 node_index,
- hicn_face_flags_t flags, hicn_face_id_t * face_id);
-
-/**
- * @brief Create an ip face and its corresponding dpo. Meant to be used for the
- * control plane.
- *
- * @param dpo: Data plane object that point to the face created.
- * @param local_addr: Ip v6 local address of the face
- * @param remote_addr: Ip v6 remote address of the face
- * @param sw_if: software interface id of the face
- * @param adj: Ip adjacency corresponding to the remote address in the face
- * @param node_index: vlib edge index to use in the packet processing
- * @param flags: Flags of the face
- * @param face_id: Identifier for the face (dpoi_index)
- * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE
- */
-int hicn_dpo_ip6_create (dpo_id_t * dpo,
- const ip6_address_t * local_addr,
- const ip6_address_t * remote_addr,
- u32 sw_if,
- adj_index_t adj,
- u32 node_index,
- hicn_face_flags_t flags, hicn_face_id_t * face_id);
+/* /\** */
+/* * @brief Create an ip face and its corresponding dpo. Meant to be used for the */
+/* * control plane. */
+/* * */
+/* * @param dpo: Data plane object that point to the face created. */
+/* * @param local_addr: Ip v4 local address of the face */
+/* * @param remote_addr: Ip v4 remote address of the face */
+/* * @param sw_if: software interface id of the face */
+/* * @param adj: Ip adjacency corresponding to the remote address in the face */
+/* * @param node_index: vlib edge index to use in the packet processing */
+/* * @param flags: Flags of the face */
+/* * @param face_id: Identifier for the face (dpoi_index) */
+/* * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE */
+/* *\/ */
+/* int hicn_dpo_ip4_create (dpo_id_t * dpo, */
+/* const ip4_address_t * local_addr, */
+/* const ip4_address_t * remote_addr, */
+/* u32 sw_if, */
+/* adj_index_t adj, */
+/* u32 node_index, */
+/* hicn_face_flags_t flags, hicn_face_id_t * face_id); */
+
+/* /\** */
+/* * @brief Create an ip face and its corresponding dpo. Meant to be used for the */
+/* * control plane. */
+/* * */
+/* * @param dpo: Data plane object that point to the face created. */
+/* * @param local_addr: Ip v6 local address of the face */
+/* * @param remote_addr: Ip v6 remote address of the face */
+/* * @param sw_if: software interface id of the face */
+/* * @param adj: Ip adjacency corresponding to the remote address in the face */
+/* * @param node_index: vlib edge index to use in the packet processing */
+/* * @param flags: Flags of the face */
+/* * @param face_id: Identifier for the face (dpoi_index) */
+/* * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE */
+/* *\/ */
+/* int hicn_dpo_ip6_create (dpo_id_t * dpo, */
+/* const ip6_address_t * local_addr, */
+/* const ip6_address_t * remote_addr, */
+/* u32 sw_if, */
+/* adj_index_t adj, */
+/* u32 node_index, */
+/* hicn_face_flags_t flags, hicn_face_id_t * face_id); */
/**
* @brief Create a dpo from an ip face
diff --git a/hicn-plugin/src/faces/ip/face_ip.c b/hicn-plugin/src/faces/ip/face_ip.c
index 6e279583c..23d3900ec 100644
--- a/hicn-plugin/src/faces/ip/face_ip.c
+++ b/hicn-plugin/src/faces/ip/face_ip.c
@@ -12,6 +12,8 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
+#include <vnet/adj/adj_midchain.h>
+#include <vnet/adj/adj.h>
#include "face_ip.h"
#include "face_ip_node.h"
@@ -96,62 +98,165 @@ hicn_face_ip_del (hicn_face_id_t face_id)
hicn_face_ip_t *face_ip = (hicn_face_ip_t *) face->data;
hicn_face_ip_key_t key;
hicn_face_ip_key_t old_key;
+ hicn_face_ip_key_t old_key2;
if (ip46_address_is_ip4 (&face_ip->local_addr))
{
hicn_face_ip4_get_key (&(face_ip->local_addr.ip4), face->shared.sw_if,
&key);
- mhash_unset (&hicn_face_ip_local_hashtb, &key, (uword *) & old_key);
- hicn_face_ip4_get_key (&(face_ip->remote_addr.ip4), face->shared.sw_if,
- &key);
- mhash_unset (&hicn_face_ip_remote_hashtb, &key, (uword *) & old_key);
+ hicn_face_ip_input_faces_t * in_faces_vec = hicn_face_ip4_get_vec(&(face_ip->local_addr.ip4), face->shared.sw_if,
+ &hicn_face_ip_local_hashtb);
+ if (in_faces_vec != NULL)
+ {
+ hicn_face_ip_vec_t * vec = pool_elt_at_index (hicn_vec_pool, in_faces_vec->vec_id);
+ u32 index_face = vec_search(*vec, face_id);
+ vec_del1(*vec, index_face);
+
+ if (vec_len(*vec) == 0)
+ {
+ pool_put_index(hicn_vec_pool, in_faces_vec->vec_id);
+ mhash_unset (&hicn_face_ip_local_hashtb, &key, (uword *) & old_key);
+ vec_free(*vec);
+ }
+ else
+ {
+ /* Check if the face we are deleting is the preferred one. */
+ /* If so, repleace with another. */
+ if (in_faces_vec->face_id == face_id)
+ {
+ in_faces_vec->face_id = (*vec)[0];
+ }
+ }
+ hicn_face_ip4_get_key (&(face_ip->remote_addr.ip4), face->shared.sw_if,
+ &key);
+ mhash_unset (&hicn_face_ip_remote_hashtb, &key, (uword *) & old_key2);
+ }
}
else
{
hicn_face_ip6_get_key (&(face_ip->local_addr.ip6), face->shared.sw_if,
&key);
- mhash_unset (&hicn_face_ip_local_hashtb, &key, (uword *) & old_key);
- hicn_face_ip6_get_key (&(face_ip->remote_addr.ip6), face->shared.sw_if,
- &key);
- mhash_unset (&hicn_face_ip_remote_hashtb, &key, (uword *) & old_key);
+
+ hicn_face_ip_input_faces_t * in_faces_vec = hicn_face_ip6_get_vec(&(face_ip->local_addr.ip6), face->shared.sw_if,
+ &hicn_face_ip_local_hashtb);
+ if (in_faces_vec != NULL)
+ {
+ hicn_face_ip_vec_t * vec = pool_elt_at_index (hicn_vec_pool, in_faces_vec->vec_id);
+ u32 index_face = vec_search(*vec, face_id);
+ vec_del1(*vec, index_face);
+
+ if (vec_len(*vec) == 0)
+ {
+ pool_put(hicn_vec_pool, vec);
+ mhash_unset (&hicn_face_ip_local_hashtb, &key, (uword *) & old_key);
+ vec_free(*vec);
+ }
+ else
+ {
+ /* Check if the face we are deleting is the preferred one. */
+ /* If so, repleace with another. */
+ if (in_faces_vec->face_id == face_id)
+ {
+ in_faces_vec->face_id = (*vec)[0];
+ }
+ }
+ hicn_face_ip6_get_key (&(face_ip->remote_addr.ip6), face->shared.sw_if,
+ &key);
+ mhash_unset (&hicn_face_ip_remote_hashtb, &key, (uword *) & old_key);
+ }
}
return hicn_face_del (face_id);
}
+/**
+ * @brief Helper for handling midchain adjacencies
+ */
+void face_midchain_fixup_t (vlib_main_t * vm,
+ struct ip_adjacency_t_ * adj,
+ vlib_buffer_t * b0,
+ const void *data) {
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0;
+};
-/*
- * Utility that adds a new face cache entry. For the moment we assume that
- * the ip_adjacency has already been set up.
+/**
+ * @brief Build a rewrite string for the face.
*/
-int
-hicn_face_ip_add (const ip46_address_t * local_addr,
- const ip46_address_t * remote_addr,
- int sw_if, hicn_face_id_t * pfaceid)
+static u8*
+face_build_rewrite_i (void)
{
- /* fib_protocol_t fib_type; */
- /* vnet_link_t link_type; */
- adj_index_t adj;
- dpo_proto_t dpo_proto;
+ /*
+ * passing the adj code a NULL rewrite means 'i don't have one cos
+ * t'other end is unresolved'. That's not the case here. For the mpls
+ * tunnel there are just no bytes of encap to apply in the adj. We'll impose
+ * the label stack once we choose a path. So return a zero length rewrite.
+ */
+ u8 *rewrite = NULL;
- /* Check if we found at least one ip address */
- if (ip46_address_is_zero (local_addr) || ip46_address_is_zero (remote_addr))
- return HICN_ERROR_FACE_NO_GLOBAL_IP;
+ vec_validate(rewrite, 0);
+ vec_reset_length(rewrite);
+ return (rewrite);
+}
+
+always_inline int
+hicn_face_ip_find_adj (const ip46_address_t * remote_addr,
+ int sw_if, adj_index_t * adj)
+{
fib_prefix_t fib_pfx;
fib_node_index_t fib_entry_index;
fib_prefix_from_ip46_addr (remote_addr, &fib_pfx);
fib_pfx.fp_len = ip46_address_is_ip4(remote_addr)? 32 : 128;
+ vnet_link_t link_type = ip46_address_is_ip4(&fib_pfx.fp_addr)? VNET_LINK_IP4 : VNET_LINK_IP6;
+ *adj = adj_nbr_find(fib_pfx.fp_proto, link_type, &fib_pfx.fp_addr, sw_if);
- u32 fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
- HICN_FIB_TABLE,
- FIB_SOURCE_PLUGIN_HI);
+ if (*adj == ADJ_INDEX_INVALID)
+ {
+ u32 fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
+ HICN_FIB_TABLE,
+ FIB_SOURCE_PLUGIN_HI);
+
+ fib_entry_index = fib_table_lookup (fib_index, &fib_pfx);
+
+ if (fib_entry_index == (FIB_NODE_INDEX_INVALID))
+ return HICN_ERROR_FACE_IP_ADJ_NOT_FOUND;
+
+ *adj = fib_entry_get_adj (fib_entry_index);
+ ip_adjacency_t * temp = NULL;
+ if (*adj != ~0)
+ temp = adj_get(*adj);
+
+ if (temp == NULL || temp->lookup_next_index <= IP_LOOKUP_NEXT_REWRITE)
+ {
+ if(sw_if != ~0)
+ *adj = adj_nbr_add_or_lock(fib_pfx.fp_proto, link_type, remote_addr, sw_if);
+ else
+ return HICN_ERROR_FACE_IP_ADJ_NOT_FOUND;
+ }
+ else
+ {
+ adj_nbr_midchain_update_rewrite(*adj, &face_midchain_fixup_t, NULL, ADJ_FLAG_NONE, face_build_rewrite_i());
+ adj_midchain_delegate_stack(*adj, fib_index, &fib_pfx);
+ }
+ }
- fib_entry_index = fib_table_lookup (fib_index, &fib_pfx);
+ return HICN_ERROR_NONE;
+}
- adj = fib_entry_get_adj (fib_entry_index);
+/*
+ * Utility that adds a new face cache entry. For the moment we assume that
+ * the ip_adjacency has already been set up.
+ */
+int
+hicn_face_ip_add (const ip46_address_t * local_addr,
+ const ip46_address_t * remote_addr,
+ int sw_if, hicn_face_id_t * pfaceid,
+ u8 is_app_prod)
+{
+ dpo_proto_t dpo_proto;
- if (adj == ~0)
- return HICN_ERROR_FACE_IP_ADJ_NOT_FOUND;
+ /* Check if we found at least one ip address */
+ if (ip46_address_is_zero (remote_addr))
+ return HICN_ERROR_FACE_NO_GLOBAL_IP;
hicn_face_flags_t flags = (hicn_face_flags_t) 0;
flags |= HICN_FACE_FLAGS_FACE;
@@ -160,17 +265,10 @@ hicn_face_ip_add (const ip46_address_t * local_addr,
if (ip46_address_is_ip4 (local_addr))
{
face =
- hicn_face_ip4_get (&(local_addr->ip4), sw_if,
- &hicn_face_ip_local_hashtb);
-
- if (face != NULL)
- return HICN_ERROR_FACE_ALREADY_CREATED;
-
- face =
hicn_face_ip4_get (&(remote_addr->ip4), sw_if,
&hicn_face_ip_remote_hashtb);
- /* If remote matches the face is a iface */
+ /* If remote matches the face we need to check if it is an incomplete face */
if (face == NULL)
{
hicn_iface_ip_add (local_addr, remote_addr, sw_if, pfaceid);
@@ -181,31 +279,83 @@ hicn_face_ip_add (const ip46_address_t * local_addr,
*pfaceid = hicn_dpoi_get_index (face);
}
+ if (!(face->shared.flags & HICN_FACE_FLAGS_IFACE))
+ return HICN_ERROR_FACE_ALREADY_CREATED;
+
hicn_face_ip_key_t key;
hicn_face_ip4_get_key (&(local_addr->ip4), sw_if, &key);
- mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) pfaceid, 0);
-
- hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
- clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip4_address_t));
- clib_memcpy (&ip_face->remote_addr, remote_addr,
- sizeof (ip4_address_t));
- face->shared.sw_if = sw_if;
- face->shared.flags = flags;
- face->shared.adj = adj;
-
- dpo_proto = DPO_PROTO_IP4;
+ hicn_face_ip_input_faces_t * in_faces =
+ hicn_face_ip4_get_vec (&(local_addr->ip4), sw_if,
+ &hicn_face_ip_local_hashtb);
+
+ if (in_faces == NULL)
+ {
+ adj_index_t adj;
+ int ret = hicn_face_ip_find_adj(remote_addr, sw_if, &adj);
+ if (ret != HICN_ERROR_NONE)
+ return ret;
+
+ hicn_face_ip_input_faces_t in_faces_temp;
+ hicn_face_ip_vec_t *vec;
+ pool_get(hicn_vec_pool, vec);
+ *vec = vec_new(hicn_face_ip_vec_t, 0);
+ u32 index = vec - hicn_vec_pool;
+ in_faces_temp.vec_id = index;
+ vec_add1(*vec, *pfaceid);
+
+ hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+ clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip4_address_t));
+ clib_memcpy (&ip_face->remote_addr, remote_addr,
+ sizeof (ip4_address_t));
+ face->shared.sw_if = sw_if;
+ face->shared.flags = flags;
+ face->shared.adj = adj;
+
+ dpo_proto = DPO_PROTO_IP4;
+
+ in_faces_temp.face_id = *pfaceid;
+
+ mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) &in_faces_temp, 0);
+ }
+ else
+ {
+ hicn_face_ip_vec_t * vec = pool_elt_at_index(hicn_vec_pool, in_faces->vec_id);
+
+ /* */
+ if (vec_search(*vec, *pfaceid) != ~0)
+ return HICN_ERROR_FACE_ALREADY_CREATED;
+
+ adj_index_t adj;
+ int ret = hicn_face_ip_find_adj(remote_addr, sw_if, &adj);
+ if (ret != HICN_ERROR_NONE)
+ return ret;
+
+ vec_add1(*vec, *pfaceid);
+
+ hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+ clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip4_address_t));
+ clib_memcpy (&ip_face->remote_addr, remote_addr,
+ sizeof (ip4_address_t));
+ face->shared.sw_if = sw_if;
+ face->shared.flags = flags;
+ face->shared.adj = adj;
+
+ dpo_proto = DPO_PROTO_IP4;
+
+ mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) in_faces, 0);
+
+ /* If the face is an application producer face, we set it as the preferred incoming face. */
+ /* This is required to handle the CS separation, and the push api in a lightway*/
+ if (is_app_prod)
+ {
+ in_faces->face_id = *pfaceid;
+ }
+ }
}
else
{
face =
- hicn_face_ip6_get (&(local_addr->ip6), sw_if,
- &hicn_face_ip_local_hashtb);
-
- if (face != NULL)
- return HICN_ERROR_FACE_ALREADY_CREATED;
-
- face =
hicn_face_ip6_get (&(remote_addr->ip6), sw_if,
&hicn_face_ip_remote_hashtb);
@@ -220,20 +370,79 @@ hicn_face_ip_add (const ip46_address_t * local_addr,
*pfaceid = hicn_dpoi_get_index (face);
}
+ if (!(face->shared.flags & HICN_FACE_FLAGS_IFACE))
+ return HICN_ERROR_FACE_ALREADY_CREATED;
+
hicn_face_ip_key_t key;
hicn_face_ip6_get_key (&(local_addr->ip6), sw_if, &key);
- mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) pfaceid, 0);
-
- hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
- clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip6_address_t));
- clib_memcpy (&ip_face->remote_addr, remote_addr,
- sizeof (ip6_address_t));
- face->shared.sw_if = sw_if;
- face->shared.flags = flags;
- face->shared.adj = adj;
-
- dpo_proto = DPO_PROTO_IP6;
+ hicn_face_ip_input_faces_t * in_faces =
+ hicn_face_ip6_get_vec (&(local_addr->ip6), sw_if,
+ &hicn_face_ip_local_hashtb);
+
+ if (in_faces == NULL)
+ {
+ adj_index_t adj;
+ int ret = hicn_face_ip_find_adj(remote_addr, sw_if, &adj);
+ if (ret != HICN_ERROR_NONE)
+ return ret;
+
+ hicn_face_ip_input_faces_t in_faces_temp;
+ hicn_face_ip_vec_t *vec;
+ pool_get(hicn_vec_pool, vec);
+ vec_alloc(*vec, 1);
+ u32 index = vec - hicn_vec_pool;
+ in_faces_temp.vec_id = index;
+ vec_add1(*vec, *pfaceid);
+
+ hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+ clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip6_address_t));
+ clib_memcpy (&ip_face->remote_addr, remote_addr,
+ sizeof (ip6_address_t));
+ face->shared.sw_if = sw_if;
+ face->shared.flags = flags;
+ face->shared.adj = adj;
+
+ dpo_proto = DPO_PROTO_IP6;
+
+ in_faces_temp.face_id = *pfaceid;
+
+ mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) &in_faces_temp, 0);
+ }
+ else
+ {
+ hicn_face_ip_vec_t *vec = pool_elt_at_index(hicn_vec_pool, in_faces->vec_id);
+
+ /* */
+ if (vec_search(*vec, *pfaceid) != ~0)
+ return HICN_ERROR_FACE_ALREADY_CREATED;
+
+ adj_index_t adj;
+ int ret = hicn_face_ip_find_adj(remote_addr, sw_if, &adj);
+ if (ret != HICN_ERROR_NONE)
+ return ret;
+
+ vec_add1(*vec, *pfaceid);
+
+ hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+ clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip6_address_t));
+ clib_memcpy (&ip_face->remote_addr, remote_addr,
+ sizeof (ip6_address_t));
+ face->shared.sw_if = sw_if;
+ face->shared.flags = flags;
+ face->shared.adj = adj;
+
+ dpo_proto = DPO_PROTO_IP6;
+
+ mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) in_faces, 0);
+
+ /* If the face is an application producer face, we set it as the preferred incoming face. */
+ /* This is required to handle the CS separation, and the push api in a lightway*/
+ if (is_app_prod)
+ {
+ in_faces->face_id = *pfaceid;
+ }
+ }
}
retx_t *retx = vlib_process_signal_event_data (vlib_get_main (),
diff --git a/hicn-plugin/src/faces/ip/face_ip.h b/hicn-plugin/src/faces/ip/face_ip.h
index 852106b70..0491af506 100644
--- a/hicn-plugin/src/faces/ip/face_ip.h
+++ b/hicn-plugin/src/faces/ip/face_ip.h
@@ -43,6 +43,24 @@ typedef struct hicn_ip_face_t_
} hicn_face_ip_t;
+/**
+ * @bried vector of faces used to collect faces having the same local address
+ *
+ */
+typedef hicn_face_id_t * hicn_face_ip_vec_t;
+
+typedef struct hicn_ip_input_faces_s_
+{
+ /* Vector of all possible input faces */
+ u32 vec_id;
+
+ /* Preferred face. If an prod_app face is in the vector it will be the preferred one. */
+ /* It's not possible to have multiple prod_app face in the same vector, they would have */
+ /* the same local address. Every prod_app face is a point-to-point face between the forwarder */
+ /* and the application. */
+ hicn_face_id_t face_id;
+
+} hicn_face_ip_input_faces_t;
/**
* Hash tables that indexes a face by local address. For fast lookup when an
@@ -57,6 +75,11 @@ extern mhash_t hicn_face_ip_local_hashtb;
extern mhash_t hicn_face_ip_remote_hashtb;
/**
+ * Pool containing the vector of possible incoming faces.
+ */
+extern hicn_face_ip_vec_t * hicn_vec_pool;
+
+/**
* Key definition for the mhash table. An ip face is uniquely identified by ip
* address and the interface id. The ip address can correspond to the remote ip
* address of the next hicn hop, or to the local address of the receiving
@@ -129,6 +152,42 @@ hicn_face_ip4_get (const ip4_address_t * addr, u32 sw_if, mhash_t * hashtb)
}
/**
+ * @brief Get the vector of faces from the ip v4 address. Does not add any lock.
+ *
+ * @param addr Ip v4 address used to create the key for the hash table.
+ * @param sw_if Software interface id used to create the key for the hash table.
+ * @param hashtb Hash table (remote or local) where to perform the lookup.
+ *
+ * @result Pointer to the face.
+ */
+always_inline hicn_face_ip_input_faces_t *
+hicn_face_ip4_get_vec (const ip4_address_t * addr, u32 sw_if, mhash_t * hashtb)
+{
+ hicn_face_ip_key_t key;
+
+ hicn_face_ip4_get_key (addr, sw_if, &key);
+ return (hicn_face_ip_input_faces_t *) mhash_get (hashtb,&key);
+}
+
+/**
+ * @brief Get the vector of faces from the ip v6 address. Does not add any lock.
+ *
+ * @param addr Ip v6 address used to create the key for the hash table.
+ * @param sw_if Software interface id used to create the key for the hash table.
+ * @param hashtb Hash table (remote or local) where to perform the lookup.
+ *
+ * @result Pointer to the face.
+ */
+always_inline hicn_face_ip_input_faces_t *
+hicn_face_ip6_get_vec (const ip6_address_t * addr, u32 sw_if, mhash_t * hashtb)
+{
+ hicn_face_ip_key_t key;
+
+ hicn_face_ip6_get_key (addr, sw_if, &key);
+ return (hicn_face_ip_input_faces_t *) mhash_get (hashtb,&key);
+}
+
+/**
* @brief Get the dpoi from the ip v6 address. Does not add any lock.
*
* @param addr Ip v6 address used to create the key for the hash table.
@@ -158,12 +217,13 @@ hicn_face_ip6_get (const ip6_address_t * addr, u32 sw_if, mhash_t * hashtb)
* @param sw_if interface associated to the face
* @param is_app_face Boolean to set the face as an application face
* @param pfaceid Pointer to return the face id
+ * @param is_app_prod if HICN_FACE_FLAGS_APPFACE_PROD the face is a local application face, all other values are ignored
* @return HICN_ERROR_FACE_NO_GLOBAL_IP if the face does not have a globally
* reachable ip address, otherwise HICN_ERROR_NONE
*/
int hicn_face_ip_add (const ip46_address_t * local_addr,
const ip46_address_t * remote_addr,
- int swif, hicn_face_id_t * pfaceid);
+ int swif, hicn_face_id_t * pfaceid, u8 is_app_prod);
/**
* @brief Create a new incomplete face ip. (Meant to be used by the data plane)
diff --git a/hicn-plugin/src/faces/ip/face_ip_cli.c b/hicn-plugin/src/faces/ip/face_ip_cli.c
index 760768be1..4c4986f97 100644
--- a/hicn-plugin/src/faces/ip/face_ip_cli.c
+++ b/hicn-plugin/src/faces/ip/face_ip_cli.c
@@ -158,7 +158,7 @@ hicn_face_ip_cli_set_command_fn (vlib_main_t * vm,
}
}
- rv = hicn_face_ip_add (&local_addr, &remote_addr, sw_if, &face_id);
+ rv = hicn_face_ip_add (&local_addr, &remote_addr, sw_if, &face_id, 0);
if (rv == HICN_ERROR_NONE)
{
@@ -194,7 +194,7 @@ hicn_face_ip_cli_set_command_fn (vlib_main_t * vm,
VLIB_CLI_COMMAND (hicn_face_ip_cli_set_command, static) =
{
.path = "hicn face ip",
- .short_help = "hicn face ip {add local <src_address> remote <dst_address> intfc <sw_if>} | {del id <face_id>}",
+ .short_help = "hicn face ip {add [local <src_address>] remote <dst_address> intfc <sw_if>} | {del id <face_id>}",
.function = hicn_face_ip_cli_set_command_fn,
};
/* *INDENT-ON* */
diff --git a/hicn-plugin/src/faces/ip/face_ip_node.c b/hicn-plugin/src/faces/ip/face_ip_node.c
index 6592dc065..3f1f6a0d0 100644
--- a/hicn-plugin/src/faces/ip/face_ip_node.c
+++ b/hicn-plugin/src/faces/ip/face_ip_node.c
@@ -144,6 +144,7 @@ typedef enum
\
ret = LOCK_FROM_LOCAL_IP##ipv \
(&(hicnb0->face_dpo_id), \
+ &(hicnb0->in_faces_vec_id), \
&hicnb0->flags, \
&(ip_hdr->dst_address), \
vnet_buffer (b0)->sw_if_index[VLIB_RX]); \
@@ -232,12 +233,14 @@ typedef enum
\
ret0 = LOCK_FROM_LOCAL_IP##ipv \
(&(hicnb0->face_dpo_id), \
+ &(hicnb0->in_faces_vec_id), \
&hicnb0->flags, \
&(ip_hdr0->dst_address), \
vnet_buffer (b0)->sw_if_index[VLIB_RX]); \
\
ret1 = LOCK_FROM_LOCAL_IP##ipv \
(&(hicnb1->face_dpo_id), \
+ &(hicnb1->in_faces_vec_id), \
&hicnb1->flags, \
&(ip_hdr1->dst_address), \
vnet_buffer (b1)->sw_if_index[VLIB_RX]); \
diff --git a/hicn-plugin/src/hicn.h b/hicn-plugin/src/hicn.h
index 87628ba53..1b57ce9e2 100644
--- a/hicn-plugin/src/hicn.h
+++ b/hicn-plugin/src/hicn.h
@@ -64,8 +64,9 @@ typedef struct
u8 dpo_ctx_id; /* used for data path */
u8 vft_id; /* " */
- dpo_id_t face_dpo_id; /* ingress face ,sizeof(iface_dpo_id)
- * <= sizeof(u64) */
+ dpo_id_t face_dpo_id; /* ingress iface, sizeof(dpo_id_t)
+ * <= sizeof(u64) */
+ u32 in_faces_vec_id; /* vector of possible input face for a data packet */
hicn_type_t type;
} hicn_buffer_t;
diff --git a/hicn-plugin/src/hicn_api.c b/hicn-plugin/src/hicn_api.c
index 9bca748e6..f8933206d 100644
--- a/hicn-plugin/src/hicn_api.c
+++ b/hicn-plugin/src/hicn_api.c
@@ -249,7 +249,7 @@ vl_api_hicn_api_face_ip_add_t_handler (vl_api_hicn_api_face_ip_add_t * mp)
}
if (rv == HICN_ERROR_NONE)
- rv = hicn_face_ip_add (&local_addr, &remote_addr, sw_if, &faceid);
+ rv = hicn_face_ip_add (&local_addr, &remote_addr, sw_if, &faceid, 0);
else
faceid = HICN_FACE_NULL;
diff --git a/hicn-plugin/src/mgmt.c b/hicn-plugin/src/mgmt.c
index b992ba15c..cfeef6cb6 100644
--- a/hicn-plugin/src/mgmt.c
+++ b/hicn-plugin/src/mgmt.c
@@ -66,10 +66,6 @@ hicn_mgmt_node_stats_get (vl_api_hicn_api_node_stats_get_reply_t * rmp)
rmp->pkts_processed +=
clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
HICNFWD_ERROR_PROCESSED]);
- n =
- vlib_get_node (this_vlib_main,
- hicn_data_pcslookup_node.index);
- node_cntr_base_idx = n->error_heap_index;
rmp->pkts_data_count +=
clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
HICNFWD_ERROR_DATAS]);
diff --git a/hicn-plugin/src/pcs.h b/hicn-plugin/src/pcs.h
index 28f9c3c37..d9c48954e 100644
--- a/hicn-plugin/src/pcs.h
+++ b/hicn-plugin/src/pcs.h
@@ -499,8 +499,16 @@ hicn_pcs_cs_update (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
policy_vft->hicn_cs_delete_get (pitcs, policy_state,
&node, &pcs_entry, &hash_entry);
- hicn_pcs_cs_delete (vm, pitcs, &pcs_entry, &node, hash_entry, NULL,
- NULL);
+ /*
+ * We don't have to decrease the lock (therefore we cannot
+ * use hicn_pcs_cs_delete function)
+ */
+ policy_vft->hicn_cs_dequeue (pitcs, node, pcs_entry, policy_state);
+
+ hicn_cs_delete_trimmed (pitcs, &pcs_entry, hash_entry, &node, vm);
+
+ /* Update the global CS counter */
+ pitcs->pcs_cs_count--;
}
}
else
@@ -541,14 +549,14 @@ hicn_pcs_cs_delete (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
}
/* A data could have been inserted in the CS through a push. In this case locks == 0 */
- if (hash_entry->locks == 0 || hash_entry->locks == 1)
+ hash_entry->locks--;
+ if (hash_entry->locks == 0)
{
hicn_pcs_delete_internal
(pitcs, pcs_entryp, hash_entry, nodep, vm, dpo_vft, hicn_dpo_id);
}
else
{
- hash_entry->locks--;
hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED;
}
}
@@ -603,8 +611,16 @@ hicn_pcs_cs_insert (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
policy_vft->hicn_cs_delete_get (pitcs, policy_state,
&node, &pcs_entry, &hash_entry);
- hicn_pcs_cs_delete (vm, pitcs, &pcs_entry, &node, hash_entry, NULL,
- NULL);
+ /*
+ * We don't have to decrease the lock (therefore we cannot
+ * use hicn_pcs_cs_delete function)
+ */
+ policy_vft->hicn_cs_dequeue (pitcs, node, pcs_entry, policy_state);
+
+ hicn_cs_delete_trimmed (pitcs, &pcs_entry, hash_entry, &node, vm);
+
+ /* Update the global CS counter */
+ pitcs->pcs_cs_count--;
}
}
return ret;
@@ -685,9 +701,9 @@ hicn_pcs_pit_delete (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id)
{
hash_entry->locks--;
- pitcs->pcs_pit_count--;
if (hash_entry->locks == 0)
{
+ pitcs->pcs_pit_count--;
hicn_pcs_delete_internal
(pitcs, pcs_entryp, hash_entry, node, vm, dpo_vft, hicn_dpo_id);
}
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 9d8267f5f..4df09c0dd 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -46,6 +46,7 @@ else ()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996")
endif ()
+add_subdirectory(includes)
add_subdirectory (src)
add_subdirectory (doc)
diff --git a/lib/includes/CMakeLists.txt b/lib/includes/CMakeLists.txt
new file mode 100644
index 000000000..d1eaa0b57
--- /dev/null
+++ b/lib/includes/CMakeLists.txt
@@ -0,0 +1,55 @@
+# 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.
+
+# XXX
+
+set(HICN_INCLUDE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR} ""
+ CACHE INTERNAL
+ "" FORCE
+)
+
+
+set(LIBHICN_HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/hicn.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/base.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/common.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/compat.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/error.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/header.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/mapme.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/name.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/policy.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ops.h
+ PARENT_SCOPE
+)
+
+set(LIBHICN_HEADER_FILES_PROTOCOL
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/ah.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/icmp.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/icmprd.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/ipv4.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/ipv6.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/tcp.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/udp.h
+ PARENT_SCOPE
+)
+
+set(LIBHICN_HEADER_FILES_UTIL
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/ip_address.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/token.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/types.h
+ PARENT_SCOPE
+)
+
diff --git a/lib/src/base.h b/lib/includes/hicn/base.h
index d8a79a9c2..d8a79a9c2 100644
--- a/lib/src/base.h
+++ b/lib/includes/hicn/base.h
diff --git a/lib/src/common.h b/lib/includes/hicn/common.h
index 33323da1b..33323da1b 100644
--- a/lib/src/common.h
+++ b/lib/includes/hicn/common.h
diff --git a/lib/src/compat.h b/lib/includes/hicn/compat.h
index 7228843bb..b31d01a0d 100644
--- a/lib/src/compat.h
+++ b/lib/includes/hicn/compat.h
@@ -234,7 +234,7 @@ int hicn_packet_get_payload (hicn_format_t format,
*/
int hicn_packet_get_locator (hicn_format_t format,
const hicn_header_t * packet,
- ip_address_t * ip_address, bool is_interest);
+ ip_prefix_t * prefix, bool is_interest);
/**
* @brief Sets the locator of an interest / data packet
@@ -246,7 +246,7 @@ int hicn_packet_get_locator (hicn_format_t format,
* @return hICN error code
*/
int hicn_packet_set_locator (hicn_format_t format, hicn_header_t * packet,
- const ip_address_t * ip_address,
+ const ip_prefix_t * prefix,
bool is_interest);
/**
@@ -396,9 +396,9 @@ int hicn_interest_set_name (hicn_format_t format, hicn_header_t * interest,
const hicn_name_t * name);
int hicn_interest_get_locator (hicn_format_t format,
const hicn_header_t * interest,
- ip_address_t * ip_address);
+ ip_prefix_t * prefix);
int hicn_interest_set_locator (hicn_format_t format, hicn_header_t * interest,
- const ip_address_t * ip_address);
+ const ip_prefix_t * prefix);
int hicn_interest_compare (const hicn_header_t * interest_1,
const hicn_header_t * interest_2);
int hicn_interest_set_lifetime (hicn_header_t * interest, u32 lifetime);
@@ -425,9 +425,9 @@ int hicn_data_get_name (hicn_format_t format, const hicn_header_t * data,
int hicn_data_set_name (hicn_format_t format, hicn_header_t * data,
const hicn_name_t * name);
int hicn_data_get_locator (hicn_format_t format, const hicn_header_t * data,
- ip_address_t * ip_address);
+ ip_prefix_t * prefix);
int hicn_data_set_locator (hicn_format_t format, hicn_header_t * data,
- const ip_address_t * ip_address);
+ const ip_prefix_t * prefix);
int hicn_data_compare (const hicn_header_t * data_1,
const hicn_header_t * data_2);
int hicn_data_get_expiry_time (const hicn_header_t * data, u32 * expiry_time);
diff --git a/lib/src/error.h b/lib/includes/hicn/error.h
index 3e027c4e5..3e027c4e5 100644
--- a/lib/src/error.h
+++ b/lib/includes/hicn/error.h
diff --git a/lib/src/header.h b/lib/includes/hicn/header.h
index b21fe5c84..b21fe5c84 100644
--- a/lib/src/header.h
+++ b/lib/includes/hicn/header.h
diff --git a/lib/src/hicn.h b/lib/includes/hicn/hicn.h
index 749fd4247..749fd4247 100644
--- a/lib/src/hicn.h
+++ b/lib/includes/hicn/hicn.h
diff --git a/lib/src/mapme.h b/lib/includes/hicn/mapme.h
index 8fae44530..8fae44530 100644
--- a/lib/src/mapme.h
+++ b/lib/includes/hicn/mapme.h
diff --git a/lib/src/name.h b/lib/includes/hicn/name.h
index 434b563b8..0a100dbce 100644
--- a/lib/src/name.h
+++ b/lib/includes/hicn/name.h
@@ -28,62 +28,14 @@
#ifndef _WIN32
#include <netinet/in.h> // struct sockadd
#endif
+#include <hicn/util/ip_address.h>
#include "common.h"
/******************************************************************************
- * IP address helpers
- ******************************************************************************/
-
-/* Presentation format */
-#ifndef INET_ADDRSTRLEN
-#define INET_ADDRSTRLEN 16
-#endif
-
-#ifndef INET6_ADDRSTRLEN
-#define INET6_ADDRSTRLEN 46
-#endif
-//#define INET_MAX_ADDRSTRLEN INET6_ADDRSTRLEN
-
-/* Address size */
-#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 TCP_SEQNO_LEN 4 /* bytes */
-
-struct ip_address
-{
- union
- {
- 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];
- ip46_address_t as_ip46;
- };
- int family;
- unsigned short prefix_len;
-};
-
-typedef struct ip_address ip_address_t;
-
-int ip_address_len (const ip_address_t * ip_address);
-bool ip_address_empty (const ip_address_t * ip_address);
-
-int hicn_ip_ntop (const ip_address_t * ip_address, char *dst,
- const size_t len);
-int hicn_ip_pton (const char *ip_address_str, ip_address_t * ip_address);
-int hicn_ip_to_sockaddr_address (const ip_address_t * ip_address,
- struct sockaddr *sockaddr_address);
-
-/******************************************************************************
* hICN names
******************************************************************************/
+#define TCP_SEQNO_LEN 4 /* bytes */
#define HICN_V4_PREFIX_LEN IPV4_ADDR_LEN
#define HICN_V6_PREFIX_LEN IPV6_ADDR_LEN
#define HICN_SEGMENT_LEN TCP_SEQNO_LEN
@@ -207,7 +159,7 @@ int hicn_name_create (const char *ip_address, u32 id, hicn_name_t * name);
* @param [out] Resulting - hICN name
* @return hICN error code
*/
-int hicn_name_create_from_ip_address (const ip_address_t * ip_address, u32 id,
+int hicn_name_create_from_ip_prefix (const ip_prefix_t * prefix, u32 id,
hicn_name_t * name);
/**
@@ -295,8 +247,8 @@ int hicn_name_to_sockaddr_address (const hicn_name_t * name,
* @param [out] ip_address - Resulting IP address
* @return hICN error code
*/
-int hicn_name_to_ip_address (const hicn_name_t * name,
- ip_address_t * ip_address);
+int hicn_name_to_ip_prefix (const hicn_name_t * name,
+ ip_prefix_t * ip_prefix);
/**
* @brief Convert an hICN name to presentation format
@@ -329,7 +281,7 @@ int hicn_name_get_family (const hicn_name_t * name, int *family);
* @param [out] prefix - Resulting prefix
* @return hICN error code
*/
-int hicn_prefix_create_from_ip_address (const ip_address_t * ip_address,
+int hicn_prefix_create_from_ip_prefix (const ip_prefix_t * ip_prefix,
hicn_prefix_t * prefix);
#endif /* HICN_NAME_H */
diff --git a/lib/src/ops.h b/lib/includes/hicn/ops.h
index 47795efd5..47795efd5 100644
--- a/lib/src/ops.h
+++ b/lib/includes/hicn/ops.h
diff --git a/ctrl/facemgr/src/util/policy.h b/lib/includes/hicn/policy.h
index e20af6560..12f8c1e12 100644
--- a/ctrl/facemgr/src/util/policy.h
+++ b/lib/includes/hicn/policy.h
@@ -22,7 +22,7 @@
#include <netinet/in.h> // INET*_ADDRSTRLEN
#include <string.h> // strcasecmp
-#include "token.h"
+#include <hicn/util/token.h>
/* POLICY TAG */
@@ -83,6 +83,14 @@ int policy_tags_has(policy_tags_t tags, policy_tag_t tag)
return tags & (1 << tag);
}
+static inline
+void policy_tags_union(policy_tags_t * tags, policy_tags_t * tags_to_union)
+{
+#define _(x, y) *tags |= policy_tags_has(*tags_to_union, POLICY_TAG_ ## x) ? (1 << POLICY_TAG_ ## x) : 0;
+foreach_policy_tag
+#undef _
+}
+
#define POLICY_TAGS_EMPTY 0
static inline
diff --git a/lib/src/protocol.h b/lib/includes/hicn/protocol.h
index a97cc99cf..a97cc99cf 100644
--- a/lib/src/protocol.h
+++ b/lib/includes/hicn/protocol.h
diff --git a/lib/src/protocol/ah.h b/lib/includes/hicn/protocol/ah.h
index a59a5051a..a59a5051a 100644
--- a/lib/src/protocol/ah.h
+++ b/lib/includes/hicn/protocol/ah.h
diff --git a/lib/src/protocol/icmp.h b/lib/includes/hicn/protocol/icmp.h
index 36954bb6d..36954bb6d 100644
--- a/lib/src/protocol/icmp.h
+++ b/lib/includes/hicn/protocol/icmp.h
diff --git a/lib/src/protocol/icmprd.h b/lib/includes/hicn/protocol/icmprd.h
index aa1fa01ae..aa1fa01ae 100644
--- a/lib/src/protocol/icmprd.h
+++ b/lib/includes/hicn/protocol/icmprd.h
diff --git a/lib/src/protocol/ipv4.h b/lib/includes/hicn/protocol/ipv4.h
index 8a5b6683b..8a5b6683b 100644
--- a/lib/src/protocol/ipv4.h
+++ b/lib/includes/hicn/protocol/ipv4.h
diff --git a/lib/src/protocol/ipv6.h b/lib/includes/hicn/protocol/ipv6.h
index 5a83abcae..5a83abcae 100644
--- a/lib/src/protocol/ipv6.h
+++ b/lib/includes/hicn/protocol/ipv6.h
diff --git a/lib/src/protocol/tcp.h b/lib/includes/hicn/protocol/tcp.h
index ded9a06b2..ded9a06b2 100644
--- a/lib/src/protocol/tcp.h
+++ b/lib/includes/hicn/protocol/tcp.h
diff --git a/lib/src/protocol/udp.h b/lib/includes/hicn/protocol/udp.h
index 75d1ea98c..75d1ea98c 100644
--- a/lib/src/protocol/udp.h
+++ b/lib/includes/hicn/protocol/udp.h
diff --git a/lib/includes/hicn/util/ip_address.h b/lib/includes/hicn/util/ip_address.h
new file mode 100644
index 000000000..542e6e4c6
--- /dev/null
+++ b/lib/includes/hicn/util/ip_address.h
@@ -0,0 +1,160 @@
+/*
+ * 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
+ */
+#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
+#include <endian.h>
+#ifdef __ANDROID__
+#include <byteswap.h>
+#endif
+#include <endian.h>
+#endif
+#include <errno.h>
+#include <netdb.h> // struct addrinfo
+#ifndef _WIN32
+#include <netinet/in.h> // struct sockadd
+#endif
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h> // snprintf
+#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)
+
+/* Presentation format */
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+//#define INET_MAX_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#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
+
+extern const ip_address_t IPV4_LOOPBACK;
+extern const ip_address_t IPV6_LOOPBACK;
+extern const ip_address_t IPV4_ANY;
+extern const ip_address_t IPV6_ANY;
+extern const ip_address_t IP_ADDRESS_EMPTY;
+
+#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) && ((int)x < MAX_PORT))
+
+#define MAXSZ_PORT_ 5
+#define MAXSZ_PORT MAXSZ_PORT_ + 1
+
+#define IS_VALID_FAMILY(x) ((x == AF_INET) || (x == AF_INET6))
+
+/* IP address */
+
+int ip_address_get_family (const char * ip_address);
+int ip_address_len (const ip_address_t * ip_address, int family);
+int ip_address_ntop (const ip_address_t * ip_address, char *dst,
+ const size_t len, int family);
+int ip_address_pton (const char *ip_address_str, ip_address_t * ip_address);
+int ip_address_snprintf(char * s, size_t size, const ip_address_t * ip_address,
+ int family);
+int ip_address_to_sockaddr(const ip_address_t * ip_address, struct sockaddr *sa,
+ int family);
+int ip_address_cmp(const ip_address_t * ip1, const ip_address_t * ip2, int family);
+int ip_address_empty(const ip_address_t * ip);
+
+/* Prefix */
+
+int ip_prefix_pton (const char *ip_address_str, ip_prefix_t * ip_prefix);
+int ip_prefix_ntop_short (const ip_prefix_t * ip_prefix, char *dst, size_t size);
+int ip_prefix_ntop (const ip_prefix_t * ip_prefix, char *dst, size_t size);
+int ip_prefix_len (const ip_prefix_t * prefix);
+bool ip_prefix_empty (const ip_prefix_t * prefix);
+int ip_prefix_to_sockaddr(const ip_prefix_t * prefix, struct sockaddr *sa);
+
+
+/* URL */
+
+#define MAXSZ_PROTO_ 8 /* inetX:// */
+#define MAXSZ_PROTO MAXSZ_PROTO_ + NULLTERM
+
+#define MAXSZ_URL4_ MAXSZ_PROTO_ + MAXSZ_IP4_ADDRESS_ + MAXSZ_PORT_
+#define MAXSZ_URL6_ MAXSZ_PROTO_ + MAXSZ_IP6_ADDRESS_ + MAXSZ_PORT_
+#define MAXSZ_URL_ MAXSZ_URL6_
+#define MAXSZ_URL4 MAXSZ_URL4_ + NULLTERM
+#define MAXSZ_URL6 MAXSZ_URL6_ + NULLTERM
+#define MAXSZ_URL MAXSZ_URL_ + NULLTERM
+
+int url_snprintf(char * s, size_t size, int family,
+ const ip_address_t * ip_address, u16 port);
+
+#endif /* UTIL_IP_ADDRESS_H */
diff --git a/ctrl/facemgr/src/util/token.h b/lib/includes/hicn/util/token.h
index 43e0a77b2..43e0a77b2 100644
--- a/ctrl/facemgr/src/util/token.h
+++ b/lib/includes/hicn/util/token.h
diff --git a/ctrl/facemgr/src/util/types.h b/lib/includes/hicn/util/types.h
index 10a0bdca0..50b368b8d 100644
--- a/ctrl/facemgr/src/util/types.h
+++ b/lib/includes/hicn/util/types.h
@@ -25,7 +25,7 @@ typedef uint64_t u64;
#define UNION_CAST(x, destType) \
(((union {__typeof__(x) a; destType b;})x).b)
-typedef unsigned int hash_t;
+//typedef unsigned int hash_t;
typedef int (*cmp_t)(const void *, const void *);
diff --git a/lib/src/CMakeLists.txt b/lib/src/CMakeLists.txt
index 65eae8d77..d8c7b11e0 100644
--- a/lib/src/CMakeLists.txt
+++ b/lib/src/CMakeLists.txt
@@ -13,41 +13,20 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-list(APPEND LIBHICN_HEADER_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/hicn.h
- ${CMAKE_CURRENT_SOURCE_DIR}/base.h
- ${CMAKE_CURRENT_SOURCE_DIR}/common.h
- ${CMAKE_CURRENT_SOURCE_DIR}/compat.h
- ${CMAKE_CURRENT_SOURCE_DIR}/error.h
- ${CMAKE_CURRENT_SOURCE_DIR}/header.h
- ${CMAKE_CURRENT_SOURCE_DIR}/mapme.h
- ${CMAKE_CURRENT_SOURCE_DIR}/name.h
- ${CMAKE_CURRENT_SOURCE_DIR}/protocol.h
- ${CMAKE_CURRENT_SOURCE_DIR}/ops.h
-)
-
-list(APPEND LIBHICN_HEADER_FILES_PROTOCOL
- ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ah.h
- ${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmp.h
- ${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmprd.h
- ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv4.h
- ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv6.h
- ${CMAKE_CURRENT_SOURCE_DIR}/protocol/tcp.h
- ${CMAKE_CURRENT_SOURCE_DIR}/protocol/udp.h
-)
-
list(APPEND LIBHICN_SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/common.c
${CMAKE_CURRENT_SOURCE_DIR}/compat.c
${CMAKE_CURRENT_SOURCE_DIR}/error.c
${CMAKE_CURRENT_SOURCE_DIR}/mapme.c
${CMAKE_CURRENT_SOURCE_DIR}/name.c
${CMAKE_CURRENT_SOURCE_DIR}/ops.c
- ${CMAKE_CURRENT_SOURCE_DIR}/common.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/policy.c
${CMAKE_CURRENT_SOURCE_DIR}/protocol/ah.c
${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmp.c
${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv4.c
${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv6.c
${CMAKE_CURRENT_SOURCE_DIR}/protocol/tcp.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/util/ip_address.c
)
set (COMPILER_DEFINITIONS "-DWITH_MAPME")
@@ -55,48 +34,26 @@ set (COMPILER_DEFINITIONS "-DWITH_MAPME")
include(BuildMacros)
include(WindowsMacros)
-if (ANDROID_API)
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
build_library(${LIBHICN}
STATIC
- SOURCES ${LIBHICN_SOURCE_FILES} ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL}
+ SOURCES ${LIBHICN_SOURCE_FILES} ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL} ${LIBHICN_HEADER_FILES_UTIL}
COMPONENT lib${LIBHICN}
- INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..
+ INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../includes
DEFINITIONS ${COMPILER_DEFINITIONS}
INSTALL_ROOT_DIR hicn
- INSTALL_HEADERS ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL}
+ INSTALL_HEADERS ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL} ${LIBHICN_HEADER_FILES_UTIL}
LINK_LIBRARIES ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY}
)
else ()
build_library(${LIBHICN}
SHARED STATIC
- SOURCES ${LIBHICN_SOURCE_FILES} ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL}
+ SOURCES ${LIBHICN_SOURCE_FILES} ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL} ${LIBHICN_HEADER_FILES_UTIL}
COMPONENT lib${LIBHICN}
- INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..
+ INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../includes
DEFINITIONS ${COMPILER_DEFINITIONS}
INSTALL_ROOT_DIR hicn
- INSTALL_HEADERS ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL}
+ INSTALL_HEADERS ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL} ${LIBHICN_HEADER_FILES_UTIL}
LINK_LIBRARIES ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY}
)
endif ()
-add_custom_command(TARGET ${LIBHICN_STATIC} PRE_BUILD
- COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/hicn
-)
-
-add_custom_command(TARGET ${LIBHICN_STATIC} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/hicn/
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBHICN_HEADER_FILES} ${CMAKE_BINARY_DIR}/hicn/
-)
-
-add_custom_command(TARGET ${LIBHICN_STATIC} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/hicn/protocol
- COMMAND ${CMAKE_COMMAND} -E copy ${LIBHICN_HEADER_FILES_PROTOCOL} ${CMAKE_BINARY_DIR}/hicn/protocol
-)
-
-set(HICN_INCLUDE_DIRS
- ${CMAKE_BINARY_DIR} ""
- CACHE INTERNAL
- "" FORCE
-)
-
-# install(FILES ${LIBHICN_HEADER_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/hicn COMPONENT libhicn)
-# install(FILES ${LIBHICN_HEADER_FILES_PROTOCOL} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/hicn/protocol COMPONENT libhicn)
diff --git a/lib/src/common.c b/lib/src/common.c
index de4ece339..78d25b770 100644
--- a/lib/src/common.c
+++ b/lib/src/common.c
@@ -28,7 +28,8 @@
#endif
#include <stdio.h>
-#include "common.h"
+#include <hicn/common.h>
+
int
diff --git a/lib/src/compat.c b/lib/src/compat.c
index 633037a0f..68f761ac0 100644
--- a/lib/src/compat.c
+++ b/lib/src/compat.c
@@ -23,12 +23,12 @@
#include <string.h> // memset
#include <stddef.h> // offsetof
-#include "common.h"
-#include "compat.h"
-#include "error.h"
-#include "header.h"
-#include "name.h"
-#include "ops.h"
+#include <hicn/common.h>
+#include <hicn/compat.h>
+#include <hicn/error.h>
+#include <hicn/header.h>
+#include <hicn/name.h>
+#include <hicn/ops.h>
#define member_size(type, member) sizeof(((type *)0)->member)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -182,8 +182,10 @@ hicn_packet_get_header_length (hicn_format_t format, const hicn_header_t * h,
int is_ipv4 = _is_ipv4 (format);
int is_ipv6 = _is_ipv6 (format);
// The signature payload is expressed as number of 32 bits words
- *header_length += (is_ah * is_ipv4) * (h->v4ah.ah.payloadlen) << 2;
- *header_length += (is_ah * is_ipv6) * (h->v6ah.ah.payloadlen) << 2;
+ if (is_ah && is_ipv4)
+ *header_length += (h->v4ah.ah.payloadlen) << 2;
+ else if(is_ah && is_ipv6)
+ *header_length += (h->v6ah.ah.payloadlen) << 2;
return HICN_LIB_ERROR_NONE;
}
@@ -319,7 +321,7 @@ hicn_packet_get_payload (hicn_format_t format, const hicn_header_t * h,
int
hicn_packet_get_locator (hicn_format_t format, const hicn_header_t * h,
- ip_address_t * ip_address, bool is_interest)
+ ip_prefix_t * prefix, bool is_interest)
{
const void *locator;
int is_ipv4 = (format & HFO_INET);
@@ -328,28 +330,28 @@ hicn_packet_get_locator (hicn_format_t format, const hicn_header_t * h,
if (is_ipv4)
{
locator = is_interest ? &h->v4.ip.saddr : &h->v4.ip.daddr;
- ip_address->family = AF_INET;
- ip_address->prefix_len = IPV4_ADDR_LEN_BITS;
+ prefix->family = AF_INET;
+ prefix->len = IPV4_ADDR_LEN_BITS;
}
else if (is_ipv6)
{
locator = is_interest ? &h->v6.ip.saddr : &h->v6.ip.daddr;
- ip_address->family = AF_INET6;
- ip_address->prefix_len = IPV6_ADDR_LEN_BITS;
+ prefix->family = AF_INET6;
+ prefix->len = IPV6_ADDR_LEN_BITS;
}
else
{
return HICN_LIB_ERROR_NOT_IMPLEMENTED;
}
- memcpy (ip_address->buffer, locator, ip_address_len (ip_address));
+ memcpy (prefix->address.buffer, locator, ip_address_len(&prefix->address, prefix->family));
return HICN_LIB_ERROR_NONE;
}
int
hicn_packet_set_locator (hicn_format_t format, hicn_header_t * h,
- const ip_address_t * ip_address, bool is_interest)
+ const ip_prefix_t * prefix, bool is_interest)
{
void *locator;
int is_ipv4 = (format & HFO_INET);
@@ -368,7 +370,7 @@ hicn_packet_set_locator (hicn_format_t format, hicn_header_t * h,
return HICN_LIB_ERROR_INVALID_PARAMETER;
}
- memcpy (locator, ip_address->buffer, ip_address_len (ip_address));
+ memcpy (locator, prefix->address.buffer, ip_address_len(&prefix->address, prefix->family));
return HICN_LIB_ERROR_NONE;
}
@@ -951,16 +953,16 @@ hicn_interest_set_name (hicn_format_t format, hicn_header_t * interest,
int
hicn_interest_get_locator (hicn_format_t format,
const hicn_header_t * interest,
- ip_address_t * ip_address)
+ ip_prefix_t * prefix)
{
- return hicn_packet_get_locator (format, interest, ip_address, _INTEREST);
+ return hicn_packet_get_locator (format, interest, prefix, _INTEREST);
}
int
hicn_interest_set_locator (hicn_format_t format, hicn_header_t * interest,
- const ip_address_t * ip_address)
+ const ip_prefix_t * prefix)
{
- return hicn_packet_set_locator (format, interest, ip_address, _INTEREST);
+ return hicn_packet_set_locator (format, interest, prefix, _INTEREST);
}
int
@@ -1043,16 +1045,16 @@ hicn_data_set_name (hicn_format_t format, hicn_header_t * data,
int
hicn_data_get_locator (hicn_format_t format, const hicn_header_t * data,
- ip_address_t * ip_address)
+ ip_prefix_t * prefix)
{
- return hicn_packet_get_locator (format, data, ip_address, _DATA);
+ return hicn_packet_get_locator (format, data, prefix, _DATA);
}
int
hicn_data_set_locator (hicn_format_t format, hicn_header_t * data,
- const ip_address_t * ip_address)
+ const ip_prefix_t * prefix)
{
- return hicn_packet_set_locator (format, data, ip_address, _DATA);
+ return hicn_packet_set_locator (format, data, prefix, _DATA);
}
int
diff --git a/lib/src/error.c b/lib/src/error.c
index 865e2b47d..ab5d6e27d 100644
--- a/lib/src/error.c
+++ b/lib/src/error.c
@@ -18,7 +18,7 @@
* @brief Implementation of error management functions.
*/
-#include "error.h"
+#include <hicn/error.h>
const char *HICN_LIB_ERROR_STRING[] = {
#define _(a,b,c) [b] = c,
diff --git a/lib/src/mapme.c b/lib/src/mapme.c
index ccd384b21..3e7e8bc80 100644
--- a/lib/src/mapme.c
+++ b/lib/src/mapme.c
@@ -18,12 +18,12 @@
* @brief Implementation of MAP-Me anchorless producer mobility management.
*/
-#include "mapme.h"
-#include "common.h"
-#include "error.h"
+#include <hicn/mapme.h>
+#include <hicn/common.h>
+#include <hicn/error.h>
-#include "protocol/ipv4.h"
-#include "protocol/ipv6.h"
+#include <hicn/protocol/ipv4.h>
+#include <hicn/protocol/ipv6.h>
size_t
hicn_mapme_v4_create_packet (u8 * buf, const hicn_prefix_t * prefix,
diff --git a/lib/src/name.c b/lib/src/name.c
index 0a0da63cf..d5ee1d520 100644
--- a/lib/src/name.c
+++ b/lib/src/name.c
@@ -26,11 +26,9 @@
#include <stdlib.h> // strtoul
#include <string.h> // memcpy
-#include "common.h"
-#include "error.h"
-#include "name.h"
-
-#define DUMMY_PORT ntohs(1234)
+#include <hicn/common.h>
+#include <hicn/error.h>
+#include <hicn/name.h>
#if ! HICN_VPP_PLUGIN
int
@@ -76,10 +74,10 @@ hicn_name_create (const char *ip_address, u32 id, hicn_name_t * name)
}
int
-hicn_name_create_from_ip_address (const ip_address_t * ip_address, u32 id,
+hicn_name_create_from_ip_prefix (const ip_prefix_t * prefix, u32 id,
hicn_name_t * name)
{
- switch (ip_address->family)
+ switch (prefix->family)
{
case AF_INET:
name->type = HNT_CONTIGUOUS_V4;
@@ -91,13 +89,14 @@ hicn_name_create_from_ip_address (const ip_address_t * ip_address, u32 id,
return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
}
- name->len = (u8) ip_address_len (ip_address);
+ name->len = (u8) (prefix->len);
if ((name->type != HNT_CONTIGUOUS_V4) && (name->type != HNT_CONTIGUOUS_V6))
{
return HICN_LIB_ERROR_NOT_IMPLEMENTED;
}
- memcpy (name->buffer, ip_address->buffer, name->len);
+ memcpy (name->buffer, prefix->address.buffer,
+ ip_address_len(&prefix->address, prefix->family));
*(u32 *) (name->buffer + name->len) = id;
return HICN_LIB_ERROR_NONE;
@@ -391,27 +390,27 @@ hicn_name_to_sockaddr_address (const hicn_name_t * name,
}
int
-hicn_name_to_ip_address (const hicn_name_t * name, ip_address_t * ip_address)
+hicn_name_to_ip_prefix (const hicn_name_t * name, ip_prefix_t * prefix)
{
switch (name->type)
{
case HNT_CONTIGUOUS_V6:
- memcpy (&ip_address->buffer, name->buffer, IPV6_ADDR_LEN);
- ip_address->family = AF_INET6;
+ memcpy (&prefix->address.buffer, name->buffer, IPV6_ADDR_LEN);
+ prefix->family = AF_INET6;
break;
case HNT_IOV_V6:
- memcpy (&ip_address->buffer, name->iov.buffers[0].iov_base,
+ memcpy (&prefix->address.buffer, name->iov.buffers[0].iov_base,
name->iov.buffers[0].iov_len);
- ip_address->family = AF_INET6;
+ prefix->family = AF_INET6;
break;
case HNT_CONTIGUOUS_V4:
- memcpy (&ip_address->buffer, name->buffer, IPV4_ADDR_LEN);
- ip_address->family = AF_INET;
+ memcpy (&prefix->address.buffer, name->buffer, IPV4_ADDR_LEN);
+ prefix->family = AF_INET;
break;
case HNT_IOV_V4:
- memcpy (&ip_address->buffer, name->iov.buffers[0].iov_base,
+ memcpy (&prefix->address.buffer, name->iov.buffers[0].iov_base,
name->iov.buffers[0].iov_len);
- ip_address->family = AF_INET;
+ prefix->family = AF_INET;
break;
default:
return HICN_LIB_ERROR_UNEXPECTED;
@@ -525,143 +524,28 @@ hicn_name_get_family (const hicn_name_t * name, int *family)
}
int
-hicn_prefix_create_from_ip_address (const ip_address_t * ip_address,
+hicn_prefix_create_from_ip_prefix (const ip_prefix_t * ip_prefix,
hicn_prefix_t * prefix)
{
- switch (ip_address->family)
+ switch (ip_prefix->family)
{
case AF_INET:
- prefix->name.ip4.as_u32 = ip_address->as_u32[0];
+ prefix->name.ip4.as_u32 = ip_prefix->address.as_u32[0];
break;
case AF_INET6:
- prefix->name.ip6.as_u64[0] = ip_address->as_u64[0];
- prefix->name.ip6.as_u64[1] = ip_address->as_u64[1];
+ prefix->name.ip6.as_u64[0] = ip_prefix->address.as_u64[0];
+ prefix->name.ip6.as_u64[1] = ip_prefix->address.as_u64[1];
break;
default:
return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
}
- prefix->len = (u8) (ip_address->prefix_len);
+ prefix->len = (u8) (ip_prefix->len);
return HICN_LIB_ERROR_NONE;
}
#endif /* ! HICN_VPP_PLUGIN */
-/********
- * IP
- */
-
-inline int
-ip_address_len (const ip_address_t * ip_address)
-{
- return (ip_address->family == AF_INET6) ? IPV6_ADDR_LEN :
- (ip_address->family == AF_INET) ? IPV4_ADDR_LEN : 0;
-}
-
-bool
-ip_address_empty (const ip_address_t * ip_address)
-{
- return ip_address->prefix_len == 0;
-}
-
-int
-hicn_ip_ntop (const ip_address_t * ip_address, char *dst, const size_t len)
-{
- const char *rc;
-
- rc = inet_ntop (ip_address->family, ip_address->buffer, dst, len);
- if (!rc)
- {
- printf ("error ntop: %d %s\n", errno, strerror (errno));
- return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
- }
-
- return HICN_LIB_ERROR_NONE;
-}
-
-/*
- * Parse ip addresses in presentation format, or prefixes (in bits, separated by a slash)
- */
-int
-hicn_ip_pton (const char *ip_address_str, ip_address_t * ip_address)
-{
- int pton_fd;
- char *p;
- char *eptr;
- u32 dst_len;
- char *addr = strdup (ip_address_str);
-
- p = strchr (addr, '/');
- if (!p)
- {
- dst_len = 0; // until we get the ip address family
- }
- else
- {
- dst_len = strtoul (p + 1, &eptr, 10);
- *p = 0;
- }
-
- ip_address->family = get_addr_family (addr);
-
- switch (ip_address->family)
- {
- case AF_INET6:
- if (dst_len > IPV6_ADDR_LEN_BITS)
- goto ERR;
- pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer);
- ip_address->prefix_len = dst_len ? dst_len : IPV6_ADDR_LEN_BITS;
- break;
- case AF_INET:
- if (dst_len > IPV4_ADDR_LEN_BITS)
- goto ERR;
- pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer);
- ip_address->prefix_len = dst_len ? dst_len : IPV4_ADDR_LEN_BITS;
- break;
- default:
- goto ERR;
- }
-
- // 0 = not in presentation format
- // < 0 = other error (use perror)
- if (pton_fd <= 0)
- {
- goto ERR;
- }
-
- return HICN_LIB_ERROR_NONE;
-ERR:
- free (addr);
- return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
-}
-
-int
-hicn_ip_to_sockaddr_address (const ip_address_t * ip_address,
- struct sockaddr *sockaddr_address)
-{
- struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sockaddr_address;
- struct sockaddr_in *tmp4 = (struct sockaddr_in *) sockaddr_address;
-
- switch (ip_address->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 HICN_LIB_ERROR_UNEXPECTED;
- }
-
- return HICN_LIB_ERROR_NONE;
-}
-
/*
* fd.io coding-style-patch-verification: ON
diff --git a/lib/src/ops.c b/lib/src/ops.c
index 3e272572a..9bb78be65 100644
--- a/lib/src/ops.c
+++ b/lib/src/ops.c
@@ -22,9 +22,9 @@
#include <netinet/in.h>
#endif
#include <stdlib.h>
-#include "ops.h"
+#include <hicn/ops.h>
-#include "header.h"
+#include <hicn/header.h>
extern const hicn_ops_t hicn_ops_ipv4;
extern const hicn_ops_t hicn_ops_icmp;
diff --git a/hicn-light/src/hicn/utils/policy.c b/lib/src/policy.c
index 6c8651ee3..336249bbb 100644
--- a/hicn-light/src/hicn/utils/policy.c
+++ b/lib/src/policy.c
@@ -19,7 +19,7 @@
*/
#include <stdio.h>
-#include "policy.h"
+#include <hicn/policy.h>
const char * policy_tag_str[] = {
#define _(x, y) [POLICY_TAG_ ## x] = STRINGIZE(x),
diff --git a/lib/src/protocol/ah.c b/lib/src/protocol/ah.c
index 5a30f66f6..c2f3f552a 100644
--- a/lib/src/protocol/ah.c
+++ b/lib/src/protocol/ah.c
@@ -19,11 +19,11 @@
*/
#include <string.h> // memcpy
-#include "../common.h"
-#include "../error.h"
-#include "../header.h"
-#include "../ops.h"
-#include "ah.h"
+#include <hicn/common.h>
+#include <hicn/error.h>
+#include <hicn/header.h>
+#include <hicn/ops.h>
+#include <hicn/protocol/ah.h>
DECLARE_get_interest_locator (ah, UNEXPECTED);
DECLARE_set_interest_locator (ah, UNEXPECTED);
diff --git a/lib/src/protocol/icmp.c b/lib/src/protocol/icmp.c
index 45a28959c..85605a2c3 100644
--- a/lib/src/protocol/icmp.c
+++ b/lib/src/protocol/icmp.c
@@ -14,10 +14,10 @@
*/
#include <string.h>
-#include "icmp.h"
+#include <hicn/protocol/icmp.h>
-#include "../error.h"
-#include "../ops.h"
+#include <hicn/error.h>
+#include <hicn/ops.h>
DECLARE_get_interest_locator (icmp, UNEXPECTED)
DECLARE_set_interest_locator (icmp, UNEXPECTED)
diff --git a/lib/src/protocol/ipv4.c b/lib/src/protocol/ipv4.c
index 3c82b3223..d8d958350 100644
--- a/lib/src/protocol/ipv4.c
+++ b/lib/src/protocol/ipv4.c
@@ -27,12 +27,12 @@
#include <stdlib.h>
#include <string.h>
-#include "../error.h"
-#include "../ops.h"
-#include "../common.h"
-#include "../header.h"
+#include <hicn/error.h>
+#include <hicn/ops.h>
+#include <hicn/common.h>
+#include <hicn/header.h>
-#include "ipv4.h"
+#include <hicn/protocol/ipv4.h>
int ipv4_get_payload_length (hicn_type_t type, const hicn_protocol_t * h,
size_t * payload_length);
diff --git a/lib/src/protocol/ipv6.c b/lib/src/protocol/ipv6.c
index 7554eadf2..622355294 100644
--- a/lib/src/protocol/ipv6.c
+++ b/lib/src/protocol/ipv6.c
@@ -16,9 +16,9 @@
#include <stdlib.h>
#include <string.h>
-#include "../common.h"
-#include "../error.h"
-#include "../ops.h"
+#include <hicn/common.h>
+#include <hicn/error.h>
+#include <hicn/ops.h>
int
ipv6_get_payload_length (hicn_type_t type, const hicn_protocol_t * h,
diff --git a/lib/src/protocol/tcp.c b/lib/src/protocol/tcp.c
index b9f1d2775..0e3155020 100644
--- a/lib/src/protocol/tcp.c
+++ b/lib/src/protocol/tcp.c
@@ -14,10 +14,10 @@
*/
#include <string.h>
-#include "tcp.h"
+#include <hicn/protocol/tcp.h>
-#include "../error.h"
-#include "../ops.h"
+#include <hicn/error.h>
+#include <hicn/ops.h>
#define TCP_DEFAULT_SRC_PORT 0x8000
#define TCP_DEFAULT_DST_PORT 0x0080
diff --git a/ctrl/facemgr/src/util/ip_address.h b/lib/src/util/ip_address.c
index 243ce048b..c54b1fae6 100644
--- a/ctrl/facemgr/src/util/ip_address.h
+++ b/lib/src/util/ip_address.c
@@ -14,120 +14,47 @@
*/
/**
- * \file ip_address.h
- * \brief IP address type support
+ * \file ip_address.c
+ * \brief Implementation of IP address type
*/
-#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
-#include <endian.h>
-#ifdef __ANDROID__
-#include <byteswap.h>
-#endif
-#endif
-#include <errno.h>
-#include <netdb.h> // struct addrinfo
-#include <netinet/in.h> // INET*_ADDRSTRLEN, IN*ADDR_LOOPBACK
-#include <stdlib.h>
-#include <stdio.h> // snprintf
-#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
+#include <hicn/util/ip_address.h>
-/* 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),
+#define SWAP(x) bswap_32(x)
#else
- .v4.as_inaddr.s_addr = __bswap_constant_32(INADDR_LOOPBACK),
+#define SWAP(x) __bswap_constant_32(x)
#endif
#else
- .v4.as_inaddr.s_addr = INADDR_LOOPBACK,
+#define SWAP(x) x
#endif
+
+
+/* No htonl() with const */
+const ip_address_t IPV4_LOOPBACK = (ip_address_t) {
+ .v4.as_inaddr.s_addr = SWAP(INADDR_LOOPBACK),
};
-static const ip_address_t IPV6_LOOPBACK = {
+const ip_address_t IPV6_LOOPBACK = (ip_address_t) {
.v6.as_in6addr = IN6ADDR_LOOPBACK_INIT,
};
-static const ip_address_t IPV4_ANY = {
+const ip_address_t IPV4_ANY = (ip_address_t) {
.v4.as_inaddr.s_addr = INADDR_ANY,
};
-static const ip_address_t IPV6_ANY = {
+const ip_address_t IPV6_ANY = (ip_address_t) {
.v6.as_in6addr = IN6ADDR_ANY_INIT,
};
-#define IP_ANY(family) (family == AF_INET) ? IPV4_ANY : IPV6_ANY
-
-static const ip_address_t IP_ADDRESS_EMPTY = {
+const ip_address_t IP_ADDRESS_EMPTY = {
.as_u64 = { 0 },
};
-#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
+/* IP address */
-#define IS_VALID_FAMILY(x) ((x == AF_INET) || (x == AF_INET6))
-
-static inline
int
ip_address_get_family (const char * ip_address)
{
@@ -149,7 +76,6 @@ ip_address_get_family (const char * ip_address)
return rc;
}
-static inline
int
ip_address_len (const ip_address_t * ip_address, int family)
{
@@ -157,7 +83,6 @@ ip_address_len (const ip_address_t * ip_address, int family)
(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)
@@ -169,24 +94,22 @@ ip_address_ntop (const ip_address_t * ip_address, char *dst, const size_t len,
/*
* 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);
+ family = ip_address_get_family (ip_address_str);
switch (family)
{
case AF_INET6:
- pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer);
+ pton_fd = inet_pton (AF_INET6, ip_address_str, &ip_address->buffer);
break;
case AF_INET:
- pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer);
+ pton_fd = inet_pton (AF_INET, ip_address_str, &ip_address->buffer);
break;
default:
goto ERR;
@@ -201,13 +124,9 @@ ip_address_pton (const char *ip_address_str, ip_address_t * ip_address)
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)
{
@@ -216,14 +135,12 @@ ip_address_snprintf(char * s, size_t size, const ip_address_t * ip_address, int
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 *sa, int family)
{
- struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sockaddr_address;
- struct sockaddr_in *tmp4 = (struct sockaddr_in *) sockaddr_address;
+ struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sa;
+ struct sockaddr_in *tmp4 = (struct sockaddr_in *) sa;
switch (family)
{
@@ -245,22 +162,23 @@ ip_address_to_sockaddr(const ip_address_t * ip_address,
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));
}
-static inline
int
ip_address_empty(const ip_address_t * ip)
{
return (memcmp(ip, &IP_ADDRESS_EMPTY, sizeof(IP_ADDRESS_EMPTY)) == 0);
}
+
+
+/* Prefix */
+
/* 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)
{
@@ -270,26 +188,27 @@ ip_prefix_pton (const char *ip_address_str, ip_prefix_t * ip_prefix)
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;
- }
+ 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 == (u8)~0)
+ ip_prefix->len = IPV6_ADDR_LEN_BITS;
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 == (u8)~0)
+ ip_prefix->len = IPV4_ADDR_LEN_BITS;
if (ip_prefix->len > IPV4_ADDR_LEN_BITS)
goto ERR;
pton_fd = inet_pton (AF_INET, addr, &ip_prefix->address.buffer);
@@ -301,19 +220,29 @@ ip_prefix_pton (const char *ip_address_str, ip_prefix_t * ip_prefix)
// 0 = not in presentation format
// < 0 = other error (use perror)
if (pton_fd <= 0)
- {
goto ERR;
- }
+ free(addr);
return 1;
ERR:
free (addr);
return -1;
}
-static inline
int
-ip_prefix_ntop (const ip_prefix_t * ip_prefix, char *dst, size_t size)
+ip_prefix_ntop_short(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", ip_s);
+
+ return (n > 0 ? 1 : -1);
+}
+
+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);
@@ -324,5 +253,78 @@ ip_prefix_ntop (const ip_prefix_t * ip_prefix, char *dst, size_t size)
return (n > 0 ? 1 : -1);
}
+int
+ip_prefix_len (const ip_prefix_t * prefix)
+{
+ return prefix->len; // ip_address_len(&prefix->address, prefix->family);
+}
+
+bool
+ip_prefix_empty (const ip_prefix_t * prefix)
+{
+ return prefix->len == 0;
+}
-#endif /* UTIL_IP_ADDRESS_H */
+int ip_prefix_to_sockaddr(const ip_prefix_t * prefix,
+ struct sockaddr *sa)
+{
+ // XXX assert len == ip_address_len
+ return ip_address_to_sockaddr(&prefix->address, sa, prefix->family);
+}
+
+
+/* URL */
+
+#define MAXSZ_PROTO_ 8 /* inetX:// */
+#define MAXSZ_PROTO MAXSZ_PROTO_ + NULLTERM
+
+#define MAXSZ_URL4_ MAXSZ_PROTO_ + MAXSZ_IP4_ADDRESS_ + MAXSZ_PORT_
+#define MAXSZ_URL6_ MAXSZ_PROTO_ + MAXSZ_IP6_ADDRESS_ + MAXSZ_PORT_
+#define MAXSZ_URL_ MAXSZ_URL6_
+#define MAXSZ_URL4 MAXSZ_URL4_ + NULLTERM
+#define MAXSZ_URL6 MAXSZ_URL6_ + NULLTERM
+#define MAXSZ_URL MAXSZ_URL_ + NULLTERM
+
+int
+url_snprintf(char * s, size_t size, int family,
+ const ip_address_t * ip_address, u16 port)
+{
+ char * cur = s;
+ int rc;
+
+ /* Other address are currently not supported */
+ if (!IS_VALID_FAMILY(family)) {
+ return -1;
+ }
+
+ 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;
+
+ 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;
+
+ rc = snprintf(cur, s + size - cur, ":");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ 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 cur - s;
+}
diff --git a/libtransport/CMakeLists.txt b/libtransport/CMakeLists.txt
index e68e45c40..dc3409c6f 100644
--- a/libtransport/CMakeLists.txt
+++ b/libtransport/CMakeLists.txt
@@ -85,7 +85,7 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(LIBTRANSPORT_SHARED ${LIBTRANSPORT}.shared)
set(LIBTRANSPORT_STATIC ${LIBTRANSPORT}.static)
else()
- if(ANDROID_API)
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
set(HICN_LIBRARIES ${LIBHICN_STATIC})
list(APPEND DEPENDENCIES
${LIBHICN_STATIC}
@@ -130,7 +130,7 @@ if (${COMPILE_TESTS})
)
endif()
-if(ANDROID_API)
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
find_package(OpenSSL REQUIRED)
endif ()
diff --git a/libtransport/src/hicn/transport/CMakeLists.txt b/libtransport/src/hicn/transport/CMakeLists.txt
index 5fe101c18..22acdcb7f 100644
--- a/libtransport/src/hicn/transport/CMakeLists.txt
+++ b/libtransport/src/hicn/transport/CMakeLists.txt
@@ -25,6 +25,8 @@ add_subdirectory(portability)
add_subdirectory(protocols)
add_subdirectory(utils)
+include(Packager)
+extract_version()
configure_file("config.h.in" "config.h" @ONLY)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h
@@ -54,11 +56,11 @@ else ()
set(CMAKE_SHARED_LINKER_FLAGS "/NODEFAULTLIB:\"MSVCRTD\"" )
endif ()
endif ()
-if (ANDROID_API)
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -isystem -lm")
endif()
-if (ANDROID_API)
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
build_library(${LIBTRANSPORT}
STATIC
SOURCES ${SOURCE_FILES} ${HEADER_FILES}
diff --git a/libtransport/src/hicn/transport/config.h.in b/libtransport/src/hicn/transport/config.h.in
index 7d47c2b3f..ef47affda 100644
--- a/libtransport/src/hicn/transport/config.h.in
+++ b/libtransport/src/hicn/transport/config.h.in
@@ -17,6 +17,10 @@
#cmakedefine TRANSPORT_HAVE_PTHREAD 1
+#define HICNTRANSPORT_VERSION_MAJOR "@VERSION_MAJOR@"
+#define HICNTRANSPORT_VERSION_MINOR "@VERSION_MINOR@"
+#define HICNTRANSPORT_VERSION_REVISION "@VERSION_REVISION@"
+
#ifndef ASIO_STANDALONE
#cmakedefine ASIO_STANDALONE
#endif
diff --git a/libtransport/src/hicn/transport/core/content_object.cc b/libtransport/src/hicn/transport/core/content_object.cc
index 83b545c05..d05239372 100644
--- a/libtransport/src/hicn/transport/core/content_object.cc
+++ b/libtransport/src/hicn/transport/core/content_object.cc
@@ -22,6 +22,7 @@ extern "C" {
TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
#endif
#include <hicn/hicn.h>
+#include <hicn/util/ip_address.h>
}
#include <cstring>
@@ -153,7 +154,7 @@ ContentObject &ContentObject::setPathLabel(uint32_t path_label) {
return *this;
}
-void ContentObject::setLocator(const ip_address_t &ip_address) {
+void ContentObject::setLocator(const ip_prefix_t &ip_address) {
if (hicn_data_set_locator(format_, packet_start_, &ip_address) < 0) {
throw errors::RuntimeException("Error setting content object locator");
}
@@ -161,8 +162,8 @@ void ContentObject::setLocator(const ip_address_t &ip_address) {
return;
}
-ip_address_t ContentObject::getLocator() const {
- ip_address_t ip;
+ip_prefix_t ContentObject::getLocator() const {
+ ip_prefix_t ip;
if (hicn_data_get_locator(format_, packet_start_, &ip) < 0) {
throw errors::RuntimeException("Error getting content object locator.");
diff --git a/libtransport/src/hicn/transport/core/content_object.h b/libtransport/src/hicn/transport/core/content_object.h
index 5af548fe4..ef5144c23 100644
--- a/libtransport/src/hicn/transport/core/content_object.h
+++ b/libtransport/src/hicn/transport/core/content_object.h
@@ -60,9 +60,9 @@ class ContentObject : public Packet {
ContentObject &setPathLabel(uint32_t path_label);
- void setLocator(const ip_address_t &ip_address) override;
+ void setLocator(const ip_prefix_t &ip_address) override;
- ip_address_t getLocator() const override;
+ ip_prefix_t getLocator() const override;
void setLifetime(uint32_t lifetime) override;
diff --git a/libtransport/src/hicn/transport/core/facade.h b/libtransport/src/hicn/transport/core/facade.h
index c28c84671..27e738e62 100644
--- a/libtransport/src/hicn/transport/core/facade.h
+++ b/libtransport/src/hicn/transport/core/facade.h
@@ -37,7 +37,7 @@ namespace core {
using HicnForwarderPortal = Portal<HicnForwarderInterface>;
#ifdef __linux__
-#ifndef __ANDROID_API__
+#ifndef __ANDROID__
using RawSocketPortal = Portal<RawSocketInterface>;
#endif
#ifdef __vpp__
diff --git a/libtransport/src/hicn/transport/core/forwarder_interface.h b/libtransport/src/hicn/transport/core/forwarder_interface.h
index 8fefba8ad..a89ed8a3c 100644
--- a/libtransport/src/hicn/transport/core/forwarder_interface.h
+++ b/libtransport/src/hicn/transport/core/forwarder_interface.h
@@ -50,7 +50,9 @@ class ForwarderInterface {
output_interface_(""),
content_store_reserved_(standard_cs_reserved) {
inet_address_.family = AF_INET;
+ inet_address_.len = IPV4_ADDR_LEN;
inet6_address_.family = AF_INET6;
+ inet6_address_.len = IPV6_ADDR_LEN;
}
public:
@@ -133,8 +135,8 @@ class ForwarderInterface {
protected:
ConnectorType &connector_;
- ip_address_t inet_address_;
- ip_address_t inet6_address_;
+ ip_prefix_t inet_address_;
+ ip_prefix_t inet6_address_;
uint16_t mtu_;
std::string output_interface_;
uint32_t content_store_reserved_;
diff --git a/libtransport/src/hicn/transport/core/hicn_binary_api.c b/libtransport/src/hicn/transport/core/hicn_binary_api.c
index 3868c0a14..8fde516fd 100644
--- a/libtransport/src/hicn/transport/core/hicn_binary_api.c
+++ b/libtransport/src/hicn/transport/core/hicn_binary_api.c
@@ -92,12 +92,12 @@ int hicn_binary_api_register_prod_app(
CONTEXT_SAVE(context_store, api, mp)
- mp->len = (u8)input_params->prefix->prefix_len;
+ mp->len = (u8)input_params->prefix->len;
mp->swif = clib_host_to_net_u32(input_params->swif);
mp->cs_reserved = clib_host_to_net_u32(input_params->cs_reserved);
- mp->prefix[0] = clib_host_to_net_u64(input_params->prefix->as_u64[0]);
- mp->prefix[1] = clib_host_to_net_u64(input_params->prefix->as_u64[1]);
+ mp->prefix[0] = clib_host_to_net_u64(input_params->prefix->address.as_u64[0]);
+ mp->prefix[1] = clib_host_to_net_u64(input_params->prefix->address.as_u64[1]);
return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
}
@@ -112,8 +112,8 @@ static void vl_api_hicn_api_register_prod_app_reply_t_handler(
vpp_binary_api_set_ret_value(binary_api->vpp_api,
clib_net_to_host_u32(mp->retval));
params->cs_reserved = mp->cs_reserved;
- params->prod_addr->as_u64[0] = mp->prod_addr[0];
- params->prod_addr->as_u64[1] = mp->prod_addr[1];
+ params->prod_addr->address.as_u64[0] = mp->prod_addr[0];
+ params->prod_addr->address.as_u64[1] = mp->prod_addr[1];
params->face_id = clib_net_to_host_u32(mp->faceid);
vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
@@ -147,9 +147,9 @@ static void vl_api_hicn_api_register_cons_app_reply_t_handler(
vpp_binary_api_set_ret_value(binary_api->vpp_api,
clib_net_to_host_u32(mp->retval));
- params->src4->as_ip46.ip4.as_u32 = clib_net_to_host_u32(mp->src_addr4);
- params->src6->as_u64[0] = clib_net_to_host_u64(mp->src_addr6[0]);
- params->src6->as_u64[1] = clib_net_to_host_u64(mp->src_addr6[1]);
+ params->src4->address.v4.as_u32 = clib_net_to_host_u32(mp->src_addr4);
+ params->src6->address.as_u64[0] = clib_net_to_host_u64(mp->src_addr6[0]);
+ params->src6->address.as_u64[1] = clib_net_to_host_u64(mp->src_addr6[1]);
params->face_id = clib_host_to_net_u32(mp->faceid);
vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
@@ -166,9 +166,9 @@ int hicn_binary_api_register_route(
CONTEXT_SAVE(context_store, api, mp)
- mp->prefix[0] = input_params->prefix->as_u64[0];
- mp->prefix[1] = input_params->prefix->as_u64[1];
- mp->len = input_params->prefix->prefix_len;
+ mp->prefix[0] = input_params->prefix->address.as_u64[0];
+ mp->prefix[1] = input_params->prefix->address.as_u64[1];
+ mp->len = input_params->prefix->len;
mp->face_ids[0] = input_params->face_id;
mp->n_faces = 1;
diff --git a/libtransport/src/hicn/transport/core/hicn_binary_api.h b/libtransport/src/hicn/transport/core/hicn_binary_api.h
index 410ffb96c..b09b5f4a7 100644
--- a/libtransport/src/hicn/transport/core/hicn_binary_api.h
+++ b/libtransport/src/hicn/transport/core/hicn_binary_api.h
@@ -16,6 +16,7 @@
#pragma once
#include <hicn/transport/config.h>
+#include <hicn/util/ip_address.h>
#ifdef __vpp__
@@ -27,10 +28,8 @@ extern "C" {
#include "stdint.h"
-typedef struct ip_address ip_address_t;
-
typedef struct {
- ip_address_t* prefix;
+ ip_prefix_t* prefix;
uint32_t swif;
uint32_t cs_reserved;
} hicn_producer_input_params;
@@ -41,18 +40,18 @@ typedef struct {
typedef struct {
uint32_t cs_reserved;
- ip_address_t* prod_addr;
+ ip_prefix_t* prod_addr;
uint32_t face_id;
} hicn_producer_output_params;
typedef struct {
- ip_address_t* src4;
- ip_address_t* src6;
+ ip_prefix_t* src4;
+ ip_prefix_t* src6;
uint32_t face_id;
} hicn_consumer_output_params;
typedef struct {
- ip_address_t* prefix;
+ ip_prefix_t* prefix;
uint32_t face_id;
} hicn_producer_set_route_params;
@@ -75,4 +74,4 @@ char* hicn_binary_api_get_error_string(int ret_val);
}
#endif
-#endif // __vpp__ \ No newline at end of file
+#endif // __vpp__
diff --git a/libtransport/src/hicn/transport/core/interest.cc b/libtransport/src/hicn/transport/core/interest.cc
index 60ab10967..6465053de 100644
--- a/libtransport/src/hicn/transport/core/interest.cc
+++ b/libtransport/src/hicn/transport/core/interest.cc
@@ -119,7 +119,7 @@ void Interest::setName(Name &&name) {
}
}
-void Interest::setLocator(const ip_address_t &ip_address) {
+void Interest::setLocator(const ip_prefix_t &ip_address) {
if (hicn_interest_set_locator(format_, packet_start_, &ip_address) < 0) {
throw errors::RuntimeException("Error setting interest locator.");
}
@@ -127,8 +127,8 @@ void Interest::setLocator(const ip_address_t &ip_address) {
return;
}
-ip_address_t Interest::getLocator() const {
- ip_address_t ip;
+ip_prefix_t Interest::getLocator() const {
+ ip_prefix_t ip;
if (hicn_interest_get_locator(format_, packet_start_, &ip) < 0) {
throw errors::RuntimeException("Error getting interest locator.");
@@ -163,4 +163,4 @@ void Interest::resetForHash() {
} // end namespace core
-} // end namespace transport \ No newline at end of file
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/interest.h b/libtransport/src/hicn/transport/core/interest.h
index 48c833a73..12fd597e5 100644
--- a/libtransport/src/hicn/transport/core/interest.h
+++ b/libtransport/src/hicn/transport/core/interest.h
@@ -55,9 +55,9 @@ class Interest
void setName(Name &&name) override;
- void setLocator(const ip_address_t &ip_address) override;
+ void setLocator(const ip_prefix_t &ip_address) override;
- ip_address_t getLocator() const override;
+ ip_prefix_t getLocator() const override;
void setLifetime(uint32_t lifetime) override;
diff --git a/libtransport/src/hicn/transport/core/name.cc b/libtransport/src/hicn/transport/core/name.cc
index 0621eeeb5..46ef98948 100644
--- a/libtransport/src/hicn/transport/core/name.cc
+++ b/libtransport/src/hicn/transport/core/name.cc
@@ -169,11 +169,11 @@ std::shared_ptr<Sockaddr> Name::getAddress() const {
return std::shared_ptr<Sockaddr>(ret);
}
-ip_address_t Name::toIpAddress() const {
- ip_address_t ret;
+ip_prefix_t Name::toIpAddress() const {
+ ip_prefix_t ret;
std::memset(&ret, 0, sizeof(ret));
- if (hicn_name_to_ip_address(&name_, &ret) < 0) {
+ if (hicn_name_to_ip_prefix(&name_, &ret) < 0) {
throw errors::InvalidIpAddressException();
}
diff --git a/libtransport/src/hicn/transport/core/name.h b/libtransport/src/hicn/transport/core/name.h
index 061371be5..35625ddd1 100644
--- a/libtransport/src/hicn/transport/core/name.h
+++ b/libtransport/src/hicn/transport/core/name.h
@@ -93,7 +93,7 @@ class Name {
Name &setSuffix(uint32_t seq_number);
- ip_address_t toIpAddress() const;
+ ip_prefix_t toIpAddress() const;
void copyToDestination(uint8_t *destination,
bool include_suffix = false) const;
diff --git a/libtransport/src/hicn/transport/core/packet.h b/libtransport/src/hicn/transport/core/packet.h
index 4ec93205a..825c4c9dd 100644
--- a/libtransport/src/hicn/transport/core/packet.h
+++ b/libtransport/src/hicn/transport/core/packet.h
@@ -133,9 +133,9 @@ class Packet : public std::enable_shared_from_this<Packet> {
void dump() const;
- virtual void setLocator(const ip_address_t &locator) = 0;
+ virtual void setLocator(const ip_prefix_t &locator) = 0;
- virtual ip_address_t getLocator() const = 0;
+ virtual ip_prefix_t getLocator() const = 0;
void setSignatureTimestamp(const uint64_t &timestamp);
diff --git a/libtransport/src/hicn/transport/core/portal.h b/libtransport/src/hicn/transport/core/portal.h
index 3ea37c938..5796308b4 100644
--- a/libtransport/src/hicn/transport/core/portal.h
+++ b/libtransport/src/hicn/transport/core/portal.h
@@ -417,8 +417,14 @@ class Portal {
pending_interest->startCountdown(portal_details::makeCustomAllocatorHandler(
async_callback_memory_, std::bind(&Portal<ForwarderInt>::timerHandler,
this, std::placeholders::_1, hash)));
- pending_interest_hash_table_.emplace(
- std::make_pair(hash, std::move(pending_interest)));
+
+ auto it = pending_interest_hash_table_.find(hash);
+ if(it != pending_interest_hash_table_.end()){
+ it->second->cancelTimer();
+ it->second = std::move(pending_interest);
+ }else{
+ pending_interest_hash_table_[hash] = std::move(pending_interest);
+ }
}
/**
@@ -644,7 +650,7 @@ class Portal {
std::move(interest_ptr->getInterest()), std::move(content_object));
}
} else {
- TRANSPORT_LOGW("No pending interests for current content (%s)",
+ TRANSPORT_LOGD("No pending interests for current content (%s)",
content_object->getName().toString().c_str());
}
}
diff --git a/libtransport/src/hicn/transport/core/prefix.cc b/libtransport/src/hicn/transport/core/prefix.cc
index 74d1466ac..6b87ccd1f 100644
--- a/libtransport/src/hicn/transport/core/prefix.cc
+++ b/libtransport/src/hicn/transport/core/prefix.cc
@@ -33,7 +33,7 @@ namespace transport {
namespace core {
-Prefix::Prefix() { std::memset(&ip_address_, 0, sizeof(ip_address_t)); }
+Prefix::Prefix() { std::memset(&ip_address_, 0, sizeof(ip_prefix_t)); }
Prefix::Prefix(const char *prefix) : Prefix(std::string(prefix)) {}
@@ -67,7 +67,7 @@ Prefix::Prefix(const core::Name &content_name, uint16_t prefix_length) {
}
ip_address_ = content_name.toIpAddress();
- ip_address_.prefix_len = prefix_length;
+ ip_address_.len = prefix_length;
ip_address_.family = family;
}
@@ -77,13 +77,13 @@ void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length,
throw errors::InvalidIpAddressException();
}
- int ret = inet_pton(family, prefix.c_str(), ip_address_.buffer);
+ int ret = inet_pton(family, prefix.c_str(), ip_address_.address.buffer);
if (ret != 1) {
throw errors::InvalidIpAddressException();
}
- ip_address_.prefix_len = prefix_length;
+ ip_address_.len = prefix_length;
ip_address_.family = family;
}
@@ -101,17 +101,17 @@ std::unique_ptr<Sockaddr> Prefix::toSockaddr() {
throw errors::InvalidIpAddressException();
}
- if (hicn_ip_to_sockaddr_address(&ip_address_, ret) < 0) {
+ if (ip_prefix_to_sockaddr(&ip_address_, ret) < 0) {
throw errors::InvalidIpAddressException();
}
return std::unique_ptr<Sockaddr>(ret);
}
-uint16_t Prefix::getPrefixLength() { return ip_address_.prefix_len; }
+uint16_t Prefix::getPrefixLength() { return ip_address_.len; }
Prefix &Prefix::setPrefixLength(uint16_t prefix_length) {
- ip_address_.prefix_len = prefix_length;
+ ip_address_.len = prefix_length;
return *this;
}
@@ -123,17 +123,17 @@ Prefix &Prefix::setAddressFamily(int address_family) {
}
std::string Prefix::getNetwork() const {
- if (!checkPrefixLengthAndAddressFamily(ip_address_.prefix_len,
+ if (!checkPrefixLengthAndAddressFamily(ip_address_.len,
ip_address_.family)) {
throw errors::InvalidIpAddressException();
}
std::size_t size =
- ip_address_.family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
+ ip_address_.family == 4 + AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
std::string network(size, 0);
- if (hicn_ip_ntop(&ip_address_, (char *)network.c_str(), size) < 0) {
+ if (ip_prefix_ntop_short(&ip_address_, (char *)network.c_str(), size) < 0) {
throw errors::RuntimeException(
"Impossible to retrieve network from ip address.");
}
@@ -147,7 +147,7 @@ Name Prefix::getName() const {
}
Prefix &Prefix::setNetwork(std::string &network) {
- if (!inet_pton(AF_INET6, network.c_str(), ip_address_.buffer)) {
+ if (!inet_pton(AF_INET6, network.c_str(), ip_address_.address.buffer)) {
throw errors::RuntimeException("The network name is not valid.");
}
@@ -163,10 +163,10 @@ Name Prefix::makeRandomName() const {
0, std::numeric_limits<uint32_t>::max());
uint64_t random_number = idis(eng);
- uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_address_.prefix_len;
+ uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_address_.len;
uint64_t ip_address[2];
- memcpy(ip_address, ip_address_.buffer, sizeof(uint64_t));
- memcpy(ip_address + 1, ip_address_.buffer + 8, sizeof(uint64_t));
+ memcpy(ip_address, ip_address_.address.buffer, sizeof(uint64_t));
+ memcpy(ip_address + 1, ip_address_.address.buffer + 8, sizeof(uint64_t));
std::string network(IPV6_ADDR_LEN * 3, 0);
// Let's do the magic ;)
@@ -208,7 +208,7 @@ bool Prefix::checkPrefixLengthAndAddressFamily(uint16_t prefix_length,
return true;
}
-ip_address_t &Prefix::toIpAddressStruct() { return ip_address_; }
+ip_prefix_t &Prefix::toIpAddressStruct() { return ip_address_; }
} // namespace core
diff --git a/libtransport/src/hicn/transport/core/prefix.h b/libtransport/src/hicn/transport/core/prefix.h
index b68c6bdf6..022e2bec2 100644
--- a/libtransport/src/hicn/transport/core/prefix.h
+++ b/libtransport/src/hicn/transport/core/prefix.h
@@ -52,7 +52,7 @@ class Prefix {
Name makeRandomName() const;
- ip_address_t &toIpAddressStruct();
+ ip_prefix_t &toIpAddressStruct();
private:
static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length,
@@ -60,9 +60,9 @@ class Prefix {
void buildPrefix(std::string &prefix, uint16_t prefix_length, int family);
- ip_address_t ip_address_;
+ ip_prefix_t ip_address_;
};
} // end namespace core
-} // end namespace transport \ No newline at end of file
+} // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.cc b/libtransport/src/hicn/transport/core/raw_socket_interface.cc
index 4cf7b2ca6..ef365fce7 100644
--- a/libtransport/src/hicn/transport/core/raw_socket_interface.cc
+++ b/libtransport/src/hicn/transport/core/raw_socket_interface.cc
@@ -45,7 +45,7 @@ void RawSocketInterface::connect(bool is_consumer) {
utils::retrieveInterfaceAddress(output_interface_, &address);
inet6_address_.family = address.sin6_family;
- std::memcpy(inet6_address_.buffer, &address.sin6_addr,
+ std::memcpy(inet6_address_.address.buffer, &address.sin6_addr,
sizeof(address.sin6_addr));
connector_.connect(output_interface_, remote_mac_address_);
}
diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc
index 61c5dfc7f..c8a4f9c88 100644
--- a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc
+++ b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc
@@ -87,8 +87,8 @@ uint32_t VPPForwarderInterface::getMemifConfiguration() {
void VPPForwarderInterface::consumerConnection() {
hicn_consumer_input_params input = {0};
hicn_consumer_output_params output = {0};
- ip_address_t ip4_address;
- ip_address_t ip6_address;
+ ip_prefix_t ip4_address;
+ ip_prefix_t ip6_address;
output.src4 = &ip4_address;
output.src6 = &ip6_address;
@@ -103,12 +103,12 @@ void VPPForwarderInterface::consumerConnection() {
}
inet_address_.family = AF_INET;
- inet_address_.prefix_len = output.src4->prefix_len;
- std::memcpy(inet_address_.buffer, output.src4->buffer, IPV6_ADDR_LEN);
+ inet_address_.len = output.src4->len;
+ std::memcpy(inet_address_.address.buffer, output.src4->address.buffer, IPV6_ADDR_LEN);
inet6_address_.family = AF_INET6;
- inet6_address_.prefix_len = output.src6->prefix_len;
- std::memcpy(inet6_address_.buffer, output.src6->buffer, IPV6_ADDR_LEN);
+ inet6_address_.len = output.src6->len;
+ std::memcpy(inet6_address_.address.buffer, output.src6->address.buffer, IPV6_ADDR_LEN);
}
void VPPForwarderInterface::producerConnection() {
@@ -144,7 +144,7 @@ void VPPForwarderInterface::registerRoute(Prefix &prefix) {
auto &addr = prefix.toIpAddressStruct();
// Same ip address for input and outurt params
- ip_address_t ip_address;
+ ip_prefix_t ip_address;
if (face_id_ == uint32_t(~0)) {
hicn_producer_input_params input;
@@ -160,10 +160,10 @@ void VPPForwarderInterface::registerRoute(Prefix &prefix) {
// memif_id, since this function should be called after the
// memif creation.
input.swif = sw_if_index_;
- input.prefix->as_u64[0] = addr.as_u64[0];
- input.prefix->as_u64[1] = addr.as_u64[1];
+ input.prefix->address.as_u64[0] = addr.address.as_u64[0];
+ input.prefix->address.as_u64[1] = addr.address.as_u64[1];
input.prefix->family = addr.family == AF_INET6 ? AF_INET6 : AF_INET;
- input.prefix->prefix_len = addr.prefix_len;
+ input.prefix->len = addr.len;
input.cs_reserved = content_store_reserved_;
int ret = hicn_binary_api_register_prod_app(
@@ -174,25 +174,25 @@ void VPPForwarderInterface::registerRoute(Prefix &prefix) {
}
if (addr.family == AF_INET6) {
- inet6_address_.prefix_len = output.prod_addr->prefix_len;
- inet6_address_.as_u64[0] = output.prod_addr->as_u64[0];
- inet6_address_.as_u64[1] = output.prod_addr->as_u64[1];
+ inet6_address_.len = output.prod_addr->len;
+ inet6_address_.address.as_u64[0] = output.prod_addr->address.as_u64[0];
+ inet6_address_.address.as_u64[1] = output.prod_addr->address.as_u64[1];
} else {
- inet_address_.prefix_len = output.prod_addr->prefix_len;
+ inet_address_.len = output.prod_addr->len;
// The ipv4 is written in the last 4 bytes of the ipv6 address, so we need
// to copy from the byte 12
- inet_address_.as_u64[0] = output.prod_addr->as_u64[0];
- inet_address_.as_u64[1] = output.prod_addr->as_u64[1];
+ inet_address_.address.as_u64[0] = output.prod_addr->address.as_u64[0];
+ inet_address_.address.as_u64[1] = output.prod_addr->address.as_u64[1];
}
face_id_ = output.face_id;
} else {
hicn_producer_set_route_params params;
params.prefix = &ip_address;
- params.prefix->as_u64[0] = addr.as_u64[0];
- params.prefix->as_u64[1] = addr.as_u64[1];
+ params.prefix->address.as_u64[0] = addr.address.as_u64[0];
+ params.prefix->address.as_u64[1] = addr.address.as_u64[1];
params.prefix->family = addr.family == AF_INET6 ? AF_INET6 : AF_INET;
- params.prefix->prefix_len = addr.prefix_len;
+ params.prefix->len = addr.len;
params.face_id = face_id_;
int ret = hicn_binary_api_register_route(VPPForwarderInterface::hicn_api_,
@@ -225,4 +225,4 @@ void VPPForwarderInterface::closeConnection() {
} // namespace transport
-#endif \ No newline at end of file
+#endif
diff --git a/libtransport/src/hicn/transport/interfaces/CMakeLists.txt b/libtransport/src/hicn/transport/interfaces/CMakeLists.txt
index a5cca78a6..0c2c73623 100644
--- a/libtransport/src/hicn/transport/interfaces/CMakeLists.txt
+++ b/libtransport/src/hicn/transport/interfaces/CMakeLists.txt
@@ -28,6 +28,7 @@ list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.cc
${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.cc
${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.cc
)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/face_cache.h b/libtransport/src/hicn/transport/interfaces/callbacks.cc
index caefb7e22..2574e7720 100644
--- a/ctrl/facemgr/src/face_cache.h
+++ b/libtransport/src/hicn/transport/interfaces/callbacks.cc
@@ -13,12 +13,14 @@
* limitations under the License.
*/
-#ifndef FACE_CACHE_H
-#define FACE_CACHE_H
+#include "callbacks.h"
-#include "face.h"
-#include "util/set.h"
+namespace transport {
-TYPEDEF_SET_H(face_cache, face_t *);
+namespace interface {
-#endif /* FACE_CACHE_H */
+std::nullptr_t VOID_HANDLER = nullptr;
+
+} // namespace interface
+
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/callbacks.h b/libtransport/src/hicn/transport/interfaces/callbacks.h
index 24f47eb75..7194cca42 100644
--- a/libtransport/src/hicn/transport/interfaces/callbacks.h
+++ b/libtransport/src/hicn/transport/interfaces/callbacks.h
@@ -18,6 +18,8 @@
#include <functional>
#include <system_error>
+#include <hicn/transport/core/facade.h>
+
namespace utils {
class MemBuf;
}
@@ -105,6 +107,8 @@ using ProducerContentObjectCallback =
using ProducerInterestCallback =
std::function<void(ProducerSocket &, core::Interest &)>;
+extern std::nullptr_t VOID_HANDLER;
+
} // namespace interface
} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc
index d1e89efdc..c1a45ebb7 100644
--- a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc
+++ b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc
@@ -13,6 +13,7 @@
* limitations under the License.
*/
+#include <hicn/transport/interfaces/callbacks.h>
#include <hicn/transport/interfaces/rtc_socket_producer.h>
#include <stdlib.h>
#include <time.h>
@@ -31,6 +32,12 @@
#define HICN_MAX_DATA_SEQ 0xefffffff
+// slow production rate param
+#define MIN_PRODUCTION_RATE \
+ 10 // in pacekts per sec. this value is computed
+ // through experiments
+#define LIFETIME_FRACTION 0.5
+
// NACK HEADER
// +-----------------------------------------+
// | 4 bytes: current segment in production |
@@ -58,12 +65,14 @@ RTCProducerSocket::RTCProducerSocket(asio::io_service &io_service)
bytesProductionRate_(INIT_PACKET_PRODUCTION_RATE * 1400),
packetsProductionRate_(INIT_PACKET_PRODUCTION_RATE),
perSecondFactor_(MILLI_IN_A_SEC / STATS_INTERVAL_DURATION),
- active_(false) {
- lastStats_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ timer_on_(false) {
srand((unsigned int)time(NULL));
prodLabel_ = ((rand() % 255) << 24UL);
+ interests_cache_timer_ =
+ std::make_unique<asio::steady_timer>(this->getIoService());
+ round_timer_ = std::make_unique<asio::steady_timer>(this->getIoService());
+ setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 10000U);
+ scheduleRoundTimer();
}
RTCProducerSocket::RTCProducerSocket()
@@ -74,12 +83,14 @@ RTCProducerSocket::RTCProducerSocket()
bytesProductionRate_(INIT_PACKET_PRODUCTION_RATE * 1400),
packetsProductionRate_(INIT_PACKET_PRODUCTION_RATE),
perSecondFactor_(MILLI_IN_A_SEC / STATS_INTERVAL_DURATION),
- active_(false) {
- lastStats_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ timer_on_(false) {
srand((unsigned int)time(NULL));
prodLabel_ = ((rand() % 255) << 24UL);
+ interests_cache_timer_ =
+ std::make_unique<asio::steady_timer>(this->getIoService());
+ round_timer_ = std::make_unique<asio::steady_timer>(this->getIoService());
+ setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 10000U);
+ scheduleRoundTimer();
}
RTCProducerSocket::~RTCProducerSocket() {}
@@ -102,18 +113,22 @@ void RTCProducerSocket::registerPrefix(const Prefix &producer_namespace) {
}
}
-void RTCProducerSocket::updateStats(uint32_t packet_size, uint64_t now) {
- producedBytes_ += packet_size;
- producedPackets_++;
- uint64_t duration = now - lastStats_;
- if (duration >= STATS_INTERVAL_DURATION) {
- lastStats_ = now;
- bytesProductionRate_ = producedBytes_ * perSecondFactor_;
- packetsProductionRate_ = producedPackets_ * perSecondFactor_;
- if (packetsProductionRate_.load() == 0) packetsProductionRate_ = 1;
- producedBytes_ = 0;
- producedPackets_ = 0;
- }
+void RTCProducerSocket::scheduleRoundTimer() {
+ round_timer_->expires_from_now(
+ std::chrono::milliseconds(STATS_INTERVAL_DURATION));
+ round_timer_->async_wait([this](std::error_code ec) {
+ if (ec) return;
+ updateStats();
+ });
+}
+
+void RTCProducerSocket::updateStats() {
+ bytesProductionRate_ = producedBytes_.load() * perSecondFactor_;
+ packetsProductionRate_ = producedPackets_.load() * perSecondFactor_;
+ if (packetsProductionRate_.load() == 0) packetsProductionRate_ = 1;
+ producedBytes_ = 0;
+ producedPackets_ = 0;
+ scheduleRoundTimer();
}
void RTCProducerSocket::produce(std::unique_ptr<utils::MemBuf> &&buffer) {
@@ -132,67 +147,143 @@ void RTCProducerSocket::produce(std::unique_ptr<utils::MemBuf> &&buffer) {
std::chrono::steady_clock::now().time_since_epoch())
.count();
- {
- utils::SpinLock::Acquire locked(lock_);
- active_ = true;
- lastProduced_ = now;
- }
-
- updateStats((uint32_t)(buffer_size + headerSize_ + TIMESTAMP_LEN), now);
-
- ContentObject content_object(flowName_.setSuffix(currentSeg_));
+ producedBytes_ += (uint32_t)(buffer_size + headerSize_ + TIMESTAMP_LEN);
+ producedPackets_++;
+ auto content_object =
+ std::make_shared<ContentObject>(flowName_.setSuffix(currentSeg_.load()));
auto payload = utils::MemBuf::create(TIMESTAMP_LEN);
memcpy(payload->writableData(), &now, TIMESTAMP_LEN);
payload->append(TIMESTAMP_LEN);
payload->prependChain(std::move(buffer));
- content_object.appendPayload(std::move(payload));
+ content_object->appendPayload(std::move(payload));
+
+ content_object->setLifetime(500); // XXX this should be set by the APP
- content_object.setLifetime(500); // XXX this should be set by the APP
+ content_object->setPathLabel(prodLabel_);
+
+ output_buffer_.insert(std::static_pointer_cast<ContentObject>(
+ content_object->shared_from_this()));
+
+ if (on_content_object_in_output_buffer_) {
+ on_content_object_in_output_buffer_(*this, *content_object);
+ }
- content_object.setPathLabel(prodLabel_);
+ portal_->sendContentObject(*content_object);
- if (on_content_object_output_ != VOID_HANDLER) {
- on_content_object_output_(*this, content_object);
+ if (on_content_object_output_) {
+ on_content_object_output_(*this, *content_object);
}
- portal_->sendContentObject(content_object);
+ uint32_t old_curr = currentSeg_.load();
+ currentSeg_ = (currentSeg_.load() + 1) % HICN_MAX_DATA_SEQ;
- currentSeg_ = (currentSeg_ + 1) % HICN_MAX_DATA_SEQ;
+ // remove interests from the interest cache if it exists
+ // this generates nacks that will tell to the consumer
+ // that a new data packet was produced
+ if (!seqs_map_.empty()) {
+ utils::SpinLock::Acquire locked(interests_cache_lock_);
+ for (auto it = seqs_map_.begin(); it != seqs_map_.end(); it++) {
+ if (it->first != old_curr) sendNack(it->first);
+ }
+ seqs_map_.clear();
+ timers_map_.clear();
+ }
}
void RTCProducerSocket::onInterest(Interest::Ptr &&interest) {
uint32_t interestSeg = interest->getName().getSuffix();
uint32_t lifetime = interest->getLifetime();
- if (on_interest_input_ != VOID_HANDLER) {
+ if (on_interest_input_) {
on_interest_input_(*this, *interest);
}
- bool isActive;
- {
- utils::SpinLock::Acquire locked(lock_);
- isActive = active_;
- if (isActive) {
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
- if ((now - lastProduced_) > INACTIVE_TIME) {
- // socket is inactive
- active_ = false;
- isActive = false;
- }
- }
+ uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+
+ if (interestSeg > HICN_MAX_DATA_SEQ) {
+ sendNack(interestSeg);
+ return;
}
- if (TRANSPORT_EXPECT_FALSE(!isActive)) {
- sendNack(*interest, false);
+ const std::shared_ptr<ContentObject> content_object =
+ output_buffer_.find(*interest);
+
+ if (content_object) {
+ if (on_interest_satisfied_output_buffer_) {
+ on_interest_satisfied_output_buffer_(*this, *interest);
+ }
+
+ if (on_content_object_output_) {
+ on_content_object_output_(*this, *content_object);
+ }
+
+ portal_->sendContentObject(*content_object);
return;
+ } else {
+ if (on_interest_process_) {
+ on_interest_process_(*this, *interest);
+ }
}
- if(interestSeg > HICN_MAX_DATA_SEQ){
- sendNack(*interest, isActive);
+ // if the production rate is less than MIN_PRODUCTION_RATE we put the
+ // interest in a queue, otherwise we handle it in the usual way
+ if (packetsProductionRate_.load() < MIN_PRODUCTION_RATE &&
+ interestSeg >= currentSeg_.load()) {
+ utils::SpinLock::Acquire locked(interests_cache_lock_);
+
+ uint64_t next_timer = ~0;
+ if (!timers_map_.empty()) {
+ next_timer = timers_map_.begin()->first;
+ }
+
+ uint64_t expiration = now + (lifetime * LIFETIME_FRACTION);
+ // check if the seq number exists already
+ auto it_seqs = seqs_map_.find(interestSeg);
+ if (it_seqs != seqs_map_.end()) {
+ // the seq already exists
+ if (expiration < it_seqs->second) {
+ // we need to update the timer becasue we got a smaller one
+ // 1) remove the entry from the multimap
+ // 2) update this entry
+ auto range = timers_map_.equal_range(it_seqs->second);
+ for (auto it_timers = range.first; it_timers != range.second;
+ it_timers++) {
+ if (it_timers->second == it_seqs->first) {
+ timers_map_.erase(it_timers);
+ break;
+ }
+ }
+ timers_map_.insert(
+ std::pair<uint64_t, uint32_t>(expiration, interestSeg));
+ it_seqs->second = expiration;
+ } else {
+ // nothing to do here
+ return;
+ }
+ } else {
+ // add the new seq
+ timers_map_.insert(
+ std::pair<uint64_t, uint32_t>(expiration, interestSeg));
+ seqs_map_.insert(std::pair<uint32_t, uint64_t>(interestSeg, expiration));
+ }
+
+ // here we have at least one interest in the queue, we need to start or
+ // update the timer
+ if (!timer_on_) {
+ // set timeout
+ timer_on_ = true;
+ scheduleCacheTimer(timers_map_.begin()->first - now);
+ } else {
+ // re-schedule the timer because a new interest will expires sooner
+ if (next_timer > timers_map_.begin()->first) {
+ interests_cache_timer_->cancel();
+ scheduleCacheTimer(timers_map_.begin()->first - now);
+ }
+ }
return;
}
@@ -201,33 +292,66 @@ void RTCProducerSocket::onInterest(Interest::Ptr &&interest) {
1000.0) *
(double)packetsProductionRate_.load()));
- if (interestSeg < currentSeg_ || interestSeg > (max_gap + currentSeg_)) {
- sendNack(*interest, true);
+ if (interestSeg < currentSeg_.load() ||
+ interestSeg > (max_gap + currentSeg_.load())) {
+ sendNack(interestSeg);
}
// else drop packet
}
-void RTCProducerSocket::sendNack(const Interest &interest, bool isActive) {
+void RTCProducerSocket::scheduleCacheTimer(uint64_t wait) {
+ interests_cache_timer_->expires_from_now(std::chrono::milliseconds(wait));
+ interests_cache_timer_->async_wait([this](std::error_code ec) {
+ if (ec) return;
+ interestCacheTimer();
+ });
+}
+
+void RTCProducerSocket::interestCacheTimer() {
+ uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+
+ utils::SpinLock::Acquire locked(interests_cache_lock_);
+
+ for (auto it_timers = timers_map_.begin(); it_timers != timers_map_.end();) {
+ uint64_t expire = it_timers->first;
+ if (expire <= now) {
+ uint32_t seq = it_timers->second;
+ sendNack(seq);
+ // remove the interest from the other map
+ seqs_map_.erase(seq);
+ it_timers = timers_map_.erase(it_timers);
+ } else {
+ // stop, we are done!
+ break;
+ }
+ }
+ if (timers_map_.empty()) {
+ timer_on_ = false;
+ } else {
+ timer_on_ = true;
+ scheduleCacheTimer(timers_map_.begin()->first - now);
+ }
+}
+
+void RTCProducerSocket::sendNack(uint32_t sequence) {
auto nack_payload = utils::MemBuf::create(NACK_HEADER_SIZE);
nack_payload->append(NACK_HEADER_SIZE);
ContentObject nack;
nack.appendPayload(std::move(nack_payload));
- nack.setName(interest.getName());
+ nack.setName(flowName_.setSuffix(sequence));
uint32_t *payload_ptr = (uint32_t *)nack.getPayload()->data();
- *payload_ptr = currentSeg_;
+ *payload_ptr = currentSeg_.load();
- if (isActive) {
- *(++payload_ptr) = bytesProductionRate_;
- } else {
- *(++payload_ptr) = 0;
- }
+ *(++payload_ptr) = bytesProductionRate_.load();
nack.setLifetime(0);
nack.setPathLabel(prodLabel_);
- if (on_content_object_output_ != VOID_HANDLER) {
+ if (on_content_object_output_) {
on_content_object_output_(*this, nack);
}
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h
index 5b9a23dd7..37ba88d8a 100644
--- a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h
+++ b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h
@@ -41,23 +41,37 @@ class RTCProducerSocket : public ProducerSocket {
void onInterest(Interest::Ptr &&interest) override;
private:
- void sendNack(const Interest &interest, bool isActive);
- void updateStats(uint32_t packet_size, uint64_t now);
+ void sendNack(uint32_t sequence);
+ void updateStats();
+ void scheduleCacheTimer(uint64_t wait);
+ void scheduleRoundTimer();
+ void interestCacheTimer();
- uint32_t currentSeg_;
+ std::atomic<uint32_t> currentSeg_;
uint32_t prodLabel_;
uint16_t headerSize_;
Name flowName_;
- uint32_t producedBytes_;
- uint32_t producedPackets_;
- uint32_t bytesProductionRate_;
+ std::atomic<uint32_t> producedBytes_;
+ std::atomic<uint32_t> producedPackets_;
+ std::atomic<uint32_t> bytesProductionRate_;
std::atomic<uint32_t> packetsProductionRate_;
uint32_t perSecondFactor_;
- uint64_t lastStats_;
- uint64_t lastProduced_;
- bool active_;
- utils::SpinLock lock_;
+ std::unique_ptr<asio::steady_timer> round_timer_;
+
+ // cache for the received interests
+ // this map maps the expiration time of an interest to
+ // its sequence number. the map is sorted by timeouts
+ // the same timeout may be used for multiple sequence numbers
+ // but for each sequence number we store only the smallest
+ // expiry time. In this way the mapping from seqs_map_ to
+ // timers_map_ is unique
+ std::multimap<uint64_t,uint32_t> timers_map_;
+ // this map does the opposite, this map is not ordered
+ std::unordered_map<uint32_t,uint64_t> seqs_map_;
+ bool timer_on_;
+ std::unique_ptr<asio::steady_timer> interests_cache_timer_;
+ utils::SpinLock interests_cache_lock_;
};
} // namespace interface
diff --git a/libtransport/src/hicn/transport/interfaces/socket.h b/libtransport/src/hicn/transport/interfaces/socket.h
index 90f6a3ef6..f0194880a 100644
--- a/libtransport/src/hicn/transport/interfaces/socket.h
+++ b/libtransport/src/hicn/transport/interfaces/socket.h
@@ -27,8 +27,6 @@
#define SOCKET_OPTION_NOT_SET 3
#define SOCKET_OPTION_DEFAULT 12345
-#define VOID_HANDLER 0
-
namespace transport {
namespace interface {
diff --git a/libtransport/src/hicn/transport/interfaces/socket_consumer.cc b/libtransport/src/hicn/transport/interfaces/socket_consumer.cc
index e1afd2161..14cd27b6b 100644
--- a/libtransport/src/hicn/transport/interfaces/socket_consumer.cc
+++ b/libtransport/src/hicn/transport/interfaces/socket_consumer.cc
@@ -45,7 +45,6 @@ ConsumerSocket::ConsumerSocket(int protocol, asio::io_service &io_service)
rate_estimation_alpha_(default_values::rate_alpha),
rate_estimation_observer_(nullptr),
rate_estimation_choice_(0),
- is_async_(false),
verifier_(std::make_shared<utils::Verifier>()),
verify_signature_(false),
on_interest_output_(VOID_HANDLER),
@@ -58,8 +57,8 @@ ConsumerSocket::ConsumerSocket(int protocol, asio::io_service &io_service)
stats_summary_(VOID_HANDLER),
read_callback_(nullptr),
virtual_download_(false),
- rtt_stats_(false),
- timer_interval_milliseconds_(0) {
+ timer_interval_milliseconds_(0),
+ guard_raaqm_params_() {
switch (protocol) {
case TransportProtocolAlgorithms::CBR:
transport_protocol_ = std::make_unique<CbrTransportProtocol>(this);
@@ -88,7 +87,6 @@ int ConsumerSocket::consume(const Name &name) {
network_name_ = name;
network_name_.setSuffix(0);
- is_async_ = false;
transport_protocol_->start();
@@ -100,7 +98,6 @@ int ConsumerSocket::asyncConsume(const Name &name) {
async_downloader_.add([this, name]() {
network_name_ = std::move(name);
network_name_.setSuffix(0);
- is_async_ = true;
transport_protocol_->start();
});
}
@@ -108,20 +105,6 @@ int ConsumerSocket::asyncConsume(const Name &name) {
return CONSUMER_RUNNING;
}
-void ConsumerSocket::asyncSendInterest(Interest::Ptr &&interest,
- Portal::ConsumerCallback *callback) {
- if (!async_downloader_.stopped()) {
- // TODO Workaround, to be fixed!
- auto i = interest.release();
- async_downloader_.add([this, i, callback]() mutable {
- Interest::Ptr _interest(i);
- portal_->setConsumerCallback(callback);
- portal_->sendInterest(std::move(_interest));
- portal_->runEventsLoop();
- });
- }
-}
-
void ConsumerSocket::stop() {
if (transport_protocol_->isRunning()) {
transport_protocol_->stop();
@@ -138,6 +121,702 @@ asio::io_service &ConsumerSocket::getIoService() {
return portal_->getIoService();
}
+// If the thread calling lambda_func is not the same of io_service, this
+// function reschedule the function on it
+template <typename Lambda, typename arg2>
+int ConsumerSocket::rescheduleOnIOService(int socket_option_key,
+ arg2 socket_option_value,
+ Lambda lambda_func) {
+ // To enforce type check
+ std::function<int(int, arg2)> func = lambda_func;
+ int result = SOCKET_OPTION_SET;
+ if (transport_protocol_->isRunning()) {
+ std::mutex mtx;
+ /* Condition variable for the wait */
+ std::condition_variable cv;
+ bool done = false;
+ io_service_.dispatch([&socket_option_key, &socket_option_value, &mtx,
+ &result, &done, &func]() {
+ std::unique_lock<std::mutex> lck(mtx);
+ done = true;
+ result = func(socket_option_key, socket_option_value);
+ });
+ std::unique_lock<std::mutex> lck(mtx);
+ if (!done) {
+ cv.wait(lck);
+ }
+ } else {
+ result = func(socket_option_key, socket_option_value);
+ }
+
+ return result;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ ReadCallback *socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key, ReadCallback *socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::READ_CALLBACK:
+ read_callback_ = socket_option_value;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ ReadCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key, ReadCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::READ_CALLBACK:
+ *socket_option_value = read_callback_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ double socket_option_value) {
+ utils::SpinLock::Acquire locked(guard_raaqm_params_);
+ switch (socket_option_key) {
+ case MIN_WINDOW_SIZE:
+ min_window_size_ = socket_option_value;
+ break;
+
+ case MAX_WINDOW_SIZE:
+ max_window_size_ = socket_option_value;
+ break;
+
+ case CURRENT_WINDOW_SIZE:
+ current_window_size_ = socket_option_value;
+ break;
+
+ case GAMMA_VALUE:
+ gamma_ = socket_option_value;
+ break;
+
+ case BETA_VALUE:
+ beta_ = socket_option_value;
+ break;
+
+ case DROP_FACTOR:
+ drop_factor_ = socket_option_value;
+ break;
+
+ case MINIMUM_DROP_PROBABILITY:
+ minimum_drop_probability_ = socket_option_value;
+ break;
+
+ case RATE_ESTIMATION_ALPHA:
+ if (socket_option_value >= 0 && socket_option_value < 1) {
+ rate_estimation_alpha_ = socket_option_value;
+ } else {
+ rate_estimation_alpha_ = default_values::alpha;
+ }
+ break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ uint32_t socket_option_value) {
+ utils::SpinLock::Acquire locked(guard_raaqm_params_);
+ switch (socket_option_key) {
+ case GeneralTransportOptions::MAX_INTEREST_RETX:
+ max_retransmissions_ = socket_option_value;
+ break;
+
+ case GeneralTransportOptions::INTEREST_LIFETIME:
+ interest_lifetime_ = socket_option_value;
+ break;
+
+ case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
+ if (socket_option_value > 0) {
+ rate_estimation_batching_parameter_ = socket_option_value;
+ } else {
+ rate_estimation_batching_parameter_ = default_values::batch;
+ }
+ break;
+
+ case RateEstimationOptions::RATE_ESTIMATION_CHOICE:
+ if (socket_option_value > 0) {
+ rate_estimation_choice_ = socket_option_value;
+ } else {
+ rate_estimation_choice_ = default_values::rate_choice;
+ }
+ break;
+
+ case GeneralTransportOptions::STATS_INTERVAL:
+ timer_interval_milliseconds_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ std::nullptr_t socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key, std::nullptr_t socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_retransmission_ = VOID_HANDLER;
+ break;
+ }
+
+ case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_timeout_ = VOID_HANDLER;
+ break;
+ }
+
+ case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_satisfied_ = VOID_HANDLER;
+ break;
+ }
+
+ case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_output_ = VOID_HANDLER;
+ break;
+ }
+
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_input_ = VOID_HANDLER;
+ break;
+ }
+
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_verification_ = VOID_HANDLER;
+ break;
+ }
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ bool socket_option_value) {
+ int result = SOCKET_OPTION_NOT_SET;
+ if (!transport_protocol_->isRunning()) {
+ switch (socket_option_key) {
+ case OtherOptions::VIRTUAL_DOWNLOAD:
+ virtual_download_ = socket_option_value;
+ result = SOCKET_OPTION_SET;
+ break;
+
+ case GeneralTransportOptions::VERIFY_SIGNATURE:
+ verify_signature_ = socket_option_value;
+ result = SOCKET_OPTION_SET;
+ break;
+
+ default:
+ return result;
+ }
+ }
+ return result;
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ConsumerContentObjectCallback socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerContentObjectCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+ on_content_object_input_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerContentObjectVerificationCallback socket_option_value)
+ -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+ on_content_object_verification_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ConsumerInterestCallback socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerInterestCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+ on_interest_retransmission_ = socket_option_value;
+ break;
+
+ case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+ on_interest_output_ = socket_option_value;
+ break;
+
+ case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+ on_interest_timeout_ = socket_option_value;
+ break;
+
+ case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+ on_interest_satisfied_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key, ConsumerManifestCallback socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerManifestCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::MANIFEST_INPUT:
+ on_manifest_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ IcnObserver *socket_option_value) {
+ utils::SpinLock::Acquire locked(guard_raaqm_params_);
+ switch (socket_option_key) {
+ case RateEstimationOptions::RATE_ESTIMATION_OBSERVER:
+ rate_estimation_observer_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+ int socket_option_key,
+ const std::shared_ptr<utils::Verifier> &socket_option_value) {
+ int result = SOCKET_OPTION_NOT_SET;
+ if (!transport_protocol_->isRunning()) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::VERIFIER:
+ verifier_ = socket_option_value;
+ result = SOCKET_OPTION_SET;
+ break;
+ default:
+ return result;
+ }
+ }
+
+ return result;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ const std::string &socket_option_value) {
+ int result = SOCKET_OPTION_NOT_SET;
+ if (!transport_protocol_->isRunning()) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::CERTIFICATE:
+ key_id_ = verifier_->addKeyFromCertificate(socket_option_value);
+
+ if (key_id_ != nullptr) {
+ result = SOCKET_OPTION_SET;
+ }
+ break;
+
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ output_interface_ = socket_option_value;
+ portal_->setOutputInterface(output_interface_);
+ result = SOCKET_OPTION_SET;
+ break;
+
+ default:
+ return result;
+ }
+ }
+ return result;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+ ConsumerTimerCallback socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerTimerCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::STATS_SUMMARY:
+ stats_summary_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ double &socket_option_value) {
+ utils::SpinLock::Acquire locked(guard_raaqm_params_);
+ switch (socket_option_key) {
+ case GeneralTransportOptions::MIN_WINDOW_SIZE:
+ socket_option_value = min_window_size_;
+ break;
+
+ case GeneralTransportOptions::MAX_WINDOW_SIZE:
+ socket_option_value = max_window_size_;
+ break;
+
+ case GeneralTransportOptions::CURRENT_WINDOW_SIZE:
+ socket_option_value = current_window_size_;
+ break;
+
+ // RAAQM parameters
+
+ case RaaqmTransportOptions::GAMMA_VALUE:
+ socket_option_value = gamma_;
+ break;
+
+ case RaaqmTransportOptions::BETA_VALUE:
+ socket_option_value = beta_;
+ break;
+
+ case RaaqmTransportOptions::DROP_FACTOR:
+ socket_option_value = drop_factor_;
+ break;
+
+ case RaaqmTransportOptions::MINIMUM_DROP_PROBABILITY:
+ socket_option_value = minimum_drop_probability_;
+ break;
+
+ case RateEstimationOptions::RATE_ESTIMATION_ALPHA:
+ socket_option_value = rate_estimation_alpha_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value) {
+ utils::SpinLock::Acquire locked(guard_raaqm_params_);
+ switch (socket_option_key) {
+ case GeneralTransportOptions::MAX_INTEREST_RETX:
+ socket_option_value = max_retransmissions_;
+ break;
+
+ case GeneralTransportOptions::INTEREST_LIFETIME:
+ socket_option_value = interest_lifetime_;
+ break;
+
+ case RaaqmTransportOptions::SAMPLE_NUMBER:
+ socket_option_value = sample_number_;
+ break;
+
+ case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
+ socket_option_value = rate_estimation_batching_parameter_;
+ break;
+
+ case RateEstimationOptions::RATE_ESTIMATION_CHOICE:
+ socket_option_value = rate_estimation_choice_;
+ break;
+
+ case GeneralTransportOptions::STATS_INTERVAL:
+ socket_option_value = timer_interval_milliseconds_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ bool &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::RUNNING:
+ socket_option_value = transport_protocol_->isRunning();
+ break;
+
+ case OtherOptions::VIRTUAL_DOWNLOAD:
+ socket_option_value = virtual_download_;
+ break;
+
+ case GeneralTransportOptions::VERIFY_SIGNATURE:
+ socket_option_value = verify_signature_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ Name **socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::NETWORK_NAME:
+ *socket_option_value = &network_name_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerContentObjectCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+ *socket_option_value = &on_content_object_input_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectVerificationCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerContentObjectVerificationCallback **socket_option_value)
+ -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+ *socket_option_value = &on_content_object_verification_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ConsumerInterestCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerInterestCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+ *socket_option_value = &on_interest_retransmission_;
+ break;
+
+ case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+ *socket_option_value = &on_interest_output_;
+ break;
+
+ case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+ *socket_option_value = &on_interest_timeout_;
+ break;
+
+ case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+ *socket_option_value = &on_interest_satisfied_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ConsumerManifestCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerManifestCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::MANIFEST_INPUT:
+ *socket_option_value = &on_manifest_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, std::shared_ptr<Portal> &socket_option_value) {
+ switch (socket_option_key) {
+ case PORTAL:
+ socket_option_value = portal_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ IcnObserver **socket_option_value) {
+ utils::SpinLock::Acquire locked(guard_raaqm_params_);
+ switch (socket_option_key) {
+ case RateEstimationOptions::RATE_ESTIMATION_OBSERVER:
+ *socket_option_value = (rate_estimation_observer_);
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key,
+ std::shared_ptr<utils::Verifier> &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::VERIFIER:
+ socket_option_value = verifier_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+ std::string &socket_option_value) {
+ switch (socket_option_key) {
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ socket_option_value = output_interface_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+ int socket_option_key, ConsumerTimerCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ConsumerTimerCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ConsumerCallbacksOptions::STATS_SUMMARY:
+ *socket_option_value = &stats_summary_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
} // namespace interface
} // end namespace transport \ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/socket_consumer.h b/libtransport/src/hicn/transport/interfaces/socket_consumer.h
index 8f7a9718c..e3620b269 100644
--- a/libtransport/src/hicn/transport/interfaces/socket_consumer.h
+++ b/libtransport/src/hicn/transport/interfaces/socket_consumer.h
@@ -179,20 +179,6 @@ class ConsumerSocket : public BaseSocket {
int asyncConsume(const Name &name);
/**
- * Send an interest asynchronously in another thread, which is the same used
- * for asyncConsume.
- *
- * @param interest - An Interest::Ptr to the interest. Notice that the
- * application looses the ownership of the interest, which is transferred to
- * the library itself.
- * @param callback - A ConsumerCallback containing the events to be trigger in
- * case of timeout or content reception.
- *
- */
- void asyncSendInterest(Interest::Ptr &&interest,
- Portal::ConsumerCallback *callback);
-
- /**
* Stops the consumer socket. If several downloads are queued (using
* asyncConsume), this call stops just the current one.
*/
@@ -211,595 +197,94 @@ class ConsumerSocket : public BaseSocket {
*/
asio::io_service &getIoService() override;
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, ReadCallback *socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::READ_CALLBACK:
- read_callback_ = socket_option_value;
- break;
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, ReadCallback **socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::READ_CALLBACK:
- *socket_option_value = read_callback_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(int socket_option_key,
- double socket_option_value) {
- switch (socket_option_key) {
- case MIN_WINDOW_SIZE:
- min_window_size_ = socket_option_value;
- break;
-
- case MAX_WINDOW_SIZE:
- max_window_size_ = socket_option_value;
- break;
-
- case CURRENT_WINDOW_SIZE:
- current_window_size_ = socket_option_value;
- break;
-
- case GAMMA_VALUE:
- gamma_ = socket_option_value;
- break;
-
- case BETA_VALUE:
- beta_ = socket_option_value;
- break;
-
- case DROP_FACTOR:
- drop_factor_ = socket_option_value;
- break;
-
- case MINIMUM_DROP_PROBABILITY:
- minimum_drop_probability_ = socket_option_value;
- break;
-
- case RATE_ESTIMATION_ALPHA:
- if (socket_option_value >= 0 && socket_option_value < 1) {
- rate_estimation_alpha_ = socket_option_value;
- } else {
- rate_estimation_alpha_ = default_values::alpha;
- }
- break;
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(int socket_option_key,
- uint32_t socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::INPUT_BUFFER_SIZE:
- input_buffer_size_ = socket_option_value;
- break;
-
- case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
- output_buffer_size_ = socket_option_value;
- break;
-
- case GeneralTransportOptions::MAX_INTEREST_RETX:
- max_retransmissions_ = socket_option_value;
- break;
-
- case GeneralTransportOptions::INTEREST_LIFETIME:
- interest_lifetime_ = socket_option_value;
- break;
-
- case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_retransmission_ = VOID_HANDLER;
- break;
- }
-
- case ConsumerCallbacksOptions::INTEREST_EXPIRED:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_timeout_ = VOID_HANDLER;
- break;
- }
-
- case ConsumerCallbacksOptions::INTEREST_SATISFIED:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_satisfied_ = VOID_HANDLER;
- break;
- }
-
- case ConsumerCallbacksOptions::INTEREST_OUTPUT:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_output_ = VOID_HANDLER;
- break;
- }
-
- case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
- if (socket_option_value == VOID_HANDLER) {
- on_content_object_input_ = VOID_HANDLER;
- break;
- }
-
- case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
- if (socket_option_value == VOID_HANDLER) {
- on_content_object_verification_ = VOID_HANDLER;
- break;
- }
-
- case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
- if (socket_option_value > 0) {
- rate_estimation_batching_parameter_ = socket_option_value;
- } else {
- rate_estimation_batching_parameter_ = default_values::batch;
- }
- break;
-
- case RateEstimationOptions::RATE_ESTIMATION_CHOICE:
- if (socket_option_value > 0) {
- rate_estimation_choice_ = socket_option_value;
- } else {
- rate_estimation_choice_ = default_values::rate_choice;
- }
- break;
-
- case GeneralTransportOptions::STATS_INTERVAL:
- timer_interval_milliseconds_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(int socket_option_key,
- bool socket_option_value) {
- switch (socket_option_key) {
- case OtherOptions::VIRTUAL_DOWNLOAD:
- virtual_download_ = socket_option_value;
- break;
-
- case RaaqmTransportOptions::RTT_STATS:
- rtt_stats_ = socket_option_value;
- break;
-
- case GeneralTransportOptions::VERIFY_SIGNATURE:
- verify_signature_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(int socket_option_key,
- Name *socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::NETWORK_NAME:
- network_name_ = *socket_option_value;
- break;
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key,
- ConsumerContentObjectCallback socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
- on_content_object_input_ = socket_option_value;
- break;
+ virtual int setSocketOption(int socket_option_key,
+ ReadCallback *socket_option_value);
+
+ virtual int getSocketOption(int socket_option_key,
+ ReadCallback **socket_option_value);
- default:
- return SOCKET_OPTION_NOT_SET;
- }
+ virtual int setSocketOption(int socket_option_key,
+ double socket_option_value);
- return SOCKET_OPTION_SET;
- }
+ virtual int setSocketOption(int socket_option_key,
+ uint32_t socket_option_value);
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
+ virtual int setSocketOption(int socket_option_key,
+ std::nullptr_t socket_option_value);
+
+ virtual int setSocketOption(int socket_option_key, bool socket_option_value);
+
+ virtual int setSocketOption(
+ int socket_option_key, ConsumerContentObjectCallback socket_option_value);
+
+ virtual int setSocketOption(
int socket_option_key,
- ConsumerContentObjectVerificationCallback socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
- on_content_object_verification_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, ConsumerInterestCallback socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
- on_interest_retransmission_ = socket_option_value;
- break;
-
- case ConsumerCallbacksOptions::INTEREST_OUTPUT:
- on_interest_output_ = socket_option_value;
- break;
-
- case ConsumerCallbacksOptions::INTEREST_EXPIRED:
- on_interest_timeout_ = socket_option_value;
- break;
-
- case ConsumerCallbacksOptions::INTEREST_SATISFIED:
- on_interest_satisfied_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, ConsumerManifestCallback socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::MANIFEST_INPUT:
- on_manifest_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, IcnObserver *socket_option_value) {
- switch (socket_option_key) {
- case RateEstimationOptions::RATE_ESTIMATION_OBSERVER:
- rate_estimation_observer_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
+ ConsumerContentObjectVerificationCallback socket_option_value);
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerInterestCallback socket_option_value);
+
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerManifestCallback socket_option_value);
+
+ virtual int setSocketOption(int socket_option_key,
+ IcnObserver *socket_option_value);
+
+ virtual int setSocketOption(
int socket_option_key,
- const std::shared_ptr<utils::Verifier> &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::VERIFIER:
- verifier_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, const std::string &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::CERTIFICATE:
- key_id_ = verifier_->addKeyFromCertificate(socket_option_value);
-
- if (key_id_ != nullptr) {
- break;
- }
-
- case DataLinkOptions::OUTPUT_INTERFACE:
- output_interface_ = socket_option_value;
- portal_->setOutputInterface(output_interface_);
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, ConsumerTimerCallback socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::STATS_SUMMARY:
- stats_summary_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(int socket_option_key,
- double &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::MIN_WINDOW_SIZE:
- socket_option_value = min_window_size_;
- break;
-
- case GeneralTransportOptions::MAX_WINDOW_SIZE:
- socket_option_value = max_window_size_;
- break;
-
- case GeneralTransportOptions::CURRENT_WINDOW_SIZE:
- socket_option_value = current_window_size_;
- break;
-
- // RAAQM parameters
-
- case RaaqmTransportOptions::GAMMA_VALUE:
- socket_option_value = gamma_;
- break;
-
- case RaaqmTransportOptions::BETA_VALUE:
- socket_option_value = beta_;
- break;
-
- case RaaqmTransportOptions::DROP_FACTOR:
- socket_option_value = drop_factor_;
- break;
-
- case RaaqmTransportOptions::MINIMUM_DROP_PROBABILITY:
- socket_option_value = minimum_drop_probability_;
- break;
-
- case RateEstimationOptions::RATE_ESTIMATION_ALPHA:
- socket_option_value = rate_estimation_alpha_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(int socket_option_key,
- uint32_t &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::INPUT_BUFFER_SIZE:
- socket_option_value = (uint32_t)input_buffer_size_;
- break;
-
- case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
- socket_option_value = (uint32_t)output_buffer_size_;
- break;
-
- case GeneralTransportOptions::MAX_INTEREST_RETX:
- socket_option_value = max_retransmissions_;
- break;
-
- case GeneralTransportOptions::INTEREST_LIFETIME:
- socket_option_value = interest_lifetime_;
- break;
-
- case RaaqmTransportOptions::SAMPLE_NUMBER:
- socket_option_value = sample_number_;
- break;
-
- case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
- socket_option_value = rate_estimation_batching_parameter_;
- break;
-
- case RateEstimationOptions::RATE_ESTIMATION_CHOICE:
- socket_option_value = rate_estimation_choice_;
- break;
-
- case GeneralTransportOptions::STATS_INTERVAL:
- socket_option_value = timer_interval_milliseconds_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(int socket_option_key,
- bool &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::ASYNC_MODE:
- socket_option_value = is_async_;
- break;
+ const std::shared_ptr<utils::Verifier> &socket_option_value);
- case GeneralTransportOptions::RUNNING:
- socket_option_value = transport_protocol_->isRunning();
- break;
+ virtual int setSocketOption(int socket_option_key,
+ const std::string &socket_option_value);
- case OtherOptions::VIRTUAL_DOWNLOAD:
- socket_option_value = virtual_download_;
- break;
-
- case RaaqmTransportOptions::RTT_STATS:
- socket_option_value = rtt_stats_;
- break;
+ virtual int setSocketOption(int socket_option_key,
+ ConsumerTimerCallback socket_option_value);
- case GeneralTransportOptions::VERIFY_SIGNATURE:
- socket_option_value = verify_signature_;
- break;
+ virtual int getSocketOption(int socket_option_key,
+ double &socket_option_value);
- default:
- return SOCKET_OPTION_NOT_GET;
- }
+ virtual int getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value);
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(int socket_option_key,
- Name **socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::NETWORK_NAME:
- *socket_option_value = &network_name_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key,
- ConsumerContentObjectCallback **socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
- *socket_option_value = &on_content_object_input_;
- break;
+ virtual int getSocketOption(int socket_option_key, bool &socket_option_value);
- default:
- return SOCKET_OPTION_NOT_GET;
- }
+ virtual int getSocketOption(int socket_option_key,
+ Name **socket_option_value);
- return SOCKET_OPTION_GET;
- }
+ virtual int getSocketOption(
+ int socket_option_key,
+ ConsumerContentObjectCallback **socket_option_value);
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
+ virtual int getSocketOption(
int socket_option_key,
- ConsumerContentObjectVerificationCallback **socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
- *socket_option_value = &on_content_object_verification_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, ConsumerInterestCallback **socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
- *socket_option_value = &on_interest_retransmission_;
- break;
-
- case ConsumerCallbacksOptions::INTEREST_OUTPUT:
- *socket_option_value = &on_interest_output_;
- break;
-
- case ConsumerCallbacksOptions::INTEREST_EXPIRED:
- *socket_option_value = &on_interest_timeout_;
- break;
-
- case ConsumerCallbacksOptions::INTEREST_SATISFIED:
- *socket_option_value = &on_interest_satisfied_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, ConsumerManifestCallback **socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::MANIFEST_INPUT:
- *socket_option_value = &on_manifest_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, std::shared_ptr<Portal> &socket_option_value) {
- switch (socket_option_key) {
- case PORTAL:
- socket_option_value = portal_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, IcnObserver **socket_option_value) {
- switch (socket_option_key) {
- case RateEstimationOptions::RATE_ESTIMATION_OBSERVER:
- *socket_option_value = (rate_estimation_observer_);
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
+ ConsumerContentObjectVerificationCallback **socket_option_value);
+
+ virtual int getSocketOption(int socket_option_key,
+ ConsumerInterestCallback **socket_option_value);
+
+ virtual int getSocketOption(int socket_option_key,
+ ConsumerManifestCallback **socket_option_value);
+
+ virtual int getSocketOption(int socket_option_key,
+ std::shared_ptr<Portal> &socket_option_value);
+
+ virtual int getSocketOption(int socket_option_key,
+ IcnObserver **socket_option_value);
+
+ virtual int getSocketOption(
int socket_option_key,
- std::shared_ptr<utils::Verifier> &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::VERIFIER:
- socket_option_value = verifier_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, std::string &socket_option_value) {
- switch (socket_option_key) {
- case DataLinkOptions::OUTPUT_INTERFACE:
- socket_option_value = output_interface_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, ConsumerTimerCallback **socket_option_value) {
- switch (socket_option_key) {
- case ConsumerCallbacksOptions::STATS_SUMMARY:
- *socket_option_value = &stats_summary_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
+ std::shared_ptr<utils::Verifier> &socket_option_value);
+
+ virtual int getSocketOption(int socket_option_key,
+ std::string &socket_option_value);
+
+ virtual int getSocketOption(int socket_option_key,
+ ConsumerTimerCallback **socket_option_value);
+
+ protected:
+ template <typename Lambda, typename arg2>
+ int rescheduleOnIOService(int socket_option_key, arg2 socket_option_value,
+ Lambda lambda_func);
private:
asio::io_service internal_io_service_;
@@ -808,6 +293,9 @@ class ConsumerSocket : public BaseSocket {
std::shared_ptr<Portal> portal_;
utils::EventThread async_downloader_;
+ // No need to protect from multiple accesses in the async consumer
+ // The parameter is accessible only with a getSocketOption and
+ // set from the consume
Name network_name_;
int interest_lifetime_;
@@ -816,8 +304,6 @@ class ConsumerSocket : public BaseSocket {
double max_window_size_;
double current_window_size_;
uint32_t max_retransmissions_;
- size_t output_buffer_size_;
- size_t input_buffer_size_;
// RAAQM Parameters
double minimum_drop_probability_;
@@ -832,12 +318,10 @@ class ConsumerSocket : public BaseSocket {
int rate_estimation_batching_parameter_;
int rate_estimation_choice_;
- bool is_async_;
-
// Verification parameters
std::shared_ptr<utils::Verifier> verifier_;
PARCKeyId *key_id_;
- bool verify_signature_;
+ std::atomic_bool verify_signature_;
ConsumerInterestCallback on_interest_retransmission_;
ConsumerInterestCallback on_interest_output_;
@@ -853,12 +337,13 @@ class ConsumerSocket : public BaseSocket {
// Virtual download for traffic generator
bool virtual_download_;
- bool rtt_stats_;
uint32_t timer_interval_milliseconds_;
// Transport protocol
std::unique_ptr<TransportProtocol> transport_protocol_;
+
+ utils::SpinLock guard_raaqm_params_;
};
} // namespace interface
diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h
index 13029e83a..bcf103b8c 100644
--- a/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h
+++ b/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h
@@ -31,8 +31,6 @@ static constexpr uint32_t content_object_expiry_time =
never_expire_time; // milliseconds -> 50 seconds
static constexpr uint32_t content_object_packet_size =
1500; // The ethernet MTU
-static constexpr uint32_t producer_socket_input_buffer_size =
- 150000; // Interests
static constexpr uint32_t producer_socket_output_buffer_size =
150000; // Content Object
static constexpr uint32_t log_2_default_buffer_size = 12;
diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_keys.h b/libtransport/src/hicn/transport/interfaces/socket_options_keys.h
index c21108186..e14f0f412 100644
--- a/libtransport/src/hicn/transport/interfaces/socket_options_keys.h
+++ b/libtransport/src/hicn/transport/interfaces/socket_options_keys.h
@@ -35,22 +35,21 @@ typedef enum {
INTEREST_LIFETIME = 107,
CONTENT_OBJECT_EXPIRY_TIME = 108,
KEY_LOCATOR = 110,
- SIGNATURE_TYPE = 111,
- MIN_WINDOW_SIZE = 112,
- MAX_WINDOW_SIZE = 113,
- CURRENT_WINDOW_SIZE = 114,
- ASYNC_MODE = 115,
- MAKE_MANIFEST = 116,
- PORTAL = 117,
- RUNNING = 118,
- APPLICATION_BUFFER = 119,
- HASH_ALGORITHM = 120,
- CRYPTO_SUITE = 121,
- IDENTITY = 122,
- VERIFIER = 123,
- CERTIFICATE = 124,
- VERIFY_SIGNATURE = 125,
- STATS_INTERVAL = 126
+ MIN_WINDOW_SIZE = 111,
+ MAX_WINDOW_SIZE = 112,
+ CURRENT_WINDOW_SIZE = 113,
+ ASYNC_MODE = 114,
+ MAKE_MANIFEST = 115,
+ PORTAL = 116,
+ RUNNING = 117,
+ APPLICATION_BUFFER = 118,
+ HASH_ALGORITHM = 119,
+ CRYPTO_SUITE = 120,
+ IDENTITY = 121,
+ VERIFIER = 122,
+ CERTIFICATE = 123,
+ VERIFY_SIGNATURE = 124,
+ STATS_INTERVAL = 125
} GeneralTransportOptions;
typedef enum {
diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.cc b/libtransport/src/hicn/transport/interfaces/socket_producer.cc
index 9ca004c41..f90197490 100644
--- a/libtransport/src/hicn/transport/interfaces/socket_producer.cc
+++ b/libtransport/src/hicn/transport/interfaces/socket_producer.cc
@@ -37,10 +37,7 @@ ProducerSocket::ProducerSocket(asio::io_service &io_service)
output_buffer_(default_values::producer_socket_output_buffer_size),
registration_status_(REGISTRATION_NOT_ATTEMPTED),
making_manifest_(false),
- signature_type_(SHA_256),
hash_algorithm_(HashAlgorithm::SHA_256),
- input_buffer_capacity_(default_values::producer_socket_input_buffer_size),
- input_buffer_size_(0),
on_interest_input_(VOID_HANDLER),
on_interest_dropped_input_buffer_(VOID_HANDLER),
on_interest_inserted_input_buffer_(VOID_HANDLER),
@@ -98,22 +95,30 @@ void ProducerSocket::listen() {
void ProducerSocket::passContentObjectToCallbacks(
const std::shared_ptr<ContentObject> &content_object) {
if (content_object) {
- if (on_new_segment_ != VOID_HANDLER) {
- on_new_segment_(*this, *content_object);
+ if (on_new_segment_) {
+ io_service_.dispatch([this, content_object]() {
+ on_new_segment_(*this, *content_object);
+ });
}
- if (on_content_object_to_sign_ != VOID_HANDLER) {
- on_content_object_to_sign_(*this, *content_object);
+ if (on_content_object_to_sign_) {
+ io_service_.dispatch([this, content_object]() {
+ on_content_object_to_sign_(*this, *content_object);
+ });
}
- if (on_content_object_in_output_buffer_ != VOID_HANDLER) {
- on_content_object_in_output_buffer_(*this, *content_object);
+ if (on_content_object_in_output_buffer_) {
+ io_service_.dispatch([this, content_object]() {
+ on_content_object_in_output_buffer_(*this, *content_object);
+ });
}
output_buffer_.insert(content_object);
- if (on_content_object_output_ != VOID_HANDLER) {
- on_content_object_output_(*this, *content_object);
+ if (on_content_object_output_) {
+ io_service_.dispatch([this, content_object]() {
+ on_content_object_output_(*this, *content_object);
+ });
}
portal_->sendContentObject(*content_object);
@@ -121,15 +126,19 @@ void ProducerSocket::passContentObjectToCallbacks(
}
void ProducerSocket::produce(ContentObject &content_object) {
- if (on_content_object_in_output_buffer_ != VOID_HANDLER) {
- on_content_object_in_output_buffer_(*this, content_object);
+ if (on_content_object_in_output_buffer_) {
+ io_service_.dispatch([this, &content_object]() {
+ on_content_object_in_output_buffer_(*this, content_object);
+ });
}
output_buffer_.insert(std::static_pointer_cast<ContentObject>(
content_object.shared_from_this()));
- if (on_content_object_output_ != VOID_HANDLER) {
- on_content_object_output_(*this, content_object);
+ if (on_content_object_output_) {
+ io_service_.dispatch([this, &content_object]() {
+ on_content_object_output_(*this, content_object);
+ });
}
portal_->sendContentObject(content_object);
@@ -142,6 +151,15 @@ uint32_t ProducerSocket::produce(Name content_name,
return 0;
}
+ // Copy the atomic variable to ensure always the same value during the a
+ // production
+ std::size_t data_packet_size = data_packet_size_;
+ uint32_t content_object_expiry_time = content_object_expiry_time_;
+ HashAlgorithm algo = hash_algorithm_;
+ bool making_manifest = making_manifest_;
+ std::shared_ptr<utils::Identity> identity;
+ getSocketOption(GeneralTransportOptions::IDENTITY, identity);
+
auto buffer_size = buffer->length();
const std::size_t hash_size = 32;
@@ -162,7 +180,7 @@ uint32_t ProducerSocket::produce(Name content_name,
std::unique_ptr<utils::CryptoHash> zero_hash;
// TODO Manifest may still be used for indexing
- if (making_manifest_ && !identity_) {
+ if (making_manifest && !identity) {
throw errors::RuntimeException(
"Making manifests without setting producer identity. Aborting.");
}
@@ -182,18 +200,18 @@ uint32_t ProducerSocket::produce(Name content_name,
}
format = hf_format;
- if (making_manifest_) {
+ if (making_manifest) {
format = hf_format;
manifest_header_size = core::Packet::getHeaderSizeFromFormat(
- hf_format_ah, identity_->getSignatureLength());
- } else if (identity_) {
+ hf_format_ah, identity->getSignatureLength());
+ } else if (identity) {
format = hf_format_ah;
- signature_length = identity_->getSignatureLength();
+ signature_length = identity->getSignatureLength();
}
header_size = core::Packet::getHeaderSizeFromFormat(format, signature_length);
- free_space_for_content = data_packet_size_ - header_size;
+ free_space_for_content = data_packet_size - header_size;
uint32_t number_of_segments =
uint32_t(std::ceil(double(buffer_size) / double(free_space_for_content)));
@@ -204,9 +222,9 @@ uint32_t ProducerSocket::produce(Name content_name,
// TODO allocate space for all the headers
- if (making_manifest_) {
+ if (making_manifest) {
auto segment_in_manifest = static_cast<float>(
- std::floor(double(data_packet_size_ - manifest_header_size -
+ std::floor(double(data_packet_size - manifest_header_size -
ContentObjectManifest::getManifestHeaderSize()) /
(4.0 + 32.0)) -
1.0);
@@ -219,8 +237,8 @@ uint32_t ProducerSocket::produce(Name content_name,
core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST,
hash_algorithm_, is_last_manifest, content_name,
core::NextSegmentCalculationStrategy::INCREMENTAL,
- identity_->getSignatureLength()));
- manifest->setLifetime(content_object_expiry_time_);
+ identity->getSignatureLength()));
+ manifest->setLifetime(content_object_expiry_time);
if (is_last) {
manifest->setFinalBlockNumber(final_block_number);
@@ -231,21 +249,21 @@ uint32_t ProducerSocket::produce(Name content_name,
uint8_t hash[hash_size];
std::memset(hash, 0, hash_size);
zero_hash = std::make_unique<utils::CryptoHash>(
- hash, hash_size, static_cast<utils::CryptoHashType>(hash_algorithm_));
+ hash, hash_size, static_cast<utils::CryptoHashType>(algo));
}
for (unsigned int packaged_segments = 0;
packaged_segments < number_of_segments; packaged_segments++) {
- if (making_manifest_) {
+ if (making_manifest) {
if (manifest->estimateManifestSize(2) >
- data_packet_size_ - manifest_header_size) {
+ data_packet_size - manifest_header_size) {
// Add next manifest
manifest->addSuffixHash(current_segment, *zero_hash);
// Send the current manifest
manifest->encode();
- identity_->getSigner().sign(*manifest);
+ identity->getSigner().sign(*manifest);
passContentObjectToCallbacks(manifest);
@@ -258,8 +276,8 @@ uint32_t ProducerSocket::produce(Name content_name,
core::ManifestType::INLINE_MANIFEST, hash_algorithm_,
is_last_manifest, content_name,
core::NextSegmentCalculationStrategy::INCREMENTAL,
- identity_->getSignatureLength()));
- manifest->setLifetime(content_object_expiry_time_);
+ identity->getSignatureLength()));
+ manifest->setLifetime(content_object_expiry_time);
if (is_last) {
manifest->setFinalBlockNumber(final_block_number);
} else {
@@ -271,7 +289,7 @@ uint32_t ProducerSocket::produce(Name content_name,
auto content_object = std::make_shared<ContentObject>(
content_name.setSuffix(current_segment), format);
- content_object->setLifetime(content_object_expiry_time_);
+ content_object->setLifetime(content_object_expiry_time);
auto b = buffer->cloneOne();
b->trimStart(free_space_for_content * packaged_segments);
@@ -280,7 +298,7 @@ uint32_t ProducerSocket::produce(Name content_name,
b->append(buffer_size - bytes_segmented);
bytes_segmented += (int)(buffer_size - bytes_segmented);
- if (is_last && making_manifest_) {
+ if (is_last && making_manifest) {
is_last_manifest = true;
} else if (is_last) {
content_object->setRst();
@@ -293,19 +311,19 @@ uint32_t ProducerSocket::produce(Name content_name,
content_object->appendPayload(std::move(b));
- if (making_manifest_) {
+ if (making_manifest) {
using namespace std::chrono_literals;
utils::CryptoHash hash = content_object->computeDigest(hash_algorithm_);
manifest->addSuffixHash(current_segment, hash);
- } else if (identity_) {
- identity_->getSigner().sign(*content_object);
+ } else if (identity) {
+ identity->getSigner().sign(*content_object);
}
current_segment++;
passContentObjectToCallbacks(content_object);
}
- if (making_manifest_) {
+ if (making_manifest) {
if (is_last_manifest) {
manifest->setFinalManifest(is_last_manifest);
}
@@ -315,13 +333,15 @@ uint32_t ProducerSocket::produce(Name content_name,
}
manifest->encode();
- identity_->getSigner().sign(*manifest);
+ identity->getSigner().sign(*manifest);
passContentObjectToCallbacks(manifest);
}
- if (on_content_produced_ != VOID_HANDLER) {
- on_content_produced_(*this, std::make_error_code(std::errc(0)),
- buffer_size);
+ if (on_content_produced_) {
+ io_service_.dispatch([this, buffer_size]() {
+ on_content_produced_(*this, std::make_error_code(std::errc(0)),
+ buffer_size);
+ });
}
return current_segment - start_offset;
@@ -347,7 +367,7 @@ void ProducerSocket::asyncProduce(const Name &suffix, const uint8_t *buf,
}
void ProducerSocket::onInterest(Interest &interest) {
- if (on_interest_input_ != VOID_HANDLER) {
+ if (on_interest_input_) {
on_interest_input_(*this, interest);
}
@@ -355,22 +375,571 @@ void ProducerSocket::onInterest(Interest &interest) {
output_buffer_.find(interest);
if (content_object) {
- if (on_interest_satisfied_output_buffer_ != VOID_HANDLER) {
+ if (on_interest_satisfied_output_buffer_) {
on_interest_satisfied_output_buffer_(*this, interest);
}
- if (on_content_object_output_ != VOID_HANDLER) {
+ if (on_content_object_output_) {
on_content_object_output_(*this, *content_object);
}
portal_->sendContentObject(*content_object);
} else {
- if (on_interest_process_ != VOID_HANDLER) {
+ if (on_interest_process_) {
on_interest_process_(*this, interest);
}
}
}
+// If the thread calling lambda_func is not the same of io_service, this
+// function reschedule the function on it
+template <typename Lambda, typename arg2>
+int ProducerSocket::rescheduleOnIOService(int socket_option_key,
+ arg2 socket_option_value,
+ Lambda lambda_func) {
+ // To enforce type check
+ std::function<int(int, arg2)> func = lambda_func;
+ int result = SOCKET_OPTION_SET;
+ if (listening_thread_.joinable() &&
+ std::this_thread::get_id() != listening_thread_.get_id()) {
+ std::mutex mtx;
+ /* Condition variable for the wait */
+ std::condition_variable cv;
+ bool done = false;
+ io_service_.dispatch([&socket_option_key, &socket_option_value, &mtx,
+ &result, &done, &func]() {
+ std::unique_lock<std::mutex> lck(mtx);
+ done = true;
+ result = func(socket_option_key, socket_option_value);
+ });
+ std::unique_lock<std::mutex> lck(mtx);
+ if (!done) {
+ cv.wait(lck);
+ }
+ } else {
+ result = func(socket_option_key, socket_option_value);
+ }
+
+ return result;
+}
+
+// If the thread calling lambda_func is not the same of io_service, this
+// function reschedule the function on it
+template <typename Lambda, typename arg2>
+int ProducerSocket::rescheduleOnIOServiceWithReference(
+ int socket_option_key, arg2 &socket_option_value, Lambda lambda_func) {
+ // To enforce type check
+ std::function<int(int, arg2 &)> func = lambda_func;
+ int result = SOCKET_OPTION_SET;
+ if (listening_thread_.joinable() &&
+ std::this_thread::get_id() != this->listening_thread_.get_id()) {
+ std::mutex mtx;
+ /* Condition variable for the wait */
+ std::condition_variable cv;
+ std::unique_lock<std::mutex> lck(mtx);
+ bool done = false;
+ io_service_.dispatch([this, &socket_option_key, &socket_option_value, &mtx,
+ &cv, &result, &done, &func]() {
+ std::unique_lock<std::mutex> lck(mtx);
+ done = true;
+ result = func(socket_option_key, socket_option_value);
+
+ if (!done) {
+ cv.wait(lck);
+ }
+ });
+ } else {
+ result = func(socket_option_key, socket_option_value);
+ }
+
+ return result;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ uint32_t socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::DATA_PACKET_SIZE:
+ if (socket_option_value < default_values::max_content_object_size &&
+ socket_option_value > 0) {
+ data_packet_size_ = socket_option_value;
+ break;
+ }
+
+ case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+ output_buffer_.setLimit(socket_option_value);
+ break;
+
+ case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
+ content_object_expiry_time_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ std::nullptr_t socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ProducerContentObjectCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::INTEREST_INPUT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_input_ = VOID_HANDLER;
+ break;
+ }
+
+ case ProducerCallbacksOptions::INTEREST_DROP:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_dropped_input_buffer_ = VOID_HANDLER;
+ break;
+ }
+
+ case ProducerCallbacksOptions::INTEREST_PASS:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_inserted_input_buffer_ = VOID_HANDLER;
+ break;
+ }
+
+ case ProducerCallbacksOptions::CACHE_HIT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_satisfied_output_buffer_ = VOID_HANDLER;
+ break;
+ }
+
+ case ProducerCallbacksOptions::CACHE_MISS:
+ if (socket_option_value == VOID_HANDLER) {
+ on_interest_process_ = VOID_HANDLER;
+ break;
+ }
+
+ case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_new_segment_ = VOID_HANDLER;
+ break;
+ }
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_to_sign_ = VOID_HANDLER;
+ break;
+ }
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_in_output_buffer_ = VOID_HANDLER;
+ break;
+ }
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+ if (socket_option_value == VOID_HANDLER) {
+ on_content_object_output_ = VOID_HANDLER;
+ break;
+ }
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ bool socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::MAKE_MANIFEST:
+ making_manifest_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ Name *socket_option_value) {
+ return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ std::list<Prefix> socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::NETWORK_NAME:
+ served_namespaces_ = socket_option_value;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ProducerContentObjectCallback socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ProducerContentObjectCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+ on_new_segment_ = socket_option_value;
+ break;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+ on_content_object_to_sign_ = socket_option_value;
+ break;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+ on_content_object_in_output_buffer_ = socket_option_value;
+ break;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+ on_content_object_output_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ProducerInterestCallback socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ProducerInterestCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::INTEREST_INPUT:
+ on_interest_input_ = socket_option_value;
+ break;
+
+ case ProducerCallbacksOptions::INTEREST_DROP:
+ on_interest_dropped_input_buffer_ = socket_option_value;
+ break;
+
+ case ProducerCallbacksOptions::INTEREST_PASS:
+ on_interest_inserted_input_buffer_ = socket_option_value;
+ break;
+
+ case ProducerCallbacksOptions::CACHE_HIT:
+ on_interest_satisfied_output_buffer_ = socket_option_value;
+ break;
+
+ case ProducerCallbacksOptions::CACHE_MISS:
+ on_interest_process_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key, ProducerContentCallback socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ProducerContentCallback socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::CONTENT_PRODUCED:
+ on_content_produced_ = socket_option_value;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+ });
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ HashAlgorithm socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::HASH_ALGORITHM:
+ hash_algorithm_ = socket_option_value;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ utils::CryptoSuite socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::CRYPTO_SUITE:
+ crypto_suite_ = socket_option_value;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::setSocketOption(
+ int socket_option_key,
+ const std::shared_ptr<utils::Identity> &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::IDENTITY: {
+ utils::SpinLock::Acquire locked(identity_lock_);
+ identity_.reset();
+ identity_ = socket_option_value;
+ } break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+ const std::string &socket_option_value) {
+ switch (socket_option_key) {
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ output_interface_ = socket_option_value;
+ portal_->setOutputInterface(output_interface_);
+ break;
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+ socket_option_value = (uint32_t)output_buffer_.getLimit();
+ break;
+
+ case GeneralTransportOptions::DATA_PACKET_SIZE:
+ socket_option_value = (uint32_t)data_packet_size_;
+ break;
+
+ case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
+ socket_option_value = content_object_expiry_time_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_SET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ bool &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::MAKE_MANIFEST:
+ socket_option_value = making_manifest_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ std::list<Prefix> &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::NETWORK_NAME:
+ socket_option_value = served_namespaces_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key,
+ ProducerContentObjectCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ProducerContentObjectCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+ *socket_option_value = &on_new_segment_;
+ break;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+ *socket_option_value = &on_content_object_to_sign_;
+ break;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+ *socket_option_value = &on_content_object_in_output_buffer_;
+ break;
+
+ case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+ *socket_option_value = &on_content_object_output_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ProducerContentCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ProducerContentCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::CONTENT_PRODUCED:
+ *socket_option_value = &on_content_produced_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, ProducerInterestCallback **socket_option_value) {
+ // Reschedule the function on the io_service to avoid race condition in case
+ // setSocketOption is called while the io_service is running.
+ return rescheduleOnIOService(
+ socket_option_key, socket_option_value,
+ [this](int socket_option_key,
+ ProducerInterestCallback **socket_option_value) -> int {
+ switch (socket_option_key) {
+ case ProducerCallbacksOptions::INTEREST_INPUT:
+ *socket_option_value = &on_interest_input_;
+ break;
+
+ case ProducerCallbacksOptions::INTEREST_DROP:
+ *socket_option_value = &on_interest_dropped_input_buffer_;
+ break;
+
+ case ProducerCallbacksOptions::INTEREST_PASS:
+ *socket_option_value = &on_interest_inserted_input_buffer_;
+ break;
+
+ case CACHE_HIT:
+ *socket_option_value = &on_interest_satisfied_output_buffer_;
+ break;
+
+ case CACHE_MISS:
+ *socket_option_value = &on_interest_process_;
+ break;
+
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+ });
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key, std::shared_ptr<Portal> &socket_option_value) {
+ switch (socket_option_key) {
+ case PORTAL:
+ socket_option_value = portal_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ ;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ HashAlgorithm &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::HASH_ALGORITHM:
+ socket_option_value = hash_algorithm_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ utils::CryptoSuite &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::HASH_ALGORITHM:
+ socket_option_value = crypto_suite_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ProducerSocket::getSocketOption(
+ int socket_option_key,
+ std::shared_ptr<utils::Identity> &socket_option_value) {
+ switch (socket_option_key) {
+ case GeneralTransportOptions::IDENTITY: {
+ utils::SpinLock::Acquire locked(identity_lock_);
+ socket_option_value = identity_;
+ } break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+ std::string &socket_option_value) {
+ switch (socket_option_key) {
+ case DataLinkOptions::OUTPUT_INTERFACE:
+ socket_option_value = output_interface_;
+ break;
+ default:
+ return SOCKET_OPTION_NOT_GET;
+ }
+
+ return SOCKET_OPTION_GET;
+}
+
asio::io_service &ProducerSocket::getIoService() { return io_service_; }
} // namespace interface
diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.h b/libtransport/src/hicn/transport/interfaces/socket_producer.h
index 18adbf4a7..5c617d761 100644
--- a/libtransport/src/hicn/transport/interfaces/socket_producer.h
+++ b/libtransport/src/hicn/transport/interfaces/socket_producer.h
@@ -91,500 +91,116 @@ class ProducerSocket : public Socket<BasePortal>,
onInterest(*interest);
};
- TRANSPORT_ALWAYS_INLINE int setSocketOption(int socket_option_key,
- uint32_t socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::DATA_PACKET_SIZE:
- if (socket_option_value < default_values::max_content_object_size &&
- socket_option_value > 0) {
- data_packet_size_ = socket_option_value;
- break;
- }
-
- case GeneralTransportOptions::INPUT_BUFFER_SIZE:
- if (socket_option_value >= 1) {
- input_buffer_capacity_ = socket_option_value;
- break;
- }
-
- case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
- output_buffer_.setLimit(socket_option_value);
- break;
-
- case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
- content_object_expiry_time_ = socket_option_value;
- break;
-
- case GeneralTransportOptions::SIGNATURE_TYPE:
- if (socket_option_value == SOCKET_OPTION_DEFAULT) {
- signature_type_ = SHA_256;
- } else {
- signature_type_ = socket_option_value;
- }
-
- if (signature_type_ == SHA_256 || signature_type_ == RSA_256) {
- signature_size_ = 32;
- }
-
- break;
-
- case ProducerCallbacksOptions::INTEREST_INPUT:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_input_ = VOID_HANDLER;
- break;
- }
-
- case ProducerCallbacksOptions::INTEREST_DROP:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_dropped_input_buffer_ = VOID_HANDLER;
- break;
- }
-
- case ProducerCallbacksOptions::INTEREST_PASS:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_inserted_input_buffer_ = VOID_HANDLER;
- break;
- }
-
- case ProducerCallbacksOptions::CACHE_HIT:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_satisfied_output_buffer_ = VOID_HANDLER;
- break;
- }
-
- case ProducerCallbacksOptions::CACHE_MISS:
- if (socket_option_value == VOID_HANDLER) {
- on_interest_process_ = VOID_HANDLER;
- break;
- }
-
- case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
- if (socket_option_value == VOID_HANDLER) {
- on_new_segment_ = VOID_HANDLER;
- break;
- }
-
- case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
- if (socket_option_value == VOID_HANDLER) {
- on_content_object_to_sign_ = VOID_HANDLER;
- break;
- }
-
- case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
- if (socket_option_value == VOID_HANDLER) {
- on_content_object_in_output_buffer_ = VOID_HANDLER;
- break;
- }
-
- case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
- if (socket_option_value == VOID_HANDLER) {
- on_content_object_output_ = VOID_HANDLER;
- break;
- }
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(int socket_option_key,
- bool socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::MAKE_MANIFEST:
- making_manifest_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(int socket_option_key,
- Name *socket_option_value) {
- return SOCKET_OPTION_NOT_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, std::list<Prefix> socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::NETWORK_NAME:
- served_namespaces_ = socket_option_value;
- break;
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
+ virtual int setSocketOption(int socket_option_key,
+ uint32_t socket_option_value);
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key,
- ProducerContentObjectCallback socket_option_value) {
- switch (socket_option_key) {
- case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
- on_new_segment_ = socket_option_value;
- break;
-
- case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
- on_content_object_to_sign_ = socket_option_value;
- break;
-
- case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
- on_content_object_in_output_buffer_ = socket_option_value;
- break;
+ virtual int setSocketOption(int socket_option_key,
+ std::nullptr_t socket_option_value);
- case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
- on_content_object_output_ = socket_option_value;
- break;
+ virtual int setSocketOption(int socket_option_key, bool socket_option_value);
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
+ virtual int setSocketOption(int socket_option_key, Name *socket_option_value);
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, ProducerInterestCallback socket_option_value) {
- switch (socket_option_key) {
- case ProducerCallbacksOptions::INTEREST_INPUT:
- on_interest_input_ = socket_option_value;
- break;
+ virtual int setSocketOption(int socket_option_key,
+ std::list<Prefix> socket_option_value);
- case ProducerCallbacksOptions::INTEREST_DROP:
- on_interest_dropped_input_buffer_ = socket_option_value;
- break;
+ virtual int setSocketOption(
+ int socket_option_key, ProducerContentObjectCallback socket_option_value);
- case ProducerCallbacksOptions::INTEREST_PASS:
- on_interest_inserted_input_buffer_ = socket_option_value;
- break;
+ virtual int setSocketOption(int socket_option_key,
+ ProducerInterestCallback socket_option_value);
- case ProducerCallbacksOptions::CACHE_HIT:
- on_interest_satisfied_output_buffer_ = socket_option_value;
- break;
-
- case ProducerCallbacksOptions::CACHE_MISS:
- on_interest_process_ = socket_option_value;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
+ virtual int setSocketOption(int socket_option_key,
+ ProducerContentCallback socket_option_value);
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, ProducerContentCallback socket_option_value) {
- switch (socket_option_key) {
- case ProducerCallbacksOptions::CONTENT_PRODUCED:
- on_content_produced_ = socket_option_value;
- break;
+ virtual int setSocketOption(int socket_option_key,
+ HashAlgorithm socket_option_value);
- default:
- return SOCKET_OPTION_NOT_SET;
- }
+ virtual int setSocketOption(int socket_option_key,
+ utils::CryptoSuite socket_option_value);
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, HashAlgorithm socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::HASH_ALGORITHM:
- hash_algorithm_ = socket_option_value;
- break;
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, utils::CryptoSuite socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::CRYPTO_SUITE:
- crypto_suite_ = socket_option_value;
- break;
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
+ virtual int setSocketOption(
int socket_option_key,
- const std::shared_ptr<utils::Identity> &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::IDENTITY:
- identity_ = socket_option_value;
- break;
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- }
-
- TRANSPORT_ALWAYS_INLINE int setSocketOption(
- int socket_option_key, const std::string &socket_option_value) {
- switch (socket_option_key) {
- case DataLinkOptions::OUTPUT_INTERFACE:
- output_interface_ = socket_option_value;
- portal_->setOutputInterface(output_interface_);
- break;
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_SET;
- ;
- }
+ const std::shared_ptr<utils::Identity> &socket_option_value);
- TRANSPORT_ALWAYS_INLINE int getSocketOption(int socket_option_key,
- uint32_t &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::INPUT_BUFFER_SIZE:
- socket_option_value = (uint32_t)input_buffer_capacity_;
- break;
+ virtual int setSocketOption(int socket_option_key,
+ const std::string &socket_option_value);
- case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
- socket_option_value = (uint32_t)output_buffer_.getLimit();
- break;
+ virtual int getSocketOption(int socket_option_key,
+ uint32_t &socket_option_value);
- case GeneralTransportOptions::DATA_PACKET_SIZE:
- socket_option_value = (uint32_t)data_packet_size_;
- break;
+ virtual int getSocketOption(int socket_option_key, bool &socket_option_value);
- case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
- socket_option_value = content_object_expiry_time_;
- break;
-
- case GeneralTransportOptions::SIGNATURE_TYPE:
- socket_option_value = signature_type_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_SET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(int socket_option_key,
- bool &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::MAKE_MANIFEST:
- socket_option_value = making_manifest_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
+ virtual int getSocketOption(int socket_option_key,
+ std::list<Prefix> &socket_option_value);
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, std::list<Prefix> &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::NETWORK_NAME:
- socket_option_value = served_namespaces_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
+ virtual int getSocketOption(
int socket_option_key,
- ProducerContentObjectCallback **socket_option_value) {
- switch (socket_option_key) {
- case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
- *socket_option_value = &on_new_segment_;
- break;
-
- case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
- *socket_option_value = &on_content_object_to_sign_;
- break;
-
- case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
- *socket_option_value = &on_content_object_in_output_buffer_;
- break;
-
- case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
- *socket_option_value = &on_content_object_output_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, ProducerContentCallback **socket_option_value) {
- switch (socket_option_key) {
- case ProducerCallbacksOptions::CONTENT_PRODUCED:
- *socket_option_value = &on_content_produced_;
- break;
-
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
-
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, ProducerInterestCallback **socket_option_value) {
- switch (socket_option_key) {
- case ProducerCallbacksOptions::INTEREST_INPUT:
- *socket_option_value = &on_interest_input_;
- break;
-
- case ProducerCallbacksOptions::INTEREST_DROP:
- *socket_option_value = &on_interest_dropped_input_buffer_;
- break;
-
- case ProducerCallbacksOptions::INTEREST_PASS:
- *socket_option_value = &on_interest_inserted_input_buffer_;
- break;
+ ProducerContentObjectCallback **socket_option_value);
- case CACHE_HIT:
- *socket_option_value = &on_interest_satisfied_output_buffer_;
- break;
+ virtual int getSocketOption(int socket_option_key,
+ ProducerContentCallback **socket_option_value);
- case CACHE_MISS:
- *socket_option_value = &on_interest_process_;
- break;
+ virtual int getSocketOption(int socket_option_key,
+ ProducerInterestCallback **socket_option_value);
- default:
- return SOCKET_OPTION_NOT_GET;
- }
+ virtual int getSocketOption(int socket_option_key,
+ std::shared_ptr<Portal> &socket_option_value);
- return SOCKET_OPTION_GET;
- }
+ virtual int getSocketOption(int socket_option_key,
+ HashAlgorithm &socket_option_value);
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, std::shared_ptr<Portal> &socket_option_value) {
- switch (socket_option_key) {
- case PORTAL:
- socket_option_value = portal_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- ;
- }
-
- return SOCKET_OPTION_GET;
- }
+ virtual int getSocketOption(int socket_option_key,
+ utils::CryptoSuite &socket_option_value);
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, HashAlgorithm &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::HASH_ALGORITHM:
- socket_option_value = hash_algorithm_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
+ virtual int getSocketOption(
+ int socket_option_key,
+ std::shared_ptr<utils::Identity> &socket_option_value);
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, utils::CryptoSuite &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::HASH_ALGORITHM:
- socket_option_value = crypto_suite_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
+ virtual int getSocketOption(int socket_option_key,
+ std::string &socket_option_value);
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key,
- std::shared_ptr<utils::Identity> &socket_option_value) {
- switch (socket_option_key) {
- case GeneralTransportOptions::IDENTITY:
- if (identity_) {
- socket_option_value = identity_;
- break;
- }
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
+ template <typename Lambda, typename arg2>
+ int rescheduleOnIOService(int socket_option_key, arg2 socket_option_value,
+ Lambda lambda_func);
- TRANSPORT_ALWAYS_INLINE int getSocketOption(
- int socket_option_key, std::string &socket_option_value) {
- switch (socket_option_key) {
- case DataLinkOptions::OUTPUT_INTERFACE:
- socket_option_value = output_interface_;
- break;
- default:
- return SOCKET_OPTION_NOT_GET;
- }
-
- return SOCKET_OPTION_GET;
- }
+ template <typename Lambda, typename arg2>
+ int rescheduleOnIOServiceWithReference(int socket_option_key,
+ arg2 &socket_option_value,
+ Lambda lambda_func);
- private:
+ protected:
// Threads
std::thread listening_thread_;
- protected:
asio::io_service internal_io_service_;
asio::io_service &io_service_;
std::shared_ptr<Portal> portal_;
- std::size_t data_packet_size_;
- std::list<Prefix> served_namespaces_;
- uint32_t content_object_expiry_time_;
+ std::atomic<size_t> data_packet_size_;
+ std::list<Prefix>
+ served_namespaces_; // No need to be threadsafe, this is always modified
+ // by the application thread
+ std::atomic<uint32_t> content_object_expiry_time_;
// buffers
+ // ContentStore is thread-safe
utils::ContentStore output_buffer_;
- private:
utils::EventThread async_thread_;
int registration_status_;
- bool making_manifest_;
+ std::atomic<bool> making_manifest_;
// map for storing sequence numbers for several calls of the publish
// function
std::unordered_map<Name, std::unordered_map<int, uint32_t>> seq_number_map_;
- int signature_type_;
- int signature_size_;
-
- HashAlgorithm hash_algorithm_;
- utils::CryptoSuite crypto_suite_;
+ std::atomic<HashAlgorithm> hash_algorithm_;
+ std::atomic<utils::CryptoSuite> crypto_suite_;
+ utils::SpinLock identity_lock_;
std::shared_ptr<utils::Identity> identity_;
- // buffers
-
- std::queue<std::shared_ptr<const Interest>> input_buffer_;
- std::atomic_size_t input_buffer_capacity_;
- std::atomic_size_t input_buffer_size_;
-
// callbacks
- protected:
ProducerInterestCallback on_interest_input_;
ProducerInterestCallback on_interest_dropped_input_buffer_;
ProducerInterestCallback on_interest_inserted_input_buffer_;
diff --git a/libtransport/src/hicn/transport/protocols/protocol.cc b/libtransport/src/hicn/transport/protocols/protocol.cc
index 9caa2eca7..8da9529d6 100644
--- a/libtransport/src/hicn/transport/protocols/protocol.cc
+++ b/libtransport/src/hicn/transport/protocols/protocol.cc
@@ -23,23 +23,28 @@ namespace protocol {
using namespace interface;
TransportProtocol::TransportProtocol(interface::ConsumerSocket *icn_socket)
- : socket_(icn_socket), is_running_(false) {
+ : socket_(icn_socket), is_running_(false), is_first_(false) {
socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal_);
}
int TransportProtocol::start() {
- // If the protocol is already running, return
+ // If the protocol is already running, return otherwise set as running
if (is_running_) return -1;
- // Set the protocol as running
- is_running_ = true;
-
// Reset the protocol state machine
reset();
+ // Set it is the first time we schedule an interest
+ is_first_ = true;
+
// Schedule next interests
scheduleNextInterests();
+ is_first_ = false;
+
+ // Set the protocol as running
+ is_running_ = true;
+
// Start Event loop
portal_->runEventsLoop();
diff --git a/libtransport/src/hicn/transport/protocols/protocol.h b/libtransport/src/hicn/transport/protocols/protocol.h
index 88889bb8c..e4821b6a0 100644
--- a/libtransport/src/hicn/transport/protocols/protocol.h
+++ b/libtransport/src/hicn/transport/protocols/protocol.h
@@ -15,6 +15,8 @@
#pragma once
+#include <atomic>
+
#include <hicn/transport/interfaces/socket.h>
#include <hicn/transport/protocols/packet_manager.h>
#include <hicn/transport/protocols/statistics.h>
@@ -60,7 +62,9 @@ class TransportProtocol : public interface::BasePortal::ConsumerCallback,
protected:
interface::ConsumerSocket *socket_;
std::shared_ptr<interface::BasePortal> portal_;
- volatile bool is_running_;
+ std::atomic<bool> is_running_;
+ // True if it si the first time we schedule an interest
+ std::atomic<bool> is_first_;
TransportStatistics stats_;
};
diff --git a/libtransport/src/hicn/transport/protocols/raaqm.cc b/libtransport/src/hicn/transport/protocols/raaqm.cc
index 574693c51..c816158f9 100644
--- a/libtransport/src/hicn/transport/protocols/raaqm.cc
+++ b/libtransport/src/hicn/transport/protocols/raaqm.cc
@@ -318,17 +318,17 @@ void RaaqmTransportProtocol::onContentObject(
}
// Call application-defined callbacks
- ConsumerContentObjectCallback *callback_content_object = nullptr;
+ ConsumerContentObjectCallback *callback_content_object = VOID_HANDLER;
socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT,
&callback_content_object);
- if (*callback_content_object != VOID_HANDLER) {
+ if (*callback_content_object) {
(*callback_content_object)(*socket_, *content_object);
}
- ConsumerInterestCallback *callback_interest = nullptr;
+ ConsumerInterestCallback *callback_interest = VOID_HANDLER;
socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_SATISFIED,
&callback_interest);
- if (*callback_content_object != VOID_HANDLER) {
+ if (*callback_content_object) {
(*callback_interest)(*socket_, *interest);
}
@@ -369,10 +369,10 @@ void RaaqmTransportProtocol::onContentSegment(
reassemble(std::move(content_object));
} else if (TRANSPORT_EXPECT_FALSE(incremental_suffix ==
index_manager_->getFinalSuffix())) {
- interface::ConsumerSocket::ReadCallback *on_payload = nullptr;
+ interface::ConsumerSocket::ReadCallback *on_payload = VOID_HANDLER;
socket_->getSocketOption(READ_CALLBACK, &on_payload);
- if (on_payload != nullptr) {
+ if (on_payload) {
on_payload->readSuccess(stats_.getBytesRecv());
}
}
@@ -404,10 +404,10 @@ void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) {
return;
}
- ConsumerInterestCallback *callback = nullptr;
+ ConsumerInterestCallback *callback = VOID_HANDLER;
socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_EXPIRED,
&callback);
- if (*callback != VOID_HANDLER) {
+ if (*callback) {
(*callback)(*socket_, *interest);
}
@@ -420,17 +420,17 @@ void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) {
max_rtx)) {
stats_.updateRetxCount(1);
- callback = nullptr;
+ callback = VOID_HANDLER;
socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_RETRANSMISSION,
&callback);
- if (*callback != VOID_HANDLER) {
+ if (*callback) {
(*callback)(*socket_, *interest);
}
- callback = nullptr;
+ callback = VOID_HANDLER;
socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
&callback);
- if ((*callback) != VOID_HANDLER) {
+ if (*callback) {
(*callback)(*socket_, *interest);
}
@@ -450,7 +450,7 @@ void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) {
}
void RaaqmTransportProtocol::scheduleNextInterests() {
- if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) {
return;
}
@@ -490,14 +490,14 @@ void RaaqmTransportProtocol::sendInterest(std::uint64_t next_suffix) {
interest_lifetime);
interest->setLifetime(interest_lifetime);
- ConsumerInterestCallback *callback = nullptr;
+ ConsumerInterestCallback *callback = VOID_HANDLER;
socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
&callback);
- if (*callback != VOID_HANDLER) {
+ if (*callback) {
callback->operator()(*socket_, *interest);
}
- if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) {
return;
}
@@ -516,10 +516,10 @@ void RaaqmTransportProtocol::sendInterest(Interest::Ptr &&interest) {
}
void RaaqmTransportProtocol::onContentReassembled(std::error_code ec) {
- interface::ConsumerSocket::ReadCallback *on_payload = nullptr;
+ interface::ConsumerSocket::ReadCallback *on_payload = VOID_HANDLER;
socket_->getSocketOption(READ_CALLBACK, &on_payload);
- if (on_payload == nullptr) {
+ if (on_payload) {
throw errors::RuntimeException(
"The read callback must be installed in the transport before "
"starting "
@@ -581,10 +581,10 @@ void RaaqmTransportProtocol::updateStats(uint32_t suffix, uint64_t rtt,
stats_.updateAverageWindowSize(current_window_size_);
// Call statistics callback
- ConsumerTimerCallback *stats_callback = nullptr;
+ ConsumerTimerCallback *stats_callback = VOID_HANDLER;
socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY,
&stats_callback);
- if (*stats_callback != VOID_HANDLER) {
+ if (*stats_callback) {
auto dt = std::chrono::duration_cast<utils::Milliseconds>(now - t0_);
uint32_t timer_interval_milliseconds = 0;
diff --git a/libtransport/src/hicn/transport/protocols/rtc.cc b/libtransport/src/hicn/transport/protocols/rtc.cc
index b3a00c58d..e6134f767 100644
--- a/libtransport/src/hicn/transport/protocols/rtc.cc
+++ b/libtransport/src/hicn/transport/protocols/rtc.cc
@@ -31,10 +31,8 @@ RTCTransportProtocol::RTCTransportProtocol(
inflightInterests_(1 << default_values::log_2_default_buffer_size),
modMask_((1 << default_values::log_2_default_buffer_size) - 1) {
icnet_socket->getSocketOption(PORTAL, portal_);
- nack_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
rtx_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
probe_timer_ = std::make_unique<asio::steady_timer>(portal_->getIoService());
- nack_timer_used_ = false;
reset();
}
@@ -89,12 +87,14 @@ void RTCTransportProtocol::reset() {
interestRetransmissions_.clear();
lastSegNacked_ = 0;
lastReceived_ = 0;
+ lastReceivedTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
highestReceived_ = 0;
firstSequenceInRound_ = 0;
- nack_timer_used_ = false;
rtx_timer_used_ = false;
- for(int i = 0; i < (1 << default_values::log_2_default_buffer_size); i++){
+ for (int i = 0; i < (1 << default_values::log_2_default_buffer_size); i++) {
inflightInterests_[i] = {0};
}
@@ -191,14 +191,13 @@ void RTCTransportProtocol::updateDelayStats(
pathTable_[pathLabel]->insertOwdSample(OWD);
pathTable_[pathLabel]->computeInterArrivalGap(segmentNumber);
- }else{
+ } else {
pathTable_[pathLabel]->receivedNack();
}
}
void RTCTransportProtocol::updateStats(uint32_t round_duration) {
- if(pathTable_.empty())
- return;
+ if (pathTable_.empty()) return;
if (receivedBytes_ != 0) {
double bytesPerSec =
@@ -213,68 +212,70 @@ void RTCTransportProtocol::updateStats(uint32_t round_duration) {
for (auto it = pathTable_.begin(); it != pathTable_.end(); it++) {
it->second->roundEnd();
- if(it->second->isActive()){
- if(it->second->getMinRtt() < minRtt){
+ if (it->second->isActive()) {
+ if (it->second->getMinRtt() < minRtt) {
minRtt = it->second->getMinRtt();
producerPathLabels_[0] = it->first;
}
- if(it->second->getMinRtt() > maxRtt){
+ if (it->second->getMinRtt() > maxRtt) {
maxRtt = it->second->getMinRtt();
producerPathLabels_[1] = it->first;
}
}
}
- if(pathTable_.find(producerPathLabels_[0]) == pathTable_.end() ||
+ if (pathTable_.find(producerPathLabels_[0]) == pathTable_.end() ||
pathTable_.find(producerPathLabels_[1]) == pathTable_.end())
- return; //this should not happen
+ return; // this should not happen
- //as a queuing delay we keep the lowest one among the two paths
- //if one path is congested the forwarder should decide to do not
- //use it soon so it does not make sens to inform the application
- //that maybe we have a problem
- if(pathTable_[producerPathLabels_[0]]->getQueuingDealy() <
+ // as a queuing delay we keep the lowest one among the two paths
+ // if one path is congested the forwarder should decide to do not
+ // use it so it does not make sense to inform the application
+ // that maybe we have a problem
+ if (pathTable_[producerPathLabels_[0]]->getQueuingDealy() <
pathTable_[producerPathLabels_[1]]->getQueuingDealy())
- queuingDelay_ = pathTable_[producerPathLabels_[0]]->getQueuingDealy();
+ queuingDelay_ = pathTable_[producerPathLabels_[0]]->getQueuingDealy();
else
- queuingDelay_ = pathTable_[producerPathLabels_[1]]->getQueuingDealy();
+ queuingDelay_ = pathTable_[producerPathLabels_[1]]->getQueuingDealy();
if (sentInterest_ != 0 && currentState_ == HICN_RTC_NORMAL_STATE) {
- uint32_t numberTheoricallyReceivedPackets_ = highestReceived_ - firstSequenceInRound_;
+ uint32_t numberTheoricallyReceivedPackets_ =
+ highestReceived_ - firstSequenceInRound_;
double lossRate = 0;
- if(numberTheoricallyReceivedPackets_ != 0)
- lossRate = (double)((double)(packetLost_ - lossRecovered_) / (double)numberTheoricallyReceivedPackets_);
+ if (numberTheoricallyReceivedPackets_ != 0)
+ lossRate = (double)((double)(packetLost_ - lossRecovered_) /
+ (double)numberTheoricallyReceivedPackets_);
- if(lossRate < 0)
- lossRate = 0;
+ if (lossRate < 0) lossRate = 0;
- if(initied){
+ if (initied) {
lossRate_ = lossRate_ * HICN_ESTIMATED_LOSSES_ALPHA +
- (lossRate * (1 - HICN_ESTIMATED_LOSSES_ALPHA));
- }else {
- lossRate_ =lossRate;
+ (lossRate * (1 - HICN_ESTIMATED_LOSSES_ALPHA));
+ } else {
+ lossRate_ = lossRate;
initied = true;
}
}
if (avgPacketSize_ == 0) avgPacketSize_ = HICN_INIT_PACKET_SIZE;
- //for the BDP we use the max rtt, so that we calibrate the window on the
- //RTT of the slowest path. In this way we are sure that the window will
- //never be too small
+ // for the BDP we use the max rtt, so that we calibrate the window on the
+ // RTT of the slowest path. In this way we are sure that the window will
+ // never be too small
uint32_t BDP = (uint32_t)ceil(
- (estimatedBw_ * (double)((double) pathTable_[producerPathLabels_[1]]->getMinRtt() /
- (double)HICN_MILLI_IN_A_SEC) *
- HICN_BANDWIDTH_SLACK_FACTOR) /
- avgPacketSize_);
+ (estimatedBw_ *
+ (double)((double)pathTable_[producerPathLabels_[1]]->getMinRtt() /
+ (double)HICN_MILLI_IN_A_SEC) *
+ HICN_BANDWIDTH_SLACK_FACTOR) /
+ avgPacketSize_);
uint32_t BW = (uint32_t)ceil(estimatedBw_);
computeMaxWindow(BW, BDP);
ConsumerTimerCallback *stats_callback = nullptr;
socket_->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY,
&stats_callback);
- if (*stats_callback != VOID_HANDLER) {
- //Send the stats to the app
+ if (*stats_callback) {
+ // Send the stats to the app
stats_.updateQueuingDelay(queuingDelay_);
stats_.updateLossRatio(lossRate_);
(*stats_callback)(*socket_, stats_);
@@ -334,8 +335,8 @@ void RTCTransportProtocol::computeMaxWindow(uint32_t productionRate,
// currentState = RTC_NORMAL_STATE
if (BDPWin != 0) {
- maxCWin_ =
- (uint32_t)ceil((double)BDPWin + ((double)BDPWin / 10.0)); // BDP + 10%
+ maxCWin_ = (uint32_t)ceil((double)BDPWin +
+ (((double)BDPWin * 30.0) / 100.0)); // BDP + 30%
} else {
maxCWin_ = min(maxWaintingInterest, maxCWin_);
}
@@ -380,22 +381,22 @@ void RTCTransportProtocol::increaseWindow() {
}
}
-void RTCTransportProtocol::probeRtt(){
+void RTCTransportProtocol::probeRtt() {
time_sent_probe_ = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
Name *interest_name = nullptr;
socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
- &interest_name);
- //get a random numbe in the probe seq range
+ &interest_name);
+ // get a random numbe in the probe seq range
std::default_random_engine eng((std::random_device())());
- std::uniform_int_distribution<uint32_t> idis(
- HICN_MIN_PROBE_SEQ, HICN_MAX_PROBE_SEQ);
+ std::uniform_int_distribution<uint32_t> idis(HICN_MIN_PROBE_SEQ,
+ HICN_MAX_PROBE_SEQ);
probe_seq_number_ = idis(eng);
interest_name->setSuffix(probe_seq_number_);
- //we considere the probe as a rtx so that we do not incresea inFlightInt
+ // we considere the probe as a rtx so that we do not incresea inFlightInt
received_probe_ = false;
sendInterest(interest_name, true);
@@ -406,7 +407,6 @@ void RTCTransportProtocol::probeRtt(){
});
}
-
void RTCTransportProtocol::sendInterest(Name *interest_name, bool rtx) {
auto interest = getPacket();
interest->setName(*interest_name);
@@ -421,11 +421,11 @@ void RTCTransportProtocol::sendInterest(Name *interest_name, bool rtx) {
socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
&on_interest_output);
- if (*on_interest_output != VOID_HANDLER) {
+ if (*on_interest_output) {
(*on_interest_output)(*socket_, *interest);
}
- if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+ if (TRANSPORT_EXPECT_FALSE(!is_running_ && !is_first_)) {
return;
}
@@ -440,20 +440,20 @@ void RTCTransportProtocol::sendInterest(Name *interest_name, bool rtx) {
void RTCTransportProtocol::scheduleNextInterests() {
checkRound();
- if (!is_running_) return;
+ if (!is_running_ && !is_first_) return;
while (inflightInterestsCount_ < currentCWin_) {
Name *interest_name = nullptr;
socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
&interest_name);
- interest_name->setSuffix(actualSegment_);
+ interest_name->setSuffix(actualSegment_);
// if the producer socket is not stated (does not reply even with nacks)
// we keep asking for something without marking anything as lost (see
// timeout). In this way when the producer socket will start the
- //consumer socket will not miss any packet
- if(TRANSPORT_EXPECT_FALSE(!firstPckReceived_)){
+ // consumer socket will not miss any packet
+ if (TRANSPORT_EXPECT_FALSE(!firstPckReceived_)) {
uint32_t pkt = actualSegment_ & modMask_;
inflightInterests_[pkt].state = sent_;
inflightInterests_[pkt].sequence = actualSegment_;
@@ -477,9 +477,9 @@ void RTCTransportProtocol::scheduleNextInterests() {
continue;
}
- //same if the packet is lost
+ // same if the packet is lost
if (inflightInterests_[pkt].state == lost_ &&
- inflightInterests_[pkt].sequence == actualSegment_){
+ inflightInterests_[pkt].sequence == actualSegment_) {
actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ;
continue;
}
@@ -489,7 +489,7 @@ void RTCTransportProtocol::scheduleNextInterests() {
std::chrono::steady_clock::now().time_since_epoch())
.count();
- //here the packet can be in any state except for lost or recevied
+ // here the packet can be in any state except for lost or recevied
inflightInterests_[pkt].state = sent_;
inflightInterests_[pkt].sequence = actualSegment_;
actualSegment_ = (actualSegment_ + 1) % HICN_MIN_PROBE_SEQ;
@@ -506,30 +506,40 @@ void RTCTransportProtocol::addRetransmissions(uint32_t val) {
void RTCTransportProtocol::addRetransmissions(uint32_t start, uint32_t stop) {
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+ bool new_rtx = false;
for (uint32_t i = start; i < stop; i++) {
auto it = interestRetransmissions_.find(i);
if (it == interestRetransmissions_.end()) {
- if (lastSegNacked_ <= i) {
+ uint32_t pkt = i & modMask_;
+ if (lastSegNacked_ <= i && inflightInterests_[pkt].state != received_) {
// it must be larger than the last past nack received
packetLost_++;
interestRetransmissions_[i] = 0;
uint32_t pkt = i & modMask_;
- //we reset the transmission time setting to now, so that rtx will
- //happne in one RTT on waint one inter arrival gap
+ // we reset the transmission time setting to now, so that rtx will
+ // happne in one RTT on waint one inter arrival gap
inflightInterests_[pkt].transmissionTime = now;
+ new_rtx = true;
}
} // if the retransmission is already there the rtx timer will
// take care of it
}
- if(!rtx_timer_used_)
+ // in case a new rtx is added to the map we need to run checkRtx()
+ if (new_rtx) {
+ if (rtx_timer_used_) {
+ // if a timer is pending we need to delete it
+ rtx_timer_->cancel();
+ rtx_timer_used_ = false;
+ }
checkRtx();
+ }
}
-void RTCTransportProtocol::retransmit() {
+uint64_t RTCTransportProtocol::retransmit() {
auto it = interestRetransmissions_.begin();
// cut len to max HICN_MAX_RTX_SIZE
@@ -540,6 +550,10 @@ void RTCTransportProtocol::retransmit() {
}
it = interestRetransmissions_.begin();
+ uint64_t smallest_timeout = ULONG_MAX;
+ uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
while (it != interestRetransmissions_.end()) {
uint32_t pkt = it->first & modMask_;
@@ -563,65 +577,75 @@ void RTCTransportProtocol::retransmit() {
continue;
}
-
- uint64_t sent_time = inflightInterests_[pkt].transmissionTime;
- uint64_t rtx_time = sent_time;
-
- if(it->second == 0){
- if(pathTable_.find(producerPathLabels_[0]) != pathTable_.end() &&
- pathTable_.find(producerPathLabels_[1]) != pathTable_.end()){
- //first rtx: wait RTTmax - RTTmin + gap
- rtx_time = sent_time + pathTable_[producerPathLabels_[1]]->getMinRtt() -
- pathTable_[producerPathLabels_[0]]->getMinRtt() +
- pathTable_[producerPathLabels_[1]]->getInterArrivalGap();
+ uint64_t rtx_time = now;
+
+ if (it->second == 0) {
+ // first rtx
+ if (producerPathLabels_[0] != producerPathLabels_[1]) {
+ // multipath
+ if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() &&
+ pathTable_.find(producerPathLabels_[1]) != pathTable_.end() &&
+ (pathTable_[producerPathLabels_[0]]->getInterArrivalGap() <
+ HICN_MIN_INTER_ARRIVAL_GAP)) {
+ rtx_time = lastReceivedTime_ +
+ (pathTable_[producerPathLabels_[1]]->getMinRtt() -
+ pathTable_[producerPathLabels_[0]]->getMinRtt()) +
+ pathTable_[producerPathLabels_[0]]->getInterArrivalGap();
+ } // else low rate producer, send it immediatly
+ } else {
+ // single path
+ if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end() &&
+ (pathTable_[producerPathLabels_[0]]->getInterArrivalGap() <
+ HICN_MIN_INTER_ARRIVAL_GAP)) {
+ rtx_time = lastReceivedTime_ +
+ pathTable_[producerPathLabels_[0]]->getInterArrivalGap();
+ } // else low rate producer send immediatly
}
- }else{
- if(pathTable_.find(producerPathLabels_[0]) != pathTable_.end()){
- //second+ rtx: waint min rtt
+ } else {
+ // second or plus rtx, wait for the min rtt
+ if (pathTable_.find(producerPathLabels_[0]) != pathTable_.end()) {
+ uint64_t sent_time = inflightInterests_[pkt].transmissionTime;
rtx_time = sent_time + pathTable_[producerPathLabels_[0]]->getMinRtt();
- }
+ } // if we don't have info we send it immediatly
}
- uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count();
-
- if(now >= rtx_time){
+ if (now >= rtx_time) {
inflightInterests_[pkt].transmissionTime = now;
it->second++;
Name *interest_name = nullptr;
socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
- &interest_name);
+ &interest_name);
interest_name->setSuffix(it->first);
sendInterest(interest_name, true);
+ } else if (rtx_time < smallest_timeout) {
+ smallest_timeout = rtx_time;
}
++it;
}
+ return smallest_timeout;
}
void RTCTransportProtocol::checkRtx() {
- if(interestRetransmissions_.empty()){
+ if (interestRetransmissions_.empty()) {
rtx_timer_used_ = false;
return;
}
- //we use the packet intearriva time on the fastest path
- //even if this stats should be the same on both
- auto pathStats = pathTable_.find(producerPathLabels_[0]);
+ uint64_t next_timeout = retransmit();
uint64_t wait = 1;
- if(pathStats != pathTable_.end()){
- wait = floor(pathStats->second->getInterArrivalGap() / 2.0);
- if(wait < 1)
- wait = 1;
+ uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+ if (next_timeout != ULONG_MAX && now < next_timeout) {
+ wait = next_timeout - now;
}
-
rtx_timer_used_ = true;
- retransmit();
rtx_timer_->expires_from_now(std::chrono::milliseconds(wait));
rtx_timer_->async_wait([this](std::error_code ec) {
if (ec) return;
+ rtx_timer_used_ = false;
checkRtx();
});
}
@@ -631,14 +655,14 @@ void RTCTransportProtocol::onTimeout(Interest::Ptr &&interest) {
uint32_t segmentNumber = interest->getName().getSuffix();
- if(segmentNumber >= HICN_MIN_PROBE_SEQ){
+ if (segmentNumber >= HICN_MIN_PROBE_SEQ) {
// this is a timeout on a probe, do nothing
return;
}
uint32_t pkt = segmentNumber & modMask_;
- if(TRANSPORT_EXPECT_FALSE(!firstPckReceived_)){
+ if (TRANSPORT_EXPECT_FALSE(!firstPckReceived_)) {
inflightInterestsCount_--;
// we do nothing, and we keep asking the same stuff over
// and over until we get at least a packet
@@ -673,37 +697,8 @@ void RTCTransportProtocol::onTimeout(Interest::Ptr &&interest) {
scheduleNextInterests();
}
-bool RTCTransportProtocol::checkIfProducerIsActive(
- const ContentObject &content_object) {
- uint32_t *payload = (uint32_t *)content_object.getPayload()->data();
- uint32_t productionSeg = *payload;
- uint32_t productionRate = *(++payload);
-
- if (productionRate == 0) {
- // the producer socket is not active
- // in this case we consider only the first nack
- if (nack_timer_used_) {
- return false;
- }
-
- nack_timer_used_ = true;
- // actualSegment_ should be the one in the nack, which will be the next in
- // production
- actualSegment_ = productionSeg;
- // all the rest (win size should not change)
- // we wait a bit before pull the socket again
- nack_timer_->expires_from_now(std::chrono::milliseconds(500));
- nack_timer_->async_wait([this](std::error_code ec) {
- if (ec) return;
- nack_timer_used_ = false;
- scheduleNextInterests();
- });
- return false;
- }
- return true;
-}
-
-bool RTCTransportProtocol::onNack(const ContentObject &content_object, bool rtx) {
+bool RTCTransportProtocol::onNack(const ContentObject &content_object,
+ bool rtx) {
uint32_t *payload = (uint32_t *)content_object.getPayload()->data();
uint32_t productionSeg = *payload;
uint32_t productionRate = *(++payload);
@@ -711,7 +706,13 @@ bool RTCTransportProtocol::onNack(const ContentObject &content_object, bool rtx)
bool old_nack = false;
- if(!rtx){
+ // if we did not received anything between lastReceived_ + 1 and productionSeg
+ // most likelly some packets got lost
+ if (lastReceived_ != 0) {
+ addRetransmissions(lastReceived_ + 1, productionSeg);
+ }
+
+ if (!rtx) {
gotNack_ = true;
// we synch the estimated production rate with the actual one
estimatedBw_ = (double)productionRate;
@@ -719,9 +720,9 @@ bool RTCTransportProtocol::onNack(const ContentObject &content_object, bool rtx)
if (productionSeg > nackSegment) {
// we are asking for stuff produced in the past
- actualSegment_ = max(productionSeg + 1, actualSegment_) % HICN_MIN_PROBE_SEQ;
+ actualSegment_ = max(productionSeg, actualSegment_) % HICN_MIN_PROBE_SEQ;
- if(!rtx) {
+ if (!rtx) {
if (currentState_ == HICN_RTC_NORMAL_STATE) {
currentState_ = HICN_RTC_SYNC_STATE;
}
@@ -730,23 +731,13 @@ bool RTCTransportProtocol::onNack(const ContentObject &content_object, bool rtx)
increaseWindow();
}
- //we need to remove the rtx for packets with seq number
- //< productionSeg
- for(auto it = interestRetransmissions_.begin(); it !=
- interestRetransmissions_.end();){
- if(it->first < productionSeg)
- it = interestRetransmissions_.erase(it);
- else
- ++it;
- }
-
lastSegNacked_ = productionSeg;
old_nack = true;
} else if (productionSeg < nackSegment) {
- actualSegment_ = (productionSeg + 1) % HICN_MIN_PROBE_SEQ;
+ actualSegment_ = productionSeg % HICN_MIN_PROBE_SEQ;
- if(!rtx){
+ if (!rtx) {
// we are asking stuff in the future
gotFutureNack_++;
computeMaxWindow(productionRate, 0);
@@ -756,14 +747,17 @@ bool RTCTransportProtocol::onNack(const ContentObject &content_object, bool rtx)
currentState_ = HICN_RTC_NORMAL_STATE;
}
}
- } // equal should not happen
+ } else {
+ // we are asking the right thing, but the producer is slow
+ // keep doing the same until the packet is produced
+ actualSegment_ = productionSeg % HICN_MIN_PROBE_SEQ;
+ }
return old_nack;
}
void RTCTransportProtocol::onContentObject(
Interest::Ptr &&interest, ContentObject::Ptr &&content_object) {
-
// as soon as we get a packet firstPckReceived_ will never be false
firstPckReceived_ = true;
@@ -771,29 +765,29 @@ void RTCTransportProtocol::onContentObject(
uint32_t payload_size = (uint32_t)payload->length();
uint32_t segmentNumber = content_object->getName().getSuffix();
uint32_t pkt = segmentNumber & modMask_;
- bool schedule_next_interest = true;
ConsumerContentObjectCallback *callback_content_object = nullptr;
socket_->getSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT,
&callback_content_object);
- if (*callback_content_object != VOID_HANDLER) {
+ if (*callback_content_object) {
(*callback_content_object)(*socket_, *content_object);
}
- if(segmentNumber >= HICN_MIN_PROBE_SEQ){
- if(segmentNumber == probe_seq_number_ && !received_probe_){
+ if (segmentNumber >= HICN_MIN_PROBE_SEQ) {
+ if (segmentNumber == probe_seq_number_ && !received_probe_) {
received_probe_ = true;
uint32_t pathLabel = content_object->getPathLabel();
- if (pathTable_.find(pathLabel) == pathTable_.end()){
- //if this path does not exists we cannot create a new one so drop
+ if (pathTable_.find(pathLabel) == pathTable_.end()) {
+ // if this path does not exists we cannot create a new one so drop
return;
}
- //this is the expected probe, update the RTT and drop the packet
+ // this is the expected probe, update the RTT and drop the packet
uint64_t RTT = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now().time_since_epoch())
- .count() - time_sent_probe_;
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count() -
+ time_sent_probe_;
pathTable_[pathLabel]->insertRttSample(RTT);
pathTable_[pathLabel]->receivedNack();
@@ -802,40 +796,40 @@ void RTCTransportProtocol::onContentObject(
}
if (payload_size == HICN_NACK_HEADER_SIZE) {
- schedule_next_interest = checkIfProducerIsActive(*content_object);
-
if (inflightInterests_[pkt].state == sent_) {
inflightInterestsCount_--;
}
- // if checkIfProducerIsActive returns false, we did all we need to do
- // inside that function, no need to call onNack
bool old_nack = false;
- if (schedule_next_interest){
- if (interestRetransmissions_.find(segmentNumber) ==
- interestRetransmissions_.end()){
- //this is not a retransmitted packet
- old_nack = onNack(*content_object, false);
- updateDelayStats(*content_object);
- } else {
- old_nack = onNack(*content_object, true);
- }
+ if (interestRetransmissions_.find(segmentNumber) ==
+ interestRetransmissions_.end()) {
+ // this is not a retransmitted packet
+ old_nack = onNack(*content_object, false);
+ updateDelayStats(*content_object);
+ } else {
+ old_nack = onNack(*content_object, true);
}
- //the nacked_ state is used only to avoid to decrease inflightInterestsCount_
- //multiple times. In fact, every time that we receive an event related to an
- //interest (timeout, nacked, content) we cange the state. In this way we are
- //sure that we do not decrease twice the counter
- if(old_nack)
+ // the nacked_ state is used only to avoid to decrease
+ // inflightInterestsCount_ multiple times. In fact, every time that we
+ // receive an event related to an interest (timeout, nacked, content) we
+ // cange the state. In this way we are sure that we do not decrease twice the
+ // counter
+ if (old_nack) {
inflightInterests_[pkt].state = lost_;
- else
+ interestRetransmissions_.erase(segmentNumber);
+ } else {
inflightInterests_[pkt].state = nacked_;
+ }
} else {
avgPacketSize_ = (HICN_ESTIMATED_PACKET_SIZE * avgPacketSize_) +
((1 - HICN_ESTIMATED_PACKET_SIZE) * payload->length());
+ receivedBytes_ += (uint32_t)(content_object->headerSize() +
+ content_object->payloadSize());
+
if (inflightInterests_[pkt].state == sent_) {
inflightInterestsCount_--; // packet sent without timeouts
}
@@ -843,36 +837,34 @@ void RTCTransportProtocol::onContentObject(
if (inflightInterests_[pkt].state == sent_ &&
interestRetransmissions_.find(segmentNumber) ==
interestRetransmissions_.end()) {
- // we count only non retransmitted data in order to take into accunt only
- // the transmition rate of the producer
- receivedBytes_ += (uint32_t)(content_object->headerSize() +
- content_object->payloadSize());
+ // delay stats are computed only for non retransmitted data
updateDelayStats(*content_object);
+ }
- addRetransmissions(lastReceived_ + 1, segmentNumber);
- if(segmentNumber > highestReceived_)
- highestReceived_ = segmentNumber;
- // lastReceived_ is updated only for data packets received without RTX
+ addRetransmissions(lastReceived_ + 1, segmentNumber);
+ if (segmentNumber > highestReceived_) {
+ highestReceived_ = segmentNumber;
+ }
+ if (segmentNumber > lastReceived_) {
lastReceived_ = segmentNumber;
+ lastReceivedTime_ =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
}
-
receivedData_++;
inflightInterests_[pkt].state = received_;
+ auto it = interestRetransmissions_.find(segmentNumber);
+ if (it != interestRetransmissions_.end()) lossRecovered_++;
+
+ interestRetransmissions_.erase(segmentNumber);
+
reassemble(std::move(content_object));
increaseWindow();
}
- // in any case we remove the packet from the rtx list
- auto it = interestRetransmissions_.find(segmentNumber);
- if(it != interestRetransmissions_.end())
- lossRecovered_ ++;
-
- interestRetransmissions_.erase(segmentNumber);
-
- if (schedule_next_interest) {
- scheduleNextInterests();
- }
+ scheduleNextInterests();
}
void RTCTransportProtocol::returnContentToApplication(
diff --git a/libtransport/src/hicn/transport/protocols/rtc.h b/libtransport/src/hicn/transport/protocols/rtc.h
index 4ebae2b90..7927e3969 100644
--- a/libtransport/src/hicn/transport/protocols/rtc.h
+++ b/libtransport/src/hicn/transport/protocols/rtc.h
@@ -49,6 +49,7 @@
#define HICN_MAX_RTX_SIZE 1024
#define HICN_MAX_RTX_MAX_AGE 10000
#define HICN_MIN_RTT_WIN 30 // rounds
+#define HICN_MIN_INTER_ARRIVAL_GAP 100 //ms
// cwin
#define HICN_INITIAL_CWIN 1 // packets
@@ -124,14 +125,10 @@ class RTCTransportProtocol : public TransportProtocol, public Reassembly {
void scheduleNextInterests() override;
void addRetransmissions(uint32_t val);
void addRetransmissions(uint32_t start, uint32_t stop);
- void retransmit();
+ uint64_t retransmit();
void checkRtx();
void probeRtt();
void onTimeout(Interest::Ptr &&interest) override;
- // checkIfProducerIsActive: return true if we need to schedule an interest
- // immediatly after, false otherwise (this happens when the producer socket
- // is not active)
- bool checkIfProducerIsActive(const ContentObject &content_object);
bool onNack(const ContentObject &content_object, bool rtx);
void onContentObject(Interest::Ptr &&interest,
ContentObject::Ptr &&content_object) override;
@@ -155,6 +152,7 @@ class RTCTransportProtocol : public TransportProtocol, public Reassembly {
uint32_t inflightInterestsCount_;
//map seq to rtx
std::map<uint32_t, uint8_t> interestRetransmissions_;
+ bool rtx_timer_used_;
std::unique_ptr<asio::steady_timer> rtx_timer_;
std::vector<sentInterest> inflightInterests_;
uint32_t lastSegNacked_; //indicates the segment id in the last received
@@ -162,12 +160,8 @@ class RTCTransportProtocol : public TransportProtocol, public Reassembly {
//for samething that is older than this value.
uint32_t lastReceived_; //segment of the last content object received
//indicates the base of the window on the client
-
- bool nack_timer_used_;
- bool rtx_timer_used_;
- std::unique_ptr<asio::steady_timer> nack_timer_; // timer used to schedule
- // a nack retransmission in case
- // of inactive prod socket
+ uint64_t lastReceivedTime_; //time at which we recevied the
+ //lastReceived_ packet
//rtt probes
//the RTC transport tends to overestimate the RTT
diff --git a/libtransport/src/hicn/transport/utils/content_store.cc b/libtransport/src/hicn/transport/utils/content_store.cc
index 1e6b9fcea..8e3435507 100644
--- a/libtransport/src/hicn/transport/utils/content_store.cc
+++ b/libtransport/src/hicn/transport/utils/content_store.cc
@@ -85,12 +85,17 @@ void ContentStore::erase(const Name &exact_name) {
}
void ContentStore::setLimit(size_t max_packets) {
+ utils::SpinLock::Acquire locked(cs_mutex_);
max_content_store_size_ = max_packets;
}
-std::size_t ContentStore::getLimit() const { return max_content_store_size_; }
+std::size_t ContentStore::getLimit() const {
+ utils::SpinLock::Acquire locked(cs_mutex_);
+ return max_content_store_size_;
+}
std::size_t ContentStore::size() const {
+ utils::SpinLock::Acquire locked(cs_mutex_);
return content_store_hash_table_.size();
}
diff --git a/libtransport/src/hicn/transport/utils/content_store.h b/libtransport/src/hicn/transport/utils/content_store.h
index a89403a01..f7dc41835 100644
--- a/libtransport/src/hicn/transport/utils/content_store.h
+++ b/libtransport/src/hicn/transport/utils/content_store.h
@@ -68,8 +68,9 @@ class ContentStore {
ContentStoreHashTable content_store_hash_table_;
FIFOList fifo_list_;
std::shared_ptr<ContentObject> empty_reference_;
- std::size_t max_content_store_size_;
- utils::SpinLock cs_mutex_;
+ // Must be atomic
+ std::atomic_size_t max_content_store_size_;
+ mutable utils::SpinLock cs_mutex_;
};
} // end namespace utils \ No newline at end of file
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index 5fc071734..4e73ab2b0 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -34,7 +34,7 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
find_package(Libtransport REQUIRED)
set(HICN_UTILS hicn-utils)
else()
- if (ANDROID_API)
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
set(LIBTRANSPORT_LIBRARIES ${LIBTRANSPORT_STATIC})
set(DEPENDENCIES ${LIBTRANSPORT_STATIC})
else ()
diff --git a/utils/src/hiperf.cc b/utils/src/hiperf.cc
index 3e39990a4..94e5d998d 100644
--- a/utils/src/hiperf.cc
+++ b/utils/src/hiperf.cc
@@ -47,7 +47,6 @@ namespace interface {
#define MIN_PROBE_SEQ 0xefffffff
-
using CryptoSuite = utils::CryptoSuite;
using Identity = utils::Identity;
@@ -67,7 +66,8 @@ struct ClientConfiguration {
download_size(0),
report_interval_milliseconds_(1000),
rtc_(false),
- test_mode_(false) {}
+ test_mode_(false),
+ interest_lifetime_(1000) {}
Name name;
bool verify;
@@ -82,6 +82,7 @@ struct ClientConfiguration {
TransportProtocolAlgorithms transport_protocol_;
bool rtc_;
bool test_mode_;
+ uint32_t interest_lifetime_;
};
/**
@@ -215,8 +216,8 @@ class HIperfClient {
expected_seg_ = productionSeg;
} else if (receivedSeg > productionSeg && receivedSeg < MIN_PROBE_SEQ) {
std::cout << "[WINDOW TO LARGE] received NACK for " << receivedSeg
- << ". Next expected packet " << productionSeg << std::endl;
- } else if (receivedSeg >= MIN_PROBE_SEQ){
+ << ". Next expected packet " << productionSeg << std::endl;
+ } else if (receivedSeg >= MIN_PROBE_SEQ) {
std::cout << "[PROBE] probe number = " << receivedSeg << std::endl;
}
return;
@@ -257,9 +258,7 @@ class HIperfClient {
void handleTimerExpiration(ConsumerSocket &c,
const protocol::TransportStatistics &stats) {
-
- if (configuration_.rtc_)
- return;
+ if (configuration_.rtc_) return;
const char separator = ' ';
const int width = 20;
@@ -325,6 +324,9 @@ class HIperfClient {
}
consumer_socket_ = std::make_unique<ConsumerSocket>(transport_protocol);
+ consumer_socket_->setSocketOption(
+ GeneralTransportOptions::INTEREST_LIFETIME,
+ configuration_.interest_lifetime_);
#if defined(DEBUG) && defined(__linux__)
std::shared_ptr<transport::BasePortal> portal;
@@ -509,11 +511,7 @@ class HIperfClient {
void readBufferAvailable(
std::unique_ptr<utils::MemBuf> &&buffer) noexcept override {
- if (client_.configuration_.receive_buffer) {
- client_.configuration_.receive_buffer->prependChain(std::move(buffer));
- } else {
- client_.configuration_.receive_buffer = std::move(buffer);
- }
+ return;
}
size_t maxBufferSize() const override { return read_size; }
@@ -898,6 +896,8 @@ void usage() {
<< std::endl;
std::cerr << "-d <drop_factor_parameter> = RAAQM drop factor parameter"
<< std::endl;
+ std::cerr << "-L\t<interest lifetime>\t\t"
+ << "Set interest lifetime." << std::endl;
std::cerr << "-M = store the content downloaded"
"(default false)"
<< std::endl;
@@ -943,8 +943,8 @@ int main(int argc, char *argv[]) {
int opt;
#ifndef _WIN32
- while ((opt = getopt(argc, argv, "DSCf:b:d:W:RMc:vA:s:rmlk:y:p:hi:xB:It")) !=
- -1) {
+ while ((opt = getopt(argc, argv,
+ "DSCf:b:d:W:RMc:vA:s:rmlk:y:p:hi:xB:ItL:")) != -1) {
switch (opt) {
// Common
case 'D': {
@@ -956,7 +956,7 @@ int main(int argc, char *argv[]) {
break;
}
#else
- while ((opt = getopt(argc, argv, "SCf:b:d:W:RMc:vA:s:rmlk:y:p:hi:xB:t")) !=
+ while ((opt = getopt(argc, argv, "SCf:b:d:W:RMc:vA:s:rmlk:y:p:hi:xB:tL:")) !=
-1) {
switch (opt) {
#endif
@@ -1021,6 +1021,11 @@ int main(int argc, char *argv[]) {
options = 1;
break;
}
+ case 'L': {
+ client_configuration.interest_lifetime_ = std::stoul(optarg);
+ options = 1;
+ break;
+ }
// Server specific
case 'A': {
server_configuration.download_size = std::stoul(optarg);