aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light
diff options
context:
space:
mode:
authorLuca Muscariello <lumuscar+fdio@cisco.com>2019-01-17 13:47:57 +0100
committerLuca Muscariello <lumuscar+fdio@cisco.com>2019-01-17 16:32:51 +0100
commitbac3da61644515f05663789b122554dc77549286 (patch)
tree898210bc8e70371d77de7d446a26c5dd4fd1165a /hicn-light
parentd5165246787301d0f13b646fda5e8a8567aef5ac (diff)
This is the first commit of the hicn projectv19.01
Change-Id: I6f2544ad9b9f8891c88cc4bcce3cf19bd3cc863f Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'hicn-light')
-rwxr-xr-xhicn-light/CMakeLists.txt74
-rwxr-xr-xhicn-light/README.md302
-rwxr-xr-xhicn-light/config/hicn-light.service29
-rwxr-xr-xhicn-light/src/CMakeLists.txt45
-rwxr-xr-xhicn-light/src/command_line/CMakeLists.txt2
-rwxr-xr-xhicn-light/src/command_line/controller/CMakeLists.txt23
-rwxr-xr-xhicn-light/src/command_line/controller/hicnLightControl_main.c284
-rwxr-xr-xhicn-light/src/command_line/daemon/CMakeLists.txt23
-rwxr-xr-xhicn-light/src/command_line/daemon/hicnLightDaemon_main.c336
-rwxr-xr-xhicn-light/src/config.h.in5
-rwxr-xr-xhicn-light/src/config/CMakeLists.txt97
-rwxr-xr-xhicn-light/src/config/commandOps.c72
-rwxr-xr-xhicn-light/src/config/commandOps.h126
-rwxr-xr-xhicn-light/src/config/commandParser.c216
-rwxr-xr-xhicn-light/src/config/commandParser.h196
-rwxr-xr-xhicn-light/src/config/commandReturn.h43
-rwxr-xr-xhicn-light/src/config/configuration.c1076
-rwxr-xr-xhicn-light/src/config/configuration.h152
-rwxr-xr-xhicn-light/src/config/configurationFile.c300
-rwxr-xr-xhicn-light/src/config/configurationFile.h93
-rwxr-xr-xhicn-light/src/config/configurationListeners.c535
-rwxr-xr-xhicn-light/src/config/configurationListeners.h62
-rwxr-xr-xhicn-light/src/config/controlAdd.c94
-rwxr-xr-xhicn-light/src/config/controlAdd.h32
-rwxr-xr-xhicn-light/src/config/controlAddConnection.c390
-rwxr-xr-xhicn-light/src/config/controlAddConnection.h31
-rwxr-xr-xhicn-light/src/config/controlAddListener.c178
-rwxr-xr-xhicn-light/src/config/controlAddListener.h30
-rwxr-xr-xhicn-light/src/config/controlAddPunting.c154
-rwxr-xr-xhicn-light/src/config/controlAddPunting.h22
-rwxr-xr-xhicn-light/src/config/controlAddRoute.c157
-rwxr-xr-xhicn-light/src/config/controlAddRoute.h30
-rwxr-xr-xhicn-light/src/config/controlCache.c91
-rwxr-xr-xhicn-light/src/config/controlCache.h22
-rwxr-xr-xhicn-light/src/config/controlCacheClear.c84
-rwxr-xr-xhicn-light/src/config/controlCacheClear.h30
-rwxr-xr-xhicn-light/src/config/controlCacheServe.c103
-rwxr-xr-xhicn-light/src/config/controlCacheServe.h22
-rwxr-xr-xhicn-light/src/config/controlCacheStore.c103
-rwxr-xr-xhicn-light/src/config/controlCacheStore.h22
-rwxr-xr-xhicn-light/src/config/controlList.c97
-rwxr-xr-xhicn-light/src/config/controlList.h30
-rwxr-xr-xhicn-light/src/config/controlListConnections.c160
-rwxr-xr-xhicn-light/src/config/controlListConnections.h30
-rwxr-xr-xhicn-light/src/config/controlListInterfaces.c76
-rwxr-xr-xhicn-light/src/config/controlListInterfaces.h31
-rwxr-xr-xhicn-light/src/config/controlListListeners.c141
-rwxr-xr-xhicn-light/src/config/controlListListeners.h31
-rwxr-xr-xhicn-light/src/config/controlListRoutes.c154
-rwxr-xr-xhicn-light/src/config/controlListRoutes.h29
-rwxr-xr-xhicn-light/src/config/controlMapMe.c94
-rwxr-xr-xhicn-light/src/config/controlMapMe.h22
-rwxr-xr-xhicn-light/src/config/controlMapMeDiscovery.c103
-rwxr-xr-xhicn-light/src/config/controlMapMeDiscovery.h22
-rwxr-xr-xhicn-light/src/config/controlMapMeEnable.c101
-rwxr-xr-xhicn-light/src/config/controlMapMeEnable.h22
-rwxr-xr-xhicn-light/src/config/controlMapMeRetx.c94
-rwxr-xr-xhicn-light/src/config/controlMapMeRetx.h22
-rwxr-xr-xhicn-light/src/config/controlMapMeTimescale.c97
-rwxr-xr-xhicn-light/src/config/controlMapMeTimescale.h22
-rwxr-xr-xhicn-light/src/config/controlQuit.c63
-rwxr-xr-xhicn-light/src/config/controlQuit.h29
-rwxr-xr-xhicn-light/src/config/controlRemove.c92
-rwxr-xr-xhicn-light/src/config/controlRemove.h29
-rwxr-xr-xhicn-light/src/config/controlRemoveConnection.c115
-rwxr-xr-xhicn-light/src/config/controlRemoveConnection.h31
-rwxr-xr-xhicn-light/src/config/controlRemovePunting.c76
-rwxr-xr-xhicn-light/src/config/controlRemovePunting.h27
-rwxr-xr-xhicn-light/src/config/controlRemoveRoute.c150
-rwxr-xr-xhicn-light/src/config/controlRemoveRoute.h31
-rwxr-xr-xhicn-light/src/config/controlRoot.c134
-rwxr-xr-xhicn-light/src/config/controlRoot.h31
-rwxr-xr-xhicn-light/src/config/controlSet.c88
-rwxr-xr-xhicn-light/src/config/controlSet.h29
-rwxr-xr-xhicn-light/src/config/controlSetDebug.c74
-rwxr-xr-xhicn-light/src/config/controlSetDebug.h30
-rwxr-xr-xhicn-light/src/config/controlSetStrategy.c183
-rwxr-xr-xhicn-light/src/config/controlSetStrategy.h22
-rwxr-xr-xhicn-light/src/config/controlSetWldr.c122
-rwxr-xr-xhicn-light/src/config/controlSetWldr.h22
-rwxr-xr-xhicn-light/src/config/controlState.c237
-rwxr-xr-xhicn-light/src/config/controlState.h233
-rwxr-xr-xhicn-light/src/config/controlUnset.c78
-rwxr-xr-xhicn-light/src/config/controlUnset.h29
-rwxr-xr-xhicn-light/src/config/controlUnsetDebug.c77
-rwxr-xr-xhicn-light/src/config/controlUnsetDebug.h30
-rwxr-xr-xhicn-light/src/config/symbolicNameTable.c175
-rwxr-xr-xhicn-light/src/config/symbolicNameTable.h131
-rwxr-xr-xhicn-light/src/content_store/CMakeLists.txt33
-rwxr-xr-xhicn-light/src/content_store/contentStoreEntry.c136
-rwxr-xr-xhicn-light/src/content_store/contentStoreEntry.h146
-rwxr-xr-xhicn-light/src/content_store/contentStoreInterface.c57
-rwxr-xr-xhicn-light/src/content_store/contentStoreInterface.h211
-rwxr-xr-xhicn-light/src/content_store/contentStoreLRU.c455
-rwxr-xr-xhicn-light/src/content_store/contentStoreLRU.h39
-rwxr-xr-xhicn-light/src/content_store/listLRU.c133
-rwxr-xr-xhicn-light/src/content_store/listLRU.h94
-rwxr-xr-xhicn-light/src/content_store/listTimeOrdered.c94
-rwxr-xr-xhicn-light/src/content_store/listTimeOrdered.h103
-rwxr-xr-xhicn-light/src/core/CMakeLists.txt55
-rwxr-xr-xhicn-light/src/core/connection.c265
-rwxr-xr-xhicn-light/src/core/connection.h148
-rwxr-xr-xhicn-light/src/core/connectionList.c68
-rwxr-xr-xhicn-light/src/core/connectionList.h70
-rwxr-xr-xhicn-light/src/core/connectionManager.c196
-rwxr-xr-xhicn-light/src/core/connectionManager.h37
-rwxr-xr-xhicn-light/src/core/connectionTable.c224
-rwxr-xr-xhicn-light/src/core/connectionTable.h99
-rwxr-xr-xhicn-light/src/core/dispatcher.c435
-rwxr-xr-xhicn-light/src/core/dispatcher.h286
-rwxr-xr-xhicn-light/src/core/forwarder.c499
-rwxr-xr-xhicn-light/src/core/forwarder.h287
-rwxr-xr-xhicn-light/src/core/logger.c173
-rwxr-xr-xhicn-light/src/core/logger.h168
-rwxr-xr-xhicn-light/src/core/mapMe.c816
-rwxr-xr-xhicn-light/src/core/mapMe.h89
-rwxr-xr-xhicn-light/src/core/message.c297
-rwxr-xr-xhicn-light/src/core/message.h180
-rwxr-xr-xhicn-light/src/core/messageHandler.h580
-rwxr-xr-xhicn-light/src/core/messagePacketType.h32
-rwxr-xr-xhicn-light/src/core/name.c236
-rwxr-xr-xhicn-light/src/core/name.h105
-rwxr-xr-xhicn-light/src/core/nameBitvector.c383
-rwxr-xr-xhicn-light/src/core/nameBitvector.h63
-rwxr-xr-xhicn-light/src/core/numberSet.c203
-rwxr-xr-xhicn-light/src/core/numberSet.h157
-rwxr-xr-xhicn-light/src/core/streamBuffer.c142
-rwxr-xr-xhicn-light/src/core/streamBuffer.h129
-rwxr-xr-xhicn-light/src/core/system.h60
-rwxr-xr-xhicn-light/src/core/ticks.h31
-rwxr-xr-xhicn-light/src/core/wldr.c182
-rwxr-xr-xhicn-light/src/core/wldr.h52
-rwxr-xr-xhicn-light/src/io/CMakeLists.txt53
-rwxr-xr-xhicn-light/src/io/addressPair.c129
-rwxr-xr-xhicn-light/src/io/addressPair.h128
-rwxr-xr-xhicn-light/src/io/hicnConnection.c517
-rwxr-xr-xhicn-light/src/io/hicnConnection.h53
-rwxr-xr-xhicn-light/src/io/hicnListener.c725
-rwxr-xr-xhicn-light/src/io/hicnListener.h42
-rwxr-xr-xhicn-light/src/io/hicnTunnel.c106
-rwxr-xr-xhicn-light/src/io/hicnTunnel.h65
-rwxr-xr-xhicn-light/src/io/ioOperations.c63
-rwxr-xr-xhicn-light/src/io/ioOperations.h394
-rwxr-xr-xhicn-light/src/io/listener.h105
-rwxr-xr-xhicn-light/src/io/listenerSet.c132
-rwxr-xr-xhicn-light/src/io/listenerSet.h137
-rwxr-xr-xhicn-light/src/io/streamConnection.c714
-rwxr-xr-xhicn-light/src/io/streamConnection.h75
-rwxr-xr-xhicn-light/src/io/tcpListener.c233
-rwxr-xr-xhicn-light/src/io/tcpListener.h37
-rwxr-xr-xhicn-light/src/io/tcpTunnel.c43
-rwxr-xr-xhicn-light/src/io/tcpTunnel.h42
-rwxr-xr-xhicn-light/src/io/udpConnection.c406
-rwxr-xr-xhicn-light/src/io/udpConnection.h53
-rwxr-xr-xhicn-light/src/io/udpListener.c533
-rwxr-xr-xhicn-light/src/io/udpListener.h32
-rwxr-xr-xhicn-light/src/io/udpTunnel.c91
-rwxr-xr-xhicn-light/src/io/udpTunnel.h42
-rwxr-xr-xhicn-light/src/messenger/CMakeLists.txt32
-rwxr-xr-xhicn-light/src/messenger/messenger.c171
-rwxr-xr-xhicn-light/src/messenger/messenger.h69
-rwxr-xr-xhicn-light/src/messenger/messengerRecipient.c62
-rwxr-xr-xhicn-light/src/messenger/messengerRecipient.h104
-rwxr-xr-xhicn-light/src/messenger/missive.c54
-rwxr-xr-xhicn-light/src/messenger/missive.h89
-rwxr-xr-xhicn-light/src/messenger/missiveDeque.c77
-rwxr-xr-xhicn-light/src/messenger/missiveDeque.h55
-rwxr-xr-xhicn-light/src/messenger/missiveType.h55
-rwxr-xr-xhicn-light/src/platforms/CMakeLists.txt31
-rwxr-xr-xhicn-light/src/platforms/README.txt17
-rwxr-xr-xhicn-light/src/platforms/android/system.c183
-rwxr-xr-xhicn-light/src/platforms/darwin/system.c146
-rwxr-xr-xhicn-light/src/platforms/linux/system.c184
-rwxr-xr-xhicn-light/src/processor/CMakeLists.txt40
-rwxr-xr-xhicn-light/src/processor/fib.c448
-rwxr-xr-xhicn-light/src/processor/fib.h43
-rwxr-xr-xhicn-light/src/processor/fibEntry.c223
-rwxr-xr-xhicn-light/src/processor/fibEntry.h143
-rwxr-xr-xhicn-light/src/processor/fibEntryList.c72
-rwxr-xr-xhicn-light/src/processor/fibEntryList.h96
-rwxr-xr-xhicn-light/src/processor/hashTableFunction.c47
-rwxr-xr-xhicn-light/src/processor/hashTableFunction.h73
-rwxr-xr-xhicn-light/src/processor/matchingRulesTable.c132
-rwxr-xr-xhicn-light/src/processor/matchingRulesTable.h113
-rwxr-xr-xhicn-light/src/processor/messageProcessor.c742
-rwxr-xr-xhicn-light/src/processor/messageProcessor.h166
-rwxr-xr-xhicn-light/src/processor/pit.c45
-rwxr-xr-xhicn-light/src/processor/pit.h114
-rwxr-xr-xhicn-light/src/processor/pitEntry.c142
-rwxr-xr-xhicn-light/src/processor/pitEntry.h164
-rwxr-xr-xhicn-light/src/processor/pitStandard.c304
-rwxr-xr-xhicn-light/src/processor/pitStandard.h41
-rwxr-xr-xhicn-light/src/processor/pitVerdict.h36
-rwxr-xr-xhicn-light/src/socket/CMakeLists.txt31
-rwxr-xr-xhicn-light/src/socket/api.c604
-rwxr-xr-xhicn-light/src/socket/api.h216
-rwxr-xr-xhicn-light/src/socket/error.c7
-rwxr-xr-xhicn-light/src/socket/error.h46
-rwxr-xr-xhicn-light/src/socket/ops.h54
-rwxr-xr-xhicn-light/src/socket/ops_linux.c1723
-rwxr-xr-xhicn-light/src/strategies/CMakeLists.txt36
-rwxr-xr-xhicn-light/src/strategies/loadBalancer.c278
-rwxr-xr-xhicn-light/src/strategies/loadBalancer.h26
-rwxr-xr-xhicn-light/src/strategies/loadBalancerWithPD.c368
-rwxr-xr-xhicn-light/src/strategies/loadBalancerWithPD.h30
-rwxr-xr-xhicn-light/src/strategies/nexthopState.c206
-rwxr-xr-xhicn-light/src/strategies/nexthopState.h94
-rwxr-xr-xhicn-light/src/strategies/nexthopStateWithPD.c254
-rwxr-xr-xhicn-light/src/strategies/nexthopStateWithPD.h106
-rwxr-xr-xhicn-light/src/strategies/rnd.c175
-rwxr-xr-xhicn-light/src/strategies/rnd.h26
-rwxr-xr-xhicn-light/src/strategies/rndSegment.c207
-rwxr-xr-xhicn-light/src/strategies/rndSegment.h27
-rwxr-xr-xhicn-light/src/strategies/strategyImpl.h66
-rwxr-xr-xhicn-light/src/utils/CMakeLists.txt36
-rwxr-xr-xhicn-light/src/utils/address.c419
-rwxr-xr-xhicn-light/src/utils/address.h498
-rwxr-xr-xhicn-light/src/utils/addressList.c133
-rwxr-xr-xhicn-light/src/utils/addressList.h196
-rwxr-xr-xhicn-light/src/utils/commands.h282
-rwxr-xr-xhicn-light/src/utils/interface.c168
-rwxr-xr-xhicn-light/src/utils/interface.h208
-rwxr-xr-xhicn-light/src/utils/interfaceSet.c149
-rwxr-xr-xhicn-light/src/utils/interfaceSet.h198
-rwxr-xr-xhicn-light/src/utils/punting.c98
-rwxr-xr-xhicn-light/src/utils/punting.h72
-rwxr-xr-xhicn-light/src/utils/utils.c258
-rwxr-xr-xhicn-light/src/utils/utils.h82
228 files changed, 34520 insertions, 0 deletions
diff --git a/hicn-light/CMakeLists.txt b/hicn-light/CMakeLists.txt
new file mode 100755
index 000000000..289e07ecc
--- /dev/null
+++ b/hicn-light/CMakeLists.txt
@@ -0,0 +1,74 @@
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+project(hicn-light)
+
+if (NOT CMAKE_BUILD_TYPE)
+ message(STATUS "No build type selected, default to Release")
+ set(CMAKE_BUILD_TYPE "Release")
+endif()
+
+set(CMAKE_MODULE_PATH
+ ${CMAKE_MODULE_PATH}
+ "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules"
+)
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+
+include( CTest )
+include( detectCacheSize )
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+if(ANDROID_API)
+ message("############ Detected cross compile for $ENV{CMAKE_SYSTEM_NAME}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS}")
+ endif()
+
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DLIBRTA_DISABLE_VALIDATION -DPARCLibrary_DISABLE_VALIDATION")
+
+include(IosMacros)
+
+find_package_wrapper(Libparc REQUIRED)
+
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+ find_package_wrapper(Libhicn REQUIRED)
+ set(LIBHICN_LIGHT hicn-light)
+ set(HICN_LIGHT_CONTROL hicnLightControl)
+ set(HICN_LIGHT_DAEMON hicnLightDaemon)
+else()
+ set(HICN_LIBRARIES ${LIBHICN_SHARED})
+ set(DEPENDENCIES
+ ${LIBHICN}
+ ${LIBHICN_SHARED}
+ )
+endif()
+
+find_package(Threads REQUIRED)
+
+set(HICN_LIGHT_LINK_LIBRARIES
+ hicn-light
+ ${HICN_LIBRARIES}
+ ${LIBPARC_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+)
+
+# Include dirs -- Order does matter!
+list(APPEND HICN_LIGHT_INCLUDE_DIRS
+ ${HICN_INCLUDE_DIRS}
+ ${LIBPARC_INCLUDE_DIRS}
+)
+
+if (UNIX)
+ list(APPEND HICN_LIGHT_LINK_LIBRARIES
+ m
+ )
+endif()
+
+set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
+ set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS} -undefined dynamic_lookup")
+ message(STATUS "Set \"-undefined dynamic_lookup\" for shared libraries")
+endif()
+
+add_subdirectory(src) \ No newline at end of file
diff --git a/hicn-light/README.md b/hicn-light/README.md
new file mode 100755
index 000000000..ba7ed77b3
--- /dev/null
+++ b/hicn-light/README.md
@@ -0,0 +1,302 @@
+hicn-light
+=======
+
+## Introduction ##
+
+hicn-light is a socket based forwarder
+
+## Using hicn-light ##
+
+### Platforms ###
+
+hicn-light has been tested in:
+
+- Ubuntu 16.04 (x86_64)
+- Debian Testing
+- MacOSX 10.12
+
+Other platforms and architectures may work.
+
+### Dependencies ###
+
+Build dependencies:
+
+- c99 ( clang / gcc )
+- CMake 3.4
+
+Basic dependencies:
+
+- OpenSSL
+- pthreads
+- Libevent
+- Libparc
+
+## hicn-light Executables ##
+
+hicn-light is a set of binary executables that are used to run a forwarder instance.
+The forwarder can be run and configured using the commands
+
+- `hicnLightDaemon`
+- `hicnLightControl`
+
+Use the `-h` option to display the help messages
+
+### hicn-light Daemon ###
+
+The command `hicnLightDaemon` runs the hicn-light forwarder. The forwarder can be executed
+with the following options:
+
+```
+hicnLightDaemon [--port port] [--daemon] [--capacity objectStoreSize] [--log facility=level]
+ [--log-file filename] [--config file]
+
+Options:
+
+--port = tcp port for local in-bound connections
+--daemon = start as daemon process
+--capacity = maximum number of content objects to cache. To disable the cache
+ objectStoreSize must be 0.
+ Default vaule for objectStoreSize is 100000
+--log = sets a facility to a given log level. You can have multiple of these.
+ facilities: all, config, core, io, message, processor
+ levels: debug, info, notice, warning, error, critical, alert, off
+ example: hicnLightDaemon --log io=debug --log core=off
+--log-file = file to write log messages to (required in daemon mode)
+--config = configuration filename
+```
+
+The configuration file contains configuration lines as per hicnLightControl (see below for all
+the available commands). If logging level or content store capacity is set in the configuration
+file, it overrides the command_line. When a configuration file is specified, no default listeners
+are setup. Only 'add listener' lines in the configuration file matter.
+
+If no configuration file is specified, hicnLightDaemon will listen on TCP and UDP ports specified
+by the --port flag (or default port). It will listen on both IPv4 and IPv6 if available. The
+default port for hicn-light is 9695. Commands are expected on port 2001.
+
+### hicn-light Control ###
+
+`hicnLightControl` can be used to send command to the hicn-light forwarder and configure it.
+The command can be executed in the following way:
+
+```
+hicnLightControl [commands]
+
+Options:
+ -h = This help screen
+ commands = configuration line to send to hicn-light (use 'help' for list)
+```
+
+#### Available Commands in hicn-light Control ####
+
+This is the full list of available commands in `hicnLightControl`. This commands can be used
+from the command line running `hicnLightControl` as explained before, or listing them in a
+configuration file.
+
+Information about the commands are also available in the `hicnLightControl` help message.
+
+`add listener`: creates a TCP or UDP listener with the specified options on the local forwarder.
+For local connections (application to hicn-light) we expect a TCP listener. The default port for
+the local listener is 9695.
+
+```
+add listener <protocol> <symbolic> <local_adress> <local_port>
+
+ <symbolic> :User defined name for listener, must start with alpha and bealphanum
+ <protocol> :tcp | udp
+ <localAddress> :IPv4 or IPv6 address
+ <local_port> :TCP/UDP port
+
+```
+
+`add listener hicn`: creates a hicn listener with the specified options on the local forwarder.
+
+```
+add listener hicn <symbolic> <local_adress>
+
+ <symbolic> :User defined name for listener, must start with alpha and be alphanum
+ <localAddress> :IPv4 or IPv6 address
+
+```
+
+`add connection`: creates a TCP or UDP connection on the local forwarder with the specified options.
+
+```
+add connection <protocol> <symbolic> <remote_ip> <remote_port> <local_ip> <local_port>
+
+ <protocol> : tcp | udp
+ <symbolic> : symbolic name, e.g. 'conn1' (must be unique, start with alpha)
+ <remote_ip> : the IPv4 or IPv6 of the remote system
+ <remote_port> : the remote TCP/UDP port
+ <local_ip> : local IP address to bind to
+ <local_port> : local TCP/UDP port
+
+```
+`add connection hicn`: creates an hicn connection on the local forwarder with the specified options.
+
+```
+add connection hicn <symbolic> <remote_ip> <local_ip>
+
+ <symbolic> : symbolic name, e.g. 'conn1' (must be unique, start with alpha)
+ <remote_ip> : the IPv4 or IPv6 of the remote system
+ <local_ip> : local IP address to bind to
+
+```
+`list`: lists the connections, routes or listeners available on the local hicn-light forwarder
+```
+list <connections | routes | listeners>
+
+```
+`add route`: adds a route to the specified connection
+
+```
+add route <symbolic | connid> <prefix> <cost>
+
+ <symbolic> :The symbolic name for an exgress (must be unique, start with alpha)
+ <connid>: :The egress connection id (see 'help list connections')
+ <prefix>: :ipAddress/netmask
+ <cost>: :positive integer representing cost
+```
+
+`remove connection`: removes the specified connection. At the moment, this commands is available
+only for UDP connections, TCP is ignored.
+
+```
+remove connection <protocol> <symbolic | connid>
+
+ <protocol> : tcp | upd. This is the protocol used to create the connection.
+ <symbolic> :The symbolic name for an exgress (must be unique, start with alpha)
+ <connid>: :The egress connection id (see 'help list connections')
+
+```
+
+`remove route`: remove the specified prefix for a local connection
+
+```
+remove route <symbolic | connid> <prefix>
+
+ <connid> : the alphanumeric name of a local connection
+ <prefix> : the prefix (ipAddress/netmask) to remove
+```
+
+`cache serve`: enables/disables replies from local content store (if available)
+
+```
+cache serve <on|off>
+```
+`cache store`: enables/disables the storage of incoming data packets in the local content store
+(if available)
+
+```
+cache store <on|off>
+
+```
+`cache clear`: removes all the cached data form the local content store (if available)
+
+```
+cache clear
+
+```
+`set strategy`: sets the forwarding strategy for a give prefix. There are 4 different strategies
+implemented in hicn-light:
+
+- random: each interest is forwarded randomly to one of the available output connections
+- random_per_dash_segment: the output connection is selected randomly for each DASH segment.
+ This can be used only for DASH video streams.
+- loadbalancer: each interest is forwarded toward the output connection with the lowest number
+ of pending interests. The pending interest are the interest sent on a certain connection but
+ not yet satisfied. More information are available in:
+ G. Carofiglio, M. Gallo, L. Muscariello, M. Papalini, S. Wang,
+ "Optimal multipath congestion control and request forwarding in information-centric networks",
+ ICNP 2013.
+- loadbalancer_with_delay: implements the same strategy as loadbalancer but it takes into account
+ also the propagation delay behind each connections.
+
+```
+set strategy <prefix> <strategy>
+
+ <preifx> : the prefix to which apply the forwarding strategy
+ <strategy> : random | random_per_dash_segment | loadbalancer | loadbalancer_with_delay
+```
+`set wldr`: turns on/off WLDR on the specified connection. WLDR (Wireless Loss Detiection and
+ Recovery) is a protocol that can be used to recover losses generated by unreliable wireless
+ connections, such as WIFI. More information on WLDR are available in:
+ G. Carofiglio, L. Muscariello, M. Papalini, N. Rozhnova, X. Zeng,
+ "Leveraging ICN In-network Control for Loss Detection and Recovery in Wireless Mobile networks",
+ ICN 2016. Notice that WLDR is currently available only for UDP connections. In order to work
+ properly, WLDR needs to be activated on both side of the connection.
+
+```
+set wldr <on|off> <symbolic | connid>
+
+ <symbolic> :The symbolic name for an exgress (must be unique, start with alpha)
+ <connid>: :The egress connection id (see 'help list connections')
+
+```
+`add punting`: Add punting rules to the forwarders.
+
+```
+add punting <symbolic> <prefix>
+
+ <symbolic> : listener symbolic name
+ <address> : prefix to add as a punting rule. (example 1234::0/64)
+```
+`mapme enable`: enables/disables mapme
+
+```
+mapme enable <on|off>
+```
+`mapme discovery`: enables/disables mapme discovery
+
+```
+mapme discovery <on|off>
+```
+
+`mapme timescale`: set the timescale value expressed in millisencods
+
+```
+mapme timescale <milliseconds>
+```
+`mapme retx`: set the retrasmission time value expressed in millisecond
+
+```
+mapme retx <milliseconds>
+```
+`quit`: Exits the interactive shell
+
+### hicn-light Configuration File Example ###
+
+This is an example of a simple configuration file for hicn-light. It can be loaded by running
+the command `hicnLightDaemon --config configFile.cfg`, assuming the file name is configFile.cfg
+
+```
+#create a local listener on port 9199. This will be used by the applications to talk
+with the forwarder
+add listener udp local0 127.0.0.1 9199
+
+#create a connection with a remote node
+add connection udp conn0 192.168.0.20 12345 127.0.0.1 9199
+
+#add a route toward the remote node
+add route conn0 192.168.0.20/24 1
+```
+
+
+## License ##
+
+This software is distributed under the following license:
+
+```
+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.
+```
diff --git a/hicn-light/config/hicn-light.service b/hicn-light/config/hicn-light.service
new file mode 100755
index 000000000..0f976fc6c
--- /dev/null
+++ b/hicn-light/config/hicn-light.service
@@ -0,0 +1,29 @@
+# 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.
+
+[Unit]
+Description=hicn-light is the cisco hicn socket based forwarder.
+#Documentation=man:hicn-light-forwarder
+
+[Service]
+Environment=PORT=9695
+Environment=LOG_FILE=/tmp/hicn_light.log
+Environment=CS_SIZE=1000
+Environment=CONFIG=/etc/hicn/hicn_light.conf
+# This will overrride the default environment
+EnvironmentFile=-/etc/default/source
+ExecStart=/usr/bin/hicnLightDaemon --port ${PORT} --log-file ${LOG_FILE} --capacity ${CS_SIZE} --config ${CONFIG}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/hicn-light/src/CMakeLists.txt b/hicn-light/src/CMakeLists.txt
new file mode 100755
index 000000000..939f38a34
--- /dev/null
+++ b/hicn-light/src/CMakeLists.txt
@@ -0,0 +1,45 @@
+# Define a few configuration variables that we want accessible in the software
+
+include(BuildMacros)
+configure_file(config.h.in config.h @ONLY)
+
+if(NOT ANDROID_API AND NOT COMPILE_FOR_IOS)
+ add_subdirectory(command_line)
+endif ()
+
+add_subdirectory(config)
+add_subdirectory(content_store)
+add_subdirectory(core)
+add_subdirectory(io)
+add_subdirectory(messenger)
+add_subdirectory(platforms)
+add_subdirectory(processor)
+add_subdirectory(socket)
+add_subdirectory(strategies)
+add_subdirectory(utils)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/config.h
+)
+
+set(COMPILER_DEFINITIONS "-DWITH_MAPME -DWITH_MAPME_FIXES")
+
+list(APPEND HICN_LIGHT_INCLUDE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+)
+
+if (INSTALL_HEADER)
+ set(TO_INSTALL_HEADERS ${HEADER_FILES})
+endif()
+
+build_library(${LIBHICN_LIGHT}
+ STATIC
+ SOURCES ${SOURCE_FILES}
+ INSTALL_HEADERS ${TO_INSTALL_HEADERS}
+ LINK_LIBRARIES ${LIBRARIES}
+ DEPENDS ${DEPENDENCIES}
+ COMPONENT hicn-light
+ INCLUDE_DIRS ${HICN_LIGHT_INCLUDE_DIRS}
+ INSTALL_ROOT_DIR hicn/hicn-light
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+)
diff --git a/hicn-light/src/command_line/CMakeLists.txt b/hicn-light/src/command_line/CMakeLists.txt
new file mode 100755
index 000000000..16c23dc5c
--- /dev/null
+++ b/hicn-light/src/command_line/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(controller)
+add_subdirectory(daemon)
diff --git a/hicn-light/src/command_line/controller/CMakeLists.txt b/hicn-light/src/command_line/controller/CMakeLists.txt
new file mode 100755
index 000000000..b53e610a1
--- /dev/null
+++ b/hicn-light/src/command_line/controller/CMakeLists.txt
@@ -0,0 +1,23 @@
+# 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 CONTROLLER_SRC
+ hicnLightControl_main.c
+)
+
+build_executable(${HICN_LIGHT_CONTROL}
+ SOURCES ${CONTROLLER_SRC}
+ LINK_LIBRARIES ${HICN_LIGHT_LINK_LIBRARIES}
+ DEPENDS hicn-light
+ COMPONENT hicn-light
+)
diff --git a/hicn-light/src/command_line/controller/hicnLightControl_main.c b/hicn-light/src/command_line/controller/hicnLightControl_main.c
new file mode 100755
index 000000000..4641bddf5
--- /dev/null
+++ b/hicn-light/src/command_line/controller/hicnLightControl_main.c
@@ -0,0 +1,284 @@
+/*
+ * 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 <src/config.h>
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#include <parc/security/parc_IdentityFile.h>
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+#include <errno.h>
+#include <src/config/controlRoot.h>
+#include <src/config/controlState.h>
+
+#include <src/utils/commands.h>
+
+size_t commandOutputLen = 0; // preserve the number of structs composing
+ // payload in case on not interactive call.
+
+// REMINDER: when a new_command is added, the following array has to be updated
+// with the sizeof(new_command). It allows to allocate the buffer for receiving
+// the payload of the DAEMON RESPONSE after the header has beed read. Each
+// command identifier (typedef enum command_id) corresponds to a position in the
+// following array.
+static int payloadLengthController[LAST_COMMAND_VALUE] = {
+ sizeof(add_listener_command),
+ sizeof(add_connection_command),
+ sizeof(list_connections_command), // needed when get response from FWD
+ sizeof(add_route_command),
+ sizeof(list_routes_command), // needed when get response from FWD
+ sizeof(remove_connection_command),
+ sizeof(remove_route_command),
+ sizeof(cache_store_command),
+ sizeof(cache_serve_command),
+ 0, // cache clear
+ sizeof(set_strategy_command),
+ sizeof(set_wldr_command),
+ sizeof(add_punting_command),
+ sizeof(list_listeners_command), // needed when get response from FWD
+ sizeof(mapme_activator_command),
+ sizeof(mapme_activator_command),
+ sizeof(mapme_timing_command),
+ sizeof(mapme_timing_command)};
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+typedef struct controller_main_state {
+ ControlState *controlState;
+} ControlMainState;
+
+static void _displayForwarderLogo(void){
+ const char cli_banner [] =
+ "\033[0;31m ____ ___ _ \033[0m __ _ __ _ __ __\n"
+ "\033[0;31m / __// _ \\ (_)___ \033[0m / / (_)____ ___ ____/ /(_)___ _ / / / /_\n"
+ "\033[0;31m / _/ / // /_ / // _ \\ \033[0m / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"
+ "\033[0;31m/_/ /____/(_)/_/ \\___/ \033[0m/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n"
+ " /___/ \n";
+ printf("%s", cli_banner);
+ printf("\n");
+}
+
+static void _displayUsage(char *programName) {
+ printf("Usage: %s -h\n", programName);
+ printf(
+ "hicn-light is the 1.0 source, which runs on each end system and as a "
+ "software source\n");
+ printf(
+ "on intermediate systems. controller is the program to configure the "
+ "source, daemon.\n");
+ printf("\n");
+ printf("Options:\n");
+ printf("-h = This help screen\n");
+ printf(
+ "commands = configuration line to send to hicn-light (use 'help' "
+ "for list)\n");
+ printf("\n");
+}
+
+static int _parseArgs(int argc, char *argv[], char **keystorePath,
+ char **keystorePassword, PARCList *commandList) {
+ static struct option longFormOptions[] = {
+ {"help", no_argument, 0, 'h'},
+ {"keystore", required_argument, 0, 'k'},
+ {"password", required_argument, 0, 'p'},
+ {0, 0, 0, 0}};
+
+ int c;
+
+ while (1) {
+ // getopt_long stores the option index here.
+ int optionIndex = 0;
+
+ c = getopt_long(argc, argv, "hk:p:", longFormOptions, &optionIndex);
+
+ // Detect the end of the options.
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'k':
+ *keystorePath = optarg;
+ break;
+
+ case 'p':
+ *keystorePassword = optarg;
+ break;
+
+ case 'h':
+ default:
+ _displayUsage(argv[0]);
+ return 0;
+ }
+ }
+
+ // Any remaining parameters get put in the command list.
+ if (optind < argc) {
+ while (optind < argc) {
+ parcList_Add(commandList, argv[optind]);
+ optind++;
+ }
+ }
+
+ return 1;
+}
+
+struct iovec *_writeAndReadMessage(ControlState *state, struct iovec *msg) {
+ parcAssertNotNull(msg, "Parameter msg must be non-null");
+ int sockfd = controlState_GetSockfd(state);
+
+ // check if request has a payload
+ if (((header_control_message *)msg[0].iov_base)->length >
+ 0) { // command with payload
+ // write header + payload (compatibility issue: two write needed instead of
+ // the writev)
+ if (write(sockfd, msg[0].iov_base, msg[0].iov_len) < 0 ||
+ write(sockfd, msg[1].iov_base, msg[1].iov_len) < 0) {
+ printf("\nError while sending the Message: cannot write on socket \n");
+ exit(EXIT_FAILURE);
+ }
+ parcMemory_Deallocate(&msg[1].iov_base);
+ } else { // command without payload, e.g. 'list'
+ // write header only
+ if (write(sockfd, msg[0].iov_base, msg[0].iov_len) < 0) {
+ printf("\nError while sending the Message: cannot write on socket \n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ parcMemory_Deallocate(&msg[0].iov_base);
+
+ // ======= RECEIVE =======
+
+ header_control_message *headerResponse =
+ (header_control_message *)parcMemory_AllocateAndClear(
+ sizeof(header_control_message));
+ if (recv(sockfd, headerResponse, sizeof(header_control_message), 0) < 0) {
+ printf("\nError in Receiving the Message \n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (headerResponse->messageType < RESPONSE_LIGHT ||
+ headerResponse->messageType >= LAST_MSG_TYPE_VALUE) {
+ char *checkFinMsg = parcMemory_Reallocate(headerResponse, 32);
+ if (recv(sockfd, checkFinMsg, sizeof(checkFinMsg),
+ MSG_PEEK | MSG_DONTWAIT) == 0) {
+ // if recv returns zero, that means the connection has been closed:
+ close(sockfd);
+ printf("\nConnection terminated by the Daemon. Exiting... \n");
+ exit(EXIT_SUCCESS);
+ } else {
+ printf("\nError: Unrecognized message type received \n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ void *payloadResponse = NULL;
+
+ if ((commandOutputLen = headerResponse->length) > 0) {
+ payloadResponse = parcMemory_AllocateAndClear(
+ payloadLengthController[headerResponse->commandID] *
+ headerResponse->length);
+
+ if (recv(sockfd, payloadResponse,
+ payloadLengthController[headerResponse->commandID] *
+ headerResponse->length,
+ 0) < 0) {
+ printf("\nError in Receiving the Message \n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ struct iovec *response =
+ parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+ response[0].iov_base = headerResponse;
+ response[0].iov_len = sizeof(header_control_message);
+ response[1].iov_base = payloadResponse;
+ response[1].iov_len = payloadLengthController[headerResponse->commandID] *
+ headerResponse->length;
+
+ return response;
+}
+
+int main(int argc, char *argv[]) {
+ _displayForwarderLogo();
+
+ if (argc == 2 && strcmp("-h", argv[1]) == 0) {
+ _displayUsage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+
+ PARCList *commands =
+ parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+
+ if (!_parseArgs(argc, argv, NULL, NULL, commands)) {
+ parcList_Release(&commands);
+ exit(EXIT_FAILURE);
+ }
+
+ ControlMainState mainState;
+ mainState.controlState =
+ controlState_Create(&mainState, _writeAndReadMessage, true);
+
+ controlState_RegisterCommand(mainState.controlState,
+ controlRoot_HelpCreate(mainState.controlState));
+ controlState_RegisterCommand(mainState.controlState,
+ controlRoot_Create(mainState.controlState));
+
+ if (parcList_Size(commands) > 0) {
+ controlState_SetInteractiveFlag(mainState.controlState, false);
+ controlState_DispatchCommand(mainState.controlState, commands);
+ char **commandOutputMain =
+ controlState_GetCommandOutput(mainState.controlState);
+ if (commandOutputMain != NULL && commandOutputLen > 0) {
+ for (size_t j = 0; j < commandOutputLen; j++) {
+ printf("Output %zu: %s \n", j, commandOutputMain[j]);
+ }
+ controlState_ReleaseCommandOutput(mainState.controlState,
+ commandOutputMain, commandOutputLen);
+ }
+ // release
+
+ } else {
+ controlState_Interactive(mainState.controlState);
+ }
+
+ parcList_Release(&commands);
+
+ controlState_Destroy(&mainState.controlState);
+
+ return EXIT_SUCCESS;
+}
diff --git a/hicn-light/src/command_line/daemon/CMakeLists.txt b/hicn-light/src/command_line/daemon/CMakeLists.txt
new file mode 100755
index 000000000..fd6cc9310
--- /dev/null
+++ b/hicn-light/src/command_line/daemon/CMakeLists.txt
@@ -0,0 +1,23 @@
+# 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 DAEMON_SRC
+ hicnLightDaemon_main.c
+)
+
+build_executable(${HICN_LIGHT_DAEMON}
+ SOURCES ${DAEMON_SRC}
+ LINK_LIBRARIES ${HICN_LIGHT_LINK_LIBRARIES}
+ DEPENDS hicn-light
+ COMPONENT hicn-light
+) \ No newline at end of file
diff --git a/hicn-light/src/command_line/daemon/hicnLightDaemon_main.c b/hicn-light/src/command_line/daemon/hicnLightDaemon_main.c
new file mode 100755
index 000000000..f6d521711
--- /dev/null
+++ b/hicn-light/src/command_line/daemon/hicnLightDaemon_main.c
@@ -0,0 +1,336 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_LogLevel.h>
+#include <parc/logging/parc_LogReporterFile.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+static void _displayForwarderLogo(void){
+ const char cli_banner [] =
+ "\033[0;31m ____ ___ _ \033[0m __ _ __ _ __ __\n"
+ "\033[0;31m / __// _ \\ (_)___ \033[0m / / (_)____ ___ ____/ /(_)___ _ / / / /_\n"
+ "\033[0;31m / _/ / // /_ / // _ \\ \033[0m / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"
+ "\033[0;31m/_/ /____/(_)/_/ \\___/ \033[0m/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n"
+ " /___/ \n";
+ printf("%s", cli_banner);
+ printf("\n");
+}
+
+static void _usage(int exitCode) {
+ printf(
+ "Usage: daemon [--port port] [--daemon] [--capacity objectStoreSize] "
+ "[--log facility=level] [--log-file filename] [--config file]\n");
+ printf("\n");
+ printf(
+ "hicn-light run as a daemon is the program to launch the forwarder, "
+ "either as a console program\n");
+ printf(
+ "or a background daemon (detatched from console). Once running, use the "
+ "program controller to\n");
+ printf("configure hicn-light.\n");
+ printf("\n");
+ printf(
+ "The configuration file contains configuration lines as per "
+ "controller\n");
+ printf(
+ "If logging level or content store capacity is set in the configuraiton "
+ "file, it overrides the command_line\n");
+ printf(
+ "When a configuration file is specified, no default listeners on 'port' "
+ "are setup. Only 'add listener' lines\n");
+ printf("in the configuration file matter.\n");
+ printf("\n");
+ printf(
+ "If no configuration file is specified, daemon will listen on TCP and "
+ "UDP ports specified by\n");
+ printf(
+ "the --port flag (or default port). It will listen on both IPv4 and "
+ "IPv6 if available.\n");
+ printf("\n");
+ printf("Options:\n");
+ printf("--port = tcp port for in-bound connections\n");
+ printf("--daemon = start as daemon process\n");
+ printf("--objectStoreSize = maximum number of content objects to cache\n");
+ printf(
+ "--log = sets a facility to a given log level. You can have "
+ "multiple of these.\n");
+ printf(
+ " facilities: all, config, core, io, message, "
+ "processor\n");
+ printf(
+ " levels: debug, info, notice, warning, error, "
+ "critical, alert, off\n");
+ printf(" example: daemon --log io=debug --log core=off\n");
+ printf(
+ "--log-file = file to write log messages to (required in daemon "
+ "mode)\n");
+ printf("--config = configuration filename\n");
+ printf("\n");
+ exit(exitCode);
+}
+
+static void _setLogLevelToLevel(int logLevelArray[LoggerFacility_END],
+ LoggerFacility facility,
+ const char *levelString) {
+ PARCLogLevel level = parcLogLevel_FromString(levelString);
+
+ if (level < PARCLogLevel_All) {
+ // we have a good facility and level
+ logLevelArray[facility] = level;
+ } else {
+ printf("Invalid log level string %s\n", levelString);
+ _usage(EXIT_FAILURE);
+ }
+}
+
+/**
+ * string: "facility=level"
+ * Set the right thing in the logger
+ */
+static void _setLogLevel(int logLevelArray[LoggerFacility_END],
+ const char *string) {
+ char *tofree = parcMemory_StringDuplicate(string, strlen(string));
+ char *p = tofree;
+
+ char *facilityString = strsep(&p, "=");
+ if (facilityString) {
+ char *levelString = p;
+
+ if (strcasecmp(facilityString, "all") == 0) {
+ for (LoggerFacility facility = 0; facility < LoggerFacility_END;
+ facility++) {
+ _setLogLevelToLevel(logLevelArray, facility, levelString);
+ }
+ } else {
+ LoggerFacility facility;
+ for (facility = 0; facility < LoggerFacility_END; facility++) {
+ if (strcasecmp(facilityString, logger_FacilityString(facility)) == 0) {
+ break;
+ }
+ }
+
+ if (facility < LoggerFacility_END) {
+ _setLogLevelToLevel(logLevelArray, facility, levelString);
+ } else {
+ printf("Invalid facility string %s\n", facilityString);
+ _usage(EXIT_FAILURE);
+ }
+ }
+ }
+
+ parcMemory_Deallocate((void **)&tofree);
+}
+
+static void _daemonize(void) {
+ if (getppid() == 1) {
+ // already a daemon
+ return;
+ }
+
+ int forkReturn = fork();
+ parcTrapUnexpectedStateIf(forkReturn < 0, "Fork error");
+
+ if (forkReturn > 0) {
+ // parent exits
+ exit(EXIT_SUCCESS);
+ }
+
+ // Child daemon detaches
+ printf("child continuing, pid = %u\n", getpid());
+
+ // get a new process group independent from old parent
+ setsid();
+
+ /* close all descriptors */
+ for (int i = getdtablesize(); i >= 0; --i) {
+ close(i);
+ }
+
+ // reset errno because it might be seg to EBADF from the close calls above
+ errno = 0;
+
+ // Redirect stdin and stdout and stderr to /dev/null
+ const char *devnull = "/dev/null";
+ int nullfile = open(devnull, O_RDWR);
+ parcAssertTrue(nullfile >= 0, "Error opening file '%s': (%d) %s", devnull,
+ errno, strerror(errno));
+
+ int ret;
+ ret = dup(nullfile);
+ parcAssertTrue(ret == 1, "Error duping fd 1 got %d file: (%d) %s", ret, errno,
+ strerror(errno));
+ ret = dup(nullfile);
+ parcAssertTrue(ret == 2, "Error duping fd 2, got %d file: (%d) %s", ret,
+ errno, strerror(errno));
+
+ // forwarder will capture signals
+}
+
+static Logger *_createLogfile(const char *logfile) {
+ int logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR);
+ if (logfd < 0) {
+ fprintf(stderr, "Error opening %s for writing: (%d) %s\n", logfile, errno,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ chmod(logfile, S_IRWXU);
+
+ PARCFileOutputStream *fos = parcFileOutputStream_Create(logfd);
+ PARCOutputStream *pos = parcFileOutputStream_AsOutputStream(fos);
+ PARCLogReporter *reporter = parcLogReporterFile_Create(pos);
+
+ Logger *logger = logger_Create(reporter, parcClock_Wallclock());
+
+ parcOutputStream_Release(&pos);
+ parcLogReporter_Release(&reporter);
+
+ return logger;
+}
+
+int main(int argc, const char *argv[]) {
+ _displayForwarderLogo();
+
+ uint16_t port = PORT_NUMBER;
+ uint16_t configurationPort = 2001;
+ bool daemon = false;
+ int capacity = -1;
+ const char *configFileName = NULL;
+
+ char *logfile = NULL;
+
+ if (argc == 2 && strcasecmp(argv[1], "-h") == 0) {
+ _usage(EXIT_SUCCESS);
+ }
+
+ int logLevelArray[LoggerFacility_END];
+ for (int i = 0; i < LoggerFacility_END; i++) {
+ logLevelArray[i] = -1;
+ }
+
+ for (int i = 0; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ if (strcmp(argv[i], "--config") == 0) {
+ configFileName = argv[i + 1];
+ i++;
+ } else if (strcmp(argv[i], "--port") == 0) {
+ port = atoi(argv[i + 1]);
+ i++;
+ } else if (strcmp(argv[i], "--daemon") == 0) {
+ daemon = true;
+ } else if (strcmp(argv[i], "--capacity") == 0 ||
+ strcmp(argv[i], "-c") == 0) {
+ capacity = atoi(argv[i + 1]);
+ i++;
+ } else if (strcmp(argv[i], "--log") == 0) {
+ _setLogLevel(logLevelArray, argv[i + 1]);
+ i++;
+ } else if (strcmp(argv[i], "--log-file") == 0) {
+ if (logfile) {
+ // error cannot repeat
+ fprintf(stderr, "Cannot specify --log-file more than once\n");
+ _usage(EXIT_FAILURE);
+ }
+
+ logfile = parcMemory_StringDuplicate(argv[i + 1], strlen(argv[i + 1]));
+ i++;
+ } else {
+ _usage(EXIT_FAILURE);
+ }
+ }
+ }
+
+ // set restrictive umask, in case we create any files
+ umask(027);
+
+ if (daemon && (logfile == NULL)) {
+ fprintf(stderr, "Must specify a logfile when running in daemon mode\n");
+ _usage(EXIT_FAILURE);
+ }
+
+ if (daemon) {
+ // inside this call, parent will EXIT_SUCCESS and child will continue
+ _daemonize();
+ }
+
+ Logger *logger = NULL;
+ if (logfile) {
+ logger = _createLogfile(logfile);
+ parcMemory_Deallocate((void **)&logfile);
+ } else {
+ PARCLogReporter *stdoutReporter = parcLogReporterTextStdout_Create();
+ logger = logger_Create(stdoutReporter, parcClock_Wallclock());
+ parcLogReporter_Release(&stdoutReporter);
+ }
+
+ for (int i = 0; i < LoggerFacility_END; i++) {
+ if (logLevelArray[i] > -1) {
+ logger_SetLogLevel(logger, i, logLevelArray[i]);
+ }
+ }
+
+ // this will update the clock to the tick clock
+ Forwarder *forwarder = forwarder_Create(logger);
+
+ Configuration *configuration = forwarder_GetConfiguration(forwarder);
+
+ if (capacity > -1) {
+ configuration_SetObjectStoreSize(configuration, capacity);
+ }
+
+ if (configFileName) {
+ forwarder_SetupAllListeners(forwarder, port, NULL);
+ forwarder_SetupFromConfigFile(forwarder, configFileName);
+ } else {
+ // NULL to not setup AF_UNIX
+ forwarder_SetupAllListeners(forwarder, port, NULL);
+ }
+
+ Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder);
+
+ logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Alert, "daemon",
+ "hicn-light running port %d configuration-port %d", port,
+ configurationPort);
+
+ dispatcher_Run(dispatcher);
+
+ logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Alert, "daemon",
+ "hicn-light exiting port %d", port);
+
+ forwarder_Destroy(&forwarder);
+
+ sleep(2);
+
+ logger_Release(&logger);
+ return 0;
+}
diff --git a/hicn-light/src/config.h.in b/hicn-light/src/config.h.in
new file mode 100755
index 000000000..16ec1ab3a
--- /dev/null
+++ b/hicn-light/src/config.h.in
@@ -0,0 +1,5 @@
+/* CPU Cache line size */
+#define LEVEL1_DCACHE_LINESIZE @LEVEL1_DCACHE_LINESIZE@
+
+#define _GNU_SOURCE
+
diff --git a/hicn-light/src/config/CMakeLists.txt b/hicn-light/src/config/CMakeLists.txt
new file mode 100755
index 000000000..5ce680bfc
--- /dev/null
+++ b/hicn-light/src/config/CMakeLists.txt
@@ -0,0 +1,97 @@
+# 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/configuration.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/commandReturn.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlState.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/configurationFile.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/configurationListeners.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlList.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/configuration.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/configurationFile.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/configurationListeners.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlState.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlList.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeRetx.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/hicn-light/src/config/commandOps.c b/hicn-light/src/config/commandOps.c
new file mode 100755
index 000000000..027c86e0a
--- /dev/null
+++ b/hicn-light/src/config/commandOps.c
@@ -0,0 +1,72 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#ifndef __ANDROID__
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#else
+extern int errno;
+#endif
+#endif
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/commandOps.h>
+#include <src/config/commandParser.h>
+
+CommandOps *commandOps_Create(void *closure, const char *command,
+ void (*init)(CommandParser *parser,
+ CommandOps *ops),
+ CommandReturn (*execute)(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args),
+ void (*destroyer)(CommandOps **opsPtr)) {
+ parcAssertNotNull(command, "Parameter command must be non-null");
+ parcAssertNotNull(execute, "Parameter execute must be non-null");
+ CommandOps *ops = parcMemory_AllocateAndClear(sizeof(CommandOps));
+ parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(CommandOps));
+
+ ops->closure = closure;
+ ops->command = parcMemory_StringDuplicate(command, strlen(command) + 1);
+ ops->init = init;
+ ops->execute = execute;
+ ops->destroyer = destroyer;
+ return ops;
+}
+
+void commandOps_Destroy(CommandOps **opsPtr) {
+ parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null");
+ parcAssertNotNull(*opsPtr,
+ "Parameter opsPtr must dereference to non-null pointer");
+
+ CommandOps *ops = *opsPtr;
+ parcMemory_Deallocate((void **)&(ops->command));
+ // DO NOT call ops->destroyer, we are one!
+ parcMemory_Deallocate((void **)&ops);
+
+ *opsPtr = NULL;
+}
diff --git a/hicn-light/src/config/commandOps.h b/hicn-light/src/config/commandOps.h
new file mode 100755
index 000000000..6428a3ebf
--- /dev/null
+++ b/hicn-light/src/config/commandOps.h
@@ -0,0 +1,126 @@
+/*
+ * 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 command_Ops.h
+ * @brief The function structure defining a CLI command
+ *
+ * The function structure that defines a CLI command. Each command will return
+ * one of these which defines how to run the command.
+ *
+ */
+
+#ifndef command_Ops_h
+#define command_Ops_h
+
+#include <parc/algol/parc_List.h>
+
+#include <src/config/commandReturn.h>
+
+// forward reference
+struct command_parser;
+
+struct command_ops;
+typedef struct command_ops CommandOps;
+
+/**
+ * @typedef CommandOps
+ * @abstract Each command implements a CommandOps
+ * @constant closure is a user-specified pointer for any state the user needs
+ * @constant command The text string of the command, must be the spelled out
+ * string, e.g. "help list routes"
+ * @constant init A function to call to initialize the command at program
+ * startup
+ * @constant execute A function to call to execute the command
+ * @constant destroyer A function to call to release the command
+ * @discussion
+ * Typically, the root of the thee has an Init function that then initilizes
+ * the rest of the tree. For example:
+ *
+ * @code
+ * const CommandOps control_Root = {
+ * .closure = NULL,
+ * .command = "", // empty string for root
+ * .init = control_Root_Init,
+ * .execute = control_Root_Execute
+ * .destroyer = NULL
+ * };
+ * @endcode
+ *
+ * The control_Root_Init function will then begin adding the subtree under root.
+ * For example:
+ *
+ * @code
+ * const CommandOps control_Add = {
+ * .closure = NULL,
+ * .command = "add",
+ * .init = control_Add_Init,
+ * .execute = control_Add_Execute,
+ * .destroyer = NULL
+ * };
+ *
+ * static void
+ * control_Root_Init(ControlState *state, CommandOps *ops)
+ * {
+ * controlState_RegisterCommand(state, &control_Add);
+ * }
+ * @endcode
+ */
+struct command_ops {
+ void *closure;
+ char *command;
+ void (*init)(struct command_parser *parser, CommandOps *ops);
+ CommandReturn (*execute)(struct command_parser *parser, CommandOps *ops,
+ PARCList *args);
+ void (*destroyer)(CommandOps **opsPtr);
+};
+
+/**
+ * A helper function to create the pubically defined CommandOps.
+ *
+ * Retruns allocated memory of the command
+ *
+ * @param [in] command The string is copied
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CommandOps *commandOps_Create(
+ void *closure, const char *command,
+ void (*init)(struct command_parser *parser, CommandOps *ops),
+ CommandReturn (*execute)(struct command_parser *parser, CommandOps *ops,
+ PARCList *args),
+ void (*destroyer)(CommandOps **opsPtr));
+
+/**
+ * De-allocates the memory of the CommandOps and the copied command string
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void commandOps_Destroy(CommandOps **opsPtr);
+#endif // command_Ops_h
diff --git a/hicn-light/src/config/commandParser.c b/hicn-light/src/config/commandParser.c
new file mode 100755
index 000000000..84d273c9d
--- /dev/null
+++ b/hicn-light/src/config/commandParser.c
@@ -0,0 +1,216 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+#include <src/config/commandParser.h>
+
+#ifndef __ANDROID__
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#else
+extern int errno;
+#endif
+#endif
+
+struct command_parser {
+ // key = command, value = CommandOps
+ PARCTreeRedBlack *commandTree;
+ bool debugFlag;
+};
+
+static int _stringCompare(const void *key1, const void *key2) {
+ return strcasecmp((const char *)key1, (const char *)key2);
+}
+
+CommandParser *commandParser_Create(void) {
+ CommandParser *state = parcMemory_AllocateAndClear(sizeof(CommandParser));
+ parcAssertNotNull(state, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(CommandParser));
+
+ state->commandTree = parcTreeRedBlack_Create(_stringCompare, // key compare
+ NULL, // key free
+ NULL, // key copy
+ NULL, // value equals
+ NULL, // value free
+ NULL // value copy
+ );
+ state->debugFlag = false;
+ return state;
+}
+
+void commandParser_Destroy(CommandParser **parserPtr) {
+ CommandParser *parser = *parserPtr;
+
+ // destroy every element if it has a destroyer
+ PARCArrayList *values = parcTreeRedBlack_Values(parser->commandTree);
+ if (values) {
+ for (int i = 0; i < parcArrayList_Size(values); i++) {
+ CommandOps *ops = parcArrayList_Get(values, i);
+ parcTreeRedBlack_Remove(parser->commandTree, ops->command);
+ if (ops->destroyer) {
+ ops->destroyer(&ops);
+ }
+ }
+ parcArrayList_Destroy(&values);
+ }
+
+ parcTreeRedBlack_Destroy(&parser->commandTree);
+
+ parcMemory_Deallocate((void **)&parser);
+ *parserPtr = NULL;
+}
+
+void commandParser_SetDebug(CommandParser *state, bool debugFlag) {
+ state->debugFlag = debugFlag;
+}
+
+bool commandParser_GetDebug(CommandParser *state) { return state->debugFlag; }
+
+void commandParser_RegisterCommand(CommandParser *state, CommandOps *ops) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ parcAssertNotNull(ops->command, "Operation command string must be non-null");
+
+ void *exists = parcTreeRedBlack_Get(state->commandTree, ops->command);
+ parcAssertNull(exists, "Command '%s' already exists in the tree %p\n",
+ ops->command, (void *)exists);
+
+ parcTreeRedBlack_Insert(state->commandTree, (void *)ops->command,
+ (void *)ops);
+
+ // if the command being registered asked for an init function to be called,
+ // call it
+ if (ops->init != NULL) {
+ ops->init(state, ops);
+ }
+}
+
+static PARCList *parseStringIntoTokens(const char *originalString) {
+ PARCList *list =
+ parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction),
+ PARCArrayListAsPARCList);
+
+ char *token;
+
+ char *tofree =
+ parcMemory_StringDuplicate(originalString, strlen(originalString) + 1);
+ char *string = tofree;
+
+ while ((token = strsep(&string, " \t\n")) != NULL) {
+ if (strlen(token) > 0) {
+ parcList_Add(list, strdup(token));
+ }
+ }
+
+ parcMemory_Deallocate((void **)&tofree);
+
+ return list;
+}
+
+/**
+ * Matches the user arguments to available commands, returning the command or
+ * NULL if not found
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static CommandOps *commandParser_MatchCommand(CommandParser *state,
+ PARCList *args) {
+ // Find the longest matching prefix command.
+ // Pretty wildly inefficient
+
+ size_t longest_token_count = 0;
+ char *longest_command = NULL;
+
+ PARCArrayList *commands = parcTreeRedBlack_Keys(state->commandTree);
+ for (int i = 0; i < parcArrayList_Size(commands); i++) {
+ char *command = parcArrayList_Get(commands, i);
+ PARCList *command_tokens = parseStringIntoTokens(command);
+
+ // is it a prefix match?
+ if (parcList_Size(args) >= parcList_Size(command_tokens)) {
+ bool possible_match = true;
+ for (int i = 0; i < parcList_Size(command_tokens) && possible_match;
+ i++) {
+ const char *a = parcList_GetAtIndex(command_tokens, i);
+ const char *b = parcList_GetAtIndex(args, i);
+ if (strncasecmp(a, b, strlen(a) + 1) != 0) {
+ possible_match = false;
+ }
+ }
+
+ if (possible_match &&
+ parcList_Size(command_tokens) > longest_token_count) {
+ longest_token_count = parcList_Size(command_tokens);
+ longest_command = command;
+ }
+ }
+
+ parcList_Release(&command_tokens);
+ }
+
+ parcArrayList_Destroy(&commands);
+
+ if (longest_token_count == 0) {
+ return NULL;
+ } else {
+ CommandOps *ops = parcTreeRedBlack_Get(state->commandTree, longest_command);
+ parcAssertNotNull(ops, "Got null operations for command '%s'\n",
+ longest_command);
+ return ops;
+ }
+}
+
+CommandReturn commandParser_DispatchCommand(CommandParser *state,
+ PARCList *args) {
+ CommandOps *ops = commandParser_MatchCommand(state, args);
+
+ if (ops == NULL) {
+ printf("Command not found.\n");
+ return CommandReturn_Failure;
+ } else {
+ return ops->execute(state, ops, args);
+ }
+}
+
+bool commandParser_ContainsCommand(CommandParser *parser, const char *command) {
+ CommandOps *ops = parcTreeRedBlack_Get(parser->commandTree, command);
+ return (ops != NULL);
+}
diff --git a/hicn-light/src/config/commandParser.h b/hicn-light/src/config/commandParser.h
new file mode 100755
index 000000000..78e19e6e3
--- /dev/null
+++ b/hicn-light/src/config/commandParser.h
@@ -0,0 +1,196 @@
+/*
+ * 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 command_Parser.h
+ * @brief Creates a dictionary of commands and parses a command_line to match
+ * against them
+ *
+ * A user creates individual CommandParserEntry that map a command_line to a
+ * function to execute. The CommandParser then does a longest-matching prefix
+ * match of a command_line to the dictionary of commands and executes the
+ * appropriate command.
+ *
+ */
+
+#ifndef command_parser_h
+#define command_parser_h
+
+#include <src/config/commandOps.h>
+#include <src/config/commandReturn.h>
+
+struct command_parser;
+typedef struct command_parser CommandParser;
+
+/**
+ * controlState_Create
+ *
+ * Creates the global state for the Control program
+ *
+ * @return non-null A command parser
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CommandParser *commandParser_Create(void);
+
+/**
+ * Destroys the control state, closing all network connections
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void commandParser_Destroy(CommandParser **statePtr);
+
+/**
+ * Registers a CommandOps with the system.
+ *
+ * Each command has its complete command prefix in the "command" field.
+ * RegisterCommand will put these command prefixes in to a tree and then match
+ * what a user types against the longest-matching prefix in the tree. If
+ * there's a match, it will call the "execute" function.
+ *
+ * When the parser is destroyed, each command's destroyer function will be
+ * called.
+ *
+ * @param [in] state An allocated ControlState
+ * @param [in] command The command to register with the system
+ *
+ * Example:
+ * @code
+ * static ControlReturn
+ * control_Root_Execute(CommandParser *parser, CommandOps *ops, PARCList
+ * *args)
+ * {
+ * printf("Root Command\n");
+ * return CommandReturn_Success;
+ * }
+ *
+ * static ControlReturn
+ * control_FooBar_Execute(CommandParser *parser, CommandOps *ops, PARCList
+ * *args)
+ * {
+ * printf("Foo Bar Command\n");
+ * return CommandReturn_Success;
+ * }
+ *
+ * const CommandOps control_Root = {
+ * .closure = NULL,
+ * .command = "", // empty string for root
+ * .init = NULL,
+ * .execute = control_Root_Execute
+ * };
+ *
+ * const CommandOps control_FooBar = {
+ * .closure = NULL,
+ * .command = "foo bar", // empty string for root
+ * .init = NULL,
+ * .execute = control_FooBar_Execute
+ * };
+ *
+ * void startup(void)
+ * {
+ * ControlState *state = controlState_Create("happy", "day");
+ * controlState_RegisterCommand(state, control_FooBar);
+ * controlState_RegisterCommand(state, control_Root);
+ *
+ * // this executes "root"
+ * controlState_DispatchCommand(state, "foo");
+ * controlState_Destroy(&state);
+ * }
+ * @endcode
+ */
+void commandParser_RegisterCommand(CommandParser *state, CommandOps *command);
+
+/**
+ * Performs a longest-matching prefix of the args to the command tree
+ *
+ * The command tree is created with controlState_RegisterCommand.
+ *
+ * @param [in] state The allocated ControlState
+ * @param [in] args Each command_line word parsed to the ordered list
+ *
+ * @return CommandReturn_Success the command was successful
+ * @return CommandReturn_Failure the command failed or was not found
+ * @return CommandReturn_Exit the command indicates that the interactive mode
+ * should exit
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CommandReturn commandParser_DispatchCommand(CommandParser *state,
+ PARCList *args);
+
+/**
+ * Sets the Debug mode, which will print out much more information.
+ *
+ * Prints out much more diagnostic information about what hicn-light controller
+ * is doing. yes, you would make a CommandOps to set and unset this :)
+ *
+ * @param [in] debugFlag true means to print debug info, false means to turn it
+ * off
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void commandParser_SetDebug(CommandParser *state, bool debugFlag);
+
+/**
+ * Returns the debug state of ControlState
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool commandParser_GetDebug(CommandParser *state);
+
+/**
+ * Checks if the command is registered
+ *
+ * Checks if the exact command given is registered. This is not a prefix match.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true The command is registered
+ * @return false The command is not registered
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool commandParser_ContainsCommand(CommandParser *parser, const char *command);
+#endif // command_parser_h
diff --git a/hicn-light/src/config/commandReturn.h b/hicn-light/src/config/commandReturn.h
new file mode 100755
index 000000000..16ee93db1
--- /dev/null
+++ b/hicn-light/src/config/commandReturn.h
@@ -0,0 +1,43 @@
+/*
+ * 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 command_Return.h
+ * @brief The return code used by CLI commands
+ *
+ * This return code is used throughout the command parser and command
+ * implementations to indicate success, failure, or if the program should exit.
+ *
+ */
+
+#ifndef command_return_h
+#define command_return_h
+
+/**
+ * @typedef ControlReturn
+ * @abstract A command returns one of (SUCCESS, FAILURE, EXIT)
+ * @constant SUCCESS means the command succeeded
+ * @constant FAILURE indicates failure
+ * @constant EXIT means the command indicated that hicn-light controller should
+ * exit.
+ * @discussion <#Discussion#>
+ */
+typedef enum command_return {
+ CommandReturn_Success, // command returned success
+ CommandReturn_Failure, // command failure
+ CommandReturn_Exit // command indicates program should exit
+} CommandReturn;
+
+#endif // command_return_h
diff --git a/hicn-light/src/config/configuration.c b/hicn-light/src/config/configuration.c
new file mode 100755
index 000000000..cccd60620
--- /dev/null
+++ b/hicn-light/src/config/configuration.c
@@ -0,0 +1,1076 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_String.h>
+
+#include <src/config/configurationListeners.h>
+#include <src/config/symbolicNameTable.h>
+
+#include <src/core/connection.h>
+#include <src/core/connectionTable.h>
+#include <src/core/forwarder.h>
+#include <src/core/system.h>
+#ifdef WITH_MAPME
+#include <src/core/mapMe.h>
+#endif /* WITH_MAPME */
+
+#include <src/io/streamConnection.h>
+
+#include <src/io/hicnTunnel.h>
+#include <src/io/tcpTunnel.h>
+#include <src/io/udpTunnel.h>
+
+#include <parc/algol/parc_Unsigned.h>
+#include <src/io/listener.h> //the listener list
+#include <src/io/listenerSet.h> // needed to print
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+#include <src/utils/address.h>
+
+#define ETHERTYPE 0x0801
+
+struct configuration {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ size_t maximumContentObjectStoreSize;
+
+ // map from prefix (parcString) to strategy (parcString)
+ PARCHashMap *strategy_map;
+
+ // translates between a symblic name and a connection id
+ SymbolicNameTable *symbolicNameTable;
+};
+
+// ========================================================================================
+
+Configuration *configuration_Create(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter hicn-fwd must be non-null");
+ Configuration *config = parcMemory_AllocateAndClear(sizeof(Configuration));
+ parcAssertNotNull(config, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Configuration));
+ config->forwarder = forwarder;
+ config->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ config->maximumContentObjectStoreSize = 100000;
+ config->strategy_map = parcHashMap_Create();
+ config->symbolicNameTable = symbolicNameTable_Create();
+
+ return config;
+}
+
+void configuration_Destroy(Configuration **configPtr) {
+ parcAssertNotNull(configPtr, "Parameter must be non-null double poitner");
+ parcAssertNotNull(*configPtr,
+ "Parameter must dereference to non-null pointer");
+
+ Configuration *config = *configPtr;
+ logger_Release(&config->logger);
+ parcHashMap_Release(&(config->strategy_map));
+ symbolicNameTable_Destroy(&config->symbolicNameTable);
+ parcMemory_Deallocate((void **)&config);
+ *configPtr = NULL;
+}
+
+struct iovec *configuration_ProcessRegisterHIcnPrefix(Configuration *config,
+ struct iovec *request,
+ unsigned ingressId) {
+ header_control_message *header = request[0].iov_base;
+ add_route_command *control = request[1].iov_base;
+
+ bool success = false;
+
+ const char *symbolicOrConnid = control->symbolicOrConnid;
+
+ if (strcmp(symbolicOrConnid, "SELF_ROUTE") == 0) {
+ success = forwarder_AddOrUpdateRoute(config->forwarder, control, ingressId);
+ } else if (utils_IsNumber(symbolicOrConnid)) {
+ // case for connid as input
+ unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL);
+ ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+
+ // check if iconnID present in the fwd table
+ if (connectionTable_FindById(table, connid)) {
+ success = forwarder_AddOrUpdateRoute(config->forwarder, control, connid);
+ } else {
+ logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error, __func__,
+ "ConnID not found, check list connections");
+ // failure
+ }
+
+ } else {
+ // case for symbolic as input: check if symbolic name can be resolved
+ unsigned connid =
+ symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid);
+ // connid = UINT_MAX when symbolicName is not found
+ if (connid != UINT32_MAX) {
+ if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+ PARCLogLevel_Debug)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug,
+ __func__, "Add route resolve name '%s' to connid %u",
+ symbolicOrConnid, connid);
+ }
+
+ success = forwarder_AddOrUpdateRoute(config->forwarder, control, connid);
+
+ } else {
+ if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+ PARCLogLevel_Warning)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Warning,
+ __func__,
+ "Add route symbolic name '%s' could not be resolved",
+ symbolicOrConnid);
+ }
+ // failure
+ }
+ }
+
+ // generate ACK/NACK
+ struct iovec *response;
+
+ if (success) { // ACK
+ response = utils_CreateAck(header, control, sizeof(add_route_command));
+ } else { // NACK
+ response = utils_CreateNack(header, control, sizeof(add_route_command));
+ }
+
+ return response;
+}
+
+struct iovec *configuration_ProcessUnregisterHIcnPrefix(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ remove_route_command *control = request[1].iov_base;
+
+ bool success = false;
+
+ const char *symbolicOrConnid = control->symbolicOrConnid;
+
+ if (utils_IsNumber(symbolicOrConnid)) {
+ // case for connid as input
+ unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL);
+ ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+
+ // check if interface index present in the fwd table
+ if (connectionTable_FindById(table, connid)) {
+ success = forwarder_RemoveRoute(config->forwarder, control, connid);
+ } else {
+ logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error, __func__,
+ "ConnID not found, check list connections");
+ // failure
+ }
+
+ } else {
+ // case for symbolic as input: chech if symbolic name can be resolved
+ unsigned connid =
+ symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid);
+ // connid = UINT_MAX when symbolicName is not found
+ if (connid != UINT32_MAX) {
+ if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+ PARCLogLevel_Debug)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug,
+ __func__, "Remove route resolve name '%s' to connid %u",
+ symbolicOrConnid, connid);
+ }
+ success = forwarder_RemoveRoute(config->forwarder, control, connid);
+ } else {
+ if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+ PARCLogLevel_Warning)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Warning,
+ __func__,
+ "Remove route symbolic name '%s' could not be resolved",
+ symbolicOrConnid);
+ }
+ // failure
+ }
+ }
+
+ // generate ACK/NACK
+ struct iovec *response;
+
+ if (success) { // ACK
+ response = utils_CreateAck(header, control, sizeof(remove_route_command));
+ } else { // NACK
+ response = utils_CreateNack(header, control, sizeof(remove_route_command));
+ }
+
+ return response;
+}
+
+struct iovec *configuration_ProcessRegistrationList(Configuration *config,
+ struct iovec *request) {
+ FibEntryList *fibList = forwarder_GetFibEntries(config->forwarder);
+
+ size_t payloadSize = fibEntryList_Length(fibList);
+ size_t pointerLocation = 0;
+ struct sockaddr_in tmpAddr;
+ struct sockaddr_in6 tmpAddr6;
+
+ // allocate payload, cast from void* to uint8_t* = bytes granularity
+ uint8_t *payloadResponse =
+ parcMemory_AllocateAndClear(sizeof(list_routes_command) * payloadSize);
+
+ for (size_t i = 0; i < fibEntryList_Length(fibList); i++) {
+ FibEntry *entry = (FibEntry *)fibEntryList_Get(fibList, i);
+ NameBitvector *prefix = name_GetContentName(fibEntry_GetPrefix(entry));
+ const NumberSet *nexthops = fibEntry_GetNexthops(entry);
+
+ if (numberSet_Length(nexthops) > 1) {
+ // payload extended, need reallocate, further entries via nexthops
+ payloadSize = payloadSize + numberSet_Length(nexthops) - 1;
+ payloadResponse = (uint8_t *)parcMemory_Reallocate(
+ payloadResponse, sizeof(list_routes_command) * payloadSize);
+ }
+
+ for (size_t j = 0; j < numberSet_Length(nexthops); j++) {
+ list_routes_command *listRouteCommand =
+ (list_routes_command *)(payloadResponse +
+ (pointerLocation *
+ sizeof(list_routes_command)));
+
+ Address *addressEntry = nameBitvector_ToAddress(prefix);
+ if (addressGetType(addressEntry) == ADDR_INET) {
+ addressGetInet(addressEntry, &tmpAddr);
+ listRouteCommand->addressType = ADDR_INET;
+ listRouteCommand->address.ipv4 = tmpAddr.sin_addr.s_addr;
+ } else if (addressGetType(addressEntry) == ADDR_INET6) {
+ addressGetInet6(addressEntry, &tmpAddr6);
+ listRouteCommand->addressType = ADDR_INET6;
+ listRouteCommand->address.ipv6 = tmpAddr6.sin6_addr;
+ }
+ listRouteCommand->connid = numberSet_GetItem(nexthops, j);
+ listRouteCommand->len = nameBitvector_GetLength(prefix);
+ listRouteCommand->cost = 1; // cost
+
+ pointerLocation++;
+ addressDestroy(&addressEntry);
+ }
+ }
+
+ // send response
+ header_control_message *header = request[0].iov_base;
+ header->messageType = RESPONSE_LIGHT;
+ header->length = payloadSize;
+
+ struct iovec *response =
+ parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+ response[0].iov_base = header;
+ response[0].iov_len = sizeof(header_control_message);
+ response[1].iov_base = payloadResponse;
+ response[1].iov_len = sizeof(list_routes_command) * payloadSize;
+
+ return response;
+}
+
+static void configuration_SendResponse(Configuration *config, struct iovec *msg,
+ unsigned egressId) {
+ ConnectionTable *connectionTable =
+ forwarder_GetConnectionTable(config->forwarder);
+ const Connection *conn = connectionTable_FindById(connectionTable, egressId);
+ parcAssertNotNull(conn,
+ "Got null connection for control message we just received");
+
+ IoOperations *ops = connection_GetIoOperations(conn);
+ streamState_SendCommandResponse(ops, msg);
+}
+
+struct iovec *configuration_ProcessCreateTunnel(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ add_connection_command *control = request[1].iov_base;
+
+ bool success = false;
+ bool exists = true;
+
+ const char *symbolicName = control->symbolic;
+
+ Address *source = NULL;
+ Address *destination = NULL;
+
+ if (!symbolicNameTable_Exists(config->symbolicNameTable, symbolicName)) {
+ if (control->ipType == ADDR_INET) {
+ source =
+ utils_AddressFromInet(&control->localIp.ipv4, &control->localPort);
+ destination =
+ utils_AddressFromInet(&control->remoteIp.ipv4, &control->remotePort);
+ } else if (control->ipType == ADDR_INET6) {
+ source =
+ utils_AddressFromInet6(&control->localIp.ipv6, &control->localPort);
+ destination =
+ utils_AddressFromInet6(&control->remoteIp.ipv6, &control->remotePort);
+ } else {
+ printf("Invalid IP type.\n"); // will generate a Nack
+ }
+
+ AddressPair *pair = addressPair_Create(source, destination);
+ const Connection *conn = connectionTable_FindByAddressPair(
+ forwarder_GetConnectionTable(config->forwarder), pair);
+
+ addressPair_Release(&pair);
+
+ if (conn == NULL) {
+ // the connection does not exists (even without a name)
+ exists = false;
+ }
+ }
+
+ if (!exists) {
+ IoOperations *ops = NULL;
+ switch (control->connectionType) {
+ case TCP_CONN:
+ // logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+ // __func__,
+ // "Unsupported tunnel protocol: TCP");
+ ops = tcpTunnel_Create(config->forwarder, source, destination);
+ break;
+ case UDP_CONN:
+ ops = udpTunnel_Create(config->forwarder, source, destination);
+ break;
+ case GRE_CONN:
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+ __func__, "Unsupported tunnel protocol: GRE");
+ break;
+#ifndef __APPLE__
+ case HICN_CONN:
+ ops = hicnTunnel_Create(config->forwarder, source, destination);
+ break;
+#endif /* __APPLE__ */
+ default:
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+ __func__, "Unsupported tunnel protocol: %d",
+ control->connectionType);
+ break;
+ }
+
+ if (ops != NULL) {
+ Connection *conn = connection_Create(ops);
+
+ connectionTable_Add(forwarder_GetConnectionTable(config->forwarder),
+ conn);
+ symbolicNameTable_Add(config->symbolicNameTable, symbolicName,
+ connection_GetConnectionId(conn));
+
+ success = true;
+
+ } else {
+ printf("failed, could not create IoOperations");
+ }
+
+ } else {
+ printf("failed, symbolic name or connextion already exist\n");
+ }
+
+ addressDestroy(&source);
+ addressDestroy(&destination);
+
+ // generate ACK/NACK
+ struct iovec *response;
+
+ if (success) { // ACK
+ response = utils_CreateAck(header, control, sizeof(add_connection_command));
+ } else { // NACK
+ response =
+ utils_CreateNack(header, control, sizeof(add_connection_command));
+ }
+
+ return response;
+}
+
+/**
+ * Add an IP-based tunnel.
+ *
+ * The call cal fail if the symbolic name is a duplicate. It could also fail if
+ * there's an problem creating the local side of the tunnel (i.e. the local
+ * socket address is not usable).
+ *
+ * @return true Tunnel added
+ * @return false Tunnel not added (an error)
+ */
+
+struct iovec *configuration_ProcessRemoveTunnel(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ remove_connection_command *control = request[1].iov_base;
+
+ bool success = false;
+
+ const char *symbolicOrConnid = control->symbolicOrConnid;
+ ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+
+ if (utils_IsNumber(symbolicOrConnid)) {
+ // case for connid as input
+ unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL);
+
+ // check if interface index present in the fwd table
+ //(it was missing and therefore caused a program crash)
+ if (connectionTable_FindById(table, connid)) {
+ // remove connection from the FIB
+ forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid);
+ // remove connection
+ connectionTable_RemoveById(table, connid);
+
+ success = true;
+ } else {
+ logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error, __func__,
+ "ConnID not found, check list connections");
+ // failure
+ }
+
+ } else {
+ // case for symbolic as input
+ // chech if symbolic name can be resolved
+ unsigned connid =
+ symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid);
+ // connid = UINT_MAX when symbolicName is not found
+ if (connid != UINT32_MAX) {
+ if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+ PARCLogLevel_Debug)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug,
+ __func__, "Remove connection resolve name '%s' to connid %u",
+ symbolicOrConnid, connid);
+ }
+
+ // remove connection from the FIB
+ forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid);
+ // remove connection
+ connectionTable_RemoveById(table, connid);
+ // remove connection from symbolicNameTable since we have symbolic input
+ symbolicNameTable_Remove(config->symbolicNameTable, symbolicOrConnid);
+ success = true; // to write
+ } else {
+ if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+ PARCLogLevel_Warning)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+ __func__,
+ "Remove connection symbolic name '%s' could not be resolved",
+ symbolicOrConnid);
+ }
+ // failure
+ }
+ }
+
+ // generate ACK/NACK
+ struct iovec *response;
+
+ if (success) { // ACK
+ response =
+ utils_CreateAck(header, control, sizeof(remove_connection_command));
+ } else { // NACK
+ response =
+ utils_CreateNack(header, control, sizeof(remove_connection_command));
+ }
+
+ return response;
+}
+
+struct iovec *configuration_ProcessConnectionList(Configuration *config,
+ struct iovec *request) {
+ ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+ ConnectionList *connList = connectionTable_GetEntries(table);
+ struct sockaddr_in tmpAddr;
+ struct sockaddr_in6 tmpAddr6;
+
+ // allocate payload, cast from void* to uint8_t* fot bytes granularity
+ uint8_t *payloadResponse = parcMemory_AllocateAndClear(
+ sizeof(list_connections_command) * connectionList_Length(connList));
+
+ for (size_t i = 0; i < connectionList_Length(connList); i++) {
+ // Don't release original, it is not stored
+ Connection *original = connectionList_Get(connList, i);
+
+ const AddressPair *addressPair = connection_GetAddressPair(original);
+ Address *localAddress = addressCopy(addressPair_GetLocal(addressPair));
+ Address *remoteAddress = addressCopy(addressPair_GetRemote(addressPair));
+
+ // Fill payload by shifting and casting at each 'i' step.
+ list_connections_command *listConnectionsCommand =
+ (list_connections_command *)(payloadResponse +
+ (i * sizeof(list_connections_command)));
+
+ // set structure fields
+ listConnectionsCommand->connid = connection_GetConnectionId(original);
+ listConnectionsCommand->state =
+ connection_IsUp(original) ? IFACE_UP : IFACE_DOWN;
+ listConnectionsCommand->connectionData.connectionType =
+ ioOperations_GetConnectionType(connection_GetIoOperations(original));
+
+ if (addressGetType(localAddress) == ADDR_INET &&
+ addressGetType(remoteAddress) == ADDR_INET) {
+ listConnectionsCommand->connectionData.ipType = ADDR_INET;
+
+ // get local port/address
+ addressGetInet(localAddress, &tmpAddr);
+ listConnectionsCommand->connectionData.localPort = tmpAddr.sin_port;
+ listConnectionsCommand->connectionData.localIp.ipv4 =
+ tmpAddr.sin_addr.s_addr;
+ memset(&tmpAddr, 0, sizeof(tmpAddr));
+ // get remote port/address
+ addressGetInet(remoteAddress, &tmpAddr);
+ listConnectionsCommand->connectionData.remotePort = tmpAddr.sin_port;
+ listConnectionsCommand->connectionData.remoteIp.ipv4 =
+ tmpAddr.sin_addr.s_addr;
+
+ } else if (addressGetType(localAddress) == ADDR_INET6 &&
+ addressGetType(remoteAddress) == ADDR_INET6) {
+ listConnectionsCommand->connectionData.ipType = ADDR_INET6;
+
+ // get local port/address
+ addressGetInet6(localAddress, &tmpAddr6);
+ listConnectionsCommand->connectionData.localPort = tmpAddr6.sin6_port;
+ listConnectionsCommand->connectionData.localIp.ipv6 = tmpAddr6.sin6_addr;
+ memset(&tmpAddr6, 0, sizeof(tmpAddr6));
+ // get remote port/address
+ addressGetInet6(remoteAddress, &tmpAddr6);
+ listConnectionsCommand->connectionData.remotePort = tmpAddr6.sin6_port;
+ listConnectionsCommand->connectionData.remoteIp.ipv6 = tmpAddr6.sin6_addr;
+
+ } // no need further else, control on the addressed already done at the
+ // time of insertion in the connection table
+ addressDestroy(&localAddress);
+ addressDestroy(&remoteAddress);
+ }
+
+ // send response
+ header_control_message *header = request[0].iov_base;
+ header->messageType = RESPONSE_LIGHT;
+ header->length = (uint16_t)connectionList_Length(connList);
+
+ struct iovec *response =
+ parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+ response[0].iov_base = header;
+ response[0].iov_len = sizeof(header_control_message);
+ response[1].iov_base = payloadResponse;
+ response[1].iov_len =
+ sizeof(list_connections_command) * connectionList_Length(connList);
+
+ return response;
+}
+
+struct iovec *configuration_ProcessListenersList(Configuration *config,
+ struct iovec *request) {
+ ListenerSet *listenerList = forwarder_GetListenerSet(config->forwarder);
+ struct sockaddr_in tmpAddr;
+ struct sockaddr_in6 tmpAddr6;
+
+ // allocate payload, cast from void* to uint8_t* fot bytes granularity
+ uint8_t *payloadResponse = parcMemory_AllocateAndClear(
+ sizeof(list_listeners_command) * listenerSet_Length(listenerList));
+
+ for (size_t i = 0; i < listenerSet_Length(listenerList); i++) {
+ ListenerOps *listenerEntry = listenerSet_Get(listenerList, i);
+
+ // Fill payload by shifting and casting at each 'i' step.
+ list_listeners_command *listListenersCommand =
+ (list_listeners_command *)(payloadResponse +
+ (i * sizeof(list_listeners_command)));
+
+ listListenersCommand->connid =
+ (uint32_t)listenerEntry->getInterfaceIndex(listenerEntry);
+ listListenersCommand->encapType =
+ (uint8_t)listenerEntry->getEncapType(listenerEntry);
+ if (addressGetType((const Address *)listenerEntry->getListenAddress(
+ listenerEntry)) == ADDR_INET) {
+ addressGetInet(
+ (const Address *)listenerEntry->getListenAddress(listenerEntry),
+ &tmpAddr);
+ listListenersCommand->addressType = ADDR_INET;
+ listListenersCommand->address.ipv4 = tmpAddr.sin_addr.s_addr;
+ listListenersCommand->port = tmpAddr.sin_port;
+ } else if (addressGetType((const Address *)listenerEntry->getListenAddress(
+ listenerEntry)) == ADDR_INET6) {
+ addressGetInet6(
+ (const Address *)listenerEntry->getListenAddress(listenerEntry),
+ &tmpAddr6);
+ listListenersCommand->addressType = ADDR_INET6;
+ listListenersCommand->address.ipv6 = tmpAddr6.sin6_addr;
+ listListenersCommand->port = tmpAddr6.sin6_port;
+ }
+ }
+
+ // send response
+ header_control_message *header = request[0].iov_base;
+ header->messageType = RESPONSE_LIGHT;
+ header->length = (uint16_t)listenerSet_Length(listenerList);
+
+ struct iovec *response =
+ parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+ response[0].iov_base = header;
+ response[0].iov_len = sizeof(header_control_message);
+ response[1].iov_base = payloadResponse;
+ response[1].iov_len =
+ sizeof(list_listeners_command) * listenerSet_Length(listenerList);
+
+ return response;
+}
+
+struct iovec *configuration_ProcessCacheStore(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ ;
+ cache_store_command *control = request[1].iov_base;
+ ;
+
+ bool success = false;
+
+ switch (control->activate) {
+ case ACTIVATE_ON:
+ forwarder_SetChacheStoreFlag(config->forwarder, true);
+ if (forwarder_GetChacheStoreFlag(config->forwarder)) {
+ success = true;
+ }
+ break;
+
+ case ACTIVATE_OFF:
+ forwarder_SetChacheStoreFlag(config->forwarder, false);
+ if (!forwarder_GetChacheStoreFlag(config->forwarder)) {
+ success = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ struct iovec *response;
+ if (success) { // ACK
+ response = utils_CreateAck(header, control, sizeof(cache_store_command));
+ } else { // NACK
+ response = utils_CreateNack(header, control, sizeof(cache_store_command));
+ }
+
+ return response;
+}
+
+struct iovec *configuration_ProcessCacheServe(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ cache_serve_command *control = request[1].iov_base;
+
+ bool success = false;
+
+ switch (control->activate) {
+ case ACTIVATE_ON:
+ forwarder_SetChacheServeFlag(config->forwarder, true);
+ if (forwarder_GetChacheServeFlag(config->forwarder)) {
+ success = true;
+ }
+ break;
+
+ case ACTIVATE_OFF:
+ forwarder_SetChacheServeFlag(config->forwarder, false);
+ if (!forwarder_GetChacheServeFlag(config->forwarder)) {
+ success = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ struct iovec *response;
+ if (success) { // ACK
+ response = utils_CreateAck(header, control, sizeof(cache_store_command));
+ } else { // NACK
+ response = utils_CreateNack(header, control, sizeof(cache_store_command));
+ }
+
+ return response;
+}
+
+struct iovec *configuration_ProcessCacheClear(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+
+ forwarder_ClearCache(config->forwarder);
+
+ struct iovec *response = utils_CreateAck(header, NULL, 0);
+ return response;
+}
+
+size_t configuration_GetObjectStoreSize(Configuration *config) {
+ return config->maximumContentObjectStoreSize;
+}
+
+void _configuration_StoreFwdStrategy(Configuration *config, const char *prefix,
+ strategy_type strategy) {
+ PARCString *prefixStr = parcString_Create(prefix);
+ PARCUnsigned *strategyValue = parcUnsigned_Create((unsigned)strategy);
+ parcHashMap_Put(config->strategy_map, prefixStr, strategyValue);
+ parcUnsigned_Release(&strategyValue);
+ parcString_Release(&prefixStr);
+}
+
+struct iovec *configuration_SetWldr(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ set_wldr_command *control = request[1].iov_base;
+ ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+ Connection *conn = NULL;
+ bool success = false;
+
+ const char *symbolicOrConnid = control->symbolicOrConnid;
+
+ if (utils_IsNumber(symbolicOrConnid)) {
+ // case for connid as input: check if connID present in the fwd table
+ conn = (Connection *)connectionTable_FindById(
+ table, (unsigned)strtold(symbolicOrConnid, NULL));
+ if (conn) {
+ success = true;
+ } else {
+ logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error, __func__,
+ "ConnID not found, check list connections"); // failure
+ }
+ } else {
+ // case for symbolic as input: check if symbolic name can be resolved
+ unsigned connid =
+ symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid);
+ if (connid != UINT32_MAX) {
+ conn = (Connection *)connectionTable_FindById(table, connid);
+ if (conn) {
+ if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+ PARCLogLevel_Debug)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug,
+ __func__, "Set wldr resolve name '%s' to connid %u",
+ symbolicOrConnid, connid);
+ }
+ success = true;
+ }
+ } else {
+ if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+ PARCLogLevel_Warning)) {
+ logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+ __func__, "Symbolic name '%s' could not be resolved",
+ symbolicOrConnid);
+ } // failure
+ }
+ }
+
+ // generate ACK/NACK
+ struct iovec *response;
+
+ if (success) {
+ switch (control->activate) {
+ case ACTIVATE_ON:
+ connection_EnableWldr(conn);
+ response = utils_CreateAck(header, control, sizeof(set_wldr_command));
+ break;
+
+ case ACTIVATE_OFF:
+ connection_DisableWldr(conn);
+ response = utils_CreateAck(header, control, sizeof(set_wldr_command));
+ break;
+
+ default: // received wrong value
+ response = utils_CreateNack(header, control, sizeof(set_wldr_command));
+ break;
+ }
+ } else {
+ response = utils_CreateNack(header, control, sizeof(set_wldr_command));
+ }
+
+ return response;
+}
+
+strategy_type configuration_GetForwardingStrategy(Configuration *config,
+ const char *prefix) {
+ PARCString *prefixStr = parcString_Create(prefix);
+ const unsigned *val = parcHashMap_Get(config->strategy_map, prefixStr);
+ parcString_Release(&prefixStr);
+
+ if (val == NULL) {
+ return LAST_STRATEGY_VALUE;
+ } else {
+ return (strategy_type)*val;
+ }
+}
+
+struct iovec *configuration_SetForwardingStrategy(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ set_strategy_command *control = request[1].iov_base;
+
+ const char *prefix = utils_PrefixLenToString(
+ control->addressType, &control->address, &control->len);
+ strategy_type strategy = control->strategyType;
+ strategy_type existingFwdStrategy =
+ configuration_GetForwardingStrategy(config, prefix);
+
+ if (existingFwdStrategy == LAST_STRATEGY_VALUE ||
+ strategy != existingFwdStrategy) {
+ // means such a new strategy is not present in the hash table or has to be
+ // updated
+ _configuration_StoreFwdStrategy(config, prefix, strategy);
+ Name *hicnPrefix = name_CreateFromAddress(control->addressType,
+ control->address, control->len);
+ forwarder_SetStrategy(config->forwarder, hicnPrefix, strategy);
+ name_Release(&hicnPrefix);
+ }
+
+ struct iovec *response =
+ utils_CreateAck(header, control, sizeof(set_strategy_command));
+
+ return response;
+}
+
+void configuration_SetObjectStoreSize(Configuration *config,
+ size_t maximumObjectCount) {
+ config->maximumContentObjectStoreSize = maximumObjectCount;
+
+ forwarder_SetContentObjectStoreSize(config->forwarder,
+ config->maximumContentObjectStoreSize);
+}
+
+Forwarder *configuration_GetForwarder(const Configuration *config) {
+ return config->forwarder;
+}
+
+Logger *configuration_GetLogger(const Configuration *config) {
+ return config->logger;
+}
+
+struct iovec *configuration_MapMeEnable(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ mapme_activator_command *control = request[1].iov_base;
+ const char *stateString[2] = {"on", "off"};
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_Format(composer,
+ "The mapme enable setting received is: %s",
+ stateString[control->activate]);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ puts(result);
+ parcMemory_Deallocate((void **)&result);
+ parcBufferComposer_Release(&composer);
+
+ struct iovec *response =
+ utils_CreateAck(header, control, sizeof(mapme_activator_command));
+
+ return response;
+}
+
+struct iovec *configuration_MapMeDiscovery(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ mapme_activator_command *control = request[1].iov_base;
+ const char *stateString[2] = {"on", "off"};
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_Format(composer,
+ "The mapme discovery setting received is: %s",
+ stateString[control->activate]);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ puts(result);
+ parcMemory_Deallocate((void **)&result);
+ parcBufferComposer_Release(&composer);
+
+ struct iovec *response =
+ utils_CreateAck(header, control, sizeof(mapme_activator_command));
+
+ return response;
+}
+
+struct iovec *configuration_MapMeTimescale(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ mapme_timing_command *control = request[1].iov_base;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_Format(composer,
+ "The mapme timescale value received is: %u",
+ control->timePeriod);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ puts(result);
+ parcMemory_Deallocate((void **)&result);
+ parcBufferComposer_Release(&composer);
+
+ struct iovec *response =
+ utils_CreateAck(header, control, sizeof(mapme_timing_command));
+
+ return response;
+}
+
+struct iovec *configuration_MapMeRetx(Configuration *config,
+ struct iovec *request) {
+ header_control_message *header = request[0].iov_base;
+ mapme_timing_command *control = request[1].iov_base;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_Format(
+ composer, "The mapme retransmission time value received is: %u",
+ control->timePeriod);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ puts(result);
+ parcMemory_Deallocate((void **)&result);
+ parcBufferComposer_Release(&composer);
+
+ struct iovec *response =
+ utils_CreateAck(header, control, sizeof(mapme_timing_command));
+
+ return response;
+}
+
+// ===========================
+// Main functions that deal with receiving commands, executing them, and sending
+// ACK/NACK
+
+struct iovec *configuration_DispatchCommand(Configuration *config,
+ command_id command,
+ struct iovec *control,
+ unsigned ingressId) {
+ struct iovec *response = NULL;
+
+ switch (command) {
+ case ADD_LISTENER:
+ response = configurationListeners_Add(config, control, ingressId);
+ break;
+
+ case ADD_CONNECTION:
+ response = configuration_ProcessCreateTunnel(config, control);
+ break;
+
+ case LIST_CONNECTIONS:
+ response = configuration_ProcessConnectionList(config, control);
+ break;
+
+ case ADD_ROUTE:
+ response =
+ configuration_ProcessRegisterHIcnPrefix(config, control, ingressId);
+ break;
+
+ case LIST_ROUTES:
+ response = configuration_ProcessRegistrationList(config, control);
+ break;
+
+ case REMOVE_CONNECTION:
+ response = configuration_ProcessRemoveTunnel(config, control);
+ break;
+
+ case REMOVE_ROUTE:
+ response = configuration_ProcessUnregisterHIcnPrefix(config, control);
+ break;
+
+ case CACHE_STORE:
+ response = configuration_ProcessCacheStore(config, control);
+ break;
+
+ case CACHE_SERVE:
+ response = configuration_ProcessCacheServe(config, control);
+ break;
+
+ case CACHE_CLEAR:
+ response = configuration_ProcessCacheClear(config, control);
+ break;
+
+ case SET_STRATEGY:
+ response = configuration_SetForwardingStrategy(config, control);
+ break;
+
+ case SET_WLDR:
+ response = configuration_SetWldr(config, control);
+ break;
+
+ case ADD_PUNTING:
+ response = configurationListeners_AddPunting(config, control, ingressId);
+ break;
+
+ case LIST_LISTENERS:
+ response = configuration_ProcessListenersList(config, control);
+ break;
+
+ case MAPME_ENABLE:
+ response = configuration_MapMeEnable(config, control);
+ break;
+
+ case MAPME_DISCOVERY:
+ response = configuration_MapMeDiscovery(config, control);
+ break;
+
+ case MAPME_TIMESCALE:
+ response = configuration_MapMeTimescale(config, control);
+ break;
+
+ case MAPME_RETX:
+ response = configuration_MapMeRetx(config, control);
+ break;
+
+ default:
+ break;
+ }
+
+ return response;
+}
+
+void configuration_ReceiveCommand(Configuration *config, command_id command,
+ struct iovec *request, unsigned ingressId) {
+ parcAssertNotNull(config, "Parameter config must be non-null");
+ parcAssertNotNull(request, "Parameter request must be non-null");
+ struct iovec *response =
+ configuration_DispatchCommand(config, command, request, ingressId);
+ configuration_SendResponse(config, response, ingressId);
+
+ switch (command) {
+ case LIST_CONNECTIONS:
+ case LIST_ROUTES: // case LIST_INTERFACES: case ETC...:
+ parcMemory_Deallocate(
+ &response[1]
+ .iov_base); // deallocate payload only if generated at fwd side
+ break;
+ default:
+ break;
+ }
+
+ // deallocate received request. It coincides with response[0].iov_base memory
+ // parcMemory_Deallocate(&request); //deallocate header and payload (if
+ // same sent by controller)
+ parcMemory_Deallocate(&response); // deallocate iovec pointer
+}
diff --git a/hicn-light/src/config/configuration.h b/hicn-light/src/config/configuration.h
new file mode 100755
index 000000000..2bf66c0b1
--- /dev/null
+++ b/hicn-light/src/config/configuration.h
@@ -0,0 +1,152 @@
+/*
+ * 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 configuration.h
+ * @brief hicn-light configuration, such as in-band commands or CLI
+ *
+ * Manages all user configuration of the system, such as from the CLI or web
+ * interface It remembers the user commands and will be able to write out a
+ * config file.
+ *
+ */
+
+#ifndef configuration_h
+#define configuration_h
+
+#include <src/utils/commands.h>
+#include <src/core/logger.h>
+
+struct configuration;
+typedef struct configuration Configuration;
+
+struct forwarder;
+typedef struct forwarder Forwarder;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Configuration *configuration_Create(Forwarder *forwarder);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void configuration_Destroy(Configuration **configPtr);
+
+void configuration_SetupAllListeners(Configuration *config, uint16_t port,
+ const char *localPath);
+
+void configuration_ReceiveCommand(Configuration *config, command_id command,
+ struct iovec *request, unsigned ingressId);
+
+/**
+ * Returns the configured size of the content store
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t configuration_GetObjectStoreSize(Configuration *config);
+
+/**
+ * Sets the size of the content store (in objects, not bytes)
+ *
+ * Must be set before starting the forwarder
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void configuration_SetObjectStoreSize(Configuration *config,
+ size_t maximumContentObjectCount);
+
+strategy_type configuration_GetForwardingStrategy(Configuration *config,
+ const char *prefix);
+
+/**
+ * Returns the Forwarder that owns the Configuration
+ *
+ * Returns the hicn-light Forwarder. Used primarily by associated classes in
+ * the configuration group.
+ *
+ * @param [in] config An allocated Configuration
+ *
+ * @return non-null The owning Forwarder
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+Forwarder *configuration_GetForwarder(const Configuration *config);
+
+/**
+ * Returns the logger used by the Configuration subsystem
+ *
+ * Returns the logger specified when the Configuration was created.
+ *
+ * @param [in] config An allocated Configuration
+ *
+ * @retval non-null The logger
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Logger *configuration_GetLogger(const Configuration *config);
+
+struct iovec *configuration_DispatchCommand(Configuration *config,
+ command_id command,
+ struct iovec *control,
+ unsigned ingressId);
+
+#endif // configuration_h
diff --git a/hicn-light/src/config/configurationFile.c b/hicn-light/src/config/configurationFile.c
new file mode 100755
index 000000000..eab8f9362
--- /dev/null
+++ b/hicn-light/src/config/configurationFile.c
@@ -0,0 +1,300 @@
+/*
+ * 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 <ctype.h>
+#include <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/configuration.h>
+#include <src/config/configurationFile.h>
+#include <src/config/controlRoot.h>
+#include <src/config/controlState.h>
+
+struct configuration_file {
+ Forwarder *forwarder;
+ const char *filename;
+ FILE *fh;
+
+ size_t linesRead;
+
+ // our custom state machine.
+ ControlState *controlState;
+};
+
+/*
+ * Called by a command to dispatch the correct command
+ */
+struct iovec *_writeRead(ControlState *state, struct iovec *msg) {
+ ConfigurationFile *configFile =
+ (ConfigurationFile *)controlState_GetUserdata(state);
+
+ parcAssertNotNull(msg, "Parameter msg must be non-null");
+ struct iovec *response = configuration_DispatchCommand(
+ forwarder_GetConfiguration(configFile->forwarder),
+ ((header_control_message *)msg[0].iov_base)->commandID, msg, 0);
+
+ return response;
+}
+
+/**
+ * Removes leading whitespace (space + tab).
+ *
+ * If the string is all whitespace, the return value will point to the
+ * terminating '\0'.
+ *
+ * @param [in] str A null-terminated c-string
+ *
+ * @retval non-null A pointer in to string of the first non-whitespace
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static char *_stripLeadingWhitespace(char *str) {
+ while (isspace(*str)) {
+ str++;
+ }
+ return str;
+}
+
+/**
+ * Removes trailing whitespace
+ *
+ * Inserts a NULL after the last non-whitespace character, modiyfing the input
+ * string.
+ *
+ * @param [in] str A null-terminated c-string
+ *
+ * @return non-null A pointer to the input string
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static char *_stripTrailingWhitespace(char *str) {
+ char *p = str + strlen(str) - 1;
+ while (p > str && isspace(*p)) {
+ p--;
+ }
+
+ // cap it. If no whitespace, p+1 == str + strlen(str), so will overwrite the
+ // current null. If all whitespace p+1 == str+1. For an empty string, p+1 =
+ // str.
+ *(p + 1) = 0;
+
+ // this does not catch the case where the entire string is whitespace
+ if (p == str && isspace(*p)) {
+ *p = 0;
+ }
+
+ return str;
+}
+
+/**
+ * Removed leading and trailing whitespace
+ *
+ * Modifies the input string (may add a NULL at the end). Will return
+ * a pointer to the first non-whitespace character or the terminating NULL.
+ *
+ * @param [in] str A null-terminated c-string
+ *
+ * @return non-null A pointer in to the input string
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+static char *_trim(char *str) {
+ return _stripTrailingWhitespace(_stripLeadingWhitespace(str));
+}
+
+/**
+ * Parse a string in to a PARCList with one word per element
+ *
+ * The string passed will be modified by inserting NULLs after each token.
+ *
+ * @param [in] str A c-string (will be modified)
+ *
+ * @retval non-null A PARCList where each item is a single word
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static PARCList *_parseArgs(char *str) {
+ PARCList *list =
+ parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+
+ const char delimiters[] = " \t";
+
+ char *token;
+ while ((token = strsep(&str, delimiters)) != NULL) {
+ parcList_Add(list, token);
+ }
+
+ return list;
+}
+
+// =============================================================
+
+static void _destroy(ConfigurationFile **configFilePtr) {
+ ConfigurationFile *configFile = *configFilePtr;
+ parcMemory_Deallocate((void **)&configFile->filename);
+
+ if (configFile->fh != NULL) {
+ fclose(configFile->fh);
+ }
+
+ controlState_Destroy(&configFile->controlState);
+}
+
+parcObject_ExtendPARCObject(ConfigurationFile, _destroy, NULL, NULL, NULL, NULL,
+ NULL, NULL);
+
+parcObject_ImplementRelease(configurationFile, ConfigurationFile);
+
+ConfigurationFile *configurationFile_Create(Forwarder *forwarder,
+ const char *filename) {
+ parcAssertNotNull(forwarder, "Parameter hicn-fwd must be non-null");
+ parcAssertNotNull(filename, "Parameter filename must be non-null");
+
+ ConfigurationFile *configFile = parcObject_CreateInstance(ConfigurationFile);
+
+ if (configFile) {
+ configFile->linesRead = 0;
+ configFile->forwarder = forwarder;
+ configFile->filename =
+ parcMemory_StringDuplicate(filename, strlen(filename));
+ parcAssertNotNull(configFile->filename, "Could not copy string '%s'",
+ filename);
+
+ // setup the control state for the command parser: last parameter NULL
+ // because
+ // writeRead still not implemented from configuration file.
+ configFile->controlState =
+ controlState_Create(configFile, _writeRead, false);
+
+ // we do not register Help commands
+ controlState_RegisterCommand(configFile->controlState,
+ controlRoot_Create(configFile->controlState));
+
+ // open the file and make sure we can read it
+ configFile->fh = fopen(configFile->filename, "r");
+
+ if (configFile->fh) {
+ if (logger_IsLoggable(forwarder_GetLogger(forwarder),
+ LoggerFacility_Config, PARCLogLevel_Debug)) {
+ logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_Config,
+ PARCLogLevel_Debug, __func__, "Open config file %s",
+ configFile->filename);
+ }
+ } else {
+ if (logger_IsLoggable(forwarder_GetLogger(forwarder),
+ LoggerFacility_Config, PARCLogLevel_Error)) {
+ logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_Config,
+ PARCLogLevel_Error, __func__,
+ "Could not open config file %s: (%d) %s",
+ configFile->filename, errno, strerror(errno));
+ }
+
+ // failure cleanup the object -- this nulls it so final return null be
+ // NULL
+ configurationFile_Release(&configFile);
+ }
+ }
+ return configFile;
+}
+
+bool configurationFile_Process(ConfigurationFile *configFile) {
+ parcAssertNotNull(configFile, "Parameter configFile must be non-null");
+
+ // default to a "true" return value and only set to false if we encounter an
+ // error.
+ bool success = true;
+
+#define BUFFERLEN 2048
+ char buffer[BUFFERLEN];
+
+ configFile->linesRead = 0;
+
+ // always clear errors and fseek to start of file in case we get called
+ // multiple times.
+ clearerr(configFile->fh);
+ rewind(configFile->fh);
+
+ while (success && fgets(buffer, BUFFERLEN, configFile->fh) != NULL) {
+ configFile->linesRead++;
+
+ char *stripedBuffer = _trim(buffer);
+ if (strlen(stripedBuffer) > 0) {
+ if (stripedBuffer[0] != '#') {
+ // not empty and not a comment
+
+ // _parseArgs will modify the string
+ char *copy =
+ parcMemory_StringDuplicate(stripedBuffer, strlen(stripedBuffer));
+ PARCList *args = _parseArgs(copy);
+ CommandReturn result =
+ controlState_DispatchCommand(configFile->controlState, args);
+
+ // we ignore EXIT from the configuration file
+ if (result == CommandReturn_Failure) {
+ if (logger_IsLoggable(forwarder_GetLogger(configFile->forwarder),
+ LoggerFacility_Config, PARCLogLevel_Error)) {
+ logger_Log(forwarder_GetLogger(configFile->forwarder),
+ LoggerFacility_Config, PARCLogLevel_Error, __func__,
+ "Error on input file %s line %d: %s",
+ configFile->filename, configFile->linesRead,
+ stripedBuffer);
+ }
+ success = false;
+ }
+ parcList_Release(&args);
+ parcMemory_Deallocate((void **)&copy);
+ }
+ }
+ }
+
+ if (ferror(configFile->fh)) {
+ if (logger_IsLoggable(forwarder_GetLogger(configFile->forwarder),
+ LoggerFacility_Config, PARCLogLevel_Error)) {
+ logger_Log(forwarder_GetLogger(configFile->forwarder),
+ LoggerFacility_Config, PARCLogLevel_Error, __func__,
+ "Error on input file %s line %d: (%d) %s",
+ configFile->filename, configFile->linesRead, errno,
+ strerror(errno));
+ }
+ success = false;
+ }
+
+ return success;
+}
diff --git a/hicn-light/src/config/configurationFile.h b/hicn-light/src/config/configurationFile.h
new file mode 100755
index 000000000..54548191d
--- /dev/null
+++ b/hicn-light/src/config/configurationFile.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 configurationFile.h
+ * @brief Accepts a filename and provides a means to read it into Configuration
+ *
+ * Reads a configuration file and converts the lines in to configuration
+ * commands for use in Configuration.
+ *
+ * Accepts '#' lines as comments. Skips blank and whitespace-only lines.
+ *
+ */
+
+#ifndef configurationFile_h
+#define configurationFile_h
+
+#include <src/core/forwarder.h>
+
+struct configuration_file;
+typedef struct configuration_file ConfigurationFile;
+
+/**
+ * Creates a ConfigurationFile to prepare to process the file
+ *
+ * Prepares the object and opens the file. Makes sure we can read the file.
+ * Does not read the file or process any commands from the file.
+ *
+ * @param [in] hicn-light An allocated Forwarder to configure with the file
+ * @param [in] filename The file to use
+ *
+ * @retval non-null An allocated ConfigurationFile that is readable
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ConfigurationFile *configurationFile_Create(Forwarder *forwarder,
+ const char *filename);
+
+/**
+ * Reads the configuration file line-by-line and issues commands to
+ * Configuration
+ *
+ * Reads the file line by line. Skips '#' and blank lines.
+ *
+ * Will stop on the first error. Lines already processed will not be un-done.
+ *
+ * @param [in] configFile An allocated ConfigurationFile
+ *
+ * @retval true The entire files was processed without error.
+ * @retval false There was an error in the file.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool configurationFile_Process(ConfigurationFile *configFile);
+
+// void configurationFile_ProcessForwardingStrategies(Configuration * config,
+// ConfigurationFile * configFile);
+
+/**
+ * Closes the underlying file and releases memory
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in,out] configFilePtr An allocated ConfigurationFile that will be
+ * NULL'd as output
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void configurationFile_Release(ConfigurationFile **configFilePtr);
+
+#endif /* defined(configurationFile_h) */
diff --git a/hicn-light/src/config/configurationListeners.c b/hicn-light/src/config/configurationListeners.c
new file mode 100755
index 000000000..be30e2a49
--- /dev/null
+++ b/hicn-light/src/config/configurationListeners.c
@@ -0,0 +1,535 @@
+/*
+ * 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 <arpa/inet.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/core/system.h>
+#include <src/utils/interfaceSet.h>
+#include <src/utils/punting.h>
+
+#include <src/config/configurationListeners.h>
+#include <src/io/hicnListener.h>
+#include <src/io/tcpListener.h>
+#include <src/io/udpListener.h>
+
+#include <src/utils/addressList.h>
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static bool _setupHIcnListenerOnInet4(Forwarder *forwarder,
+ const char *symbolic, Address *address) {
+ bool success = false;
+#ifndef __APPLE__
+ ListenerOps *ops =
+ hicnListener_CreateInet(forwarder, (char *)symbolic, address);
+ if (ops != NULL) {
+ success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+ parcAssertTrue(success, "Failed to add HIcn listener %s to ListenerSet",
+ symbolic);
+ }
+#endif /* __APPLE__ */
+ return success;
+}
+
+static bool _setupHIcnListenerOnInet6(Forwarder *forwarder,
+ const char *symbolic, Address *address) {
+ bool success = false;
+#ifndef __APPLE__
+ ListenerOps *ops =
+ hicnListener_CreateInet6(forwarder, (char *)symbolic, address);
+ if (ops != NULL) {
+ success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+ parcAssertTrue(success, "Failed to add HIcn listener %s to ListenerSet",
+ symbolic);
+ }
+#endif /* __APPLE__ */
+ return success;
+}
+
+bool configurationListeners_Remove(const Configuration *config) {
+ Logger *logger = configuration_GetLogger(config);
+ if (logger_IsLoggable(logger, LoggerFacility_Config, PARCLogLevel_Warning)) {
+ logger_Log(logger, LoggerFacility_Config, PARCLogLevel_Warning, __func__,
+ "Removing a listener not supported: ingress %u control %s");
+ }
+
+ return false;
+}
+
+bool _AddPuntingInet(const Configuration *config, Punting *punting,
+ unsigned ingressId) {
+#ifndef __APPLE__
+ struct sockaddr *addr = parcNetwork_SockAddress("0.0.0.0", 1234);
+ if (addr == NULL) {
+ printf("Error creating address\n");
+ return false;
+ }
+
+ Address *fakeAddr = addressCreateFromInet((struct sockaddr_in *)addr);
+
+ ListenerOps *listenerOps = listenerSet_Find(
+ forwarder_GetListenerSet(configuration_GetForwarder(config)), ENCAP_HICN,
+ fakeAddr);
+ addressDestroy(&fakeAddr);
+
+ if (listenerOps == NULL) {
+ printf("the main listener (IPV4) does not exists\n");
+ return false;
+ }
+
+ struct sockaddr_in puntingAddr;
+
+ Address *address = puntingGetAddress(punting);
+ if (address == NULL) return false;
+
+ bool res = addressGetInet(address, &puntingAddr);
+ if (!res) {
+ printf("unable to read the punting address\n");
+ return false;
+ }
+
+ char prefix[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, &(puntingAddr.sin_addr), prefix, INET_ADDRSTRLEN);
+
+ char len[5];
+ sprintf(len, "%d", puntingPrefixLen(punting));
+
+ char *prefixStr =
+ malloc(strlen(prefix) + strlen(len) + 2); //+1 for the zero-terminator
+ if (prefixStr == NULL) {
+ printf("error while create the prefix string\n");
+ return false;
+ }
+ strcpy(prefixStr, prefix);
+ strcat(prefixStr, "/");
+ strcat(prefixStr, len);
+
+ res = hicnListener_Punting(listenerOps, prefixStr);
+ if (!res) {
+ printf("error while adding the punting rule\n");
+ return false;
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool _AddPuntingInet6(const Configuration *config, Punting *punting,
+ unsigned ingressId) {
+#ifndef __APPLE__
+ struct sockaddr *addr = parcNetwork_SockAddress("0::0", 1234);
+ if (addr == NULL) {
+ printf("Error creating address\n");
+ return false;
+ }
+
+ Address *fakeAddr = addressCreateFromInet6((struct sockaddr_in6 *)addr);
+
+ // comments:
+ // EncapType: I use the HIcn encap since the puting is available only for HIcn
+ // listeners LocalAddress: The only listern for which we need punting rules is
+ // the main one, which has no address
+ // so I create a fake empty address. This need to be consistent
+ // with the address set at creation time
+
+ ListenerOps *listenerOps = listenerSet_Find(
+ forwarder_GetListenerSet(configuration_GetForwarder(config)), ENCAP_HICN,
+ fakeAddr);
+ addressDestroy(&fakeAddr);
+
+ if (listenerOps == NULL) {
+ printf("the main listener does not exists\n");
+ return false;
+ }
+
+ struct sockaddr_in6 puntingAddr;
+ bool res = addressGetInet6(puntingGetAddress(punting), &puntingAddr);
+ if (!res) {
+ printf("unable to read the punting address\n");
+ return false;
+ }
+
+ char prefix[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &(puntingAddr.sin6_addr), prefix, INET6_ADDRSTRLEN);
+
+ char len[5];
+ sprintf(len, "%d", puntingPrefixLen(punting));
+
+ char *prefixStr =
+ malloc(strlen(prefix) + strlen(len) + 2); //+1 for the zero-terminator
+ if (prefixStr == NULL) {
+ printf("error while create the prefix string\n");
+ return false;
+ }
+ strcpy(prefixStr, prefix);
+ strcat(prefixStr, "/");
+ strcat(prefixStr, len);
+
+ res = hicnListener_Punting(listenerOps, prefixStr);
+ if (!res) {
+ printf("error while adding the punting rule\n");
+ return false;
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+//============= LIGHT COMMAN ===============
+
+static bool _addEther(Configuration *config, add_listener_command *control,
+ unsigned ingressId) {
+ // Not implemented
+ return false;
+}
+
+static bool _setupTcpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
+ uint16_t *port) {
+ bool success = false;
+
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = *port;
+ addr.sin_addr.s_addr = *addr4;
+
+ ListenerOps *ops = tcpListener_CreateInet(forwarder, addr);
+ if (ops) {
+ success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+ parcAssertTrue(success, "Failed to add TCP listener on %s to ListenerSet",
+ addressToString(ops->getListenAddress(ops)));
+ }
+ return success;
+}
+
+static bool _setupUdpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
+ uint16_t *port) {
+ bool success = false;
+
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = *port;
+ addr.sin_addr.s_addr = *addr4;
+
+ ListenerOps *ops = udpListener_CreateInet(forwarder, addr);
+ if (ops) {
+ success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+ parcAssertTrue(success, "Failed to add UDP listener on %s to ListenerSet",
+ addressToString(ops->getListenAddress(ops)));
+ }
+ return success;
+}
+
+static bool _setupTcpListenerOnInet6Light(Forwarder *forwarder,
+ ipv6_addr_t *addr6, uint16_t *port,
+ uint32_t scopeId) {
+ bool success = false;
+
+ struct sockaddr_in6 addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = *port;
+ addr.sin6_addr = *addr6;
+ addr.sin6_scope_id = scopeId;
+
+ ListenerOps *ops = tcpListener_CreateInet6(forwarder, addr);
+ if (ops) {
+ success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+ parcAssertTrue(success, "Failed to add TCP6 listener on %s to ListenerSet",
+ addressToString(ops->getListenAddress(ops)));
+ }
+ return success;
+}
+
+static bool _setupUdpListenerOnInet6Light(Forwarder *forwarder,
+ ipv6_addr_t *addr6, uint16_t *port) {
+ bool success = false;
+
+ struct sockaddr_in6 addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = *port;
+ addr.sin6_addr = *addr6;
+ addr.sin6_scope_id = 0;
+
+ ListenerOps *ops = udpListener_CreateInet6(forwarder, addr);
+ if (ops) {
+ success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+ parcAssertTrue(success, "Failed to add UDP6 listener on %s to ListenerSet",
+ addressToString(ops->getListenAddress(ops)));
+ }
+ return success;
+}
+
+bool _addHicn(Configuration *config, add_listener_command *control,
+ unsigned ingressId) {
+ bool success = false;
+ const char *symbolic = control->symbolic;
+ Address *localAddress = NULL;
+
+ switch (control->addressType) {
+ case ADDR_INET: {
+ localAddress =
+ utils_AddressFromInet(&control->address.ipv4, &control->port);
+ success = _setupHIcnListenerOnInet4(configuration_GetForwarder(config),
+ symbolic, localAddress);
+ break;
+ }
+
+ case ADDR_INET6: {
+ localAddress =
+ utils_AddressFromInet6(&control->address.ipv6, &control->port);
+ success = _setupHIcnListenerOnInet6(configuration_GetForwarder(config),
+ symbolic, localAddress);
+ break;
+ }
+
+ default:
+ if (logger_IsLoggable(configuration_GetLogger(config),
+ LoggerFacility_Config, PARCLogLevel_Warning)) {
+ logger_Log(configuration_GetLogger(config), LoggerFacility_Config,
+ PARCLogLevel_Warning, __func__,
+ "Unsupported address type for HICN (ingress id %u): "
+ "must be either IPV4 or IPV6",
+ ingressId);
+ }
+ break;
+ }
+
+ if (success == true && localAddress != NULL) {
+ if (logger_IsLoggable(configuration_GetLogger(config),
+ LoggerFacility_Config, PARCLogLevel_Info)) {
+ logger_Log(configuration_GetLogger(config), LoggerFacility_Config,
+ PARCLogLevel_Info, __func__,
+ "Setup hicn listener on address %s",
+ addressToString(localAddress));
+ }
+ }
+
+ addressDestroy(&localAddress);
+
+ return success;
+}
+
+bool _addIP(Configuration *config, add_listener_command *control,
+ unsigned ingressId) {
+ bool success = false;
+
+ switch (control->addressType) {
+ case ADDR_INET: {
+ 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);
+ }
+ break;
+ }
+
+ case ADDR_INET6: {
+ 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);
+ }
+ break;
+ }
+
+ default:
+ if (logger_IsLoggable(configuration_GetLogger(config),
+ LoggerFacility_Config, PARCLogLevel_Warning)) {
+ char *addrStr = utils_CommandAddressToString(
+ control->addressType, &control->address, &control->port);
+ logger_Log(
+ configuration_GetLogger(config), LoggerFacility_Config,
+ PARCLogLevel_Warning, __func__,
+ "Unsupported address type for IP encapsulation ingress id %u: %s",
+ ingressId, addrStr);
+ parcMemory_Deallocate((void **)&addrStr);
+ }
+ break;
+ }
+
+ if (success) {
+ if (logger_IsLoggable(configuration_GetLogger(config),
+ LoggerFacility_Config, PARCLogLevel_Info)) {
+ char *addrStr = utils_CommandAddressToString(
+ control->addressType, &control->address, &control->port);
+ logger_Log(configuration_GetLogger(config), LoggerFacility_Config,
+ PARCLogLevel_Info, __func__, "Setup listener on address %s",
+ addrStr);
+ parcMemory_Deallocate((void **)&addrStr);
+ }
+ }
+
+ return success;
+}
+
+struct iovec *configurationListeners_Add(Configuration *config,
+ struct iovec *request,
+ unsigned ingressId) {
+ header_control_message *header = request[0].iov_base;
+ add_listener_command *control = request[1].iov_base;
+
+ 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);
+ }
+ }
+
+ // generate ACK/NACK
+ struct iovec *response;
+
+ if (success) { // ACK
+ response = utils_CreateAck(header, control, sizeof(add_listener_command));
+ } else { // NACK
+ response = utils_CreateNack(header, control, sizeof(add_listener_command));
+ }
+
+ return response;
+}
+
+struct iovec *configurationListeners_AddPunting(Configuration *config,
+ struct iovec *request,
+ unsigned ingressId) {
+ header_control_message *header = request[0].iov_base;
+ add_punting_command *control = request[1].iov_base;
+
+ const char *symbolicOrConnid = control->symbolicOrConnid;
+ uint32_t len = control->len;
+ in_port_t port = htons(1234);
+ bool success = false;
+
+ if (control->addressType == ADDR_INET) {
+ Address *address = utils_AddressFromInet(&control->address.ipv4, &port);
+ Punting *punting = puntingCreate(symbolicOrConnid, address, len);
+ success = _AddPuntingInet(config, punting, ingressId);
+ addressDestroy(&address);
+ } else if (control->addressType == ADDR_INET6) {
+ Address *address = utils_AddressFromInet6(&control->address.ipv6, &port);
+ Punting *punting = puntingCreate(symbolicOrConnid, address, len);
+ success = _AddPuntingInet6(config, punting, ingressId);
+ addressDestroy(&address);
+ } else {
+ printf("Invalid IP type.\n"); // will generate a Nack
+ return utils_CreateNack(header, control, sizeof(add_punting_command));
+ }
+
+ // generate ACK/NACK
+ struct iovec *response;
+ if (success) { // ACK
+ response = utils_CreateAck(header, control, sizeof(add_punting_command));
+ } else { // NACK
+ response = utils_CreateNack(header, control, sizeof(add_punting_command));
+ }
+
+ return response;
+}
+
+//=========================== INITIAL LISTENERS ====================
+
+static void _setupListenersOnAddress(Forwarder *forwarder,
+ const Address *address, uint16_t port,
+ const char *interfaceName) {
+ address_type type = addressGetType(address);
+ switch (type) {
+ case ADDR_INET: {
+ struct sockaddr_in tmp;
+ addressGetInet(address, &tmp);
+ _setupTcpListenerOnInet(forwarder, &tmp.sin_addr.s_addr, &port);
+ break;
+ }
+
+ case ADDR_INET6: {
+ struct sockaddr_in6 tmp;
+ addressGetInet6(address, &tmp);
+ _setupTcpListenerOnInet6Light(forwarder, &tmp.sin6_addr, &port,
+ tmp.sin6_scope_id);
+ break;
+ }
+
+ case ADDR_LINK:
+ // not used
+ break;
+
+ default:
+ // dont' know how to handle this, so no listeners
+ break;
+ }
+}
+
+void configurationListeners_SetupAll(const Configuration *config, uint16_t port,
+ const char *localPath) {
+ Forwarder *forwarder = configuration_GetForwarder(config);
+ InterfaceSet *set = system_Interfaces(forwarder);
+
+ size_t interfaceSetLen = interfaceSetLength(set);
+ for (size_t i = 0; i < interfaceSetLen; i++) {
+ Interface *iface = interfaceSetGetByOrdinalIndex(set, i);
+
+ const AddressList *addresses = interfaceGetAddresses(iface);
+ size_t addressListLen = addressListLength(addresses);
+
+ for (size_t j = 0; j < addressListLen; j++) {
+ const Address *address = addressListGetItem(addresses, j);
+
+ // Do not start on link address
+ if (addressGetType(address) != ADDR_LINK) {
+ _setupListenersOnAddress(forwarder, address, htons(port),
+ interfaceGetName(iface));
+ }
+ }
+ }
+
+ // if (localPath != NULL) {
+ // _setupLocalListener(forwarder, localPath);
+ //}
+
+ interfaceSetDestroy(&set);
+}
diff --git a/hicn-light/src/config/configurationListeners.h b/hicn-light/src/config/configurationListeners.h
new file mode 100755
index 000000000..7332b0c64
--- /dev/null
+++ b/hicn-light/src/config/configurationListeners.h
@@ -0,0 +1,62 @@
+/*
+ * 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 configurationListeners.h
+ * @brief Configuration routines related to Listeners
+ *
+ * Adding and removing listeners.
+ *
+ */
+
+#ifndef configurationListeners_h
+#define configurationListeners_h
+
+#include <src/config/configuration.h>
+#include <src/core/forwarder.h>
+
+#include <src/utils/address.h>
+
+/**
+ * Setup udp, tcp, and local listeners
+ *
+ * Will bind to all available IP protocols on the given port.
+ * Does not add Ethernet listeners.
+ *
+ * @param port is the UPD and TCP port to use
+ * @param localPath is the AF_UNIX path to use, if NULL no AF_UNIX listener is
+ * setup
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void configurationListeners_SetupAll(const Configuration *config, uint16_t port,
+ const char *localPath);
+
+bool configurationListeners_Remove(const Configuration *config);
+
+// light functions
+
+struct iovec *configurationListeners_Add(Configuration *config,
+ struct iovec *request,
+ unsigned ingressId);
+
+struct iovec *configurationListeners_AddPunting(Configuration *config,
+ struct iovec *request,
+ unsigned ingressId);
+
+#endif /* defined(configurationListeners_h) */
diff --git a/hicn-light/src/config/controlAdd.c b/hicn-light/src/config/controlAdd.c
new file mode 100755
index 000000000..72f8e9759
--- /dev/null
+++ b/hicn-light/src/config/controlAdd.c
@@ -0,0 +1,94 @@
+/*
+ * 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 <src/config.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlAdd.h>
+#include <src/config/controlAddConnection.h>
+#include <src/config/controlAddListener.h>
+#include <src/config/controlAddPunting.h>
+#include <src/config/controlAddRoute.h>
+
+// ===================================================
+
+static void _controlAdd_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlAdd_Execute(CommandParser *parser, CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlAdd_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+
+// ===================================================
+
+static const char *command_add = "add";
+static const char *help_command_add = "help add";
+
+CommandOps *webControlAdd_Create(ControlState *state) {
+ return commandOps_Create(state, command_add, _controlAdd_Init,
+ _controlAdd_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAdd_CreateHelp(ControlState *state) {
+ return commandOps_Create(state, help_command_add, NULL,
+ _controlAdd_HelpExecute, commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandReturn _controlAdd_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ CommandOps *ops_add_connection = controlAddConnection_Create(NULL);
+ CommandOps *ops_add_route = controlAddRoute_Create(NULL);
+ CommandOps *ops_add_punting = controlAddPunting_Create(NULL);
+ CommandOps *ops_add_listener = controlAddListener_Create(NULL);
+
+ printf("Available commands:\n");
+ printf(" %s\n", ops_add_connection->command);
+ printf(" %s\n", ops_add_route->command);
+ printf(" %s\n", ops_add_punting->command);
+ printf(" %s\n", ops_add_listener->command);
+ printf("\n");
+
+ commandOps_Destroy(&ops_add_connection);
+ commandOps_Destroy(&ops_add_route);
+ commandOps_Destroy(&ops_add_punting);
+ commandOps_Destroy(&ops_add_listener);
+ return CommandReturn_Success;
+}
+
+static void _controlAdd_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+ controlState_RegisterCommand(state, controlAddListener_HelpCreate(state));
+ controlState_RegisterCommand(state, controlAddListener_Create(state));
+ controlState_RegisterCommand(state, controlAddConnection_HelpCreate(state));
+ controlState_RegisterCommand(state, controlAddRoute_HelpCreate(state));
+ controlState_RegisterCommand(state, controlAddConnection_Create(state));
+ controlState_RegisterCommand(state, controlAddRoute_Create(state));
+ controlState_RegisterCommand(state, controlAddPunting_Create(state));
+ controlState_RegisterCommand(state, controlAddPunting_HelpCreate(state));
+}
+
+static CommandReturn _controlAdd_Execute(CommandParser *parser, CommandOps *ops,
+ PARCList *args) {
+ return _controlAdd_HelpExecute(parser, ops, args);
+}
diff --git a/hicn-light/src/config/controlAdd.h b/hicn-light/src/config/controlAdd.h
new file mode 100755
index 000000000..e1955f200
--- /dev/null
+++ b/hicn-light/src/config/controlAdd.h
@@ -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.
+ */
+
+/**
+ * @file control_Add.h
+ * @brief Command-line "add" node
+ *
+ * Implements the "add" node of the CLI tree
+ *
+ *
+ */
+
+#ifndef control_Add_h
+#define control_Add_h
+
+#include <src/config/controlState.h>
+
+CommandOps *webControlAdd_Create(ControlState *state);
+CommandOps *controlAdd_CreateHelp(ControlState *state);
+#endif // control_Add_h
diff --git a/hicn-light/src/config/controlAddConnection.c b/hicn-light/src/config/controlAddConnection.c
new file mode 100755
index 000000000..a0a966ddf
--- /dev/null
+++ b/hicn-light/src/config/controlAddConnection.c
@@ -0,0 +1,390 @@
+/*
+ * 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 <src/config.h>
+
+#include <ctype.h>
+#include <parc/assert/parc_Assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/config/controlAddConnection.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+// ===================================================
+
+static void _controlAddConnection_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlAddConnection_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlAddConnection_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+// ===================================================
+
+static CommandReturn _controlAddConnection_HIcnHelpExecute(
+ CommandParser *parser, CommandOps *ops, PARCList *args);
+static CommandReturn _controlAddConnection_HIcnExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static CommandReturn _controlAddConnection_UdpHelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlAddConnection_UdpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static CommandReturn _controlAddConnection_TcpHelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlAddConnection_TcpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+// ===================================================
+
+static const char *_commandAddConnection = "add connection";
+static const char *_commandAddConnectionHIcn = "add connection hicn";
+static const char *_commandAddConnectionUdp = "add connection udp";
+static const char *_commandAddConnectionTcp = "add connection tcp";
+static const char *_commandAddConnectionHelp = "help add connection";
+static const char *_commandAddConnectionHIcnHelp = "help add connection hicn";
+static const char *_commandAddConnectionUdpHelp = "help add connection udp";
+static const char *_commandAddConnectionTcpHelp = "help add connection tcp";
+
+// ===================================================
+
+CommandOps *controlAddConnection_Create(ControlState *state) {
+ return commandOps_Create(state, _commandAddConnection,
+ _controlAddConnection_Init,
+ _controlAddConnection_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAddConnection_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddConnectionHelp, NULL,
+ _controlAddConnection_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandOps *_controlAddConnection_HIcnCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddConnectionHIcn, NULL,
+ _controlAddConnection_HIcnExecute,
+ commandOps_Destroy);
+}
+
+static CommandOps *_controlAddConnection_UdpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddConnectionUdp, NULL,
+ _controlAddConnection_UdpExecute,
+ commandOps_Destroy);
+}
+
+static CommandOps *_controlAddConnection_TcpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddConnectionTcp, NULL,
+ _controlAddConnection_TcpExecute,
+ commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandOps *_controlAddConnection_HIcnHelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddConnectionHIcnHelp, NULL,
+ _controlAddConnection_HIcnHelpExecute,
+ commandOps_Destroy);
+}
+
+static CommandOps *_controlAddConnection_UdpHelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddConnectionUdpHelp, NULL,
+ _controlAddConnection_UdpHelpExecute,
+ commandOps_Destroy);
+}
+
+static CommandOps *_controlAddConnection_TcpHelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddConnectionTcpHelp, NULL,
+ _controlAddConnection_TcpHelpExecute,
+ commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandReturn _controlAddConnection_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("Available commands:\n");
+ printf(" %s\n", _commandAddConnectionHIcn);
+ printf(" %s\n", _commandAddConnectionUdp);
+ printf(" %s\n", _commandAddConnectionTcp);
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static void _controlAddConnection_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+ controlState_RegisterCommand(state,
+ _controlAddConnection_HIcnHelpCreate(state));
+ controlState_RegisterCommand(state,
+ _controlAddConnection_UdpHelpCreate(state));
+ controlState_RegisterCommand(state,
+ _controlAddConnection_TcpHelpCreate(state));
+
+ controlState_RegisterCommand(state, _controlAddConnection_HIcnCreate(state));
+ controlState_RegisterCommand(state, _controlAddConnection_UdpCreate(state));
+ controlState_RegisterCommand(state, _controlAddConnection_TcpCreate(state));
+}
+
+static CommandReturn _controlAddConnection_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ return _controlAddConnection_HelpExecute(parser, ops, args);
+}
+
+// ===================================================
+// functions general to all connection types
+
+/**
+ * Create a tunnel in the forwarder based on the addresses
+ *
+ * Caller retains ownership of memory.
+ * The symbolic name will be used to refer to this connection. It must be unqiue
+ * otherwise the forwarder will reject this commend.
+ *
+ * @param [in] parser An allocated CommandParser
+ * @param [in] ops Allocated CommandOps (needed to extract ControlState)
+ * @param [in] localAddress the local IP and port. The port may be the wildcard
+ * value.
+ * @param [in] remoteAddress The remote IP and port (both must be specified)
+ * @param [in] tunnelType The tunneling protocol
+ * @param [in] symbolic The symbolic name for the connection (must be unique)
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in *anyAddress = parcNetwork_SockInet4AddressAny();
+ * struct sockaddr_in *remote =
+ * parcNetwork_SockInet4Address("192.168.1.2", 9695);
+ *
+ * Address *localAddress = addressCreateFromInet(anyAddress);
+ * Address *remoteAddress = addressCreateFromInet(remote);
+ *
+ * control_CreateTunnel(state, localAddress, remoteAddress, IPTUN_TCP,
+ * "conn7");
+ *
+ * addressDestroy(&localAddress);
+ * addressDestroy(&remoteAddress);
+ * parcMemory_Deallocate((void **)&remote);
+ * parcMemory_Deallocate((void **)&anyAddress);
+ * }
+ * @endcode
+ */
+
+static CommandReturn _controlAddConnection_CreateTunnel(
+ CommandParser *parser, CommandOps *ops, const char *local_ip,
+ const char *local_port, const char *remote_ip, const char *remote_port,
+ connection_type tunnelType, const char *symbolic) {
+ ControlState *state = ops->closure;
+ // a request like this always has an interface index of 0 [FIELD REMOVED]
+ // unsigned int interfaceIndex = 0;
+
+ // allocate command payload
+ add_connection_command *addConnectionCommand =
+ parcMemory_AllocateAndClear(sizeof(add_connection_command));
+
+ // check and set IP addresses
+ if (inet_pton(AF_INET, remote_ip, &addConnectionCommand->remoteIp.ipv4) ==
+ 1 &&
+ inet_pton(AF_INET, local_ip, &addConnectionCommand->localIp.ipv4) == 1) {
+ addConnectionCommand->ipType = ADDR_INET;
+
+ } else if (inet_pton(AF_INET6, remote_ip,
+ &addConnectionCommand->remoteIp.ipv6) == 1 &&
+ inet_pton(AF_INET6, local_ip,
+ &addConnectionCommand->localIp.ipv6) == 1) {
+ addConnectionCommand->ipType = ADDR_INET6;
+
+ } else {
+ printf("Error: local address %s not same type as remote address %s\n",
+ local_ip, remote_ip);
+ parcMemory_Deallocate(&addConnectionCommand);
+ return CommandReturn_Failure;
+ }
+
+ // Fill remaining payload fields
+ addConnectionCommand->connectionType = tunnelType;
+ strcpy(addConnectionCommand->symbolic, symbolic);
+ addConnectionCommand->remotePort = htons((uint16_t)atoi(remote_port));
+ addConnectionCommand->localPort = htons((uint16_t)atoi(local_port));
+
+ // send message and receive response
+ struct iovec *response =
+ utils_SendRequest(state, ADD_CONNECTION, addConnectionCommand,
+ sizeof(add_connection_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_IpHelp(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args,
+ const char *protocol) {
+ printf("add connection hicn <symbolic> <remote_ip> <local_ip>\n");
+ printf(
+ "add connection udp <symbolic> <remote_ip> <port> <local_ip> <port>\n");
+ printf(
+ " <symbolic> : symbolic name, e.g. 'conn1' (must be "
+ "unique, start with alpha)\n");
+ printf(
+ " <remote_ip> : the IPv4 or IPv6 or hostname of the remote system\n");
+ printf(" <local_ip> : optional local IP address to bind to\n");
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_HIcnHelpExecute(
+ CommandParser *parser, CommandOps *ops, PARCList *args) {
+ _controlAddConnection_IpHelp(parser, ops, args, "hicn");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_HIcnExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ static const int _indexSymbolic = 3;
+ static const int _indexRemAddr = 4;
+ static const int _indexLocAddr = 5;
+
+ if (parcList_Size(args) != 6) {
+ _controlAddConnection_HIcnHelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ char *symbolic = parcList_GetAtIndex(args, _indexSymbolic);
+
+ if (!utils_ValidateSymbolicName(symbolic)) {
+ printf(
+ "Invalid symbolic name. Must begin with alpha and contain only "
+ "alphanum.\n");
+ return CommandReturn_Failure;
+ }
+
+ char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr);
+ char *local_ip = parcList_GetAtIndex(args, _indexLocAddr);
+ char *port = "1234"; // this is a random port number that will be ignored
+
+ return _controlAddConnection_CreateTunnel(
+ parser, ops, local_ip, port, remote_ip, port, HICN_CONN, symbolic);
+}
+
+static CommandReturn _controlAddConnection_UdpHelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ _controlAddConnection_IpHelp(parser, ops, args, "udp");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_UdpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ static const int _indexSymbolic = 3;
+ static const int _indexRemAddr = 4;
+ static const int _indexRemPort = 5;
+ static const int _indexLocAddr = 6;
+ static const int _indexLocPort = 7;
+
+ if (parcList_Size(args) != 8) {
+ _controlAddConnection_UdpHelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ char *symbolic = parcList_GetAtIndex(args, _indexSymbolic);
+
+ if (!utils_ValidateSymbolicName(symbolic)) {
+ printf(
+ "Invalid symbolic name. Must begin with alpha and contain only "
+ "alphanum.\n");
+ return CommandReturn_Failure;
+ }
+
+ char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr);
+ char *local_ip = parcList_GetAtIndex(args, _indexLocAddr);
+
+ char *remote_port = parcList_GetAtIndex(args, _indexRemPort);
+ char *local_port = parcList_GetAtIndex(args, _indexLocPort);
+
+ return _controlAddConnection_CreateTunnel(parser, ops, local_ip, local_port,
+ remote_ip, remote_port, UDP_CONN,
+ symbolic);
+}
+
+static CommandReturn _controlAddConnection_TcpHelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ _controlAddConnection_IpHelp(parser, ops, args, "tcp");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_TcpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ static const int _indexSymbolic = 3;
+ static const int _indexRemAddr = 4;
+ static const int _indexRemPort = 5;
+ static const int _indexLocAddr = 6;
+ static const int _indexLocPort = 7;
+
+ if (parcList_Size(args) != 8) {
+ _controlAddConnection_UdpHelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ char *symbolic = parcList_GetAtIndex(args, _indexSymbolic);
+
+ if (!utils_ValidateSymbolicName(symbolic)) {
+ printf(
+ "Invalid symbolic name. Must begin with alpha and contain only "
+ "alphanum.\n");
+ return CommandReturn_Failure;
+ }
+
+ char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr);
+ char *local_ip = parcList_GetAtIndex(args, _indexLocAddr);
+
+ char *remote_port = parcList_GetAtIndex(args, _indexRemPort);
+ char *local_port = parcList_GetAtIndex(args, _indexLocPort);
+
+ return _controlAddConnection_CreateTunnel(parser, ops, local_ip, local_port,
+ remote_ip, remote_port, TCP_CONN,
+ symbolic);
+}
diff --git a/hicn-light/src/config/controlAddConnection.h b/hicn-light/src/config/controlAddConnection.h
new file mode 100755
index 000000000..788306989
--- /dev/null
+++ b/hicn-light/src/config/controlAddConnection.h
@@ -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.
+ */
+
+/**
+ * @file control_AddConnection.h
+ * @brief Command-line "add connection" node
+ *
+ * Implements the "add connection" node of the CLI tree
+ *
+ *
+ */
+
+#ifndef controlAddConnection_h
+#define controlAddConnection_h
+
+#include <src/config/controlState.h>
+CommandOps *controlAddConnection_Create(ControlState *state);
+CommandOps *controlAddConnection_HelpCreate(ControlState *state);
+#endif // controlAddConnection_h
diff --git a/hicn-light/src/config/controlAddListener.c b/hicn-light/src/config/controlAddListener.c
new file mode 100755
index 000000000..8f687c3a6
--- /dev/null
+++ b/hicn-light/src/config/controlAddListener.c
@@ -0,0 +1,178 @@
+/*
+ * 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 <src/config.h>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/config/controlAddListener.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlAddListener_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlAddListener_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *command_add_listener = "add listener";
+static const char *command_help_add_listener = "help add listener";
+
+CommandOps *controlAddListener_Create(ControlState *state) {
+ return commandOps_Create(state, command_add_listener, NULL,
+ _controlAddListener_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAddListener_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, command_help_add_listener, NULL,
+ _controlAddListener_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static const int _indexProtocol = 2;
+static const int _indexSymbolic = 3;
+static const int _indexAddress = 4;
+static const int _indexPort = 5;
+
+static CommandReturn _controlAddListener_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("commands:\n");
+ printf(" add listener hicn <symbolic> <localAddress> \n");
+ printf(" add listener udp <symbolic> <localAddress> <port> \n");
+ printf(" add listener tcp <symbolic> <localAddress> <port> \n");
+ printf("\n");
+ printf(
+ " symbolic: User defined name for listener, must start with "
+ "alpha and be alphanum\n");
+ printf(" protocol: hicn | udp\n");
+ printf(
+ " localAddress: IPv4 or IPv6 address (or prefix protocol = hicn) "
+ "assigend to the local interface\n");
+ printf(" port: Udp port\n");
+ printf("\n");
+ printf("Notes:\n");
+ printf(" The symblic name must be unique or the source will reject it.\n");
+ printf(
+ " If protocol = hinc: the address 0::0 indicates the main listern, "
+ "for which we can set punting rules.\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops,
+ const char *symbolic, const char *addr,
+ const char *port, listener_mode mode,
+ connection_type type) {
+ ControlState *state = ops->closure;
+
+ // allocate command payload
+ add_listener_command *addListenerCommand =
+ parcMemory_AllocateAndClear(sizeof(add_listener_command));
+
+ // check and set IP address
+ if (inet_pton(AF_INET, addr, &addListenerCommand->address.ipv4) == 1) {
+ addListenerCommand->addressType = ADDR_INET;
+
+ } else if (inet_pton(AF_INET6, addr, &addListenerCommand->address.ipv6) ==
+ 1) {
+ addListenerCommand->addressType = ADDR_INET6;
+
+ } else {
+ printf("Error: %s is not a valid network address \n", addr);
+ parcMemory_Deallocate(&addListenerCommand);
+ return CommandReturn_Failure;
+ }
+
+ // Fill remaining payload fields
+ addListenerCommand->listenerMode = mode;
+ addListenerCommand->connectionType = type;
+ addListenerCommand->port = htons((uint16_t)atoi(port));
+ strcpy(addListenerCommand->symbolic, symbolic);
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(
+ state, ADD_LISTENER, addListenerCommand, sizeof(add_listener_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddListener_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 5 && parcList_Size(args) != 6) {
+ _controlAddListener_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ CommandReturn result = CommandReturn_Failure;
+
+ const char *symbolic = parcList_GetAtIndex(args, _indexSymbolic);
+
+ if (!utils_ValidateSymbolicName(symbolic)) {
+ printf(
+ "Error: symbolic name must begin with an alpha and be alphanum "
+ "after\n");
+ return result;
+ }
+
+ const char *host = parcList_GetAtIndex(args, _indexAddress);
+ const char *protocol = parcList_GetAtIndex(args, _indexProtocol);
+
+ 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.
+ return _CreateListener(parser, ops, symbolic, host, port, HICN_MODE,
+ HICN_CONN);
+ }
+
+ const char *port = parcList_GetAtIndex(args, _indexPort);
+
+ if ((strcasecmp("udp", protocol) == 0)) {
+ return _CreateListener(parser, ops, symbolic, host, port, IP_MODE,
+ UDP_CONN);
+ } else if ((strcasecmp("tcp", protocol) == 0)) {
+ return _CreateListener(parser, ops, symbolic, host, port, IP_MODE,
+ TCP_CONN);
+ } else {
+ _controlAddListener_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ if (result == CommandReturn_Failure) printf("creation failed\n");
+
+ return result;
+}
diff --git a/hicn-light/src/config/controlAddListener.h b/hicn-light/src/config/controlAddListener.h
new file mode 100755
index 000000000..d3fc55aaf
--- /dev/null
+++ b/hicn-light/src/config/controlAddListener.h
@@ -0,0 +1,30 @@
+/*
+ * 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 control_AddListener.h
+ * @brief Add a listener to an interface
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef Control_AddListener_h
+#define Control_AddListener_h
+
+#include <src/config/controlState.h>
+CommandOps *controlAddListener_Create(ControlState *state);
+CommandOps *controlAddListener_HelpCreate(ControlState *state);
+#endif // Control_AddListener_h
diff --git a/hicn-light/src/config/controlAddPunting.c b/hicn-light/src/config/controlAddPunting.c
new file mode 100755
index 000000000..bd87e517c
--- /dev/null
+++ b/hicn-light/src/config/controlAddPunting.c
@@ -0,0 +1,154 @@
+/*
+ * 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <src/utils/punting.h>
+
+#include <src/config/controlAddPunting.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlAddPunting_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlAddPunting_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandAddPunting = "add punting";
+static const char *_commandAddPuntingHelp = "help add punting";
+
+static const int _indexSymbolic = 2;
+static const int _indexPrefix = 3;
+
+CommandOps *controlAddPunting_Create(ControlState *state) {
+ return commandOps_Create(state, _commandAddPunting, NULL,
+ _controlAddPunting_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAddPunting_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddPuntingHelp, NULL,
+ _controlAddPunting_HelpExecute, commandOps_Destroy);
+}
+
+// =====================================================
+
+static CommandReturn _controlAddPunting_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("add punting <symbolic> <prefix>\n");
+ printf(" <symbolic> : listener symbolic name\n");
+ printf(
+ " <address> : prefix to add as a punting rule. (example "
+ "1234::0/64)\n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddPunting_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ ControlState *state = ops->closure;
+
+ if (parcList_Size(args) != 4) {
+ _controlAddPunting_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ const char *symbolicOrConnid = parcList_GetAtIndex(args, _indexSymbolic);
+
+ if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+ !utils_IsNumber(symbolicOrConnid)) {
+ printf(
+ "ERROR: Invalid symbolic or connid:\n"
+ "symbolic name must begin with an alpha followed by alphanum;\nconnid "
+ "must be an integer\n");
+ return CommandReturn_Failure;
+ }
+
+ const char *prefixStr = parcList_GetAtIndex(args, _indexPrefix);
+ char addr[strlen(prefixStr) + 1];
+
+ // separate address and len
+ char *slash;
+ uint32_t len = 0;
+ strcpy(addr, prefixStr);
+ slash = strrchr(addr, '/');
+ if (slash != NULL) {
+ len = atoi(slash + 1);
+ *slash = '\0';
+ }
+
+ if (len == 0) {
+ printf("ERROR: a prefix can not be of length 0\n");
+ return CommandReturn_Failure;
+ }
+
+ // allocate command payload
+ add_punting_command *addPuntingCommand =
+ parcMemory_AllocateAndClear(sizeof(add_punting_command));
+
+ // check and set IP address
+ if (inet_pton(AF_INET, addr, &addPuntingCommand->address.ipv4) == 1) {
+ if (len > 32) {
+ printf("ERROR: exceeded INET mask length, max=32\n");
+ parcMemory_Deallocate(&addPuntingCommand);
+ return CommandReturn_Failure;
+ }
+ addPuntingCommand->addressType = ADDR_INET;
+ } else if (inet_pton(AF_INET6, addr, &addPuntingCommand->address.ipv6) == 1) {
+ if (len > 128) {
+ printf("ERROR: exceeded INET6 mask length, max=128\n");
+ parcMemory_Deallocate(&addPuntingCommand);
+ return CommandReturn_Failure;
+ }
+ addPuntingCommand->addressType = ADDR_INET6;
+ } else {
+ printf("Error: %s is not a valid network address \n", addr);
+ parcMemory_Deallocate(&addPuntingCommand);
+ return CommandReturn_Failure;
+ }
+
+ // Fill remaining payload fields
+ addPuntingCommand->len = len;
+ strcpy(addPuntingCommand->symbolicOrConnid, symbolicOrConnid);
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(
+ state, ADD_PUNTING, addPuntingCommand, sizeof(add_punting_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlAddPunting.h b/hicn-light/src/config/controlAddPunting.h
new file mode 100755
index 000000000..e4d4aac7e
--- /dev/null
+++ b/hicn-light/src/config/controlAddPunting.h
@@ -0,0 +1,22 @@
+/*
+ * 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 controlAddPunting_h
+#define controlAddPunting_h
+
+#include <src/config/controlState.h>
+CommandOps *controlAddPunting_Create(ControlState *state);
+CommandOps *controlAddPunting_HelpCreate(ControlState *state);
+#endif
diff --git a/hicn-light/src/config/controlAddRoute.c b/hicn-light/src/config/controlAddRoute.c
new file mode 100755
index 000000000..c5ddab523
--- /dev/null
+++ b/hicn-light/src/config/controlAddRoute.c
@@ -0,0 +1,157 @@
+/*
+ * 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/config/controlAddRoute.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlAddRoute_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlAddRoute_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandAddRoute = "add route";
+static const char *_commandAddRouteHelp = "help add route";
+
+CommandOps *controlAddRoute_Create(ControlState *state) {
+ return commandOps_Create(state, _commandAddRoute, NULL,
+ _controlAddRoute_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAddRoute_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandAddRouteHelp, NULL,
+ _controlAddRoute_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlAddRoute_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("commands:\n");
+ printf(" add route <symbolic | connid> <prefix> <cost>\n");
+ printf("\n");
+ printf(" symbolic: The symbolic name for an exgress\n");
+ printf(
+ " connid: The egress connection id (see 'help list connections')\n");
+ printf(
+ " prefix: The hicn name as IPv4 or IPv6 address (e.g 1234::0/64)\n");
+ printf(" cost: positive integer representing cost\n");
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddRoute_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ ControlState *state = ops->closure;
+
+ if (parcList_Size(args) != 5) {
+ _controlAddRoute_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ const char *symbolicOrConnid = parcList_GetAtIndex(args, 2);
+
+ if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+ !utils_IsNumber(symbolicOrConnid)) {
+ printf(
+ "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an "
+ "alpha followed by alphanum;\nconnid must be an integer\n");
+ return CommandReturn_Failure;
+ }
+
+ unsigned cost = atoi(parcList_GetAtIndex(args, 4));
+
+ if (cost == 0) {
+ printf("ERROR: cost must be positive integer, got %u from '%s'\n", cost,
+ (char *)parcList_GetAtIndex(args, 4));
+ return CommandReturn_Failure;
+ }
+
+ const char *prefixStr = parcList_GetAtIndex(args, 3);
+ char addr[strlen(prefixStr) + 1];
+
+ // separate address and len
+ char *slash;
+ uint32_t len = 0;
+ strcpy(addr, prefixStr);
+ slash = strrchr(addr, '/');
+ if (slash != NULL) {
+ len = atoi(slash + 1);
+ *slash = '\0';
+ }
+
+ if (len == 0) {
+ printf("ERROR: a prefix can not be of length 0\n");
+ return CommandReturn_Failure;
+ }
+
+ // allocate command payload
+ add_route_command *addRouteCommand =
+ parcMemory_AllocateAndClear(sizeof(add_route_command));
+
+ // check and set IP address
+ if (inet_pton(AF_INET, addr, &addRouteCommand->address.ipv4) == 1) {
+ if (len > 32) {
+ printf("ERROR: exceeded INET mask length, max=32\n");
+ parcMemory_Deallocate(&addRouteCommand);
+ return CommandReturn_Failure;
+ }
+ addRouteCommand->addressType = ADDR_INET;
+ } else if (inet_pton(AF_INET6, addr, &addRouteCommand->address.ipv6) == 1) {
+ if (len > 128) {
+ printf("ERROR: exceeded INET6 mask length, max=128\n");
+ parcMemory_Deallocate(&addRouteCommand);
+ return CommandReturn_Failure;
+ }
+ addRouteCommand->addressType = ADDR_INET6;
+ } else {
+ printf("Error: %s is not a valid network address \n", addr);
+ parcMemory_Deallocate(&addRouteCommand);
+ return CommandReturn_Failure;
+ }
+
+ // Fill remaining payload fields
+ addRouteCommand->len = len;
+ addRouteCommand->cost = (uint16_t)cost;
+ strcpy(addRouteCommand->symbolicOrConnid, symbolicOrConnid);
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(state, ADD_ROUTE, addRouteCommand,
+ sizeof(add_route_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlAddRoute.h b/hicn-light/src/config/controlAddRoute.h
new file mode 100755
index 000000000..be0ad1368
--- /dev/null
+++ b/hicn-light/src/config/controlAddRoute.h
@@ -0,0 +1,30 @@
+/*
+ * 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 control_AddRoute.h
+ * @brief Add a static route
+ *
+ * Implements the "add route" node of the CLI tree
+ *
+ */
+
+#ifndef Control_AddRoute_h
+#define Control_AddRoute_h
+
+#include <src/config/controlState.h>
+CommandOps *controlAddRoute_Create(ControlState *state);
+CommandOps *controlAddRoute_HelpCreate(ControlState *state);
+#endif // Control_AddRoute_h
diff --git a/hicn-light/src/config/controlCache.c b/hicn-light/src/config/controlCache.c
new file mode 100755
index 000000000..d7afbfe7d
--- /dev/null
+++ b/hicn-light/src/config/controlCache.c
@@ -0,0 +1,91 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlCache.h>
+#include <src/config/controlCacheClear.h>
+#include <src/config/controlCacheServe.h>
+#include <src/config/controlCacheStore.h>
+
+static void _controlCache_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlCache_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlCache_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+
+static const char *_commandCache = "cache";
+static const char *_commandCacheHelp = "help cache";
+
+CommandOps *controlCache_Create(ControlState *state) {
+ return commandOps_Create(state, _commandCache, _controlCache_Init,
+ _controlCache_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlCache_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandCacheHelp, NULL,
+ _controlCache_HelpExecute, commandOps_Destroy);
+}
+
+// =====================================================
+
+static CommandReturn _controlCache_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ CommandOps *ops_cache_serve = controlCacheServe_HelpCreate(NULL);
+ CommandOps *ops_cache_store = controlCacheStore_HelpCreate(NULL);
+ CommandOps *ops_cache_clear = controlCacheClear_HelpCreate(NULL);
+
+ printf("Available commands:\n");
+ printf(" %s\n", ops_cache_serve->command);
+ printf(" %s\n", ops_cache_store->command);
+ printf(" %s\n", ops_cache_clear->command);
+ printf("\n");
+
+ commandOps_Destroy(&ops_cache_serve);
+ commandOps_Destroy(&ops_cache_store);
+ commandOps_Destroy(&ops_cache_clear);
+
+ return CommandReturn_Success;
+}
+
+static void _controlCache_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+ controlState_RegisterCommand(state, controlCacheServe_HelpCreate(state));
+ controlState_RegisterCommand(state, controlCacheStore_HelpCreate(state));
+ controlState_RegisterCommand(state, controlCacheClear_HelpCreate(state));
+ controlState_RegisterCommand(state, controlCacheServe_Create(state));
+ controlState_RegisterCommand(state, controlCacheStore_Create(state));
+ controlState_RegisterCommand(state, controlCacheClear_Create(state));
+}
+
+static CommandReturn _controlCache_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ return _controlCache_HelpExecute(parser, ops, args);
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlCache.h b/hicn-light/src/config/controlCache.h
new file mode 100755
index 000000000..a3614fce1
--- /dev/null
+++ b/hicn-light/src/config/controlCache.h
@@ -0,0 +1,22 @@
+/*
+ * 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 controlCache_h
+#define controlCache_h
+
+#include <src/config/controlState.h>
+CommandOps *controlCache_Create(ControlState *state);
+CommandOps *controlCache_HelpCreate(ControlState *state);
+#endif // controlCache_h
diff --git a/hicn-light/src/config/controlCacheClear.c b/hicn-light/src/config/controlCacheClear.c
new file mode 100755
index 000000000..c5a4e9fde
--- /dev/null
+++ b/hicn-light/src/config/controlCacheClear.c
@@ -0,0 +1,84 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlCacheClear.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlCacheClear_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlCacheClear_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandCacheClear = "cache clear";
+static const char *_commandCacheClearHelp = "help cache clear";
+
+// ====================================================
+
+CommandOps *controlCacheClear_Create(ControlState *state) {
+ return commandOps_Create(state, _commandCacheClear, NULL,
+ _controlCacheClear_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlCacheClear_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandCacheClearHelp, NULL,
+ _controlCacheClear_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlCacheClear_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("cache clear\n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlCacheClear_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 2) {
+ _controlCacheClear_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ ControlState *state = ops->closure;
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(state, CACHE_CLEAR, NULL, 0);
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlCacheClear.h b/hicn-light/src/config/controlCacheClear.h
new file mode 100755
index 000000000..348ddba12
--- /dev/null
+++ b/hicn-light/src/config/controlCacheClear.h
@@ -0,0 +1,30 @@
+/*
+ * 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 controlCacheClear.h
+ * @brief Clear the cache
+ *
+ * Removes all the cached data form the local content store (if available)
+ *
+ */
+
+#ifndef Control_CacheClear_h
+#define Control_CacheClear_h
+
+#include <src/config/controlState.h>
+CommandOps *controlCacheClear_Create(ControlState *state);
+CommandOps *controlCacheClear_HelpCreate(ControlState *state);
+#endif // Control_CacheClear_h
diff --git a/hicn-light/src/config/controlCacheServe.c b/hicn-light/src/config/controlCacheServe.c
new file mode 100755
index 000000000..85d598025
--- /dev/null
+++ b/hicn-light/src/config/controlCacheServe.c
@@ -0,0 +1,103 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlCacheServe.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlCacheServe_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlCacheServe_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandCacheServe = "cache serve";
+static const char *_commandCacheServeHelp = "help cache serve";
+
+// ====================================================
+
+CommandOps *controlCacheServe_Create(ControlState *state) {
+ return commandOps_Create(state, _commandCacheServe, NULL,
+ _controlCacheServe_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlCacheServe_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandCacheServeHelp, NULL,
+ _controlCacheServe_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlCacheServe_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("cache serve [on|off]\n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlCacheServe_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 3) {
+ _controlCacheServe_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ bool active;
+ if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+ active = true;
+ } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+ active = false;
+ } else {
+ _controlCacheServe_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ cache_serve_command *cacheServeCommand =
+ parcMemory_AllocateAndClear(sizeof(cache_serve_command));
+ if (active) {
+ cacheServeCommand->activate = ACTIVATE_ON;
+ } else {
+ cacheServeCommand->activate = ACTIVATE_OFF;
+ }
+
+ ControlState *state = ops->closure;
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(
+ state, CACHE_SERVE, cacheServeCommand, sizeof(cache_serve_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlCacheServe.h b/hicn-light/src/config/controlCacheServe.h
new file mode 100755
index 000000000..4bcec51f0
--- /dev/null
+++ b/hicn-light/src/config/controlCacheServe.h
@@ -0,0 +1,22 @@
+/*
+ * 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 Control_CacheServe_h
+#define Control_CacheServe_h
+
+#include <src/config/controlState.h>
+CommandOps *controlCacheServe_Create(ControlState *state);
+CommandOps *controlCacheServe_HelpCreate(ControlState *state);
+#endif // Control_CacheServe_h
diff --git a/hicn-light/src/config/controlCacheStore.c b/hicn-light/src/config/controlCacheStore.c
new file mode 100755
index 000000000..3bbb34386
--- /dev/null
+++ b/hicn-light/src/config/controlCacheStore.c
@@ -0,0 +1,103 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlCacheStore.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlCacheStore_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlCacheStore_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandCacheStore = "cache store";
+static const char *_commandCacheStoreHelp = "help cache store";
+
+// ====================================================
+
+CommandOps *controlCacheStore_Create(ControlState *state) {
+ return commandOps_Create(state, _commandCacheStore, NULL,
+ _controlCacheStore_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlCacheStore_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandCacheStoreHelp, NULL,
+ _controlCacheStore_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlCacheStore_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("cache store [on|off]\n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlCacheStore_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 3) {
+ _controlCacheStore_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ bool active;
+ if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+ active = true;
+ } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+ active = false;
+ } else {
+ _controlCacheStore_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ cache_store_command *cacheStoreCommand =
+ parcMemory_AllocateAndClear(sizeof(cache_store_command));
+ if (active) {
+ cacheStoreCommand->activate = ACTIVATE_ON;
+ } else {
+ cacheStoreCommand->activate = ACTIVATE_OFF;
+ }
+
+ ControlState *state = ops->closure;
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(
+ state, CACHE_STORE, cacheStoreCommand, sizeof(cache_store_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlCacheStore.h b/hicn-light/src/config/controlCacheStore.h
new file mode 100755
index 000000000..ef5aca504
--- /dev/null
+++ b/hicn-light/src/config/controlCacheStore.h
@@ -0,0 +1,22 @@
+/*
+ * 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 Control_CacheStore_h
+#define Control_CacheStore_h
+
+#include <src/config/controlState.h>
+CommandOps *controlCacheStore_Create(ControlState *state);
+CommandOps *controlCacheStore_HelpCreate(ControlState *state);
+#endif // Control_CacheStore_h
diff --git a/hicn-light/src/config/controlList.c b/hicn-light/src/config/controlList.c
new file mode 100755
index 000000000..8afaa60dc
--- /dev/null
+++ b/hicn-light/src/config/controlList.c
@@ -0,0 +1,97 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlList.h>
+#include <src/config/controlListConnections.h>
+//#include <src/config/controlListInterfaces.h>
+#include <src/config/controlListListeners.h>
+#include <src/config/controlListRoutes.h>
+
+static void _controlList_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlList_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlList_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+
+static const char *_commandList = "list";
+static const char *_commandListHelp = "help list";
+
+CommandOps *controlList_Create(ControlState *state) {
+ return commandOps_Create(state, _commandList, _controlList_Init,
+ _controlList_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlList_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandListHelp, NULL,
+ _controlList_HelpExecute, commandOps_Destroy);
+}
+
+// =====================================================
+
+static CommandReturn _controlList_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ CommandOps *ops_list_connections = controlListConnections_HelpCreate(NULL);
+ // CommandOps *ops_list_interfaces = controlListInterfaces_HelpCreate(NULL);
+ CommandOps *ops_list_routes = controlListRoutes_HelpCreate(NULL);
+ CommandOps *ops_list_listeners = controlListListeners_HelpCreate(NULL);
+
+ printf("Available commands:\n");
+ printf(" %s\n", ops_list_connections->command);
+ // printf(" %s\n", ops_list_interfaces->command);
+ printf(" %s\n", ops_list_routes->command);
+ printf(" %s\n", ops_list_listeners->command);
+ printf("\n");
+
+ commandOps_Destroy(&ops_list_connections);
+ // commandOps_Destroy(&ops_list_interfaces);
+ commandOps_Destroy(&ops_list_routes);
+ commandOps_Destroy(&ops_list_listeners);
+
+ return CommandReturn_Success;
+}
+
+static void _controlList_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+ controlState_RegisterCommand(state, controlListConnections_HelpCreate(state));
+ // controlState_RegisterCommand(state,
+ // controlListInterfaces_HelpCreate(state));
+ controlState_RegisterCommand(state, controlListListeners_HelpCreate(state));
+ controlState_RegisterCommand(state, controlListRoutes_HelpCreate(state));
+ controlState_RegisterCommand(state, controlListConnections_Create(state));
+ // controlState_RegisterCommand(state, controlListInterfaces_Create(state));
+ controlState_RegisterCommand(state, controlListRoutes_Create(state));
+ controlState_RegisterCommand(state, controlListListeners_Create(state));
+}
+
+static CommandReturn _controlList_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ return _controlList_HelpExecute(parser, ops, args);
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlList.h b/hicn-light/src/config/controlList.h
new file mode 100755
index 000000000..53197331f
--- /dev/null
+++ b/hicn-light/src/config/controlList.h
@@ -0,0 +1,30 @@
+/*
+ * 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 control_List.h
+ * @brief Root node for the "list" commands
+ *
+ * Implements the "list" node of the CLI tree.
+ *
+ */
+
+#ifndef controlList_h
+#define controlList_h
+
+#include <src/config/controlState.h>
+CommandOps *controlList_Create(ControlState *state);
+CommandOps *controlList_HelpCreate(ControlState *state);
+#endif // controlList_h
diff --git a/hicn-light/src/config/controlListConnections.c b/hicn-light/src/config/controlListConnections.c
new file mode 100755
index 000000000..474ddc45f
--- /dev/null
+++ b/hicn-light/src/config/controlListConnections.c
@@ -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.
+ */
+
+#include <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlListConnections.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlListConnections_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlListConnections_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandListConnections = "list connections";
+static const char *_commandListConnectionsHelp = "help list connections";
+const char *connTypeString[6] = {"GRE", "TCP", "UDP", "MCAST", "L2", "HICN"};
+const char *stateString[3] = {"UP", "DOWN", "UNKNOWN"};
+
+CommandOps *controlListConnections_Create(ControlState *state) {
+ return commandOps_Create(state, _commandListConnections, NULL,
+ _controlListConnections_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlListConnections_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandListConnectionsHelp, NULL,
+ _controlListConnections_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlListConnections_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("list connections: displays a 1-line summary of each connection\n");
+ printf("\n");
+ printf("The columns are:\n");
+ printf(" connection id : an integer index for the connection\n");
+ printf(" state : UP or DOWN\n");
+ printf(
+ " local address : the local network address associated with the "
+ "connection\n");
+ printf(
+ " remote address: the remote network address associated with the "
+ "connection\n");
+ printf(
+ " protocol : the network protocol (tcp, udp, gre, mcast, "
+ "ether)\n");
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlListConnections_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 2) {
+ _controlListConnections_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ ControlState *state = ops->closure;
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(state, LIST_CONNECTIONS, NULL, 0);
+ if (!response) { // get NULL pointer = FAILURE
+ return CommandReturn_Failure;
+ }
+
+ // Process/Print message
+ header_control_message *receivedHeader =
+ (header_control_message *)response[0].iov_base;
+ uint8_t *receivedPayload = (uint8_t *)response[1].iov_base;
+
+ char *sourceString = NULL;
+ char *destinationString = NULL;
+
+ // Allocate output to pass to the main function if the call is not interactive
+ char **commandOutputMain = NULL;
+ if (!controlState_IsInteractive(state) && receivedHeader->length > 0) {
+ commandOutputMain =
+ parcMemory_Allocate(sizeof(char *) * receivedHeader->length);
+ for (size_t j = 0; j < receivedHeader->length; j++) {
+ commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128);
+ }
+ }
+
+ // Process/Print payload
+ for (int i = 0; i < receivedHeader->length; i++) {
+ list_connections_command *listConnectionsCommand =
+ (list_connections_command *)(receivedPayload +
+ (i * sizeof(list_connections_command)));
+
+ sourceString = utils_CommandAddressToString(
+ listConnectionsCommand->connectionData.ipType,
+ &listConnectionsCommand->connectionData.localIp,
+ &listConnectionsCommand->connectionData.localPort);
+
+ destinationString = utils_CommandAddressToString(
+ listConnectionsCommand->connectionData.ipType,
+ &listConnectionsCommand->connectionData.remoteIp,
+ &listConnectionsCommand->connectionData.remotePort);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_Format(
+ composer, "%5d %4s %s %s %s", listConnectionsCommand->connid,
+ stateString[listConnectionsCommand->state], sourceString,
+ destinationString,
+ connTypeString[listConnectionsCommand->connectionData.connectionType]);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ if (!controlState_IsInteractive(state)) {
+ strcpy(commandOutputMain[i], result);
+ }
+
+ puts(result);
+ parcMemory_Deallocate((void **)&result);
+ parcBufferComposer_Release(&composer);
+ }
+
+ controlState_SetCommandOutput(state, commandOutputMain);
+
+ // DEALLOCATE
+ parcMemory_Deallocate((void **)&sourceString);
+ parcMemory_Deallocate((void **)&destinationString);
+ parcMemory_Deallocate(&receivedHeader); // free response[0].iov_base
+ parcMemory_Deallocate(&receivedPayload); // free response[1].iov_base
+ parcMemory_Deallocate(&response); // free iovec pointer
+
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlListConnections.h b/hicn-light/src/config/controlListConnections.h
new file mode 100755
index 000000000..17422c963
--- /dev/null
+++ b/hicn-light/src/config/controlListConnections.h
@@ -0,0 +1,30 @@
+/*
+ * 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 control_ListConnections.h
+ * @brief List the current connections of hicn-light
+ *
+ * Implements the "list connections" node of the CLI tree
+ *
+ */
+
+#ifndef Control_ListConnections_h
+#define Control_ListConnections_h
+
+#include <src/config/controlState.h>
+CommandOps *controlListConnections_Create(ControlState *state);
+CommandOps *controlListConnections_HelpCreate(ControlState *state);
+#endif // Control_ListConnections_h
diff --git a/hicn-light/src/config/controlListInterfaces.c b/hicn-light/src/config/controlListInterfaces.c
new file mode 100755
index 000000000..20338b553
--- /dev/null
+++ b/hicn-light/src/config/controlListInterfaces.c
@@ -0,0 +1,76 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlListInterfaces.h>
+
+static CommandReturn _controlListInterfaces_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlListInterfaces_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandListInterfaces = "list interfaces";
+static const char *_commandListInterfacesHelp = "help list interfaces";
+
+// ====================================================
+
+CommandOps *controlListInterfaces_Create(ControlState *state) {
+ return commandOps_Create(state, _commandListInterfaces, NULL,
+ _controlListInterfaces_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlListInterfaces_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandListInterfacesHelp, NULL,
+ _controlListInterfaces_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlListInterfaces_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("list interfaces\n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlListInterfaces_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 2) {
+ _controlListInterfaces_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ //========================== NOT IMPLEMENTED
+ //===========================
+
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlListInterfaces.h b/hicn-light/src/config/controlListInterfaces.h
new file mode 100755
index 000000000..0c0ca95cf
--- /dev/null
+++ b/hicn-light/src/config/controlListInterfaces.h
@@ -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.
+ */
+
+/**
+ * @file control_ListInterfaces.h
+ * @brief List the icn-light interfaces
+ *
+ * Implements the "list interfaces" and "help list interfaces" nodes of the
+ * command tree
+ *
+ */
+
+#ifndef Control_ListInterfaces_h
+#define Control_ListInterfaces_h
+
+#include <src/config/controlState.h>
+CommandOps *controlListInterfaces_Create(ControlState *state);
+CommandOps *controlListInterfaces_HelpCreate(ControlState *state);
+#endif // Control_ListInterfaces_h
diff --git a/hicn-light/src/config/controlListListeners.c b/hicn-light/src/config/controlListListeners.c
new file mode 100755
index 000000000..a149051e2
--- /dev/null
+++ b/hicn-light/src/config/controlListListeners.c
@@ -0,0 +1,141 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/config/controlListListeners.h>
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlListListeners_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlListListeners_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandListListeners = "list listeners";
+static const char *_commandListListenersHelp = "help list listeners";
+static const char *listenerType[5] = {"TCP", "UDP", "ETHER", "LOCAL", "HICN"};
+
+// ====================================================
+
+CommandOps *controlListListeners_Create(ControlState *state) {
+ return commandOps_Create(state, _commandListListeners, NULL,
+ _controlListListeners_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlListListeners_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandListListenersHelp, NULL,
+ _controlListListeners_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlListListeners_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("list listeners\n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlListListeners_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 2) {
+ _controlListListeners_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ ControlState *state = ops->closure;
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(state, LIST_LISTENERS, NULL, 0);
+ if (!response) { // get NULL pointer = FAILURE
+ return CommandReturn_Failure;
+ }
+
+ // Process/Print message
+ header_control_message *receivedHeader =
+ (header_control_message *)response[0].iov_base;
+ uint8_t *receivedPayload = (uint8_t *)response[1].iov_base;
+
+ // Allocate output to pass to the main function if the call is not interactive
+ char **commandOutputMain = NULL;
+ if (!controlState_IsInteractive(state) && receivedHeader->length > 0) {
+ commandOutputMain =
+ parcMemory_Allocate(sizeof(char *) * receivedHeader->length);
+ for (size_t j = 0; j < receivedHeader->length; j++) {
+ commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128);
+ }
+ }
+
+ char *addrString = NULL;
+ if (receivedHeader->length > 0) {
+ printf("%6.6s %50.70s %s\n", "iface", "address", "type");
+ } else {
+ printf(" --- No entry in the list \n");
+ }
+
+ for (int i = 0; i < receivedHeader->length; i++) {
+ list_listeners_command *listListenersCommand =
+ (list_listeners_command *)(receivedPayload +
+ (i * sizeof(list_listeners_command)));
+
+ addrString = utils_CommandAddressToString(listListenersCommand->addressType,
+ &listListenersCommand->address,
+ &listListenersCommand->port);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_Format(composer, "%6u %50.70s %3s",
+ listListenersCommand->connid, 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);
+ }
+
+ puts(result);
+ parcMemory_Deallocate((void **)&result);
+ parcBufferComposer_Release(&composer);
+ }
+
+ controlState_SetCommandOutput(state, commandOutputMain);
+
+ // DEALLOCATE
+ parcMemory_Deallocate((void **)&addrString);
+ parcMemory_Deallocate(&receivedHeader); // free response[0].iov_base
+ parcMemory_Deallocate(&receivedPayload); // free response[1].iov_base
+ parcMemory_Deallocate(&response); // free iovec pointer
+
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlListListeners.h b/hicn-light/src/config/controlListListeners.h
new file mode 100755
index 000000000..1f34eea56
--- /dev/null
+++ b/hicn-light/src/config/controlListListeners.h
@@ -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.
+ */
+
+/**
+ * @file control_ListListeners.h
+ * @brief List the icn-light listeners
+ *
+ * Implements the "list listeners" and "help list listeners" nodes of the
+ * command tree
+ *
+ */
+
+#ifndef Control_ListListeners_h
+#define Control_ListListeners_h
+
+#include <src/config/controlState.h>
+CommandOps *controlListListeners_Create(ControlState *state);
+CommandOps *controlListListeners_HelpCreate(ControlState *state);
+#endif // Control_ListListeners_h
diff --git a/hicn-light/src/config/controlListRoutes.c b/hicn-light/src/config/controlListRoutes.c
new file mode 100755
index 000000000..4a21b5ef4
--- /dev/null
+++ b/hicn-light/src/config/controlListRoutes.c
@@ -0,0 +1,154 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+
+#include <src/config/controlListRoutes.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlListRoutes_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlListRoutes_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandListRoutes = "list routes";
+static const char *_commandListRoutesHelp = "help list routes";
+
+// ====================================================
+
+CommandOps *controlListRoutes_Create(ControlState *state) {
+ return commandOps_Create(state, _commandListRoutes, NULL,
+ _controlListRoutes_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlListRoutes_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandListRoutesHelp, NULL,
+ _controlListRoutes_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlListRoutes_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("command: list routes\n");
+ printf("\n");
+ printf(
+ "This command will fetch the prefix routing table. For each route, it "
+ "will list:\n");
+ printf(" iface: interface\n");
+ printf(
+ " protocol: the routing protocol, such as STATIC, CONNECTED, etc.\n");
+ printf(
+ " type: LMP or EXACT (longest matching prefix or exact match)\n");
+ printf(" cost: The route cost, lower being preferred\n");
+ printf(" next: List of next hops by interface id\n");
+ printf(" prefix: name prefix\n");
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlListRoutes_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 2) {
+ _controlListRoutes_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ ControlState *state = ops->closure;
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(state, LIST_ROUTES, NULL, 0);
+ if (!response) { // get NULL pointer = FAILURE
+ return CommandReturn_Failure;
+ }
+
+ // Process/Print message
+ header_control_message *receivedHeader =
+ (header_control_message *)response[0].iov_base;
+ uint8_t *receivedPayload = (uint8_t *)response[1].iov_base;
+
+ // Allocate output to pass to the main function if the call is not interactive
+ char **commandOutputMain = NULL;
+ if (!controlState_IsInteractive(state) && receivedHeader->length > 0) {
+ commandOutputMain =
+ parcMemory_Allocate(sizeof(char *) * receivedHeader->length);
+ for (size_t j = 0; j < receivedHeader->length; j++) {
+ commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128);
+ }
+ }
+
+ char *addrString = NULL;
+ in_port_t port = htons(1234); // this is a random port number that is ignored
+
+ if (receivedHeader->length > 0) {
+ printf("%6.6s %8.8s %70.70s %s\n", "iface", "cost", "prefix", "len");
+ } else {
+ printf(" --- No entry in the list \n");
+ }
+
+ for (int i = 0; i < receivedHeader->length; i++) {
+ list_routes_command *listRoutesCommand =
+ (list_routes_command *)(receivedPayload +
+ (i * sizeof(list_routes_command)));
+
+ addrString = utils_CommandAddressToString(
+ listRoutesCommand->addressType, &listRoutesCommand->address, &port);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_Format(
+ composer, "%6u %8u %70.70s %3d", listRoutesCommand->connid,
+ listRoutesCommand->cost, addrString, listRoutesCommand->len);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ if (!controlState_IsInteractive(state)) {
+ strcpy(commandOutputMain[i], result);
+ }
+
+ puts(result);
+ parcMemory_Deallocate((void **)&result);
+ parcBufferComposer_Release(&composer);
+ }
+
+ controlState_SetCommandOutput(state, commandOutputMain);
+
+ // DEALLOCATE
+ parcMemory_Deallocate((void **)&addrString);
+ parcMemory_Deallocate(&receivedHeader); // free response[0].iov_base
+ parcMemory_Deallocate(&receivedPayload); // free response[1].iov_base
+ parcMemory_Deallocate(&response); // free iovec pointer
+
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlListRoutes.h b/hicn-light/src/config/controlListRoutes.h
new file mode 100755
index 000000000..018c88ab0
--- /dev/null
+++ b/hicn-light/src/config/controlListRoutes.h
@@ -0,0 +1,29 @@
+/*
+ * 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 control_ListRoutes.h
+ * @brief List the icn-light routes
+ *
+ * Implements the "list routes" and "help list routes" nodes of the command tree
+ *
+ */
+#ifndef Control_ListRoutes_h
+#define Control_ListRoutes_h
+
+#include <src/config/controlState.h>
+CommandOps *controlListRoutes_Create(ControlState *state);
+CommandOps *controlListRoutes_HelpCreate(ControlState *state);
+#endif // Control_ListRoutes_h
diff --git a/hicn-light/src/config/controlMapMe.c b/hicn-light/src/config/controlMapMe.c
new file mode 100755
index 000000000..2253f52b6
--- /dev/null
+++ b/hicn-light/src/config/controlMapMe.c
@@ -0,0 +1,94 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/config/controlMapMe.h>
+#include <src/config/controlMapMeDiscovery.h>
+#include <src/config/controlMapMeEnable.h>
+#include <src/config/controlMapMeRetx.h>
+#include <src/config/controlMapMeTimescale.h>
+
+static void _controlMapMe_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlMapMe_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlMapMe_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+
+static const char *_commandMapMe = "mapme";
+static const char *_commandMapMeHelp = "help mapme";
+
+CommandOps *controlMapMe_Create(ControlState *state) {
+ return commandOps_Create(state, _commandMapMe, _controlMapMe_Init,
+ _controlMapMe_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMe_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeHelp, NULL,
+ _controlMapMe_HelpExecute, commandOps_Destroy);
+}
+
+// =====================================================
+
+static CommandReturn _controlMapMe_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ CommandOps *ops_mapme_enable = controlMapMeEnable_HelpCreate(NULL);
+ CommandOps *ops_mapme_discovery = controlMapMeDiscovery_HelpCreate(NULL);
+ CommandOps *ops_mapme_timescale = controlMapMeTimescale_HelpCreate(NULL);
+ CommandOps *ops_mapme_retx = controlMapMeRetx_HelpCreate(NULL);
+
+ printf("Available commands:\n");
+ printf(" %s\n", ops_mapme_enable->command);
+ printf(" %s\n", ops_mapme_discovery->command);
+ printf(" %s\n", ops_mapme_timescale->command);
+ printf(" %s\n", ops_mapme_retx->command);
+ printf("\n");
+
+ commandOps_Destroy(&ops_mapme_enable);
+ commandOps_Destroy(&ops_mapme_discovery);
+ commandOps_Destroy(&ops_mapme_timescale);
+ commandOps_Destroy(&ops_mapme_retx);
+
+ return CommandReturn_Success;
+}
+
+static void _controlMapMe_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+ controlState_RegisterCommand(state, controlMapMeEnable_HelpCreate(state));
+ controlState_RegisterCommand(state, controlMapMeDiscovery_HelpCreate(state));
+ controlState_RegisterCommand(state, controlMapMeTimescale_HelpCreate(state));
+ controlState_RegisterCommand(state, controlMapMeRetx_HelpCreate(state));
+ controlState_RegisterCommand(state, controlMapMeEnable_Create(state));
+ controlState_RegisterCommand(state, controlMapMeDiscovery_Create(state));
+ controlState_RegisterCommand(state, controlMapMeTimescale_Create(state));
+ controlState_RegisterCommand(state, controlMapMeRetx_Create(state));
+}
+
+static CommandReturn _controlMapMe_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ return _controlMapMe_HelpExecute(parser, ops, args);
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlMapMe.h b/hicn-light/src/config/controlMapMe.h
new file mode 100755
index 000000000..d9cfdb82c
--- /dev/null
+++ b/hicn-light/src/config/controlMapMe.h
@@ -0,0 +1,22 @@
+/*
+ * 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 controlMapMe_h
+#define controlMapMe_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMe_Create(ControlState *state);
+CommandOps *controlMapMe_HelpCreate(ControlState *state);
+#endif // controlMapMe_h
diff --git a/hicn-light/src/config/controlMapMeDiscovery.c b/hicn-light/src/config/controlMapMeDiscovery.c
new file mode 100755
index 000000000..f8f4bf082
--- /dev/null
+++ b/hicn-light/src/config/controlMapMeDiscovery.c
@@ -0,0 +1,103 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/controlMapMeDiscovery.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlMapMeDiscovery_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlMapMeDiscovery_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandMapMeDiscovery = "mapme discovery";
+static const char *_commandMapMeDiscoveryHelp = "help mapme discovery";
+
+// ====================================================
+
+CommandOps *controlMapMeDiscovery_Create(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeDiscovery, NULL,
+ _controlMapMeDiscovery_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMeDiscovery_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeDiscoveryHelp, NULL,
+ _controlMapMeDiscovery_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlMapMeDiscovery_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("mapme discovery [on|off]\n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlMapMeDiscovery_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 3) {
+ _controlMapMeDiscovery_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ bool active;
+ if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+ active = true;
+ } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+ active = false;
+ } else {
+ _controlMapMeDiscovery_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ mapme_activator_command *mapmeDiscoveryCommand =
+ parcMemory_AllocateAndClear(sizeof(mapme_activator_command));
+ if (active) {
+ mapmeDiscoveryCommand->activate = ACTIVATE_ON;
+ } else {
+ mapmeDiscoveryCommand->activate = ACTIVATE_OFF;
+ }
+
+ ControlState *state = ops->closure;
+ // send message and receive response
+ struct iovec *response =
+ utils_SendRequest(state, MAPME_DISCOVERY, mapmeDiscoveryCommand,
+ sizeof(mapme_activator_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlMapMeDiscovery.h b/hicn-light/src/config/controlMapMeDiscovery.h
new file mode 100755
index 000000000..c492fa0ab
--- /dev/null
+++ b/hicn-light/src/config/controlMapMeDiscovery.h
@@ -0,0 +1,22 @@
+/*
+ * 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 Control_MapMeDiscovery_h
+#define Control_MapMeDiscovery_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMeDiscovery_Create(ControlState *state);
+CommandOps *controlMapMeDiscovery_HelpCreate(ControlState *state);
+#endif // Control_MapMeDiscovery_h
diff --git a/hicn-light/src/config/controlMapMeEnable.c b/hicn-light/src/config/controlMapMeEnable.c
new file mode 100755
index 000000000..db77450e5
--- /dev/null
+++ b/hicn-light/src/config/controlMapMeEnable.c
@@ -0,0 +1,101 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/controlMapMeEnable.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlMapMeEnable_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlMapMeEnable_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandMapMeEnable = "mapme enable";
+static const char *_commandMapMeEnableHelp = "help mapme enable";
+
+// ====================================================
+
+CommandOps *controlMapMeEnable_Create(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeEnable, NULL,
+ _controlMapMeEnable_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMeEnable_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeEnableHelp, NULL,
+ _controlMapMeEnable_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlMapMeEnable_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("mapme enable [on|off]\n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlMapMeEnable_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 3) {
+ _controlMapMeEnable_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ bool active;
+ if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+ active = true;
+ } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+ active = false;
+ } else {
+ _controlMapMeEnable_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ mapme_activator_command *mapmeEnableCommand =
+ parcMemory_AllocateAndClear(sizeof(mapme_activator_command));
+ if (active) {
+ mapmeEnableCommand->activate = ACTIVATE_ON;
+ } else {
+ mapmeEnableCommand->activate = ACTIVATE_OFF;
+ }
+
+ ControlState *state = ops->closure;
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(
+ state, MAPME_ENABLE, mapmeEnableCommand, sizeof(mapme_activator_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlMapMeEnable.h b/hicn-light/src/config/controlMapMeEnable.h
new file mode 100755
index 000000000..f7ca6204d
--- /dev/null
+++ b/hicn-light/src/config/controlMapMeEnable.h
@@ -0,0 +1,22 @@
+/*
+ * 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 Control_MapMeEnable_h
+#define Control_MapMeEnable_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMeEnable_Create(ControlState *state);
+CommandOps *controlMapMeEnable_HelpCreate(ControlState *state);
+#endif // Control_MapMeEnable_h
diff --git a/hicn-light/src/config/controlMapMeRetx.c b/hicn-light/src/config/controlMapMeRetx.c
new file mode 100755
index 000000000..bb16b8833
--- /dev/null
+++ b/hicn-light/src/config/controlMapMeRetx.c
@@ -0,0 +1,94 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/controlMapMeRetx.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlMapMeRetx_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlMapMeRetx_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandMapMeRetx = "mapme retx";
+static const char *_commandMapMeRetxHelp = "help mapme retx";
+
+// ====================================================
+
+CommandOps *controlMapMeRetx_Create(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeRetx, NULL,
+ _controlMapMeRetx_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMeRetx_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeRetxHelp, NULL,
+ _controlMapMeRetx_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlMapMeRetx_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("mapme retx <milliseconds>n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlMapMeRetx_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 3) {
+ _controlMapMeRetx_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ const char *rtx = parcList_GetAtIndex(args, 2);
+ if (!utils_IsNumber(rtx)) {
+ printf(
+ "ERROR: retransmission value (expressed in ms) must be a positive "
+ "integer \n");
+ return CommandReturn_Failure;
+ }
+
+ mapme_timing_command *mapmeRetxCommand =
+ parcMemory_AllocateAndClear(sizeof(mapme_timing_command));
+ mapmeRetxCommand->timePeriod = (unsigned)strtold(rtx, NULL);
+
+ ControlState *state = ops->closure;
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(
+ state, MAPME_RETX, mapmeRetxCommand, sizeof(mapme_timing_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlMapMeRetx.h b/hicn-light/src/config/controlMapMeRetx.h
new file mode 100755
index 000000000..611bd3663
--- /dev/null
+++ b/hicn-light/src/config/controlMapMeRetx.h
@@ -0,0 +1,22 @@
+/*
+ * 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 Control_MapMeRetx_h
+#define Control_MapMeRetx_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMeRetx_Create(ControlState *state);
+CommandOps *controlMapMeRetx_HelpCreate(ControlState *state);
+#endif // Control_MapMeRetx_h
diff --git a/hicn-light/src/config/controlMapMeTimescale.c b/hicn-light/src/config/controlMapMeTimescale.c
new file mode 100755
index 000000000..9303b4b0f
--- /dev/null
+++ b/hicn-light/src/config/controlMapMeTimescale.c
@@ -0,0 +1,97 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/controlMapMeTimescale.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlMapMeTimescale_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlMapMeTimescale_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandMapMeTimescale = "mapme timescale";
+static const char *_commandMapMeTimescaleHelp = "help mapme timescale";
+
+// ====================================================
+
+CommandOps *controlMapMeTimescale_Create(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeTimescale, NULL,
+ _controlMapMeTimescale_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMeTimescale_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandMapMeTimescaleHelp, NULL,
+ _controlMapMeTimescale_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlMapMeTimescale_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("mapme timescale <milliseconds>n");
+ printf("\n");
+
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlMapMeTimescale_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 3) {
+ _controlMapMeTimescale_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ const char *ts = parcList_GetAtIndex(args, 2);
+ if (!utils_IsNumber(ts)) {
+ printf(
+ "ERROR: timescale value (expressed in ms) must be a positive integer "
+ "\n");
+ return CommandReturn_Failure;
+ }
+
+ mapme_timing_command *mapmeTimescaleCommand =
+ parcMemory_AllocateAndClear(sizeof(mapme_timing_command));
+ mapmeTimescaleCommand->timePeriod = (unsigned)strtold(ts, NULL);
+
+ ControlState *state = ops->closure;
+ // send message and receive response
+ struct iovec *response =
+ utils_SendRequest(state, MAPME_TIMESCALE, mapmeTimescaleCommand,
+ sizeof(mapme_timing_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlMapMeTimescale.h b/hicn-light/src/config/controlMapMeTimescale.h
new file mode 100755
index 000000000..d4b383696
--- /dev/null
+++ b/hicn-light/src/config/controlMapMeTimescale.h
@@ -0,0 +1,22 @@
+/*
+ * 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 Control_MapMeTimescale_h
+#define Control_MapMeTimescale_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMeTimescale_Create(ControlState *state);
+CommandOps *controlMapMeTimescale_HelpCreate(ControlState *state);
+#endif // Control_MapMeTimescale_h
diff --git a/hicn-light/src/config/controlQuit.c b/hicn-light/src/config/controlQuit.c
new file mode 100755
index 000000000..635fe278f
--- /dev/null
+++ b/hicn-light/src/config/controlQuit.c
@@ -0,0 +1,63 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_Security.h>
+
+#include <src/config/controlQuit.h>
+
+static CommandReturn _controlQuit_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlQuit_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+
+static const char *_commandQuit = "quit";
+static const char *_commandQuitHelp = "help quit";
+
+// ====================================================
+
+CommandOps *controlQuit_Create(ControlState *state) {
+ return commandOps_Create(state, _commandQuit, NULL, _controlQuit_Execute,
+ commandOps_Destroy);
+}
+
+CommandOps *controlQuit_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandQuitHelp, NULL,
+ _controlQuit_HelpExecute, commandOps_Destroy);
+}
+
+// ==============================================
+
+static CommandReturn _controlQuit_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ printf("Exits the interactive control program\n\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlQuit_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ printf("exiting interactive shell\n");
+ return CommandReturn_Exit;
+}
diff --git a/hicn-light/src/config/controlQuit.h b/hicn-light/src/config/controlQuit.h
new file mode 100755
index 000000000..e2ba3540e
--- /dev/null
+++ b/hicn-light/src/config/controlQuit.h
@@ -0,0 +1,29 @@
+/*
+ * 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 control_Quit.h
+ * @brief The quit command
+ *
+ * Implements the "quit" and "help quit" nodes of the command tree
+ *
+ */
+#ifndef Control_Quit_h
+#define Control_Quit_h
+
+#include <src/config/controlState.h>
+CommandOps *controlQuit_Create(ControlState *state);
+CommandOps *controlQuit_HelpCreate(ControlState *state);
+#endif // Control_Quit_h
diff --git a/hicn-light/src/config/controlRemove.c b/hicn-light/src/config/controlRemove.c
new file mode 100755
index 000000000..ede075a1b
--- /dev/null
+++ b/hicn-light/src/config/controlRemove.c
@@ -0,0 +1,92 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlRemove.h>
+#include <src/config/controlRemoveConnection.h>
+#include <src/config/controlRemovePunting.h>
+#include <src/config/controlRemoveRoute.h>
+
+static void _controlRemove_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlRemove_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlRemove_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandRemove = "remove";
+static const char *_commandRemoveHelp = "help remove";
+
+// ====================================================
+
+CommandOps *controlRemove_Create(ControlState *state) {
+ return commandOps_Create(state, _commandRemove, _controlRemove_Init,
+ _controlRemove_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlRemove_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandRemoveHelp, NULL,
+ _controlRemove_HelpExecute, commandOps_Destroy);
+}
+
+// ==============================================
+
+static CommandReturn _controlRemove_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ CommandOps *ops_remove_connection = controlRemoveConnection_Create(NULL);
+ CommandOps *ops_remove_route = controlRemoveRoute_Create(NULL);
+ CommandOps *ops_remove_punting = controlRemovePunting_Create(NULL);
+
+ printf("Available commands:\n");
+ printf(" %s\n", ops_remove_connection->command);
+ printf(" %s\n", ops_remove_route->command);
+ printf(" %s\n", ops_remove_punting->command);
+ printf("\n");
+
+ commandOps_Destroy(&ops_remove_connection);
+ commandOps_Destroy(&ops_remove_route);
+ commandOps_Destroy(&ops_remove_punting);
+ return CommandReturn_Success;
+}
+
+static void _controlRemove_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+ controlState_RegisterCommand(state,
+ controlRemoveConnection_HelpCreate(state));
+ controlState_RegisterCommand(state, controlRemoveRoute_HelpCreate(state));
+ controlState_RegisterCommand(state, controlRemoveConnection_Create(state));
+ controlState_RegisterCommand(state, controlRemoveRoute_Create(state));
+ controlState_RegisterCommand(state, controlRemovePunting_Create(state));
+ controlState_RegisterCommand(state, controlRemovePunting_HelpCreate(state));
+}
+
+static CommandReturn _controlRemove_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ return _controlRemove_HelpExecute(parser, ops, args);
+}
diff --git a/hicn-light/src/config/controlRemove.h b/hicn-light/src/config/controlRemove.h
new file mode 100755
index 000000000..d75ecfe70
--- /dev/null
+++ b/hicn-light/src/config/controlRemove.h
@@ -0,0 +1,29 @@
+/*
+ * 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 control_Remove.h
+ * @brief Implements the remove node of the CLI tree
+ *
+ * Implements the "remove" and "help remove" nodes of the command tree
+ *
+ */
+#ifndef controlRemove_h
+#define controlRemove_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRemove_Create(ControlState *state);
+CommandOps *controlRemove_HelpCreate(ControlState *state);
+#endif // controlRemove_h
diff --git a/hicn-light/src/config/controlRemoveConnection.c b/hicn-light/src/config/controlRemoveConnection.c
new file mode 100755
index 000000000..93365ad17
--- /dev/null
+++ b/hicn-light/src/config/controlRemoveConnection.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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <src/utils/address.h>
+
+#include <src/config/controlRemoveConnection.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlRemoveConnection_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlRemoveConnection_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+// ===================================================
+
+static const char *_commandRemoveConnection = "remove connection";
+static const char *_commandRemoveConnectionHelp = "help remove connection";
+
+// ====================================================
+
+CommandOps *controlRemoveConnection_Create(ControlState *state) {
+ return commandOps_Create(state, _commandRemoveConnection, NULL,
+ _controlRemoveConnection_Execute,
+ commandOps_Destroy);
+}
+
+CommandOps *controlRemoveConnection_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandRemoveConnectionHelp, NULL,
+ _controlRemoveConnection_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlRemoveConnection_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("command:\n");
+ printf(" remove connection <symbolic|id>\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlRemoveConnection_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ ControlState *state = ops->closure;
+
+ if (parcList_Size(args) != 3) {
+ _controlRemoveConnection_HelpExecute(parser, ops, args);
+ return false;
+ }
+
+ if ((strcmp(parcList_GetAtIndex(args, 0), "remove") != 0) ||
+ (strcmp(parcList_GetAtIndex(args, 1), "connection") != 0)) {
+ _controlRemoveConnection_HelpExecute(parser, ops, args);
+ return false;
+ }
+
+ const char *symbolicOrConnid = parcList_GetAtIndex(args, 2);
+
+ if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+ !utils_IsNumber(symbolicOrConnid)) {
+ printf(
+ "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an "
+ "alpha followed by alphanum;\nconnid must be an integer\n");
+ return CommandReturn_Failure;
+ }
+
+ // allocate command payload
+ remove_connection_command *removeConnectionCommand =
+ parcMemory_AllocateAndClear(sizeof(remove_connection_command));
+ // fill payload
+ strcpy(removeConnectionCommand->symbolicOrConnid, symbolicOrConnid);
+
+ // send message and receive response
+ struct iovec *response =
+ utils_SendRequest(state, REMOVE_CONNECTION, removeConnectionCommand,
+ sizeof(remove_connection_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlRemoveConnection.h b/hicn-light/src/config/controlRemoveConnection.h
new file mode 100755
index 000000000..1dd1af23b
--- /dev/null
+++ b/hicn-light/src/config/controlRemoveConnection.h
@@ -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.
+ */
+
+/**
+ * @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
+ *
+ */
+
+#ifndef Control_RemoveConnection_h
+#define Control_RemoveConnection_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRemoveConnection_Create(ControlState *state);
+CommandOps *controlRemoveConnection_HelpCreate(ControlState *state);
+#endif // Control_RemoveConnection_h
diff --git a/hicn-light/src/config/controlRemovePunting.c b/hicn-light/src/config/controlRemovePunting.c
new file mode 100755
index 000000000..cf4c4fbd4
--- /dev/null
+++ b/hicn-light/src/config/controlRemovePunting.c
@@ -0,0 +1,76 @@
+/*
+ * 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <src/utils/address.h>
+
+#include <src/config/controlRemovePunting.h>
+
+static CommandReturn _controlRemovePunting_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlRemovePunting_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+// ===================================================
+
+static const char *_commandRemovePunting = "remove punting";
+static const char *_commandRemovePuntingHelp = "help punting connection";
+
+// ====================================================
+
+CommandOps *controlRemovePunting_Create(ControlState *state) {
+ return commandOps_Create(state, _commandRemovePunting, NULL,
+ _controlRemovePunting_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlRemovePunting_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandRemovePuntingHelp, NULL,
+ _controlRemovePunting_HelpExecute,
+ commandOps_Destroy);
+}
+
+// ====================================================
+
+// ====================================================
+
+static CommandReturn _controlRemovePunting_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("remove punting <symbolic> <prefix>\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlRemovePunting_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("command not implemented\n");
+ return _controlRemovePunting_HelpExecute(parser, ops, args);
+}
+
+// ==================================================
diff --git a/hicn-light/src/config/controlRemovePunting.h b/hicn-light/src/config/controlRemovePunting.h
new file mode 100755
index 000000000..89b1343e7
--- /dev/null
+++ b/hicn-light/src/config/controlRemovePunting.h
@@ -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.
+ */
+
+/**
+ * @file control_RemovePunting.h
+ *
+ */
+
+#ifndef Control_RemovePunting_h
+#define Control_RemovePunting_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRemovePunting_Create(ControlState *state);
+CommandOps *controlRemovePunting_HelpCreate(ControlState *state);
+#endif // Control_RemovePunting_h
diff --git a/hicn-light/src/config/controlRemoveRoute.c b/hicn-light/src/config/controlRemoveRoute.c
new file mode 100755
index 000000000..b9b4ed1e4
--- /dev/null
+++ b/hicn-light/src/config/controlRemoveRoute.c
@@ -0,0 +1,150 @@
+/*
+ * 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/utils/address.h>
+
+#include <src/config/controlRemoveRoute.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlRemoveRoute_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlRemoveRoute_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+// ===================================================
+
+static const char *_commandRemoveRoute = "remove route";
+static const char *_commandRemoveRouteHelp = "help remove route";
+
+// ====================================================
+
+CommandOps *controlRemoveRoute_Create(ControlState *state) {
+ return commandOps_Create(state, _commandRemoveRoute, NULL,
+ _controlRemoveRoute_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlRemoveRoute_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandRemoveRouteHelp, NULL,
+ _controlRemoveRoute_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlRemoveRoute_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("commands:\n");
+ printf(" remove route <symbolic | connid> <prefix>\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlRemoveRoute_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ ControlState *state = ops->closure;
+
+ if (parcList_Size(args) != 4) {
+ _controlRemoveRoute_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ const char *symbolicOrConnid = parcList_GetAtIndex(args, 2);
+
+ if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+ !utils_IsNumber(symbolicOrConnid)) {
+ printf(
+ "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an "
+ "alpha followed by alphanum;\nconnid must be an integer\n");
+ return CommandReturn_Failure;
+ }
+
+ const char *prefixStr = parcList_GetAtIndex(args, 3);
+ char addr[strlen(prefixStr) + 1];
+
+ // separate address and len
+ char *slash;
+ uint32_t len = 0;
+ strcpy(addr, prefixStr);
+ slash = strrchr(addr, '/');
+ if (slash != NULL) {
+ len = atoi(slash + 1);
+ *slash = '\0';
+ }
+
+ if (len == 0) {
+ printf("ERROR: a prefix can not be of length 0\n");
+ return CommandReturn_Failure;
+ }
+
+ // allocate command payload
+ remove_route_command *removeRouteCommand =
+ parcMemory_AllocateAndClear(sizeof(remove_route_command));
+
+ // check and set IP address
+ if (inet_pton(AF_INET, addr, &removeRouteCommand->address.ipv4) == 1) {
+ if (len > 32) {
+ printf("ERROR: exceeded INET mask length, max=32\n");
+ parcMemory_Deallocate(&removeRouteCommand);
+ return CommandReturn_Failure;
+ }
+ removeRouteCommand->addressType = ADDR_INET;
+ } else if (inet_pton(AF_INET6, addr, &removeRouteCommand->address.ipv6) ==
+ 1) {
+ if (len > 128) {
+ printf("ERROR: exceeded INET6 mask length, max=128\n");
+ parcMemory_Deallocate(&removeRouteCommand);
+ return CommandReturn_Failure;
+ }
+ removeRouteCommand->addressType = ADDR_INET6;
+ } else {
+ printf("Error: %s is not a valid network address \n", addr);
+ parcMemory_Deallocate(&removeRouteCommand);
+ return CommandReturn_Failure;
+ }
+
+ // Fill remaining payload fields
+ removeRouteCommand->len = len;
+ strcpy(removeRouteCommand->symbolicOrConnid, symbolicOrConnid);
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(
+ state, REMOVE_ROUTE, removeRouteCommand, sizeof(remove_route_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlRemoveRoute.h b/hicn-light/src/config/controlRemoveRoute.h
new file mode 100755
index 000000000..a3c0ee46a
--- /dev/null
+++ b/hicn-light/src/config/controlRemoveRoute.h
@@ -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.
+ */
+
+/**
+ * @file control_RemoveRoute.h
+ * @brief Remove a route from the FIB
+ *
+ * Implements the "remove route" and "help remove route" nodes of the command
+ * tree
+ *
+ */
+
+#ifndef Control_RemoveRoute_h
+#define Control_RemoveRoute_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRemoveRoute_Create(ControlState *state);
+CommandOps *controlRemoveRoute_HelpCreate(ControlState *state);
+#endif // Control_RemoveRoute_h
diff --git a/hicn-light/src/config/controlRoot.c b/hicn-light/src/config/controlRoot.c
new file mode 100755
index 000000000..5d6c5f98e
--- /dev/null
+++ b/hicn-light/src/config/controlRoot.c
@@ -0,0 +1,134 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/config/controlAdd.h>
+#include <src/config/controlCache.h>
+#include <src/config/controlList.h>
+#include <src/config/controlMapMe.h>
+#include <src/config/controlQuit.h>
+#include <src/config/controlRemove.h>
+#include <src/config/controlRoot.h>
+#include <src/config/controlSet.h>
+#include <src/config/controlUnset.h>
+
+static void _controlRoot_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlRoot_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlRoot_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+
+static const char *_commandRoot = "";
+static const char *_commandRootHelp = "help";
+
+// ====================================================
+
+CommandOps *controlRoot_Create(ControlState *state) {
+ return commandOps_Create(state, _commandRoot, _controlRoot_Init,
+ _controlRoot_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlRoot_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandRootHelp, NULL,
+ _controlRoot_HelpExecute, commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandReturn _controlRoot_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ printf("Command-line execution:\n");
+ printf(
+ " controller [--keystore <keystorepath>] [--password <password>] "
+ "command\n");
+ printf("\n");
+ printf("Interactive execution:\n");
+ printf(" controller [--keystore <keystorepath>] [--password <password>]\n");
+ printf("\n");
+ printf(
+ "If the keystore is not specified, the default path is used. Keystore "
+ "must exist prior to running program.\n");
+ printf("If the password is not specified, the user will be prompted.\n");
+ printf("\n");
+
+ CommandOps *ops_help_add = controlAdd_CreateHelp(NULL);
+ CommandOps *ops_help_list = controlList_HelpCreate(NULL);
+ CommandOps *ops_help_quit = controlQuit_HelpCreate(NULL);
+ CommandOps *ops_help_remove = controlRemove_HelpCreate(NULL);
+ CommandOps *ops_help_set = controlSet_HelpCreate(NULL);
+ CommandOps *ops_help_unset = controlUnset_HelpCreate(NULL);
+ CommandOps *ops_help_cache = controlCache_HelpCreate(NULL);
+ CommandOps *ops_help_mapme = controlMapMe_HelpCreate(NULL);
+
+ printf("Available commands:\n");
+ printf(" %s\n", ops_help_add->command);
+ printf(" %s\n", ops_help_list->command);
+ printf(" %s\n", ops_help_quit->command);
+ printf(" %s\n", ops_help_remove->command);
+ printf(" %s\n", ops_help_set->command);
+ printf(" %s\n", ops_help_unset->command);
+ printf(" %s\n", ops_help_cache->command);
+ printf(" %s\n", ops_help_mapme->command);
+ printf("\n");
+
+ commandOps_Destroy(&ops_help_add);
+ commandOps_Destroy(&ops_help_list);
+ commandOps_Destroy(&ops_help_quit);
+ commandOps_Destroy(&ops_help_remove);
+ commandOps_Destroy(&ops_help_set);
+ commandOps_Destroy(&ops_help_unset);
+ commandOps_Destroy(&ops_help_cache);
+ commandOps_Destroy(&ops_help_mapme);
+
+ return CommandReturn_Success;
+}
+
+static void _controlRoot_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+
+ controlState_RegisterCommand(state, controlAdd_CreateHelp(state));
+ controlState_RegisterCommand(state, controlList_HelpCreate(state));
+ controlState_RegisterCommand(state, controlQuit_HelpCreate(state));
+ controlState_RegisterCommand(state, controlRemove_HelpCreate(state));
+ controlState_RegisterCommand(state, controlSet_HelpCreate(state));
+ controlState_RegisterCommand(state, controlUnset_HelpCreate(state));
+ controlState_RegisterCommand(state, controlCache_HelpCreate(state));
+ controlState_RegisterCommand(state, controlMapMe_HelpCreate(state));
+
+ controlState_RegisterCommand(state, webControlAdd_Create(state));
+ controlState_RegisterCommand(state, controlList_Create(state));
+ controlState_RegisterCommand(state, controlQuit_Create(state));
+ controlState_RegisterCommand(state, controlRemove_Create(state));
+ controlState_RegisterCommand(state, controlSet_Create(state));
+ controlState_RegisterCommand(state, controlUnset_Create(state));
+ controlState_RegisterCommand(state, controlCache_Create(state));
+ controlState_RegisterCommand(state, controlMapMe_Create(state));
+}
+
+static CommandReturn _controlRoot_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ return CommandReturn_Success;
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlRoot.h b/hicn-light/src/config/controlRoot.h
new file mode 100755
index 000000000..a62126eba
--- /dev/null
+++ b/hicn-light/src/config/controlRoot.h
@@ -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.
+ */
+
+/**
+ * @file control_Root.h
+ * @brief Root of the command tree
+ *
+ * Implements the root of the command tree. This is the one module that
+ * needs to be seeded to the control state to build the whole tree.
+ *
+ */
+
+#ifndef Control_Root_h
+#define Control_Root_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRoot_Create(ControlState *state);
+CommandOps *controlRoot_HelpCreate(ControlState *state);
+#endif // Control_Root_h
diff --git a/hicn-light/src/config/controlSet.c b/hicn-light/src/config/controlSet.c
new file mode 100755
index 000000000..c6fd9aa3e
--- /dev/null
+++ b/hicn-light/src/config/controlSet.c
@@ -0,0 +1,88 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_Security.h>
+
+#include <src/config/controlSet.h>
+#include <src/config/controlSetDebug.h>
+#include <src/config/controlSetStrategy.h>
+#include <src/config/controlSetWldr.h>
+
+static void _controlSet_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlSet_Execute(CommandParser *parser, CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlSet_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+
+static const char *_commandSet = "set";
+static const char *_commandSetHelp = "help set";
+
+// ===========================================================
+
+CommandOps *controlSet_Create(ControlState *state) {
+ return commandOps_Create(state, _commandSet, _controlSet_Init,
+ _controlSet_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlSet_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandSetHelp, NULL,
+ _controlSet_HelpExecute, commandOps_Destroy);
+}
+
+// ===========================================================
+
+static void _controlSet_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+ controlState_RegisterCommand(state, controlSetDebug_Create(state));
+ controlState_RegisterCommand(state, controlSetDebug_HelpCreate(state));
+ controlState_RegisterCommand(state, controlSetStrategy_Create(state));
+ controlState_RegisterCommand(state, controlSetStrategy_HelpCreate(state));
+ controlState_RegisterCommand(state, controlSetWldr_Create(state));
+ controlState_RegisterCommand(state, controlSetWldr_HelpCreate(state));
+}
+
+static CommandReturn _controlSet_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ CommandOps *ops_help_set_debug = controlSetDebug_HelpCreate(NULL);
+ CommandOps *ops_help_set_strategy = controlSetStrategy_HelpCreate(NULL);
+ CommandOps *ops_help_set_wldr = controlSetWldr_HelpCreate(NULL);
+
+ printf("Available commands:\n");
+ printf(" %s\n", ops_help_set_debug->command);
+ printf(" %s\n", ops_help_set_strategy->command);
+ printf(" %s\n", ops_help_set_wldr->command);
+ printf("\n");
+
+ commandOps_Destroy(&ops_help_set_debug);
+ commandOps_Destroy(&ops_help_set_strategy);
+ commandOps_Destroy(&ops_help_set_wldr);
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlSet_Execute(CommandParser *parser, CommandOps *ops,
+ PARCList *args) {
+ return _controlSet_HelpExecute(parser, ops, args);
+}
diff --git a/hicn-light/src/config/controlSet.h b/hicn-light/src/config/controlSet.h
new file mode 100755
index 000000000..4289aad8c
--- /dev/null
+++ b/hicn-light/src/config/controlSet.h
@@ -0,0 +1,29 @@
+/*
+ * 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 control_Set.h
+ * @brief Implements the set node of the CLI tree
+ *
+ * Implements the "set" and "help set" nodes of the command tree
+ *
+ */
+#ifndef Control_Set_h
+#define Control_Set_h
+
+#include <src/config/controlState.h>
+CommandOps *controlSet_Create(ControlState *state);
+CommandOps *controlSet_HelpCreate(ControlState *state);
+#endif // Control_Set_h
diff --git a/hicn-light/src/config/controlSetDebug.c b/hicn-light/src/config/controlSetDebug.c
new file mode 100755
index 000000000..ca432420e
--- /dev/null
+++ b/hicn-light/src/config/controlSetDebug.c
@@ -0,0 +1,74 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlSetDebug.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+static CommandReturn _controlSetDebug_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlSetDebug_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandSetDebug = "set debug";
+static const char *_commandSetDebugHelp = "help set debug";
+
+// ====================================================
+
+CommandOps *controlSetDebug_Create(ControlState *state) {
+ return commandOps_Create(state, _commandSetDebug, NULL,
+ _controlSetDebug_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlSetDebug_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandSetDebugHelp, NULL,
+ _controlSetDebug_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlSetDebug_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("set debug: will enable the debug flag for more verbose output\n");
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlSetDebug_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ if (parcList_Size(args) != 2) {
+ _controlSetDebug_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ ControlState *state = ops->closure;
+ controlState_SetDebug(state, true);
+ printf("Debug flag set\n\n");
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlSetDebug.h b/hicn-light/src/config/controlSetDebug.h
new file mode 100755
index 000000000..5335ebcab
--- /dev/null
+++ b/hicn-light/src/config/controlSetDebug.h
@@ -0,0 +1,30 @@
+/*
+ * 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 control_SetDebug.h
+ * @brief Sets the debug flag for more verbose output
+ *
+ * Implements the "set debug" and "help set debug" nodes of the command tree
+ *
+ */
+
+#ifndef Control_SetDebug_h
+#define Control_SetDebug_h
+
+#include <src/config/controlState.h>
+CommandOps *controlSetDebug_Create(ControlState *state);
+CommandOps *controlSetDebug_HelpCreate(ControlState *state);
+#endif // Control_SetDebug_h
diff --git a/hicn-light/src/config/controlSetStrategy.c b/hicn-light/src/config/controlSetStrategy.c
new file mode 100755
index 000000000..7b7c11762
--- /dev/null
+++ b/hicn-light/src/config/controlSetStrategy.c
@@ -0,0 +1,183 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/config/controlSetDebug.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlSetStrategy_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlSetStrategy_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandSetStrategy = "set strategy";
+static const char *_commandSetStrategyHelp = "help set strategy";
+
+static const char *_commandSetStrategyOptions[LAST_STRATEGY_VALUE] = {
+ "loadbalancer",
+ "random",
+ "random_per_dash_segment",
+ "loadbalancer_with_delay",
+ "loadbalancer_by_rate",
+ "loadbalancer_best_route"};
+
+// ====================================================
+
+CommandOps *controlSetStrategy_Create(ControlState *state) {
+ return commandOps_Create(state, _commandSetStrategy, NULL,
+ _controlSetStrategy_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlSetStrategy_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandSetStrategyHelp, NULL,
+ _controlSetStrategy_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+strategy_type _validStrategy(const char *strategy) {
+ strategy_type validStrategy = LAST_STRATEGY_VALUE;
+
+ for (int i = 0; i < LAST_STRATEGY_VALUE; i++) {
+ if (strcmp(_commandSetStrategyOptions[i], strategy) == 0) {
+ validStrategy = i;
+ break;
+ }
+ }
+ return validStrategy;
+}
+
+static CommandReturn _controlSetStrategy_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("set strategy <prefix> <strategy>\n");
+ printf("prefix: ipv4/ipv6 address (ex: 1234::/64)\n");
+ printf("strategy: strategy identifier\n");
+ printf("available strategies:\n");
+ printf(" random\n");
+ printf(" loadbalancer\n");
+ printf(" random_per_dash_segment\n");
+ printf(" loadbalancer_with_delay\n");
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlSetStrategy_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ ControlState *state = ops->closure;
+
+ if (parcList_Size(args) != 4) {
+ _controlSetStrategy_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ if (((strcmp(parcList_GetAtIndex(args, 0), "set") != 0) ||
+ (strcmp(parcList_GetAtIndex(args, 1), "strategy") != 0))) {
+ _controlSetStrategy_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ const char *prefixStr = parcList_GetAtIndex(args, 2);
+ char addr[strlen(prefixStr) + 1];
+ // separate address and len
+ char *slash;
+ uint32_t len = UINT32_MAX;
+ strcpy(addr, prefixStr);
+ slash = strrchr(addr, '/');
+ if (slash != NULL) {
+ len = atoi(slash + 1);
+ *slash = '\0';
+ }
+ if (len == 0) {
+ printf("ERROR: a prefix can not be of length 0\n");
+ return CommandReturn_Failure;
+ }
+
+ // allocate command payload
+ set_strategy_command *setStrategyCommand =
+ parcMemory_AllocateAndClear(sizeof(set_strategy_command));
+
+ // check and set IP address
+ if (inet_pton(AF_INET, addr, &setStrategyCommand->address.ipv4) == 1) {
+ if (len == UINT32_MAX) {
+ printf("Netmask not specified: set to 32 by default\n");
+ len = 32;
+ } else if (len > 32) {
+ printf("ERROR: exceeded INET mask length, max=32\n");
+ parcMemory_Deallocate(&setStrategyCommand);
+ return CommandReturn_Failure;
+ }
+ setStrategyCommand->addressType = ADDR_INET;
+ } else if (inet_pton(AF_INET6, addr, &setStrategyCommand->address.ipv6) ==
+ 1) {
+ if (len == UINT32_MAX) {
+ printf("Netmask not specified: set to 128 by default\n");
+ len = 128;
+ } else if (len > 128) {
+ printf("ERROR: exceeded INET6 mask length, max=128\n");
+ parcMemory_Deallocate(&setStrategyCommand);
+ return CommandReturn_Failure;
+ }
+ setStrategyCommand->addressType = ADDR_INET6;
+ } else {
+ printf("Error: %s is not a valid network address \n", addr);
+ parcMemory_Deallocate(&setStrategyCommand);
+ return CommandReturn_Failure;
+ }
+
+ const char *strategyStr = parcList_GetAtIndex(args, 3);
+ // check valid strategy
+ strategy_type strategy;
+ if ((strategy = _validStrategy(strategyStr)) == LAST_STRATEGY_VALUE) {
+ printf("Error: invalid strategy \n");
+ parcMemory_Deallocate(&setStrategyCommand);
+ _controlSetStrategy_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ // Fill remaining payload fields
+ setStrategyCommand->len = len;
+ setStrategyCommand->strategyType = strategy;
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(
+ state, SET_STRATEGY, setStrategyCommand, sizeof(set_strategy_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlSetStrategy.h b/hicn-light/src/config/controlSetStrategy.h
new file mode 100755
index 000000000..53ce8912c
--- /dev/null
+++ b/hicn-light/src/config/controlSetStrategy.h
@@ -0,0 +1,22 @@
+/*
+ * 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 Control_SetStrategy_h
+#define Control_SetStrategy_h
+
+#include <src/config/controlState.h>
+CommandOps *controlSetStrategy_Create(ControlState *state);
+CommandOps *controlSetStrategy_HelpCreate(ControlState *state);
+#endif // Control_SetStrategy_h
diff --git a/hicn-light/src/config/controlSetWldr.c b/hicn-light/src/config/controlSetWldr.c
new file mode 100755
index 000000000..9da404036
--- /dev/null
+++ b/hicn-light/src/config/controlSetWldr.c
@@ -0,0 +1,122 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlSetDebug.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlSetWldr_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlSetWldr_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandSetWldr = "set wldr";
+static const char *_commandSetWldrHelp = "help set wldr";
+
+// ====================================================
+
+CommandOps *controlSetWldr_Create(ControlState *state) {
+ return commandOps_Create(state, _commandSetWldr, NULL,
+ _controlSetWldr_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlSetWldr_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandSetWldrHelp, NULL,
+ _controlSetWldr_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlSetWldr_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("set wldr <on|off> <connection_id>\n");
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlSetWldr_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ ControlState *state = ops->closure;
+
+ if (parcList_Size(args) != 4) {
+ _controlSetWldr_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ if (((strcmp(parcList_GetAtIndex(args, 0), "set") != 0) ||
+ (strcmp(parcList_GetAtIndex(args, 1), "wldr") != 0))) {
+ _controlSetWldr_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ bool active;
+ if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+ active = true;
+ } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+ active = false;
+ } else {
+ _controlSetWldr_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ // check if valid connid
+ const char *symbolicOrConnid = parcList_GetAtIndex(args, 3);
+
+ if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+ !utils_IsNumber(symbolicOrConnid)) {
+ printf(
+ "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an "
+ "alpha followed by alphanum;\nconnid must be an integer\n");
+ return CommandReturn_Failure;
+ }
+
+ // allocate command payload
+ set_wldr_command *setWldrCommand =
+ parcMemory_AllocateAndClear(sizeof(set_wldr_command));
+ strcpy(setWldrCommand->symbolicOrConnid, symbolicOrConnid);
+ if (active) {
+ setWldrCommand->activate = ACTIVATE_ON;
+ } else {
+ setWldrCommand->activate = ACTIVATE_OFF;
+ }
+
+ // send message and receive response
+ struct iovec *response = utils_SendRequest(state, SET_WLDR, setWldrCommand,
+ sizeof(set_wldr_command));
+
+ if (!response) { // get NULL pointer
+ return CommandReturn_Failure;
+ }
+
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlSetWldr.h b/hicn-light/src/config/controlSetWldr.h
new file mode 100755
index 000000000..59c0b0fe6
--- /dev/null
+++ b/hicn-light/src/config/controlSetWldr.h
@@ -0,0 +1,22 @@
+/*
+ * 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 Control_SetWldr_h
+#define Control_SetWldr_h
+
+#include <src/config/controlState.h>
+CommandOps *controlSetWldr_Create(ControlState *state);
+CommandOps *controlSetWldr_HelpCreate(ControlState *state);
+#endif // Control_SetWldr_h
diff --git a/hicn-light/src/config/controlState.c b/hicn-light/src/config/controlState.c
new file mode 100755
index 000000000..d8260e8e8
--- /dev/null
+++ b/hicn-light/src/config/controlState.c
@@ -0,0 +1,237 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+#include <src/config/commandParser.h>
+#include <src/config/controlRoot.h>
+#include <src/config/controlState.h>
+
+#include <src/utils/commands.h>
+
+#define SRV_IP "127.0.0.1"
+#define PORT 9695
+
+struct controller_state {
+ CommandParser *parser;
+ bool debugFlag;
+
+ void *userdata;
+ struct iovec *(*writeRead)(ControlState *state, struct iovec *msg);
+ int sockfd;
+ char **commandOutput;
+ bool isInteractive;
+};
+
+int controlState_connectToFwdDeamon() {
+ int sockfd;
+ struct sockaddr_in servaddr;
+
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("\nSocket Creation Failed \n");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&servaddr, 0, sizeof(servaddr));
+
+ // Filling server information
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(PORT);
+ servaddr.sin_addr.s_addr = INADDR_ANY;
+
+ // Establish connection
+ if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
+ printf("\nConnection Failed: hicn-light Daemon is not running \n");
+ exit(EXIT_FAILURE);
+ }
+
+ return sockfd;
+}
+
+ControlState *controlState_Create(
+ void *userdata,
+ struct iovec *(*writeRead)(ControlState *state, struct iovec *msg),
+ bool openControllerConnetion) {
+ ControlState *state = parcMemory_AllocateAndClear(sizeof(ControlState));
+ parcAssertNotNull(state, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ControlState));
+ state->parser = commandParser_Create();
+
+ state->userdata = userdata;
+ state->writeRead = writeRead;
+ state->debugFlag = false;
+ state->commandOutput = NULL;
+ state->isInteractive = true;
+
+ if (openControllerConnetion) {
+ state->sockfd = controlState_connectToFwdDeamon();
+ } else {
+ state->sockfd = 2; // stderr
+ }
+
+ return state;
+}
+
+void controlState_Destroy(ControlState **statePtr) {
+ parcAssertNotNull(statePtr, "Parameter statePtr must be non-null");
+ parcAssertNotNull(*statePtr,
+ "Parameter statePtr must dereference t non-null");
+ ControlState *state = *statePtr;
+ // printf("sockid destroyed: %d\n", state->sockfd);
+ // close the connection with the fwd deamon
+ shutdown(state->sockfd, 2);
+
+ commandParser_Destroy(&state->parser);
+ parcMemory_Deallocate((void **)&state);
+ *statePtr = NULL;
+}
+
+void controlState_SetDebug(ControlState *state, bool debugFlag) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ state->debugFlag = debugFlag;
+ commandParser_SetDebug(state->parser, debugFlag);
+}
+
+bool controlState_GetDebug(ControlState *state) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ return state->debugFlag;
+}
+
+void controlState_RegisterCommand(ControlState *state, CommandOps *ops) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ commandParser_RegisterCommand(state->parser, ops);
+}
+
+struct iovec *controlState_WriteRead(ControlState *state, struct iovec *msg) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ parcAssertNotNull(msg, "Parameter msg must be non-null");
+
+ return state->writeRead(state, msg);
+}
+
+static PARCList *_controlState_ParseStringIntoTokens(
+ const char *originalString) {
+ PARCList *list =
+ parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction),
+ PARCArrayListAsPARCList);
+
+ char *token;
+
+ char *tofree =
+ parcMemory_StringDuplicate(originalString, strlen(originalString) + 1);
+ char *string = tofree;
+
+ while ((token = strsep(&string, " \t\n")) != NULL) {
+ if (strlen(token) > 0) {
+ parcList_Add(list, strdup(token));
+ }
+ }
+
+ parcMemory_Deallocate((void **)&tofree);
+
+ return list;
+}
+
+CommandReturn controlState_DispatchCommand(ControlState *state,
+ PARCList *args) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ return commandParser_DispatchCommand(state->parser, args);
+}
+
+int controlState_Interactive(ControlState *state) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ char *line = NULL;
+ size_t linecap = 0;
+ CommandReturn controlReturn = CommandReturn_Success;
+
+ while (controlReturn != CommandReturn_Exit && !feof(stdin)) {
+ fputs("> ", stdout);
+ fflush(stdout);
+ ssize_t failure = getline(&line, &linecap, stdin);
+ parcAssertTrue(failure > -1, "Error getline");
+
+ PARCList *args = _controlState_ParseStringIntoTokens(line);
+ controlReturn = controlState_DispatchCommand(state, args);
+ // release and get command
+ parcList_Release(&args);
+ }
+ return 0;
+}
+
+void controlState_SetCommandOutput(ControlState *state, char **commandData) {
+ state->commandOutput = commandData;
+}
+
+void controlState_ReleaseCommandOutput(ControlState *state, char **commandData,
+ size_t commandLenght) {
+ for (size_t i = 0; i < commandLenght; i++) {
+ parcMemory_Deallocate(&commandData[i]);
+ }
+ parcMemory_Deallocate(&commandData);
+ state->commandOutput = NULL;
+}
+
+char **controlState_GetCommandOutput(ControlState *state) {
+ return state->commandOutput;
+}
+
+// size_t
+// controlState_GetCommandLen(ControlState *state){
+
+// }
+
+void controlState_SetInteractiveFlag(ControlState *state, bool interactive) {
+ state->isInteractive = interactive;
+}
+
+bool controlState_IsInteractive(ControlState *state) {
+ return state->isInteractive;
+}
+
+int controlState_GetSockfd(ControlState *state) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ return state->sockfd;
+}
+
+void *controlState_GetUserdata(ControlState *state) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ return state->userdata;
+}
+
+bool controlState_isConfigFile(ControlState *state) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ if (state->sockfd != 2) {
+ return false;
+ } else {
+ return true;
+ }
+} \ No newline at end of file
diff --git a/hicn-light/src/config/controlState.h b/hicn-light/src/config/controlState.h
new file mode 100755
index 000000000..905c56c30
--- /dev/null
+++ b/hicn-light/src/config/controlState.h
@@ -0,0 +1,233 @@
+/*
+ * 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 controlState.h
+ * @brief A control program for hicn-light using CLI commands
+ *
+ * Implements the state machine for the control program. It takes a "writeRead"
+ * function as part of the constructor. This abstracts out the backend. It
+ * could be a Portal from hicnLightControl program down to the forwarder or it
+ * could be an internal function within hicn-light.
+ *
+ */
+
+#ifndef control_h
+#define control_h
+
+#include <parc/algol/parc_List.h>
+#include <src/config/commandParser.h>
+
+#include <src/utils/commands.h>
+
+struct controller_state;
+typedef struct controller_state ControlState;
+
+/**
+ * controlState_Create
+ *
+ * Creates the global state for the Control program. The user provides the
+ * writeRead function for sending and receiving the message wrapping command
+ * arguments. For configuration file inside hicn-light, it would make direct
+ * calls to Configuration -> Dispatcher.
+ *
+ * @param [in] userdata A closure passed back to the user when calling
+ * writeRead.
+ * @param [in] writeRead The function to write then read configuration messages
+ * to hicn-light
+ *
+ * @return non-null The control state
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+ControlState *controlState_Create(
+ void *userdata,
+ struct iovec *(*writeRead)(ControlState *state, struct iovec *msg),
+ bool openControllerConnetion);
+
+/**
+ * Destroys the control state, closing all network connections
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void controlState_Destroy(ControlState **statePtr);
+
+/**
+ * Registers a CommandOps with the system.
+ *
+ * Each command has its complete command prefix in the "command" field.
+ * RegisterCommand will put these command prefixes in to a tree and then match
+ * what a user types against the longest-matching prefix in the tree. If
+ * there's a match, it will call the "execute" function.
+ *
+ * @param [in] state An allocated ControlState
+ * @param [in] command The command to register with the system
+ *
+ * Example:
+ * @code
+ * static CommandReturn
+ * control_Root_Execute(CommandParser *parser, CommandOps *ops, PARCList
+ * *args)
+ * {
+ * printf("Root Command\n");
+ * return CommandReturn_Success;
+ * }
+ *
+ * static CommandReturn
+ * control_FooBar_Execute(CommandParser *parser, CommandOps *ops, PARCList
+ * *args)
+ * {
+ * printf("Foo Bar Command\n");
+ * return CommandReturn_Success;
+ * }
+ *
+ * const CommandOps control_Root = {
+ * .command = "", // empty string for root
+ * .init = NULL,
+ * .execute = control_Root_Execute
+ * };
+ *
+ * const CommandOps control_FooBar = {
+ * .command = "foo bar", // empty string for root
+ * .init = NULL,
+ * .execute = control_FooBar_Execute
+ * };
+ *
+ * void startup(void)
+ * {
+ * ControlState *state = controlState_Create("happy", "day");
+ * controlState_RegisterCommand(state, control_FooBar);
+ * controlState_RegisterCommand(state, control_Root);
+ *
+ * // this executes "root"
+ * controlState_DispatchCommand(state, "foo");
+ * controlState_Destroy(&state);
+ * }
+ * @endcode
+ */
+void controlState_RegisterCommand(ControlState *state, CommandOps *command);
+
+/**
+ * Performs a longest-matching prefix of the args to the command tree
+ *
+ * The command tree is created with controlState_RegisterCommand.
+ *
+ * @param [in] state The allocated ControlState
+ * @param [in] args Each command_line word parsed to the ordered list
+ *
+ * @return CommandReturn_Success the command was successful
+ * @return CommandReturn_Failure the command failed or was not found
+ * @return CommandReturn_Exit the command indicates that the interactive mode
+ * should exit
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CommandReturn controlState_DispatchCommand(ControlState *state, PARCList *args);
+
+/**
+ * Begin an interactive shell
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int controlState_Interactive(ControlState *state);
+
+/**
+ * Write then Read a command
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct iovec *controlState_WriteRead(ControlState *state, struct iovec *msg);
+
+/**
+ * Sets the Debug mode, which will print out much more information.
+ *
+ * Prints out much more diagnostic information about what hicn-light controller
+ * is doing. yes, you would make a CommandOps to set and unset this :)
+ *
+ * @param [in] debugFlag true means to print debug info, false means to turn it
+ * off
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void controlState_SetDebug(ControlState *state, bool debugFlag);
+
+/**
+ * Returns the debug state of ControlState
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool controlState_GetDebug(ControlState *state);
+#endif // control_h
+
+void controlState_SetCommandOutput(ControlState *state, char **commandData);
+
+void controlState_ReleaseCommandOutput(ControlState *state, char **commandData,
+ size_t commandLenght);
+
+char **controlState_GetCommandOutput(ControlState *state);
+
+void controlState_SetInteractiveFlag(ControlState *state, bool interactive);
+
+bool controlState_IsInteractive(ControlState *state);
+
+void *controlState_GetUserdata(ControlState *state);
+
+bool controlState_isConfigFile(ControlState *state);
+
+int controlState_GetSockfd(ControlState *state);
diff --git a/hicn-light/src/config/controlUnset.c b/hicn-light/src/config/controlUnset.c
new file mode 100755
index 000000000..2da6a6518
--- /dev/null
+++ b/hicn-light/src/config/controlUnset.c
@@ -0,0 +1,78 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_Security.h>
+
+#include <src/config/controlUnset.h>
+#include <src/config/controlUnsetDebug.h>
+
+static void _controlUnset_Init(CommandParser *parser, CommandOps *ops);
+
+static CommandReturn _controlUnset_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+static CommandReturn _controlUnset_HelpExecute(CommandParser *parser,
+ CommandOps *ops, PARCList *args);
+
+static const char *_commandUnset = "unset";
+static const char *_commandUnsetHelp = "help unset";
+
+// ===========================================================
+
+CommandOps *controlUnset_Create(ControlState *state) {
+ return commandOps_Create(state, _commandUnset, _controlUnset_Init,
+ _controlUnset_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlUnset_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandUnsetHelp, NULL,
+ _controlUnset_HelpExecute, commandOps_Destroy);
+}
+
+// ===========================================================
+
+static void _controlUnset_Init(CommandParser *parser, CommandOps *ops) {
+ ControlState *state = ops->closure;
+ controlState_RegisterCommand(state, controlUnsetDebug_Create(state));
+ controlState_RegisterCommand(state, controlUnsetDebug_HelpCreate(state));
+}
+
+static CommandReturn _controlUnset_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ CommandOps *ops_help_unset_debug = controlUnsetDebug_HelpCreate(NULL);
+
+ printf("Available commands:\n");
+ printf(" %s\n", ops_help_unset_debug->command);
+ printf("\n");
+
+ commandOps_Destroy(&ops_help_unset_debug);
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlUnset_Execute(CommandParser *parser,
+ CommandOps *ops, PARCList *args) {
+ return _controlUnset_HelpExecute(parser, ops, args);
+}
diff --git a/hicn-light/src/config/controlUnset.h b/hicn-light/src/config/controlUnset.h
new file mode 100755
index 000000000..6eeb983f7
--- /dev/null
+++ b/hicn-light/src/config/controlUnset.h
@@ -0,0 +1,29 @@
+/*
+ * 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 control_Unset.h
+ * @brief Implements the unset node of the CLI tree
+ *
+ * Implements the "unset" and "help unset" nodes of the command tree
+ *
+ */
+#ifndef Control_Unset_h
+#define Control_Unset_h
+
+#include <src/config/controlState.h>
+CommandOps *controlUnset_Create(ControlState *state);
+CommandOps *controlUnset_HelpCreate(ControlState *state);
+#endif // Control_Unset_h
diff --git a/hicn-light/src/config/controlUnsetDebug.c b/hicn-light/src/config/controlUnsetDebug.c
new file mode 100755
index 000000000..4892bd513
--- /dev/null
+++ b/hicn-light/src/config/controlUnsetDebug.c
@@ -0,0 +1,77 @@
+/*
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlUnsetDebug.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+static CommandReturn _controlUnsetDebug_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+static CommandReturn _controlUnsetDebug_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args);
+
+static const char *_commandUnsetDebug = "unset debug";
+static const char *_commandUnsetDebugHelp = "help unset debug";
+
+// ====================================================
+
+CommandOps *controlUnsetDebug_Create(ControlState *state) {
+ return commandOps_Create(state, _commandUnsetDebug, NULL,
+ _controlUnsetDebug_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlUnsetDebug_HelpCreate(ControlState *state) {
+ return commandOps_Create(state, _commandUnsetDebugHelp, NULL,
+ _controlUnsetDebug_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlUnsetDebug_HelpExecute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ printf("unset debug: will disable the debug flag\n");
+ printf("\n");
+ return CommandReturn_Success;
+}
+
+static CommandReturn _controlUnsetDebug_Execute(CommandParser *parser,
+ CommandOps *ops,
+ PARCList *args) {
+ if (parcList_Size(args) != 2) {
+ _controlUnsetDebug_HelpExecute(parser, ops, args);
+ return CommandReturn_Failure;
+ }
+
+ ControlState *state = ops->closure;
+ controlState_SetDebug(state, false);
+ printf("Debug flag cleared\n\n");
+
+ return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlUnsetDebug.h b/hicn-light/src/config/controlUnsetDebug.h
new file mode 100755
index 000000000..e34f8aa5f
--- /dev/null
+++ b/hicn-light/src/config/controlUnsetDebug.h
@@ -0,0 +1,30 @@
+/*
+ * 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 control_UnsetDebug.h
+ * @brief Unsets the debug flag for more verbose output
+ *
+ * Implements the "unset debug" and "help unset debug" nodes of the CLI tree
+ *
+ */
+
+#ifndef Control_UnsetDebug_h
+#define Control_UnsetDebug_h
+
+#include <src/config/controlState.h>
+CommandOps *controlUnsetDebug_Create(ControlState *state);
+CommandOps *controlUnsetDebug_HelpCreate(ControlState *state);
+#endif // Control_UnsetDebug_h
diff --git a/hicn-light/src/config/symbolicNameTable.c b/hicn-light/src/config/symbolicNameTable.c
new file mode 100755
index 000000000..ccf416d67
--- /dev/null
+++ b/hicn-light/src/config/symbolicNameTable.c
@@ -0,0 +1,175 @@
+/*
+ * 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 <ctype.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/config/symbolicNameTable.h>
+
+struct symblic_name_table {
+ PARCHashCodeTable *symbolicNameTable;
+ PARCHashCodeTable *indexToNameTable;
+};
+
+// ========================================================================================
+// symbolic name table functions
+
+static bool _symbolicNameEquals(const void *keyA, const void *keyB) {
+ return (strcasecmp((const char *)keyA, (const char *)keyB) == 0);
+}
+
+static HashCodeType _symbolicNameHash(const void *keyA) {
+ const char *str = (const char *)keyA;
+ size_t length = strlen(str);
+ return parcHash32_Data(str, length);
+}
+
+static bool _connectionIdEquals(const void *keyA, const void *keyB) {
+ unsigned idA = *((unsigned *)keyA);
+ unsigned idB = *((unsigned *)keyB);
+ return (idA == idB);
+}
+
+static HashCodeType _connectionIdHash(const void *keyA) {
+ unsigned idA = *((unsigned *)keyA);
+ return parcHash32_Int32(idA);
+}
+
+// ========================================================================================
+
+SymbolicNameTable *symbolicNameTable_Create(void) {
+ SymbolicNameTable *table = parcMemory_Allocate(sizeof(SymbolicNameTable));
+
+ if (table) {
+ // key = char *
+ // value = uint32_t *
+ table->symbolicNameTable = parcHashCodeTable_Create(
+ _symbolicNameEquals, _symbolicNameHash, parcMemory_DeallocateImpl,
+ parcMemory_DeallocateImpl);
+ table->indexToNameTable = parcHashCodeTable_Create(
+ _connectionIdEquals, _connectionIdHash, parcMemory_DeallocateImpl,
+ parcMemory_DeallocateImpl);
+ }
+
+ return table;
+}
+
+void symbolicNameTable_Destroy(SymbolicNameTable **tablePtr) {
+ SymbolicNameTable *table = *tablePtr;
+ parcHashCodeTable_Destroy(&table->symbolicNameTable);
+ // parcHashCodeTable_Destroy(&table->indexToNameTable);
+ parcMemory_Deallocate((void **)&table);
+ *tablePtr = NULL;
+}
+
+static char *_createKey(const char *symbolicName) {
+ char *key = parcMemory_StringDuplicate(symbolicName, strlen(symbolicName));
+
+ // convert key to upper case
+ char *p = key;
+
+ // keeps looping until the first null
+ while ((*p = toupper(*p))) {
+ p++;
+ }
+ return key;
+}
+
+bool symbolicNameTable_Exists(SymbolicNameTable *table,
+ const char *symbolicName) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null");
+
+ char *key = _createKey(symbolicName);
+ bool found = (parcHashCodeTable_Get(table->symbolicNameTable, key) != NULL);
+ parcMemory_Deallocate((void **)&key);
+ return found;
+}
+
+void symbolicNameTable_Remove(SymbolicNameTable *table,
+ const char *symbolicName) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null");
+
+ char *key = _createKey(symbolicName);
+
+ unsigned id = symbolicNameTable_Get(table, symbolicName);
+ uint32_t *value = parcMemory_Allocate(sizeof(uint32_t));
+ *value = id;
+
+ parcHashCodeTable_Del(table->symbolicNameTable, key);
+ parcHashCodeTable_Del(table->indexToNameTable, value);
+ parcMemory_Deallocate((void **)&key);
+ parcMemory_Deallocate((void **)&value);
+}
+
+bool symbolicNameTable_Add(SymbolicNameTable *table, const char *symbolicName,
+ unsigned connid) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null");
+ parcAssertTrue(connid < UINT32_MAX, "Parameter connid must be less than %u",
+ UINT32_MAX);
+
+ char *key = _createKey(symbolicName);
+
+ uint32_t *value = parcMemory_Allocate(sizeof(uint32_t));
+ *value = 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);
+ }
+
+ return success;
+}
+
+unsigned symbolicNameTable_Get(SymbolicNameTable *table,
+ const char *symbolicName) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null");
+
+ unsigned connid = UINT32_MAX;
+
+ char *key = _createKey(symbolicName);
+
+ uint32_t *value = parcHashCodeTable_Get(table->symbolicNameTable, key);
+ if (value) {
+ connid = *value;
+ }
+
+ parcMemory_Deallocate((void **)&key);
+ return connid;
+}
+
+const char *symbolicNameTable_GetNameByIndex(SymbolicNameTable *table,
+ unsigned id) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+
+ uint32_t *value = parcMemory_Allocate(sizeof(uint32_t));
+ *value = id;
+
+ const char *name = parcHashCodeTable_Get(table->indexToNameTable, value);
+ if (name == NULL) name = "";
+
+ parcMemory_Deallocate((void **)&value);
+ return name;
+}
diff --git a/hicn-light/src/config/symbolicNameTable.h b/hicn-light/src/config/symbolicNameTable.h
new file mode 100755
index 000000000..69919cf00
--- /dev/null
+++ b/hicn-light/src/config/symbolicNameTable.h
@@ -0,0 +1,131 @@
+/*
+ * 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 symbolicNameTable.h
+ * @brief The symbolic name table maps a string name to a connection id
+ *
+ * When configuring tunnels/connections, the user provides a string name
+ * (symbolic name) that they will use to refer to that connection. The symblic
+ * name table translates that symbolic name to a connection id.
+ *
+ */
+
+#ifndef symbolicNameTable_h
+#define symbolicNameTable_h
+
+struct symblic_name_table;
+typedef struct symblic_name_table SymbolicNameTable;
+
+#include <stdbool.h>
+
+/**
+ * Creates a symbolic name table
+ *
+ * Allocates a SymbolicNameTable, which will store the symbolic names
+ * in a hash table.
+ *
+ * @retval non-null An allocated SymbolicNameTable
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+SymbolicNameTable *symbolicNameTable_Create(void);
+
+/**
+ * Destroys a name table
+ *
+ * All keys and data are released.
+ *
+ * @param [in,out] tablePtr A pointer to a SymbolicNameTable, which will be
+ * NULL'd
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void symbolicNameTable_Destroy(SymbolicNameTable **tablePtr);
+
+/**
+ * Checks if the name (case insensitive) is in the table
+ *
+ * Does a case-insensitive match to see if the name is in the table
+ *
+ * @param [in] table An allocated SymbolicNameTable
+ * @param [in] symbolicName The name to check for
+ *
+ * @retval true The name is in the table
+ * @retval false The name is not in the talbe
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool symbolicNameTable_Exists(SymbolicNameTable *table,
+ const char *symbolicName);
+
+/**
+ * Adds a (name, connid) pair to the table.
+ *
+ * The name is stored case insensitive. The value UINT_MAX is used to indicate
+ * a non-existent key, so it should not be stored as a value in the table.
+ *
+ * @param [in] table An allocated SymbolicNameTable
+ * @param [in] symbolicName The name to save (will make a copy)
+ * @param [in] connid The connection id to associate with the name
+ *
+ * @retval true The pair was added
+ * @retval false The pair was not added (likely duplicate key)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool symbolicNameTable_Add(SymbolicNameTable *table, const char *symbolicName,
+ unsigned connid);
+
+/**
+ * Returns the connection id associated with the symbolic name
+ *
+ * This function will look for the given name (case insensitive) and return the
+ * corresponding connid. If the name is not in the table, the function will
+ * return UINT_MAX.
+ *
+ * @param [in] table An allocated SymbolicNameTable
+ * @param [in] symbolicName The name to retrieve
+ *
+ * @retval UINT_MAX symbolicName not found
+ * @retval number the corresponding connid.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+unsigned symbolicNameTable_Get(SymbolicNameTable *table,
+ const char *symbolicName);
+
+void symbolicNameTable_Remove(SymbolicNameTable *table,
+ const char *symbolicName);
+const char *symbolicNameTable_GetNameByIndex(SymbolicNameTable *table,
+ unsigned id);
+
+#endif /* defined(symbolicNameTable_h) */
diff --git a/hicn-light/src/content_store/CMakeLists.txt b/hicn-light/src/content_store/CMakeLists.txt
new file mode 100755
index 000000000..85643cf5e
--- /dev/null
+++ b/hicn-light/src/content_store/CMakeLists.txt
@@ -0,0 +1,33 @@
+# 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreEntry.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreInterface.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreLRU.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/listTimeOrdered.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/listLRU.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreInterface.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreLRU.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/listLRU.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/listTimeOrdered.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreEntry.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/hicn-light/src/content_store/contentStoreEntry.c b/hicn-light/src/content_store/contentStoreEntry.c
new file mode 100755
index 000000000..d36ed61a0
--- /dev/null
+++ b/hicn-light/src/content_store/contentStoreEntry.c
@@ -0,0 +1,136 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <src/content_store/contentStoreEntry.h>
+
+#include <parc/assert/parc_Assert.h>
+
+const uint64_t contentStoreEntry_MaxExpiryTime = UINT64_MAX;
+
+struct contentstore_entry {
+ Message *message;
+ ListLruEntry *lruEntry;
+ unsigned refcount;
+ bool hasExpiryTimeTicks;
+ uint64_t expiryTimeTicks;
+};
+
+ContentStoreEntry *contentStoreEntry_Create(Message *contentMessage,
+ ListLru *listLRU) {
+ parcAssertNotNull(contentMessage, "Parameter objectMessage must be non-null");
+
+ ContentStoreEntry *entry =
+ parcMemory_AllocateAndClear(sizeof(ContentStoreEntry));
+ parcAssertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ContentStoreEntry));
+ entry->message = message_Acquire(contentMessage);
+ entry->refcount = 1;
+
+ if (listLRU != NULL) {
+ entry->lruEntry = listLRU_NewHeadEntry(listLRU, entry);
+ }
+
+ entry->hasExpiryTimeTicks = message_HasContentExpiryTime(contentMessage);
+
+ if (entry->hasExpiryTimeTicks) {
+ entry->expiryTimeTicks = message_GetContentExpiryTimeTicks(contentMessage);
+ }
+
+ return entry;
+}
+
+ContentStoreEntry *contentStoreEntry_Acquire(
+ const ContentStoreEntry *original) {
+ parcAssertNotNull(original, "Parameter must be non-null");
+ ((ContentStoreEntry *)original)->refcount++;
+ return (ContentStoreEntry *)original;
+}
+
+void contentStoreEntry_Release(ContentStoreEntry **entryPtr) {
+ parcAssertNotNull(entryPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*entryPtr,
+ "Parameter must dereference to non-null pointer");
+
+ ContentStoreEntry *entry = *entryPtr;
+ parcAssertTrue(entry->refcount > 0, "Illegal state: has refcount of 0");
+
+ entry->refcount--;
+ if (entry->refcount == 0) {
+ if (entry->lruEntry) {
+ listLRU_EntryDestroy(&entry->lruEntry);
+ }
+ message_Release(&entry->message);
+ parcMemory_Deallocate((void **)&entry);
+ }
+ *entryPtr = NULL;
+}
+
+Message *contentStoreEntry_GetMessage(const ContentStoreEntry *storeEntry) {
+ parcAssertNotNull(storeEntry, "Parameter must be non-null");
+ return storeEntry->message;
+}
+
+bool contentStoreEntry_HasExpiryTimeTicks(const ContentStoreEntry *storeEntry) {
+ parcAssertNotNull(storeEntry, "Parameter must be non-null");
+ return storeEntry->hasExpiryTimeTicks;
+}
+
+uint64_t contentStoreEntry_GetExpiryTimeTicks(
+ const ContentStoreEntry *storeEntry) {
+ parcAssertNotNull(storeEntry, "Parameter must be non-null");
+ parcAssertTrue(storeEntry->hasExpiryTimeTicks,
+ "storeEntry has no ExpiryTimeTicks. Did you call "
+ "contentStoreEntry_HasExpiryTimeTicks() first?");
+ return storeEntry->expiryTimeTicks;
+}
+
+int contentStoreEntry_CompareExpiryTime(const ContentStoreEntry *value1,
+ const ContentStoreEntry *value2) {
+ // A signum comparison. negative if key 1 is smaller, 0 if key1 == key2,
+ // greater than 0 if key1 is bigger.
+
+ ContentStoreEntry *v1 = (ContentStoreEntry *)value1;
+ ContentStoreEntry *v2 = (ContentStoreEntry *)value2;
+
+ if (v1->expiryTimeTicks < v2->expiryTimeTicks) {
+ return -1;
+ } else if (v1->expiryTimeTicks > v2->expiryTimeTicks) {
+ return +1;
+ } else {
+ // At this point, the times are the same. Use the address of the message as
+ // the decider. This allows us to store multiple messages with the same
+ // expiry/cache time.
+ if (v1->message < v2->message) {
+ return -1;
+ } else if (v1->message > v2->message) {
+ return +1;
+ }
+ }
+
+ return 0; // The same message has been encountered.
+}
+
+void contentStoreEntry_MoveToHead(ContentStoreEntry *storeEntry) {
+ parcAssertNotNull(storeEntry, "Parameter must be non-null");
+ parcAssertNotNull(storeEntry->lruEntry,
+ "ContentStoreEntry is not attached to an ListLru");
+ if (storeEntry->lruEntry) {
+ listLRU_EntryMoveToHead(storeEntry->lruEntry);
+ }
+}
diff --git a/hicn-light/src/content_store/contentStoreEntry.h b/hicn-light/src/content_store/contentStoreEntry.h
new file mode 100755
index 000000000..766cc15e4
--- /dev/null
+++ b/hicn-light/src/content_store/contentStoreEntry.h
@@ -0,0 +1,146 @@
+/*
+ * 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 contentStoreEntry_h
+#define contentStoreEntry_h
+
+#include <src/content_store/listLRU.h>
+#include <src/core/message.h>
+
+struct contentstore_entry;
+typedef struct contentstore_entry ContentStoreEntry;
+
+/**
+ * The max time allowed for an ExpiryTime. Will never be exceeded.
+ */
+extern const uint64_t contentStoreEntry_MaxExpiryTime;
+
+/**
+ * Creates a new `ContentStoreEntry` instance, acquiring a reference to the
+ * supplied `Message`.
+ *
+ * @param message the message to store
+ * @param listLRU the LRU list that this entry will be stored in.
+ * @return A newly created `ContentStoreEntry` instance that must eventually be
+ * released by calling
+ * {@link contentStoreEntry_Release}.
+ *
+ * @see contentStoreEntry_Release
+ */
+ContentStoreEntry *contentStoreEntry_Create(Message *objectMessage,
+ ListLru *listLRU);
+
+/**
+ * Returns a reference counted copy of the supplied `ContentStoreEntry`.
+ *
+ * @param original the ContentStoreEntry to return a reference to.
+ * @return Reference counted copy, must call
+ * <code>contentStoreEntry_Destroy()</code> on it.
+ */
+ContentStoreEntry *contentStoreEntry_Acquire(const ContentStoreEntry *original);
+
+/**
+ * Releases one reference count and destroys object when reaches zero
+ *
+ * @param [in,out] entryPtr A pointer to an allocated ContentStoreEntry
+ *
+ */
+void contentStoreEntry_Release(ContentStoreEntry **entryPtr);
+
+/**
+ * Returns a pointer to the contained {@link Message}.
+ * The caller must called {@link message_Acquire()} if they want to keep a
+ * reference to the returned message.
+ *
+ * @param storeEntry the ContentStoreEntry from which to retrieve the `Message`
+ * pointer.
+ * @return the address of the `Message` contained in the storeEntry.
+ * @see message_Acquire
+ */
+Message *contentStoreEntry_GetMessage(const ContentStoreEntry *storeEntry);
+
+/**
+ * Return true if the message stored in this `ContentStoreEntry` has an
+ * ExpiryTime.
+ *
+ * @param storeEntry the ContentStoreEntry containing the message.
+ * @return true if the referenced message has an ExpiryTime. False, otherwise.
+ */
+bool contentStoreEntry_HasExpiryTimeTicks(const ContentStoreEntry *storeEntry);
+
+/**
+ * Return the ExpiryTime stored in this `ContentStoreEntry`.
+ *
+ * @param storeEntry the ContentStoreEntry from which to retrieve the `Message`
+ * pointer.
+ * @return the address of the `Message` contained in the storeEntry.
+ */
+uint64_t contentStoreEntry_GetExpiryTimeTicks(
+ const ContentStoreEntry *storeEntry);
+
+/**
+ * A signum function comparing two `ContentStoreEntry` instances, using their
+ * ExpiryTime and, if necessary, the addresses of the referenced Message. In
+ * other words, if two ContentStoreEntries have the same ExpiryTime, the
+ * comparison will then be made on the memory addresses of the Messages
+ * referenced by the ContentStoreEntrys. So, the only way two ContentStoreEntrys
+ * will compare equally (0) is if they both have the same ExpiryTime and
+ * reference the same Message.
+ *
+ * Used to determine the ordering relationship of two `ContentStoreEntry`
+ * instances. This is used by the {@link ListTimeOrdered} to keep a list of
+ * ContentStoreEntrys, sorted by ExpiryTime.
+ *
+ * @param [in] storeEntry1 A pointer to a `ContentStoreEntry` instance.
+ * @param [in] storeEntry2 A pointer to a `ContentStoreEntry` instance to be
+ * compared to `storeEntry1`.
+ *
+ * @return 0 if `storeEntry1` and `storeEntry2` are equivalent
+ * @return < 0 if `storeEntry1` < `storeEntry2`
+ * @return > 0 if `storeEntry1` > `storeEntry2`
+ *
+ * Example:
+ * @code
+ * {
+ * ContentStoreEntry *entry1 = contentStoreEntry_Create(...);
+ * ContentStoreEntry *entry2 = contentStoreEntry_Create(...);
+ *
+ * int val = contentStoreEntry_CompareExpiryTime(entry1, entry2);
+ * if (val < 0) {
+ * // entry1 has a lower ExpiryTime, or the same ExpiryTime as entry2
+ * and a different message. } else if (val > 0) {
+ * // entry2 has a lower ExpiryTime, or the same ExpiryTime as entry1
+ * and a different message. } else {
+ * // entry1 and entry2 have the same ExpiryTime AND the same message.
+ * }
+ *
+ * contentStoreEntry_Release(&entry1);
+ * contentStoreEntry_Release(&entry2);
+ *
+ * }
+ * @endcode
+ */
+int contentStoreEntry_CompareExpiryTime(const ContentStoreEntry *storeEntry1,
+ const ContentStoreEntry *storeEntry2);
+
+/**
+ * Move this entry to the head of the LRU list
+ *
+ * Moves the entry to the head of the LRU list it was created with
+ *
+ * @param [in] storeEntry An allocated ContenstoreEntry
+ */
+void contentStoreEntry_MoveToHead(ContentStoreEntry *storeEntry);
+#endif // contentStoreEntry_h
diff --git a/hicn-light/src/content_store/contentStoreInterface.c b/hicn-light/src/content_store/contentStoreInterface.c
new file mode 100755
index 000000000..a42041670
--- /dev/null
+++ b/hicn-light/src/content_store/contentStoreInterface.c
@@ -0,0 +1,57 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <src/content_store/contentStoreInterface.h>
+
+void contentStoreInterface_Release(ContentStoreInterface **storeImplPtr) {
+ (*storeImplPtr)->release(storeImplPtr);
+}
+
+bool contentStoreInterface_PutContent(ContentStoreInterface *storeImpl,
+ Message *content,
+ uint64_t currentTimeTicks) {
+ return storeImpl->putContent(storeImpl, content, currentTimeTicks);
+}
+
+bool contentStoreInterface_RemoveContent(ContentStoreInterface *storeImpl,
+ Message *content) {
+ return storeImpl->removeContent(storeImpl, content);
+}
+
+Message *contentStoreInterface_MatchInterest(ContentStoreInterface *storeImpl,
+ Message *interest,
+ uint64_t currentTimeTicks) {
+ return storeImpl->matchInterest(storeImpl, interest, currentTimeTicks);
+}
+
+size_t contentStoreInterface_GetObjectCapacity(
+ ContentStoreInterface *storeImpl) {
+ return storeImpl->getObjectCapacity(storeImpl);
+}
+
+size_t contentStoreInterface_GetObjectCount(ContentStoreInterface *storeImpl) {
+ return storeImpl->getObjectCount(storeImpl);
+}
+
+void contentStoreInterface_Log(ContentStoreInterface *storeImpl) {
+ storeImpl->log(storeImpl);
+}
+
+void *contentStoreInterface_GetPrivateData(ContentStoreInterface *storeImpl) {
+ return storeImpl->_privateData;
+}
diff --git a/hicn-light/src/content_store/contentStoreInterface.h b/hicn-light/src/content_store/contentStoreInterface.h
new file mode 100755
index 000000000..d73c63019
--- /dev/null
+++ b/hicn-light/src/content_store/contentStoreInterface.h
@@ -0,0 +1,211 @@
+/*
+ * 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 contentStoreInterface_h
+#define contentStoreInterface_h
+
+#include <stdio.h>
+
+#include <src/core/message.h>
+
+typedef struct contentstore_config {
+ size_t objectCapacity;
+} ContentStoreConfig;
+
+typedef struct contentstore_interface ContentStoreInterface;
+
+struct contentstore_interface {
+ /**
+ * Place a Message representing a ContentObject into the ContentStore. If
+ * necessary to make room, remove expired content or content that has exceeded
+ * the Recommended Cache Time.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param content - a pointer to a `Message` to place in the store.
+ * @param currentTimeTicks - the current time, in hicn-light ticks, since the
+ * UTC epoch.
+ */
+ bool (*putContent)(ContentStoreInterface *storeImpl, Message *content,
+ uint64_t currentTimeTicks);
+
+ /**
+ * The function to call to remove content from the ContentStore.
+ * It will Release any references that were created when the content was
+ * placed into the ContentStore.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param content - a pointer to a `Message` to remove from the store.
+ */
+ bool (*removeContent)(ContentStoreInterface *storeImpl, Message *content);
+
+ /**
+ * Given a Message that represents and Interest, try to find a matching
+ * ContentObject.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param interest - a pointer to a `Message` representing the Interest to
+ * match.
+ *
+ * @return a pointer to a Message containing the matching ContentObject
+ * @return NULL if no matching ContentObject was found
+ */
+ Message *(*matchInterest)(ContentStoreInterface *storeImpl, Message *interest,
+ uint64_t currentTimeTicks);
+
+ /**
+ * Return the maximum number of ContentObjects that can be stored in this
+ * ContentStore. This is a raw count, not based on memory size.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ *
+ * @return the maximum number of ContentObjects that can be stored
+ */
+ size_t (*getObjectCapacity)(ContentStoreInterface *storeImpl);
+
+ /**
+ * Return the number of ContentObjects currently stored in the ContentStore.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ *
+ * @return the current number of ContentObjects in the ContentStore
+ */
+ size_t (*getObjectCount)(ContentStoreInterface *storeImpl);
+
+ /**
+ * Log a ContentStore implementation specific version of store-related
+ * information.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+ void (*log)(ContentStoreInterface *storeImpl);
+
+ /**
+ * Acquire a new reference to the specified ContentStore instance. This
+ * reference will eventually need to be released by calling {@link
+ * contentStoreInterface_Release}.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+ ContentStoreInterface *(*acquire)(const ContentStoreInterface *storeImpl);
+
+ /**
+ * Release the ContentStore, which will also Release any references held by
+ * it.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+ void (*release)(ContentStoreInterface **storeImpl);
+
+ /**
+ * A pointer to opaque private data used by the ContentStore instance
+ * represented by this instance of ContentStoreInterface.
+ */
+ void *_privateData;
+};
+
+/**
+ * Place a Message representing a ContentObject into the ContentStore. If
+ * necessary to make room, remove expired content or content that has exceeded
+ * the Recommended Cache Time.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param content - a pointer to a `Message` to place in the store.
+ *
+ * @param currentTimeTicks - the current time, in hicn-light ticks, since the
+ * UTC epoch.
+ */
+bool contentStoreInterface_PutContent(ContentStoreInterface *storeImpl,
+ Message *content,
+ uint64_t currentTimeTicks);
+
+/**
+ * The function to call to remove content from the ContentStore.
+ * It will Release any references that were created when the content was placed
+ * into the ContentStore.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param content - a pointer to a `Message` to remove from the store.
+ */
+bool contentStoreInterface_RemoveContent(ContentStoreInterface *storeImpl,
+ Message *content);
+
+/**
+ * Given a Message that represents and Interest, try to find a matching
+ * ContentObject.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param interest - a pointer to a `Message` representing the Interest to
+ * match.
+ *
+ * @return a pointer to a Message containing the matching ContentObject
+ * @return NULL if no matching ContentObject was found
+ */
+Message *contentStoreInterface_MatchInterest(ContentStoreInterface *storeImpl,
+ Message *interest,
+ uint64_t currentTimeTicks);
+
+/**
+ * Return the maximum number of ContentObjects that can be stored in this
+ * ContentStore. This is a raw count, not based on memory size.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ *
+ * @return the maximum number of ContentObjects that can be stored
+ */
+size_t contentStoreInterface_GetObjectCapacity(
+ ContentStoreInterface *storeImpl);
+
+/**
+ * Return the number of ContentObjects currently stored in the ContentStore.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ *
+ * @return the current number of ContentObjects in the ContentStore
+ */
+size_t contentStoreInterface_GetObjectCount(ContentStoreInterface *storeImpl);
+
+/**
+ * Loga ContentStore implementation specific version of store-related
+ * information.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+void contentStoreInterface_Log(ContentStoreInterface *storeImpl);
+
+/**
+ * Acquire a new reference to the specified ContentStore instance. This
+ * reference will eventually need to be released by calling {@link
+ * contentStoreInterface_Release}.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+ContentStoreInterface *contentStoreInterface_Aquire(
+ const ContentStoreInterface *storeImpl);
+
+/**
+ * Release the ContentStore, which will also Release any references held by it.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+void contentStoreInterface_Release(ContentStoreInterface **storeImplPtr);
+
+/**
+ * Return a pointer to the data private to this implementation of the
+ * ContentStore interface.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+void *contentStoreInterface_GetPrivateData(ContentStoreInterface *storeImpl);
+#endif // contentStoreInterface_h
diff --git a/hicn-light/src/content_store/contentStoreLRU.c b/hicn-light/src/content_store/contentStoreLRU.c
new file mode 100755
index 000000000..9b69d51c0
--- /dev/null
+++ b/hicn-light/src/content_store/contentStoreLRU.c
@@ -0,0 +1,455 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+#include <sys/queue.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Object.h>
+
+#include <src/core/logger.h>
+
+#include <src/content_store/contentStoreLRU.h>
+
+#include <src/content_store/contentStoreEntry.h>
+#include <src/content_store/contentStoreInterface.h>
+#include <src/content_store/listLRU.h>
+#include <src/content_store/listTimeOrdered.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/processor/hashTableFunction.h>
+
+typedef struct contentstore_stats {
+ uint64_t countExpiryEvictions;
+ uint64_t countRCTEvictions;
+ uint64_t countLruEvictions;
+ uint64_t countAdds;
+ uint64_t countHits;
+ uint64_t countMisses;
+} _ContentStoreLRUStats;
+
+typedef struct contentstore_lru_data {
+ size_t objectCapacity;
+ size_t objectCount;
+
+ Logger *logger;
+
+ // This LRU is just for keeping track of insertion and access order.
+ ListLru *lru;
+
+ ListTimeOrdered *indexByExpirationTime;
+
+ PARCHashCodeTable *storageByName;
+
+ _ContentStoreLRUStats stats;
+} _ContentStoreLRU;
+
+static void _destroyIndexes(_ContentStoreLRU *store) {
+ if (store->indexByExpirationTime != NULL) {
+ listTimeOrdered_Release(&(store->indexByExpirationTime));
+ }
+
+ if (store->storageByName != NULL) {
+ parcHashCodeTable_Destroy(&(store->storageByName));
+ }
+
+ if (store->lru != NULL) {
+ listLRU_Destroy(&(store->lru));
+ }
+}
+
+static void _contentStoreInterface_Destroy(
+ ContentStoreInterface **storeImplPtr) {
+ _ContentStoreLRU *store = contentStoreInterface_GetPrivateData(*storeImplPtr);
+
+ parcObject_Release((PARCObject **)&store);
+}
+
+static bool _contentStoreLRU_Destructor(_ContentStoreLRU **storePtr) {
+ _ContentStoreLRU *store = *storePtr;
+
+ _destroyIndexes(store);
+ logger_Release(&store->logger);
+
+ return true;
+}
+
+parcObject_Override(_ContentStoreLRU, PARCObject,
+ .destructor = (PARCObjectDestructor *)
+ _contentStoreLRU_Destructor);
+
+parcObject_ExtendPARCObject(ContentStoreInterface,
+ _contentStoreInterface_Destroy, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+
+static parcObject_ImplementAcquire(_contentStoreLRU, ContentStoreInterface);
+static parcObject_ImplementRelease(_contentStoreLRU, ContentStoreInterface);
+
+static void _hashTableFunction_ContentStoreEntryDestroyer(void **dataPtr) {
+ contentStoreEntry_Release((ContentStoreEntry **)dataPtr);
+}
+
+static bool _contentStoreLRU_Init(_ContentStoreLRU *store,
+ ContentStoreConfig *config, Logger *logger) {
+ bool result = false;
+
+ store->logger = logger_Acquire(logger);
+
+ size_t initialSize = config->objectCapacity * 2;
+ memset(&store->stats, 0, sizeof(_ContentStoreLRUStats));
+
+ store->objectCapacity = config->objectCapacity;
+ store->objectCount = 0;
+
+ // initial size must be at least 1 or else the data structures break.
+ initialSize = (initialSize == 0) ? 1 : initialSize;
+
+ store->indexByExpirationTime = listTimeOrdered_Create(
+ (TimeOrderList_KeyCompare *)contentStoreEntry_CompareExpiryTime);
+
+ store->storageByName = parcHashCodeTable_Create_Size(
+ hashTableFunction_MessageNameEquals,
+ hashTableFunction_MessageNameHashCode, NULL,
+ _hashTableFunction_ContentStoreEntryDestroyer, initialSize);
+
+ store->lru = listLRU_Create();
+
+ // If any of the index tables couldn't be allocated, we can't continue.
+ if ((store->indexByExpirationTime == NULL) ||
+ (store->storageByName == NULL) || (store->lru == NULL)) {
+ if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+ PARCLogLevel_Error)) {
+ logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Error,
+ __func__,
+ "ContentStoreLRU could not be created. Could not allocate all "
+ "index tables.",
+ (void *)store, store->objectCapacity);
+ }
+
+ _destroyIndexes(store);
+ result = false;
+ } else {
+ result = true;
+ }
+ return result;
+}
+
+/**
+ * Remove a ContentStoreEntry from all tables and indices.
+ */
+static void _contentStoreLRU_PurgeStoreEntry(_ContentStoreLRU *store,
+ ContentStoreEntry *entryToPurge) {
+ if (contentStoreEntry_HasExpiryTimeTicks(entryToPurge)) {
+ listTimeOrdered_Remove(store->indexByExpirationTime, entryToPurge);
+ }
+
+ Message *content = contentStoreEntry_GetMessage(entryToPurge);
+
+ // This _Del call will call the Release/Destroy on the ContentStoreEntry,
+ // which will remove it from the LRU as well.
+ parcHashCodeTable_Del(store->storageByName, content);
+
+ store->objectCount--;
+}
+
+static bool _contentStoreLRU_RemoveLeastUsed(_ContentStoreLRU *store) {
+ bool result = false;
+
+ if (store->objectCount > 0) {
+ ListLruEntry *lruEntry = listLRU_PopTail(store->lru);
+ ContentStoreEntry *storeEntry =
+ (ContentStoreEntry *)listLRU_EntryGetData(lruEntry);
+
+ if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(
+ store->logger, LoggerFacility_Processor, PARCLogLevel_Debug, __func__,
+ "ContentStore %p evict message %p by LRU (LRU evictions %" PRIu64 ")",
+ (void *)store, (void *)contentStoreEntry_GetMessage(storeEntry),
+ store->stats.countLruEvictions);
+ }
+
+ _contentStoreLRU_PurgeStoreEntry(store, storeEntry);
+
+ result = true;
+ }
+ return result;
+}
+
+static void _evictByStorePolicy(_ContentStoreLRU *store,
+ uint64_t currentTimeInTicks) {
+ // We need to make room. Here's the plan:
+ // 1) Check to see if anything has expired. If so, remove it and we're done.
+ // If not, 2) Remove the least recently used item.
+
+ ContentStoreEntry *entry =
+ listTimeOrdered_GetOldest(store->indexByExpirationTime);
+ if (entry && contentStoreEntry_HasExpiryTimeTicks(entry) &&
+ (currentTimeInTicks > contentStoreEntry_GetExpiryTimeTicks(entry))) {
+ // Found an expired entry. Remove it, and we're done.
+
+ store->stats.countExpiryEvictions++;
+ if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__,
+ "ContentStore %p evict message %p by ExpiryTime (ExpiryTime "
+ "evictions %" PRIu64 ")",
+ (void *)store, (void *)contentStoreEntry_GetMessage(entry),
+ store->stats.countExpiryEvictions);
+ }
+
+ _contentStoreLRU_PurgeStoreEntry(store, entry);
+ } else {
+ store->stats.countLruEvictions++;
+ _contentStoreLRU_RemoveLeastUsed(store);
+ }
+}
+
+static bool _contentStoreLRU_PutContent(ContentStoreInterface *storeImpl,
+ Message *content,
+ uint64_t currentTimeTicks)
+
+{
+ bool result = false;
+ _ContentStoreLRU *store =
+ (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+ parcAssertNotNull(store, "Parameter store must be non-null");
+ parcAssertNotNull(content, "Parameter objectMessage must be non-null");
+
+ parcAssertTrue(message_GetType(content) == MessagePacketType_ContentObject,
+ "Parameter objectMessage must be a Content Object");
+
+ if (store->objectCapacity == 0) {
+ return false;
+ }
+
+ uint64_t expiryTimeTicks = contentStoreEntry_MaxExpiryTime;
+
+ if (message_HasContentExpiryTime(content)) {
+ expiryTimeTicks = message_GetContentExpiryTimeTicks(content);
+ }
+ // Don't add anything that's already expired or has exceeded RCT.
+ if (currentTimeTicks >= expiryTimeTicks) {
+ return false;
+ }
+
+ if (store->objectCount >= store->objectCapacity) {
+ // Store is full. Need to make room.
+ _evictByStorePolicy(store, currentTimeTicks);
+ }
+
+ // And now add a new entry to the head of the LRU.
+
+ ContentStoreEntry *entry = contentStoreEntry_Create(content, store->lru);
+
+ if (entry != NULL) {
+ if (parcHashCodeTable_Add(store->storageByName, content, entry)) {
+ if (contentStoreEntry_HasExpiryTimeTicks(entry)) {
+ listTimeOrdered_Add(store->indexByExpirationTime, entry);
+ }
+
+ store->objectCount++;
+ store->stats.countAdds++;
+
+ if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__,
+ "ContentStoreLRU %p saved message %p (object count %" PRIu64
+ ")",
+ (void *)store, (void *)content, store->objectCount);
+ }
+
+ result = true;
+ } else {
+ // Free what we just created, but did not add. 'entry' has ownership of
+ // 'copy', and so will call _Release() on it
+ contentStoreEntry_Release(&entry);
+
+ if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+ PARCLogLevel_Warning)) {
+ logger_Log(store->logger, LoggerFacility_Processor,
+ PARCLogLevel_Warning, __func__,
+ "ContentStoreLRU %p failed to add message %p to hash table",
+ (void *)store, (void *)content);
+ }
+ }
+ }
+
+ return result;
+}
+
+static Message *_contentStoreLRU_MatchInterest(ContentStoreInterface *storeImpl,
+ Message *interest,
+ uint64_t currentTimeTicks) {
+ Message *result = NULL;
+
+ _ContentStoreLRU *store =
+ (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+
+ parcAssertNotNull(store, "Parameter store must be non-null");
+ parcAssertNotNull(interest, "Parameter interestMessage must be non-null");
+ parcAssertTrue(message_GetType(interest) == MessagePacketType_Interest,
+ "Parameter interestMessage must be an Interest");
+
+ PARCHashCodeTable *table;
+ table = store->storageByName;
+
+ ContentStoreEntry *storeEntry = parcHashCodeTable_Get(table, interest);
+
+ bool foundEntry = false;
+
+ if (storeEntry) {
+ if (contentStoreEntry_HasExpiryTimeTicks(storeEntry) &&
+ contentStoreEntry_GetExpiryTimeTicks(storeEntry) < currentTimeTicks) {
+ // the entry is expired, we can remove it
+ _contentStoreLRU_PurgeStoreEntry(store, storeEntry);
+ } else {
+ foundEntry = true;
+ }
+ }
+
+ if (foundEntry) {
+ contentStoreEntry_MoveToHead(storeEntry);
+ result = contentStoreEntry_GetMessage(storeEntry);
+
+ store->stats.countHits++;
+
+ if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__,
+ "ContentStoreLRU %p matched interest %p (hits %" PRIu64
+ ", misses %" PRIu64 ")",
+ (void *)store, (void *)interest, store->stats.countHits,
+ store->stats.countMisses);
+ }
+ } else {
+ store->stats.countMisses++;
+
+ if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__,
+ "ContentStoreLRU %p missed interest %p (hits %" PRIu64
+ ", misses %" PRIu64 ")",
+ (void *)store, (void *)interest, store->stats.countHits,
+ store->stats.countMisses);
+ }
+ }
+
+ return result;
+}
+
+static bool _contentStoreLRU_RemoveContent(ContentStoreInterface *storeImpl,
+ Message *content) {
+ bool result = false;
+ _ContentStoreLRU *store =
+ (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+
+ ContentStoreEntry *storeEntry =
+ parcHashCodeTable_Get(store->storageByName, content);
+
+ if (storeEntry != NULL) {
+ _contentStoreLRU_PurgeStoreEntry(store, storeEntry);
+ result = true;
+ }
+
+ return result;
+}
+
+static void _contentStoreLRU_Log(ContentStoreInterface *storeImpl) {
+ _ContentStoreLRU *store =
+ (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+
+ logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_All,
+ __func__,
+ "ContentStoreLRU @%p {count = %zu, capacity = %zu {"
+ "stats = @%p {adds = %" PRIu64 ", hits = %" PRIu64
+ ", misses = %" PRIu64 ", LRUEvictons = %" PRIu64
+ ", ExpiryEvictions = %" PRIu64 ", RCTEvictions = %" PRIu64 "} }",
+ store, store->objectCount, store->objectCapacity, &store->stats,
+ store->stats.countAdds, store->stats.countHits,
+ store->stats.countMisses, store->stats.countLruEvictions,
+ store->stats.countExpiryEvictions, store->stats.countRCTEvictions);
+}
+
+static size_t _contentStoreLRU_GetObjectCapacity(
+ ContentStoreInterface *storeImpl) {
+ _ContentStoreLRU *store =
+ (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+ return store->objectCapacity;
+}
+
+static size_t _contentStoreLRU_GetObjectCount(
+ ContentStoreInterface *storeImpl) {
+ _ContentStoreLRU *store =
+ (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+ return store->objectCount;
+}
+
+static size_t _contentStoreLRU_SetObjectCapacity(
+ ContentStoreInterface *storeImpl, size_t newCapacity) {
+ _ContentStoreLRU *store =
+ (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+ return store->objectCapacity = newCapacity;
+}
+
+ContentStoreInterface *contentStoreLRU_Create(ContentStoreConfig *config,
+ Logger *logger) {
+ ContentStoreInterface *storeImpl = NULL;
+
+ parcAssertNotNull(logger, "ContentStoreLRU requires a non-NULL logger");
+
+ storeImpl = parcObject_CreateAndClearInstance(ContentStoreInterface);
+
+ if (storeImpl != NULL) {
+ storeImpl->_privateData =
+ parcObject_CreateAndClearInstance(_ContentStoreLRU);
+
+ if (_contentStoreLRU_Init(storeImpl->_privateData, config, logger)) {
+ storeImpl->putContent = &_contentStoreLRU_PutContent;
+ storeImpl->removeContent = &_contentStoreLRU_RemoveContent;
+
+ storeImpl->matchInterest = &_contentStoreLRU_MatchInterest;
+
+ storeImpl->getObjectCount = &_contentStoreLRU_GetObjectCount;
+ storeImpl->getObjectCapacity = &_contentStoreLRU_GetObjectCapacity;
+
+ storeImpl->log = &_contentStoreLRU_Log;
+
+ storeImpl->acquire = &_contentStoreLRU_Acquire;
+ storeImpl->release = &_contentStoreLRU_Release;
+
+ // Initialize from the config passed to us.
+ _contentStoreLRU_SetObjectCapacity(storeImpl, config->objectCapacity);
+
+ if (logger_IsLoggable(logger, LoggerFacility_Processor,
+ PARCLogLevel_Info)) {
+ logger_Log(logger, LoggerFacility_Processor, PARCLogLevel_Info,
+ __func__, "ContentStoreLRU %p created with capacity %zu",
+ (void *)storeImpl,
+ contentStoreInterface_GetObjectCapacity(storeImpl));
+ }
+ }
+ } else {
+ parcObject_Release((void **)&storeImpl);
+ }
+
+ return storeImpl;
+}
diff --git a/hicn-light/src/content_store/contentStoreLRU.h b/hicn-light/src/content_store/contentStoreLRU.h
new file mode 100755
index 000000000..3c0815ebd
--- /dev/null
+++ b/hicn-light/src/content_store/contentStoreLRU.h
@@ -0,0 +1,39 @@
+/*
+ * 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 contentStoreLRU_h
+#define contentStoreLRU_h
+
+#include <src/content_store/contentStoreInterface.h>
+#include <src/core/logger.h>
+#include <stdio.h>
+
+/**
+ * Create and Initialize an instance of contentStoreLRU. A newly allocated
+ * {@link ContentStoreInterface} object is initialized and returned. It must
+ * eventually be released by calling {@link contentStoreInterface_Release}.
+ *
+ *
+ * @param config An instance of `ContentStoreConfig`, specifying options to be
+ * applied by the underlying contentStoreLRU instance.
+ * @param logger An instance of a {@link Logger} to use for logging content
+ * store events.
+ *
+ * @return a newly created contentStoreLRU instance.
+ *
+ */
+ContentStoreInterface *contentStoreLRU_Create(ContentStoreConfig *config,
+ Logger *logger);
+#endif // contentStoreLRU_h
diff --git a/hicn-light/src/content_store/listLRU.c b/hicn-light/src/content_store/listLRU.c
new file mode 100755
index 000000000..42b491d7c
--- /dev/null
+++ b/hicn-light/src/content_store/listLRU.c
@@ -0,0 +1,133 @@
+/*
+ * 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 <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/queue.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/content_store/listLRU.h>
+
+struct list_lru_entry {
+ void *userData;
+
+ // always set to the list
+ ListLru *parentList;
+
+ // indicates if the Entry is currently in the list
+ bool inList;
+
+ TAILQ_ENTRY(list_lru_entry) list;
+};
+
+// this defines the TAILQ structure so we can access the tail pointer
+TAILQ_HEAD(lru_s, list_lru_entry);
+
+struct list_lru {
+ struct lru_s head;
+ size_t itemsInList;
+};
+
+void listLRU_EntryDestroy(ListLruEntry **entryPtr) {
+ parcAssertNotNull(entryPtr,
+ "Parameter entryPtr must be non-null double pointer");
+
+ ListLruEntry *entry = *entryPtr;
+ if (entry->inList) {
+ TAILQ_REMOVE(&entry->parentList->head, entry, list);
+ parcAssertTrue(
+ entry->parentList->itemsInList > 0,
+ "Invalid state, removed entry from list, but itemsInList is 0");
+ entry->parentList->itemsInList--;
+ }
+
+ parcMemory_Deallocate((void **)&entry);
+ *entryPtr = NULL;
+}
+
+void listLRU_EntryMoveToHead(ListLruEntry *entry) {
+ parcAssertNotNull(entry, "Parameter entry must be non-null");
+
+ TAILQ_REMOVE(&entry->parentList->head, entry, list);
+ TAILQ_INSERT_HEAD(&entry->parentList->head, entry, list);
+}
+
+void *listLRU_EntryGetData(ListLruEntry *entry) { return entry->userData; }
+
+ListLru *listLRU_Create() {
+ ListLru *list = parcMemory_AllocateAndClear(sizeof(ListLru));
+ parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListLru));
+ list->itemsInList = 0;
+ TAILQ_INIT(&list->head);
+ return list;
+}
+
+void listLRU_Destroy(ListLru **lruPtr) {
+ parcAssertNotNull(lruPtr, "Parameter lruPtr must be non-null double pointer");
+
+ ListLru *lru = *lruPtr;
+
+ ListLruEntry *entry = TAILQ_FIRST(&lru->head);
+ while (entry != NULL) {
+ ListLruEntry *next = TAILQ_NEXT(entry, list);
+ listLRU_EntryDestroy(&entry);
+ entry = next;
+ }
+
+ parcMemory_Deallocate((void **)&lru);
+ *lruPtr = NULL;
+}
+
+ListLruEntry *listLRU_NewHeadEntry(ListLru *lru, void *data) {
+ parcAssertNotNull(lru, "Parameter lru must be non-null");
+ parcAssertNotNull(data, "Parameter data must be non-null");
+
+ ListLruEntry *entry = parcMemory_AllocateAndClear(sizeof(ListLruEntry));
+ parcAssertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListLruEntry));
+ entry->userData = data;
+ entry->parentList = lru;
+ entry->inList = true;
+
+ TAILQ_INSERT_HEAD(&lru->head, entry, list);
+ lru->itemsInList++;
+
+ return entry;
+}
+
+ListLruEntry *listLRU_PopTail(ListLru *lru) {
+ parcAssertNotNull(lru, "Parameter lru must be non-null");
+
+ ListLruEntry *entry = TAILQ_LAST(&lru->head, lru_s);
+
+ if (entry) {
+ parcAssertTrue(
+ lru->itemsInList > 0,
+ "Invalid state, removed entry from list, but itemsInList is 0");
+ lru->itemsInList--;
+ TAILQ_REMOVE(&lru->head, entry, list);
+ entry->inList = false;
+ }
+
+ return entry;
+}
+
+size_t listLRU_Length(const ListLru *lru) {
+ parcAssertNotNull(lru, "Parameter lru must be non-null");
+ return lru->itemsInList;
+}
diff --git a/hicn-light/src/content_store/listLRU.h b/hicn-light/src/content_store/listLRU.h
new file mode 100755
index 000000000..75f698b61
--- /dev/null
+++ b/hicn-light/src/content_store/listLRU.h
@@ -0,0 +1,94 @@
+/*
+ * 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 listLRU.h
+ * @brief Maintains an LRU for the content store
+ *
+ * An LRU list is make up of LRU entries. The entries are bound to the list.
+ * The user of the list is reponsible for knowing when there's too many things
+ * and wants to remove one. The LRU list will grow without bound otherwise.
+ *
+ * The LRU list is meant to be used as an auxiliary data structure, not the
+ * primary storage of data elements.
+ *
+ */
+
+#ifndef listLRU_h
+#define listLRU_h
+
+struct list_lru_entry;
+typedef struct list_lru_entry ListLruEntry;
+
+struct list_lru;
+typedef struct list_lru ListLru;
+
+/**
+ * @function lruEntry_Destroy
+ * @abstract Destroys and element. This will also remove it from the list.
+ */
+void listLRU_EntryDestroy(ListLruEntry **entryPtr);
+
+/**
+ * @function listLRU_EntryMoveToHead
+ * @abstract move an element to head
+ */
+void listLRU_EntryMoveToHead(ListLruEntry *entry);
+
+/**
+ * @function lruEntry_GetData
+ * @abstract Returns the user-supplied opaque data when the entry was created
+ */
+void *listLRU_EntryGetData(ListLruEntry *entry);
+
+/**
+ * @function listLRU_Create
+ * @abstract Creates a new Least-Recently-Used list
+ */
+ListLru *listLRU_Create();
+
+/**
+ * @function listLRU_Destroy
+ * @abstract Destroys a list and frees all the elements in it
+ */
+void listLRU_Destroy(ListLru **listPtr);
+
+/**
+ * Returns the number of items in the list
+ *
+ * @param [in] lru An allocated ListLru
+ * @retval number The number of items in the LRU list
+ */
+size_t listLRU_Length(const ListLru *lru);
+
+/**
+ * @function listLRU_NewHeadEntry
+ * @abstract Creates a new entry for the list. It is inserted at the head of
+ * the list.
+ */
+ListLruEntry *listLRU_NewHeadEntry(ListLru *lru, void *data);
+
+/**
+ * @function listLRU_PopTail
+ * @abstract Removes the tail element from the list and returns it to the user
+ * @discussion
+ * Pops the tail element. The user should examine its data to destroy their
+ * tail object, then call <code>LruEntry_Destroy()</code> to free the
+ * LRU entry.
+ *
+ * @return The tail element, or NULL for an empty list
+ */
+ListLruEntry *listLRU_PopTail(ListLru *list);
+#endif // listLRU_h
diff --git a/hicn-light/src/content_store/listTimeOrdered.c b/hicn-light/src/content_store/listTimeOrdered.c
new file mode 100755
index 000000000..44697d202
--- /dev/null
+++ b/hicn-light/src/content_store/listTimeOrdered.c
@@ -0,0 +1,94 @@
+/*
+ * 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 <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <src/content_store/listTimeOrdered.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+/**
+ * A list of ContentStoreEntrys, kept in sorted order by time. The ordering is
+ * calculated by a key compare function (e.g. {@link TimeOrderList_KeyCompare}),
+ * passed in.
+ *
+ * This container does not hold references to the objects that it contains. In
+ * other words, it does not Acquire() the Messages that are placed in it. That
+ * reference count is managed by the owning ContentStore. This is purely an
+ * index, and provides an easy to way index Messages based on a specified time
+ * value. Typically, that would be the Expiration Time.
+ *
+ * It maintains a tree, sorted by the time values passed in to the Add()
+ * function. It does not manage capacity, and can grow uncontrollably if the
+ * owning ContentStore does not manage it. Items are indexed first by time, then
+ * address of the Message (just as a distringuishing attribute). This allows us
+ * to store multiple items with the same expiration time.
+ */
+
+struct list_timeordered {
+ PARCTreeRedBlack *timeOrderedTree;
+};
+
+static void _finalRelease(ListTimeOrdered **listP) {
+ ListTimeOrdered *list = *listP;
+ parcTreeRedBlack_Destroy(&list->timeOrderedTree);
+}
+
+parcObject_ExtendPARCObject(ListTimeOrdered, _finalRelease, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(listTimeOrdered, ListTimeOrdered);
+
+parcObject_ImplementRelease(listTimeOrdered, ListTimeOrdered);
+
+ListTimeOrdered *listTimeOrdered_Create(
+ TimeOrderList_KeyCompare *keyCompareFunction) {
+ ListTimeOrdered *result = parcObject_CreateInstance(ListTimeOrdered);
+ if (NULL != result) {
+ result->timeOrderedTree =
+ parcTreeRedBlack_Create(keyCompareFunction, // keyCompare
+ NULL, // keyFree
+ NULL, // keyCopy
+ NULL, // valueEquals
+ NULL, // valueFree
+ NULL); // valueCopy
+ }
+ return result;
+}
+
+void listTimeOrdered_Add(ListTimeOrdered *list, ContentStoreEntry *entry) {
+ parcTreeRedBlack_Insert(list->timeOrderedTree, entry, entry);
+}
+
+ContentStoreEntry *listTimeOrdered_GetOldest(ListTimeOrdered *list) {
+ return parcTreeRedBlack_FirstKey(list->timeOrderedTree);
+}
+
+bool listTimeOrdered_Remove(ListTimeOrdered *list,
+ ContentStoreEntry *storeEntry) {
+ bool result = false;
+
+ ContentStoreEntry *entry = (ContentStoreEntry *)parcTreeRedBlack_Remove(
+ list->timeOrderedTree, storeEntry);
+ if (entry != NULL) {
+ result = true;
+ }
+ return result;
+}
+
+size_t listTimeOrdered_Length(ListTimeOrdered *list) {
+ return (size_t)parcTreeRedBlack_Size(list->timeOrderedTree);
+}
diff --git a/hicn-light/src/content_store/listTimeOrdered.h b/hicn-light/src/content_store/listTimeOrdered.h
new file mode 100755
index 000000000..b18bd16f7
--- /dev/null
+++ b/hicn-light/src/content_store/listTimeOrdered.h
@@ -0,0 +1,103 @@
+/*
+ * 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 listTimeOrdered_h
+#define listTimeOrdered_h
+
+#include <parc/algol/parc_TreeRedBlack.h>
+#include <src/content_store/contentStoreEntry.h>
+#include <src/core/message.h>
+#include <stdio.h>
+
+struct list_timeordered;
+typedef struct list_timeordered ListTimeOrdered;
+
+/**
+ * A signum function that takes two instances of ContentStoreEntrys and
+ * returns a value based on their relative values.
+ */
+typedef PARCTreeRedBlack_KeyCompare TimeOrderList_KeyCompare;
+
+/**
+ * Create a new instance of `ListTimeOrdered` that will maintain the order of
+ * its list items using the supplied `keyCompareFunction`.
+ *
+ * The newly created `ListTimeOrdered` must eventually be released by calling
+ * {@link listTimeOrdered_Release}.
+ *
+ * @param keyCompareFunction the signum comparison function to use to sort
+ * stored items.
+ * @return a new instance of `TimeOrderList`.
+ * @return NULL if the new instance couldn't be created.
+ *
+ */
+ListTimeOrdered *listTimeOrdered_Create(
+ TimeOrderList_KeyCompare *keyCompareFunction);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ */
+void listTimeOrdered_Release(ListTimeOrdered **listP);
+
+/**
+ * Add a {@link ContentStoreEntry} instance to the specified list. Note that a
+ * new refernece to the specified `storeEntry` is not acquired.
+ *
+ * @param list the list instance into which to add the specified storeEntry.
+ * @param storeEntry the storeEntry instance to add.
+ *
+ */
+void listTimeOrdered_Add(ListTimeOrdered *list, ContentStoreEntry *storeEntry);
+
+/**
+ * Remove a {@link ContentStoreEntry} instance from the specified list.
+ *
+ * @param list the list instance from which to remove the specified storeEntry.
+ * @param storeEntry the storeEntry instance to remove.
+ * @return true if the removal was succesful.
+ * @return false if the removal was not succesful.
+ *
+ */
+bool listTimeOrdered_Remove(ListTimeOrdered *list,
+ ContentStoreEntry *storeEntry);
+
+/**
+ * Return the oldest {@link ContentStoreEntry} instance in this list. That is,
+ * the one with the smallest time value.
+ *
+ * @param list the list instance from which to retrieve the oldest storeEntry.
+ * @param the oldest `ContentStoreEntry` in the list
+ * @param NULL if no `ContentStoreEntry` was available.
+ *
+ */
+ContentStoreEntry *listTimeOrdered_GetOldest(ListTimeOrdered *list);
+
+/**
+ * Return the number of items currently stored in the list.
+ *
+ * @param list the `ListTimeOrdered` instance from which to retrieve the count.
+ * @return the number of items in the list.
+ *
+ */
+size_t listTimeOrdered_Length(ListTimeOrdered *list);
+#endif /* defined(listTimeOrdered_h) */
diff --git a/hicn-light/src/core/CMakeLists.txt b/hicn-light/src/core/CMakeLists.txt
new file mode 100755
index 000000000..1d7dc03e9
--- /dev/null
+++ b/hicn-light/src/core/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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/ticks.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/connection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/logger.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/message.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/messagePacketType.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/system.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mapMe.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/wldr.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/messageHandler.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/name.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/connection.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/logger.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/message.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mapMe.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/name.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/hicn-light/src/core/connection.c b/hicn-light/src/core/connection.c
new file mode 100755
index 000000000..073b7260f
--- /dev/null
+++ b/hicn-light/src/core/connection.c
@@ -0,0 +1,265 @@
+/*
+ * 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 <limits.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/core/connection.h>
+#include <src/core/messageHandler.h>
+#include <src/core/ticks.h>
+#include <src/core/wldr.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+struct connection {
+ const AddressPair *addressPair;
+ IoOperations *ops;
+
+ unsigned refCount;
+
+ bool probing_active;
+ unsigned probing_interval;
+ unsigned counter;
+ Ticks last_sent;
+ Ticks delay;
+
+ bool wldrAutoStart; // if true, wldr can be set automatically
+ // by default this value is set to true.
+ // if wldr is activated using a command (config
+ // file/hicnLightControl) this value is set to false so
+ // that a base station can not disable wldr at the client
+ Wldr *wldr;
+};
+
+Connection *connection_Create(IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ Connection *conn = parcMemory_AllocateAndClear(sizeof(Connection));
+ parcAssertNotNull(conn, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Connection));
+ conn->addressPair = ioOperations_GetAddressPair(ops);
+ conn->ops = ops;
+ conn->refCount = 1;
+ conn->wldr = NULL;
+ conn->probing_active = false;
+
+ conn->wldrAutoStart = true;
+ conn->probing_interval = 0;
+ conn->counter = 0;
+ conn->last_sent = 0;
+ conn->delay = INT_MAX;
+ return conn;
+}
+
+Connection *connection_Acquire(Connection *connection) {
+ parcAssertNotNull(connection, "Parameter conn must be non-null");
+ connection->refCount++;
+ return connection;
+}
+
+void connection_Release(Connection **connectionPtr) {
+ parcAssertNotNull(connectionPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*connectionPtr,
+ "Parameter must dereference to non-null pointer");
+ Connection *conn = *connectionPtr;
+
+ parcAssertTrue(
+ conn->refCount > 0,
+ "Invalid state, connection reference count should be positive, got 0.");
+ conn->refCount--;
+ if (conn->refCount == 0) {
+ // don't destroy addressPair, its part of ops.
+ ioOperations_Release(&conn->ops);
+ if (conn->wldr != NULL) {
+ wldr_Destroy(&(conn->wldr));
+ }
+ parcMemory_Deallocate((void **)&conn);
+ }
+ *connectionPtr = NULL;
+}
+
+bool connection_Send(const Connection *conn, Message *message) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+
+ if (ioOperations_IsUp(conn->ops)) {
+ if (message_GetType(message) == MessagePacketType_ContentObject) {
+ uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn);
+ message_UpdatePathLabel(message, connectionId);
+ }
+ if (conn->wldr != NULL) {
+ wldr_SetLabel(conn->wldr, message);
+ } else {
+ message_ResetWldrLabel(message);
+ }
+ return ioOperations_Send(conn->ops, NULL, message);
+ }
+ return false;
+}
+
+static void _sendProbe(Connection *conn, unsigned probeType, uint8_t *message) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+
+ if (probeType == PACKET_TYPE_PROBE_REQUEST) {
+ Ticks now = ioOperations_SendProbe(conn->ops, probeType, message);
+ if (now != 0) {
+ conn->last_sent = now;
+ }
+ } else {
+ ioOperations_SendProbe(conn->ops, probeType, message);
+ }
+}
+
+void connection_Probe(Connection *conn) {
+ _sendProbe(conn, PACKET_TYPE_PROBE_REQUEST, NULL);
+}
+
+void connection_HandleProbe(Connection *conn, uint8_t *probe,
+ Ticks actualTime) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ parcAssertNotNull(probe, "Parameter pkt must be non-null");
+
+ uint8_t probeType = messageHandler_GetProbePacketType(probe);
+ if (probeType == PACKET_TYPE_PROBE_REQUEST) {
+ _sendProbe(conn, PACKET_TYPE_PROBE_REPLY, probe);
+ } else if (probeType == PACKET_TYPE_PROBE_REPLY) {
+ Ticks delay = actualTime - conn->last_sent;
+ if (delay == 0) {
+ delay = 1;
+ }
+ if (delay < conn->delay) {
+ conn->delay = delay;
+ }
+ } else {
+ printf("receivde unkwon probe type\n");
+ }
+}
+
+uint64_t connection_GetDelay(Connection *conn) { return (uint64_t)conn->delay; }
+
+IoOperations *connection_GetIoOperations(const Connection *conn) {
+ return conn->ops;
+}
+
+unsigned connection_GetConnectionId(const Connection *conn) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ return ioOperations_GetConnectionId(conn->ops);
+}
+
+const AddressPair *connection_GetAddressPair(const Connection *conn) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ return ioOperations_GetAddressPair(conn->ops);
+}
+
+bool connection_IsUp(const Connection *conn) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ if (!conn->ops) return false;
+ return ioOperations_IsUp(conn->ops);
+}
+
+bool connection_IsLocal(const Connection *conn) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ return ioOperations_IsLocal(conn->ops);
+}
+
+const void *connection_Class(const Connection *conn) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ return ioOperations_Class(conn->ops);
+}
+
+bool connection_ReSend(const Connection *conn, Message *message,
+ bool notification) {
+ parcAssertNotNull(conn, "Parameter conn must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ bool res = false;
+
+ if (connection_IsUp(conn)) {
+ // here the wldr header is alreay set: this message is a retransmission or a
+ // notification
+
+ // we need to recompiute the path lable since we always store a pointer to
+ // the same message if this message will be sent again to someonelse, the new
+ // path label must be computed starting from the orignal labelorignal label.
+ // Notice that we heve the same problem in case of PIT aggregation. That case
+ // is handled insied the MessageProcessor. This is specific to WLDR
+ // retransmittions. This is done only for data packets
+
+ if (message_GetType(message) == MessagePacketType_ContentObject) {
+ uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn);
+ uint32_t old_path_label = message_GetPathLabel(message);
+ message_UpdatePathLabel(message, connectionId);
+
+ res = ioOperations_Send(conn->ops, NULL, message);
+
+ message_SetPathLabel(message, old_path_label);
+ } else {
+ res = ioOperations_Send(conn->ops, NULL, message);
+ }
+ }
+
+ if (notification) {
+ // the notification is never destroyed
+ message_Release(&message);
+ }
+
+ return res;
+}
+
+void connection_AllowWldrAutoStart(Connection *conn, bool allow) {
+ conn->wldrAutoStart = allow;
+}
+
+void connection_EnableWldr(Connection *conn) {
+ if (!connection_IsLocal(conn)) {
+ if (conn->wldr == NULL) {
+ printf("----------------- enable wldr\n");
+ conn->wldr = wldr_Init();
+ }
+ }
+}
+
+void connection_DisableWldr(Connection *conn) {
+ if (!connection_IsLocal(conn)) {
+ if (conn->wldr != NULL) {
+ printf("----------------- disable wldr\n");
+ wldr_Destroy(&(conn->wldr));
+ conn->wldr = NULL;
+ }
+ }
+}
+
+bool connection_HasWldr(const Connection *conn) {
+ if (conn->wldr == NULL) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool connection_WldrAutoStartAllowed(const Connection *conn) {
+ return conn->wldrAutoStart;
+}
+
+void connection_DetectLosses(Connection *conn, Message *message) {
+ if (conn->wldr != NULL) wldr_DetectLosses(conn->wldr, conn, message);
+}
+
+void connection_HandleWldrNotification(Connection *conn, Message *message) {
+ if (conn->wldr != NULL)
+ wldr_HandleWldrNotification(conn->wldr, conn, message);
+}
diff --git a/hicn-light/src/core/connection.h b/hicn-light/src/core/connection.h
new file mode 100755
index 000000000..b5c703527
--- /dev/null
+++ b/hicn-light/src/core/connection.h
@@ -0,0 +1,148 @@
+/*
+ * 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 connection.h
+ * @brief Wrapper for different types of connections
+ *
+ * A connection wraps a specific set of {@link IoOperations}. Those operations
+ * allow for input and output. Connections get stored in the Connection Table.
+ *
+ */
+
+#ifndef connection_h
+#define connection_h
+#include <src/config.h>
+#include <src/io/ioOperations.h>
+#include <src/utils/address.h>
+
+// packet types for probing
+#define PACKET_TYPE_PROBE_REQUEST 5
+#define PACKET_TYPE_PROBE_REPLY 6
+
+struct connection;
+typedef struct connection Connection;
+
+/**
+ * Creates a connection object.
+ */
+Connection *connection_Create(IoOperations *ops);
+
+/**
+ * @function connection_Release
+ * @abstract Releases a reference count, destroying on last release
+ * @discussion
+ * Only frees the memory on the final reference count. The pointer will
+ * always be NULL'd.
+ */
+void connection_Release(Connection **connectionPtr);
+
+/**
+ * @function connection_Acquire
+ * @abstract A reference counted copy.
+ * @discussion
+ * A shallow copy, they share the same memory.
+ */
+Connection *connection_Acquire(Connection *connection);
+
+/**
+ * @function connection_Send
+ * @abstract Sends the message on the connection
+ * @return true if message sent, false if connection not up
+ */
+bool connection_Send(const Connection *conn, Message *message);
+
+/**
+ * Return the `IoOperations` instance associated with the specified `Connection`
+ * instance.
+ * @param [in] connection The allocated connection
+ * @return a pointer to the IoOperations instance associated by th specified
+ * connection.
+ */
+IoOperations *connection_GetIoOperations(const Connection *conn);
+
+/**
+ * Returns the unique identifier of the connection
+ * Calls the underlying IoOperations to fetch the connection id
+ * @param [in] connection The allocated connection
+ * @return unsigned The unique connection id
+ */
+unsigned connection_GetConnectionId(const Connection *conn);
+
+/**
+ * Returns the (remote, local) address pair that describes the connection
+ * @param [in] connection The allocated connection
+ * @return non-null The connection's remote and local address
+ * @return null Should never return NULL
+ */
+const AddressPair *connection_GetAddressPair(const Connection *conn);
+
+/**
+ * Checks if the connection is in the "up" state
+ * @param [in] connection The allocated connection
+ * @return true The connection is in the "up" state
+ * @return false The connection is not in the "up" state
+ */
+bool connection_IsUp(const Connection *conn);
+
+/**
+ * Checks if the connection is to a Local/Loopback address
+ *
+ * A local connection is PF_LOCAL (PF_UNIX) and a loopback connection is
+ * 127.0.0.0/8 or ::1 for IPv6.
+ *
+ * @param [in] connection The allocated connection
+ *
+ * @retval true The connection is local or loopback
+ * @retval false The connection is not local or loopback
+ */
+bool connection_IsLocal(const Connection *conn);
+
+/**
+ * Returns an opaque pointer representing the class of the Io Operations
+ *
+ * Returns an opaque pointer that an implementation can use to detect if
+ * the connection is based on that class.
+ *
+ * @param [in] conn The Connection to analyze
+ *
+ * @return non-null An opaque pointer for each concrete implementation
+ */
+const void *connection_Class(const Connection *conn);
+
+bool connection_ReSend(const Connection *conn, Message *message,
+ bool notification);
+
+void connection_Probe(Connection *conn);
+
+void connection_HandleProbe(Connection *conn, uint8_t *message,
+ Ticks actualTime);
+
+uint64_t connection_GetDelay(Connection *conn);
+
+void connection_AllowWldrAutoStart(Connection *conn, bool allow);
+
+void connection_EnableWldr(Connection *conn);
+
+void connection_DisableWldr(Connection *conn);
+
+bool connection_HasWldr(const Connection *conn);
+
+bool connection_WldrAutoStartAllowed(const Connection *conn);
+
+void connection_DetectLosses(Connection *conn, Message *message);
+
+void connection_HandleWldrNotification(Connection *conn, Message *message);
+#endif // connection_h
diff --git a/hicn-light/src/core/connectionList.c b/hicn-light/src/core/connectionList.c
new file mode 100755
index 000000000..b2913fa05
--- /dev/null
+++ b/hicn-light/src/core/connectionList.c
@@ -0,0 +1,68 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/core/connectionList.h>
+
+struct connection_list {
+ PARCArrayList *listOfConnections;
+};
+
+static void connectionList_ArrayDestroyer(void **voidPtr) {
+ Connection **entryPtr = (Connection **)voidPtr;
+ connection_Release(entryPtr);
+}
+
+ConnectionList *connectionList_Create() {
+ ConnectionList *list = parcMemory_AllocateAndClear(sizeof(ConnectionList));
+ parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ConnectionList));
+ list->listOfConnections = parcArrayList_Create(connectionList_ArrayDestroyer);
+ return list;
+}
+
+void connectionList_Destroy(ConnectionList **listPtr) {
+ parcAssertNotNull(listPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*listPtr, "Parameter must dereference to non-null pointer");
+ ConnectionList *list = *listPtr;
+ parcArrayList_Destroy(&list->listOfConnections);
+ parcMemory_Deallocate((void **)&list);
+ *listPtr = NULL;
+}
+
+void connectionList_Append(ConnectionList *list, Connection *entry) {
+ parcAssertNotNull(list, "Parameter list must be non-null");
+ parcAssertNotNull(entry, "Parameter entry must be non-null");
+
+ parcArrayList_Add(list->listOfConnections, connection_Acquire(entry));
+}
+
+size_t connectionList_Length(const ConnectionList *list) {
+ parcAssertNotNull(list, "Parameter list must be non-null");
+ return parcArrayList_Size(list->listOfConnections);
+}
+
+Connection *connectionList_Get(ConnectionList *list, size_t index) {
+ parcAssertNotNull(list, "Parameter list must be non-null");
+ Connection *original =
+ (Connection *)parcArrayList_Get(list->listOfConnections, index);
+ return original;
+}
diff --git a/hicn-light/src/core/connectionList.h b/hicn-light/src/core/connectionList.h
new file mode 100755
index 000000000..cdca12993
--- /dev/null
+++ b/hicn-light/src/core/connectionList.h
@@ -0,0 +1,70 @@
+/*
+ * 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 connectionList.h
+ * @brief A typesafe list of Connection objects
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef connectionList_h
+#define connectionList_h
+
+struct connection_list;
+typedef struct connection_list ConnectionList;
+
+#include <src/core/connection.h>
+
+/**
+ * Creates a lis of Connection
+ *
+ * @return non-null An allocated list
+ * @return null An error
+ */
+ConnectionList *connectionList_Create(void);
+
+/**
+ * Destroys the list and all objects inside it
+ */
+void connectionList_Destroy(ConnectionList **listPtr);
+
+/**
+ * @function connectionList_Append
+ * @abstract Adds a connection entry to the list.
+ * @discussion
+ * Acquires a reference to the passed entry and stores it in the list.
+ */
+void connectionList_Append(ConnectionList *list, Connection *entry);
+
+/**
+ * Returns the number of items on the list
+ * @param [in] list The allocated list to check
+ * @return number The number of items on the list
+ */
+size_t connectionList_Length(const ConnectionList *list);
+
+/**
+ * @function connectionList_Get
+ * @abstract Returns the connection entry.
+ * @discussion
+ * Caller must not destroy the returned value. If you will store the
+ * entry in your own data structure, you should acquire your own reference.
+ * Will assert if you go beyond the end of the list.
+ *
+ */
+Connection *connectionList_Get(ConnectionList *list, size_t index);
+#endif // connectionList_h
diff --git a/hicn-light/src/core/connectionManager.c b/hicn-light/src/core/connectionManager.c
new file mode 100755
index 000000000..2089e1495
--- /dev/null
+++ b/hicn-light/src/core/connectionManager.c
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+/**
+ * The Connection Manager sets itself up as a listener to the Messenger so it
+ * can take action based on system events.
+ *
+ * The Connection Manager queues and then processes in a later time slice the
+ * messages.
+ *
+ */
+
+#include <src/config.h>
+#include <src/core/connectionManager.h>
+#include <src/core/forwarder.h>
+#include <src/messenger/messenger.h>
+#include <src/messenger/messengerRecipient.h>
+#include <src/messenger/missiveDeque.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct connection_manager {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ MessengerRecipient *messengerRecipient;
+
+ // we queue missives as they come in to process in our own
+ // event timeslice
+ MissiveDeque *missiveQueue;
+
+ // for deferred queue processing
+ PARCEventTimer *timerEvent;
+};
+
+/**
+ * Receives missives from the messenger, queues them, and schedules our
+ * execution
+ *
+ * We defer processing of missives to a later time slice
+ */
+static void connectionManager_MessengerCallback(MessengerRecipient *recipient,
+ Missive *missive);
+
+/**
+ * Event callback
+ *
+ * This is our main run loop to process our queue of messages. It is scheduled
+ * in {@link connectionManager_MessengerCallback} when the queue becomes
+ * non-empty.
+ *
+ * When we are called here, we have exclusive use of the system, so we will not
+ * create any message loops
+ *
+ * @param [in] fd unused, required for compliance with function prototype
+ * @param [in] which_event unused, required for compliance with function
+ * prototype
+ * @param [in] connManagerVoidPtr A void* to ConnectionManager
+ *
+ */
+static void connectionManager_ProcessQueue(int fd, PARCEventType which_event,
+ void *connManagerVoidPtr);
+
+static void connectionManager_ProcessClosedMissive(
+ ConnectionManager *connManager, const Missive *missive);
+
+// ========================================================
+// Public API
+
+ConnectionManager *connectionManager_Create(Forwarder *forwarder) {
+ ConnectionManager *connManager =
+ parcMemory_AllocateAndClear(sizeof(ConnectionManager));
+ parcAssertNotNull(connManager,
+ "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ConnectionManager));
+ connManager->forwarder = forwarder;
+ connManager->missiveQueue = missiveDeque_Create();
+ connManager->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+ Messenger *messenger = forwarder_GetMessenger(connManager->forwarder);
+
+ // creates the timer, but does not start it
+ PARCEventScheduler *base =
+ dispatcher_GetEventScheduler(forwarder_GetDispatcher(forwarder));
+ connManager->timerEvent = parcEventTimer_Create(
+ base, 0, connectionManager_ProcessQueue, connManager);
+
+ connManager->messengerRecipient = messengerRecipient_Create(
+ connManager, connectionManager_MessengerCallback);
+ messenger_Register(messenger, connManager->messengerRecipient);
+ return connManager;
+}
+
+void connectionManager_Destroy(ConnectionManager **managerPtr) {
+ parcAssertNotNull(managerPtr, "Double pointer must be non-null");
+ parcAssertNotNull(*managerPtr, "Double pointer must dereference to non-null");
+
+ ConnectionManager *connManager = *managerPtr;
+
+ Messenger *messenger = forwarder_GetMessenger(connManager->forwarder);
+ parcEventTimer_Destroy(&(connManager->timerEvent));
+ messenger_Unregister(messenger, connManager->messengerRecipient);
+ messengerRecipient_Destroy(&connManager->messengerRecipient);
+ missiveDeque_Release(&connManager->missiveQueue);
+ logger_Release(&connManager->logger);
+
+ parcMemory_Deallocate((void **)&connManager);
+ *managerPtr = NULL;
+}
+
+// ========================================================
+// Internal Functions
+
+static void connectionManager_MessengerCallback(MessengerRecipient *recipient,
+ Missive *missive) {
+ ConnectionManager *connManager =
+ messengerRecipient_GetRecipientContext(recipient);
+
+ // we do not release our reference count, we store it until later
+ // We are called with our own reference, so we do not need to acquire the
+ // missive here.
+ missiveDeque_Append(connManager->missiveQueue, missive);
+
+ if (missiveDeque_Size(connManager->missiveQueue) == 1) {
+ // When it becomes non-empty, schedule {@link
+ // connectionManager_ProcessQueue}
+ struct timeval immediateTimeout = {0, 0};
+ parcEventTimer_Start(connManager->timerEvent, &immediateTimeout);
+ }
+}
+
+static void connectionManager_ProcessQueue(int fd, PARCEventType which_event,
+ void *connManagerVoidPtr) {
+ ConnectionManager *connManager = (ConnectionManager *)connManagerVoidPtr;
+
+ Missive *missive;
+ while ((missive = missiveDeque_RemoveFirst(connManager->missiveQueue)) !=
+ NULL) {
+ switch (missive_GetType(missive)) {
+ case MissiveType_ConnectionCreate:
+ // hook to signal that a new connection was created
+ break;
+ case MissiveType_ConnectionUp:
+ // hook to signal that a new connection is up
+ break;
+ case MissiveType_ConnectionDown:
+ // hook to signal that a connection is down
+ break;
+ case MissiveType_ConnectionClosed:
+ connectionManager_ProcessClosedMissive(connManager, missive);
+ break;
+ case MissiveType_ConnectionDestroyed:
+ // hook to signal that a connection was destroyed
+ break;
+ default:
+ parcTrapUnexpectedState("Missive %p of unknown type: %d",
+ (void *)missive, missive_GetType(missive));
+ }
+ missive_Release(&missive);
+ }
+}
+
+static void connectionManager_ProcessClosedMissive(
+ ConnectionManager *connManager, const Missive *missive) {
+ logger_Log(connManager->logger, LoggerFacility_Core, PARCLogLevel_Debug,
+ __func__, "Processing CLOSED message for connid %u",
+ missive_GetConnectionId(missive));
+
+ ConnectionTable *table = forwarder_GetConnectionTable(connManager->forwarder);
+ const Connection *conn =
+ connectionTable_FindById(table, missive_GetConnectionId(missive));
+
+ if (conn) {
+ // this will destroy the connection if its the last reference count
+ connectionTable_Remove(table, conn);
+
+ // remove from FIB
+ forwarder_RemoveConnectionIdFromRoutes(connManager->forwarder,
+ missive_GetConnectionId(missive));
+ }
+}
diff --git a/hicn-light/src/core/connectionManager.h b/hicn-light/src/core/connectionManager.h
new file mode 100755
index 000000000..b77553e0d
--- /dev/null
+++ b/hicn-light/src/core/connectionManager.h
@@ -0,0 +1,37 @@
+/*
+ * 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 connectionManager.h
+ * @brief The connection manager handles connection events, such as going down
+ *
+ * The connection manager listens to the event notification system. Based on
+ * those events, the connection manager will take specific actions. This is
+ * expected to be a singleton instantiated by the forwarder.
+ *
+ */
+
+#ifndef connectionManager_h
+#define connectionManager_h
+
+#include <src/core/forwarder.h>
+
+struct connection_manager;
+typedef struct connection_manager ConnectionManager;
+
+ConnectionManager *connectionManager_Create(Forwarder *forwarder);
+
+void connectionManager_Destroy(ConnectionManager **managerPtr);
+#endif // connectionManager_h
diff --git a/hicn-light/src/core/connectionTable.c b/hicn-light/src/core/connectionTable.c
new file mode 100755
index 000000000..ba0942ddb
--- /dev/null
+++ b/hicn-light/src/core/connectionTable.c
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header ConnectionTable
+ * @abstract Records all the current connections and references to them
+ * @discussion
+ *
+ */
+
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+#include <src/core/connectionTable.h>
+#include <src/io/addressPair.h>
+
+struct connection_table {
+ // The main storage table that has a Destroy method.
+ // The key is an unsigned int pointer. We use an unsigned int pointer
+ // because we want to be able to lookup by the id alone, and not have to
+ // have the IoOperations everywhere.
+ PARCHashCodeTable *storageTableById;
+
+ // The key is a AddressPair
+ // It does not have a destroy method for the data or key,
+ // as they are derived from the storage table.
+ PARCHashCodeTable *indexByAddressPair;
+
+ // An iterable stucture organized by connection id. The keys and
+ // values are the same pointers as in storageTableById, so there
+ // are no destructors in the tree.
+ // The only reason to keep this tree is so we have an iterable list
+ // of connections, which the hash table does not give us.
+ PARCTreeRedBlack *listById;
+};
+
+static bool connectionTable_ConnectionIdEquals(const void *keyA,
+ const void *keyB) {
+ unsigned idA = *((unsigned *)keyA);
+ unsigned idB = *((unsigned *)keyB);
+ return (idA == idB);
+}
+
+static int connectionTable_ConnectionIdCompare(const void *keyA,
+ const void *keyB) {
+ unsigned idA = *((unsigned *)keyA);
+ unsigned idB = *((unsigned *)keyB);
+ if (idA < idB) {
+ return -1;
+ }
+ if (idA > idB) {
+ return +1;
+ }
+ return 0;
+}
+
+static bool connectionTable_AddressPairEquals(const void *keyA,
+ const void *keyB) {
+ const AddressPair *pairA = (const AddressPair *)keyA;
+ const AddressPair *pairB = (const AddressPair *)keyB;
+
+ return addressPair_Equals(pairA, pairB);
+}
+
+static HashCodeType connectionTable_ConnectionIdHashCode(const void *keyA) {
+ unsigned idA = *((unsigned *)keyA);
+ return parcHash32_Int32(idA);
+}
+
+static HashCodeType connectionTable_AddressPairHashCode(const void *keyA) {
+ const AddressPair *pairA = (const AddressPair *)keyA;
+ return addressPair_HashCode(pairA);
+}
+
+static void connectionTable_ConnectionIdDestroyer(void **dataPtr) {
+ unsigned *idA = (unsigned *)*dataPtr;
+ parcMemory_Deallocate((void **)&idA);
+ *dataPtr = NULL;
+}
+
+static void connectionTable_ConnectionDestroyer(void **dataPtr) {
+ connection_Release((Connection **)dataPtr);
+}
+
+ConnectionTable *connectionTable_Create() {
+ size_t initialSize = 16384;
+
+ ConnectionTable *conntable =
+ parcMemory_AllocateAndClear(sizeof(ConnectionTable));
+ parcAssertNotNull(conntable, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ConnectionTable));
+
+ conntable->storageTableById = parcHashCodeTable_Create_Size(
+ connectionTable_ConnectionIdEquals, connectionTable_ConnectionIdHashCode,
+ connectionTable_ConnectionIdDestroyer,
+ connectionTable_ConnectionDestroyer, initialSize);
+
+ // no key or data destroyer, this is an index into storageByid.
+ conntable->indexByAddressPair = parcHashCodeTable_Create_Size(
+ connectionTable_AddressPairEquals, connectionTable_AddressPairHashCode,
+ NULL, NULL, initialSize);
+
+ conntable->listById =
+ parcTreeRedBlack_Create(connectionTable_ConnectionIdCompare,
+ NULL, // key free
+ NULL, // key copy
+ NULL, // value equals
+ NULL, // value free
+ NULL); // value copy
+
+ return conntable;
+}
+
+void connectionTable_Destroy(ConnectionTable **conntablePtr) {
+ parcAssertNotNull(conntablePtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*conntablePtr,
+ "Parameter must dereference to non-null pointer");
+
+ ConnectionTable *conntable = *conntablePtr;
+
+ parcTreeRedBlack_Destroy(&conntable->listById);
+ parcHashCodeTable_Destroy(&conntable->indexByAddressPair);
+ parcHashCodeTable_Destroy(&conntable->storageTableById);
+ parcMemory_Deallocate((void **)&conntable);
+ *conntablePtr = NULL;
+}
+
+/**
+ * @function connectionTable_Add
+ * @abstract Add a connection, takes ownership of memory
+ */
+void connectionTable_Add(ConnectionTable *table, Connection *connection) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ parcAssertNotNull(connection, "Parameter connection must be non-null");
+
+ unsigned *connectionIdKey = parcMemory_Allocate(sizeof(unsigned));
+ parcAssertNotNull(connectionIdKey, "parcMemory_Allocate(%zu) returned NULL",
+ sizeof(unsigned));
+ *connectionIdKey = connection_GetConnectionId(connection);
+
+ if (parcHashCodeTable_Add(table->storageTableById, connectionIdKey,
+ connection)) {
+ parcHashCodeTable_Add(table->indexByAddressPair,
+ (void *)connection_GetAddressPair(connection),
+ connection);
+ parcTreeRedBlack_Insert(table->listById, connectionIdKey, connection);
+ } else {
+ parcTrapUnexpectedState(
+ "Could not add connection id %u -- is it a duplicate?",
+ *connectionIdKey);
+ }
+}
+
+/**
+ * @function connectionTable_Remove
+ * @abstract Removes the connection, calling Destroy on our copy
+ */
+void connectionTable_Remove(ConnectionTable *table,
+ const Connection *connection) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ parcAssertNotNull(connection, "Parameter connection must be non-null");
+
+ unsigned connid = connection_GetConnectionId(connection);
+
+ parcTreeRedBlack_Remove(table->listById, &connid);
+ parcHashCodeTable_Del(table->indexByAddressPair,
+ connection_GetAddressPair(connection));
+ parcHashCodeTable_Del(table->storageTableById, &connid);
+}
+
+void connectionTable_RemoveById(ConnectionTable *table, unsigned id) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ const Connection *connection = connectionTable_FindById(table, id);
+ if (connection) {
+ connectionTable_Remove(table, connection);
+ }
+}
+
+const Connection *connectionTable_FindByAddressPair(ConnectionTable *table,
+ const AddressPair *pair) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ return (Connection *)parcHashCodeTable_Get(table->indexByAddressPair, pair);
+}
+
+const Connection *connectionTable_FindById(ConnectionTable *table,
+ unsigned id) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ return (Connection *)parcHashCodeTable_Get(table->storageTableById, &id);
+}
+
+ConnectionList *connectionTable_GetEntries(const ConnectionTable *table) {
+ parcAssertNotNull(table, "Parameter table must be non-null");
+ ConnectionList *list = connectionList_Create();
+
+ PARCArrayList *values = parcTreeRedBlack_Values(table->listById);
+ for (size_t i = 0; i < parcArrayList_Size(values); i++) {
+ Connection *original = parcArrayList_Get(values, i);
+ connectionList_Append(list, original);
+ }
+ parcArrayList_Destroy(&values);
+ return list;
+}
diff --git a/hicn-light/src/core/connectionTable.h b/hicn-light/src/core/connectionTable.h
new file mode 100755
index 000000000..30517ae1d
--- /dev/null
+++ b/hicn-light/src/core/connectionTable.h
@@ -0,0 +1,99 @@
+/*
+ * 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 connectionTable_h
+#define connectionTable_h
+
+#include <src/core/connection.h>
+#include <src/core/connectionList.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+
+struct connection_table;
+typedef struct connection_table ConnectionTable;
+
+/**
+ * Creates an empty connection table
+ */
+ConnectionTable *connectionTable_Create(void);
+
+/**
+ * Destroys the connection table
+ * This will release the reference to all connections stored in the connection
+ * table.
+ * @param [in,out] conntablePtr Pointer to the allocated connection table, will
+ * be NULL'd
+ */
+void connectionTable_Destroy(ConnectionTable **conntablePtr);
+
+/**
+ * @function connectionTable_Add
+ * @abstract Add a connection, takes ownership of memory
+ */
+void connectionTable_Add(ConnectionTable *table, Connection *connection);
+
+/**
+ * @function connectionTable_Remove
+ * @abstract Removes the connection, calling Destroy on our copy
+ */
+void connectionTable_Remove(ConnectionTable *table,
+ const Connection *connection);
+
+/**
+ * Removes a connection from the connection table
+ *
+ * Looks up a connection by its connection ID and removes it from the connection
+ * table. Removing the connection will call connection_Release() on the
+ * connection object.
+ *
+ * @param [in] table The allocated connection table
+ * @param [in] id The connection ID
+ */
+void connectionTable_RemoveById(ConnectionTable *table, unsigned id);
+
+/**
+ * Lookup a connection by the (local, remote) addres pair
+ *
+ * @param [in] table The allocated connection table
+ * @param [in] pair The address pair to match, based on the inner values of the
+ * local and remote addresses
+ *
+ * @retval non-null The matched conneciton
+ * @retval null No match found or error
+ */
+const Connection *connectionTable_FindByAddressPair(ConnectionTable *table,
+ const AddressPair *pair);
+
+/**
+ * @function connectionTable_FindById
+ * @abstract Find a connection by its numeric id.
+ * @return NULL if not found
+ */
+const Connection *connectionTable_FindById(ConnectionTable *table, unsigned id);
+
+/**
+ * @function connectionTable_GetEntries
+ * @abstract Returns a list of connections. They are reference counted copies
+ * from the table.
+ * @discussion
+ * An allocated list of connections in the table. Each list entry is a
+ * reference counted copy of the connection in the table, thus they are "live"
+ * objects.
+ */
+ConnectionList *connectionTable_GetEntries(const ConnectionTable *table);
+#endif // connectionTable_h
diff --git a/hicn-light/src/core/dispatcher.c b/hicn-light/src/core/dispatcher.c
new file mode 100755
index 000000000..078087c59
--- /dev/null
+++ b/hicn-light/src/core/dispatcher.c
@@ -0,0 +1,435 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header dispatcher.c
+ * @abstract Event dispatcher for hicn-light. Uses parcEvent
+ * @discussion
+ * Wraps the functions we use in parcEvent, along with StreamBuffer and
+ * Message. The dispatcher is the event loop, so it manages things like signals,
+ * timers, and network events.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <src/config.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <parc/algol/parc_EventQueue.h>
+#include <parc/algol/parc_EventTimer.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/core/dispatcher.h>
+
+#ifndef INPORT_ANY
+#define INPORT_ANY 0
+#endif
+
+struct dispatcher {
+ PARCEventScheduler *Base;
+ Logger *logger;
+};
+
+// ==========================================
+// Public API
+
+PARCEventScheduler *dispatcher_GetEventScheduler(Dispatcher *dispatcher) {
+ return dispatcher->Base;
+}
+
+Dispatcher *dispatcher_Create(Logger *logger) {
+ Dispatcher *dispatcher = parcMemory_AllocateAndClear(sizeof(Dispatcher));
+ parcAssertNotNull(dispatcher,
+ "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Dispatcher));
+
+ dispatcher->Base = parcEventScheduler_Create();
+ dispatcher->logger = logger_Acquire(logger);
+
+ parcAssertNotNull(dispatcher->Base,
+ "Got NULL from parcEventScheduler_Create()");
+
+ return dispatcher;
+}
+
+void dispatcher_Destroy(Dispatcher **dispatcherPtr) {
+ parcAssertNotNull(dispatcherPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*dispatcherPtr,
+ "Parameter must dereference to non-null pointer");
+ Dispatcher *dispatcher = *dispatcherPtr;
+
+ logger_Release(&dispatcher->logger);
+ parcEventScheduler_Destroy(&(dispatcher->Base));
+ parcMemory_Deallocate((void **)&dispatcher);
+ *dispatcherPtr = NULL;
+}
+
+void dispatcher_Stop(Dispatcher *dispatcher) {
+ struct timeval delay = {0, 1000};
+
+ parcEventScheduler_Stop(dispatcher->Base, &delay);
+}
+
+void dispatcher_Run(Dispatcher *dispatcher) {
+ parcAssertNotNull(dispatcher, "Parameter must be non-null");
+
+ parcEventScheduler_Start(dispatcher->Base, 0);
+}
+
+void dispatcher_RunDuration(Dispatcher *dispatcher, struct timeval *duration) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(duration, "Parameter duration must be non-null");
+
+ parcEventScheduler_Stop(dispatcher->Base, duration);
+ parcEventScheduler_Start(dispatcher->Base, 0);
+}
+
+void dispatcher_RunCount(Dispatcher *dispatcher, unsigned count) {
+ parcAssertNotNull(dispatcher, "Parameter must be non-null");
+
+ for (unsigned i = 0; i < count; i++) {
+ parcEventScheduler_Start(dispatcher->Base,
+ PARCEventSchedulerDispatchType_LoopOnce);
+ }
+}
+
+PARCEventSocket *dispatcher_CreateListener(Dispatcher *dispatcher,
+ PARCEventSocket_Callback *callback,
+ void *user_data, int backlog,
+ const struct sockaddr *sa,
+ int socklen) {
+ PARCEventSocket *listener = parcEventSocket_Create(
+ dispatcher->Base, callback, NULL, user_data, sa, socklen);
+ if (listener == NULL) {
+ perror("Problem creating listener");
+ }
+ return listener;
+}
+
+void dispatcher_DestroyListener(Dispatcher *dispatcher,
+ PARCEventSocket **listenerPtr) {
+ parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*listenerPtr,
+ "Parameter must dereference to non-null pointer");
+ parcEventSocket_Destroy(listenerPtr);
+}
+
+PARCEventQueue *dispatcher_CreateStreamBufferFromSocket(Dispatcher *dispatcher,
+ SocketType fd) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ PARCEventQueue *buffer = parcEventQueue_Create(
+ dispatcher->Base, fd,
+ PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks);
+ parcAssertNotNull(buffer,
+ "Got null from parcEventBufver_Create for socket %d", fd);
+ return buffer;
+}
+
+PARCEventTimer *dispatcher_CreateTimer(Dispatcher *dispatcher, bool isPeriodic,
+ PARCEvent_Callback *callback,
+ void *userData) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(callback, "Parameter callback must be non-null");
+
+ PARCEventType flags = 0;
+ if (isPeriodic) {
+ flags |= PARCEventType_Persist;
+ }
+ PARCEventTimer *event =
+ parcEventTimer_Create(dispatcher->Base, flags, callback, userData);
+ return event;
+}
+
+void dispatcher_StartTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent,
+ struct timeval *delay) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(timerEvent, "Parameter timerEvent must be non-null");
+ int failure = parcEventTimer_Start(timerEvent, delay);
+ parcAssertFalse(failure < 0, "Error starting timer event %p: (%d) %s",
+ (void *)timerEvent, errno, strerror(errno));
+}
+
+void dispatcher_StopTimer(Dispatcher *dispatcher, PARCEventTimer *event) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(event, "Parameter event must be non-null");
+
+ int failure = parcEventTimer_Stop(event);
+ parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
+ (void *)event, errno, strerror(errno));
+}
+
+void dispatcher_DestroyTimerEvent(Dispatcher *dispatcher,
+ PARCEventTimer **eventPtr) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(eventPtr,
+ "Parameter eventPtr must be non-null double pointer");
+ parcAssertNotNull(*eventPtr,
+ "Paramter eventPtr must dereference to non-null pointer");
+
+ parcEventTimer_Destroy(eventPtr);
+ eventPtr = NULL;
+}
+
+PARCEvent *dispatcher_CreateNetworkEvent(Dispatcher *dispatcher,
+ bool isPersistent,
+ PARCEvent_Callback *callback,
+ void *userData, int fd) {
+ short flags = PARCEventType_Timeout | PARCEventType_Read;
+ if (isPersistent) {
+ flags |= PARCEventType_Persist;
+ }
+
+ PARCEvent *event =
+ parcEvent_Create(dispatcher->Base, fd, flags, callback, userData);
+ parcAssertNotNull(event, "Got null from parcEvent_Create for socket %d", fd);
+ return event;
+}
+
+void dispatcher_DestroyNetworkEvent(Dispatcher *dispatcher,
+ PARCEvent **eventPtr) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(eventPtr,
+ "Parameter eventPtr must be non-null double pointer");
+ parcAssertNotNull(*eventPtr,
+ "Paramter eventPtr must dereference to non-null pointer");
+
+ parcEvent_Destroy(eventPtr);
+ eventPtr = NULL;
+}
+
+void dispatcher_StartNetworkEvent(Dispatcher *dispatcher, PARCEvent *event) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(event, "Parameter event must be non-null");
+
+ int failure = parcEvent_Start(event);
+ parcAssertFalse(failure < 0, "Error starting signal event %p: (%d) %s",
+ (void *)event, errno, strerror(errno));
+}
+
+void dispatcher_StopNetworkEvent(Dispatcher *dispatcher, PARCEvent *event) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(event, "Parameter event must be non-null");
+
+ int failure = parcEvent_Stop(event);
+ parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
+ (void *)event, errno, strerror(errno));
+}
+
+PARCEventSignal *dispatcher_CreateSignalEvent(
+ Dispatcher *dispatcher, PARCEventSignal_Callback *callback, void *userData,
+ int signal) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(callback, "Parameter callback must be non-null");
+
+ PARCEventSignal *event = parcEventSignal_Create(
+ dispatcher->Base, signal, PARCEventType_Signal | PARCEventType_Persist,
+ callback, userData);
+ parcAssertNotNull(event,
+ "Got null event when creating signal catcher for signal %d",
+ signal);
+
+ return event;
+}
+
+void dispatcher_DestroySignalEvent(Dispatcher *dispatcher,
+ PARCEventSignal **eventPtr) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(eventPtr,
+ "Parameter eventPtr must be non-null double pointer");
+ parcAssertNotNull(*eventPtr,
+ "Paramter eventPtr must dereference to non-null pointer");
+
+ parcEventSignal_Destroy(eventPtr);
+ eventPtr = NULL;
+}
+
+void dispatcher_StartSignalEvent(Dispatcher *dispatcher,
+ PARCEventSignal *event) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(event, "Parameter event must be non-null");
+
+ int failure = parcEventSignal_Start(event);
+ parcAssertFalse(failure < 0, "Error starting signal event %p: (%d) %s",
+ (void *)event, errno, strerror(errno));
+}
+
+void dispatcher_StopSignalEvent(Dispatcher *dispatcher,
+ PARCEventSignal *event) {
+ parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+ parcAssertNotNull(event, "Parameter event must be non-null");
+
+ int failure = parcEventSignal_Stop(event);
+ parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
+ (void *)event, errno, strerror(errno));
+}
+
+/**
+ * Bind to a local address/port then connect to peer.
+ */
+static bool dispatcher_StreamBufferBindAndConnect(Dispatcher *dispatcher,
+ PARCEventQueue *buffer,
+ struct sockaddr *localSock,
+ socklen_t localSockLength,
+ struct sockaddr *remoteSock,
+ socklen_t remoteSockLength) {
+ // we need to bind, then connect. Special operation, so we make our
+ // own fd then pass it off to the buffer event
+
+ int fd = socket(localSock->sa_family, SOCK_STREAM, 0);
+ if (fd < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ // Set non-blocking flag
+ int flags = fcntl(fd, F_GETFL, NULL);
+ if (flags < 0) {
+ perror("F_GETFL");
+ close(fd);
+ return -1;
+ }
+ int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ if (failure) {
+ perror("F_SETFL");
+ close(fd);
+ return -1;
+ }
+
+ failure = bind(fd, localSock, localSockLength);
+ if (failure) {
+ perror("bind");
+ close(fd);
+ return false;
+ }
+
+ parcEventQueue_SetFileDescriptor(buffer, fd);
+
+ failure = parcEventQueue_ConnectSocket(buffer, remoteSock, remoteSockLength);
+ if (failure && (errno != EINPROGRESS)) {
+ perror("connect");
+ close(fd);
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Connect to an INET peer
+ * @return NULL on error, otherwise a streambuffer
+ */
+static PARCEventQueue *dispatcher_StreamBufferConnect_INET(
+ Dispatcher *dispatcher, const Address *localAddress,
+ const Address *remoteAddress) {
+ struct sockaddr_in localSock, remoteSock;
+ addressGetInet(localAddress, &localSock);
+ addressGetInet(remoteAddress, &remoteSock);
+
+ PARCEventQueue *buffer = parcEventQueue_Create(
+ dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree);
+ parcAssertNotNull(buffer, "got null buffer from parcEventQueue_Create()");
+
+ bool success = dispatcher_StreamBufferBindAndConnect(
+ dispatcher, buffer, (struct sockaddr *)&localSock, sizeof(localSock),
+ (struct sockaddr *)&remoteSock, sizeof(remoteSock));
+ if (!success) {
+ parcEventQueue_Destroy(&buffer);
+ buffer = NULL;
+ }
+
+ return buffer;
+}
+
+/**
+ * Connect to an INET peer
+ * @return NULL on error, otherwise a streambuffer
+ */
+static PARCEventQueue *
+// static StreamBuffer *
+dispatcher_StreamBufferConnect_INET6(Dispatcher *dispatcher,
+ const Address *localAddress,
+ const Address *remoteAddress) {
+ struct sockaddr_in6 localSock, remoteSock;
+ addressGetInet6(localAddress, &localSock);
+ addressGetInet6(remoteAddress, &remoteSock);
+
+ PARCEventQueue *buffer = parcEventQueue_Create(
+ dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree);
+ parcAssertNotNull(buffer, "got null buffer from parcEventQueue_Create()");
+
+ bool success = dispatcher_StreamBufferBindAndConnect(
+ dispatcher, buffer, (struct sockaddr *)&localSock, sizeof(localSock),
+ (struct sockaddr *)&remoteSock, sizeof(remoteSock));
+ if (!success) {
+ parcEventQueue_Destroy(&buffer);
+ buffer = NULL;
+ }
+
+ return buffer;
+}
+
+PARCEventQueue *dispatcher_StreamBufferConnect(Dispatcher *dispatcher,
+ const AddressPair *pair) {
+ const Address *localAddress = addressPair_GetLocal(pair);
+ const Address *remoteAddress = addressPair_GetRemote(pair);
+
+ // they must be of the same address family
+ if (addressGetType(localAddress) != addressGetType(remoteAddress)) {
+ char message[2048];
+ char *localAddressString = addressToString(localAddress);
+ char *remoteAddressString = addressToString(remoteAddress);
+ snprintf(message, 2048,
+ "Remote address not same type as local address, expected %d got "
+ "%d\nlocal %s remote %s",
+ addressGetType(localAddress), addressGetType(remoteAddress),
+ localAddressString, remoteAddressString);
+
+ parcMemory_Deallocate((void **)&localAddressString);
+ parcMemory_Deallocate((void **)&remoteAddressString);
+
+ parcAssertTrue(
+ addressGetType(localAddress) == addressGetType(remoteAddress), "%s",
+ message);
+ }
+
+ address_type type = addressGetType(localAddress);
+
+ PARCEventQueue *result = NULL;
+
+ switch (type) {
+ case ADDR_INET:
+ return dispatcher_StreamBufferConnect_INET(dispatcher, localAddress,
+ remoteAddress);
+ break;
+ case ADDR_INET6:
+ return dispatcher_StreamBufferConnect_INET6(dispatcher, localAddress,
+ remoteAddress);
+ break;
+ default:
+ parcTrapIllegalValue(type, "local address unsupported address type: %d",
+ type);
+ }
+ return result;
+}
diff --git a/hicn-light/src/core/dispatcher.h b/hicn-light/src/core/dispatcher.h
new file mode 100755
index 000000000..35d804a00
--- /dev/null
+++ b/hicn-light/src/core/dispatcher.h
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header hicn-light Dispatcher
+ * @abstract The dispatcher is the event loop run by Forwarder.
+ * @discussion
+ * These functions manage listeners, timers, and network events inside
+ * the event loop.
+ *
+ * Curently, it is a thin wrapper around an event so we don't have to
+ * expose that implementation detail to other modules.
+ *
+ */
+
+#ifndef dispatcher_h
+#define dispatcher_h
+
+#include <stdbool.h>
+#include <sys/socket.h>
+
+struct dispatcher;
+typedef struct dispatcher Dispatcher;
+
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_EventQueue.h>
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventSignal.h>
+#include <parc/algol/parc_EventSocket.h>
+#include <parc/algol/parc_EventTimer.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/core/logger.h>
+
+PARCEventScheduler *dispatcher_GetEventScheduler(Dispatcher *dispatcher);
+/**
+ * Creates an event dispatcher
+ *
+ * Event dispatcher based on PARCEvent
+ *
+ * @return non-null Allocated event dispatcher
+ * @return null An error
+ */
+Dispatcher *dispatcher_Create(Logger *logger);
+
+/**
+ * Destroys event dispatcher
+ *
+ * Caller is responsible for destroying call events before destroying
+ * the event dispatcher.
+ */
+void dispatcher_Destroy(Dispatcher **dispatcherPtr);
+
+/**
+ * @function dispatcher_Stop
+ * @abstract Called from a different thread, tells the dispatcher to stop
+ * @discussion
+ * Called from a user thread or from an interrupt handler.
+ * Does not block. Use <code>dispatcher_WaitForStopped()</code> to
+ * block until stopped after calling this.
+ */
+void dispatcher_Stop(Dispatcher *dispatcher);
+
+/**
+ * @function dispatcher_WaitForStopped
+ * @abstract Blocks until dispatcher in stopped state
+ * @discussion
+ * Used after <code>dispatcher_Stop()</code> to wait for stop.
+ */
+void dispatcher_WaitForStopped(Dispatcher *dispatcher);
+
+/**
+ * @function dispatcher_Run
+ * @abstract Runs the forwarder, blocks.
+ */
+void dispatcher_Run(Dispatcher *dispatcher);
+
+/**
+ * @function dispatcher_RunDuration
+ * @abstract Runs forwarder for at most duration, blocks.
+ * @discussion
+ * Blocks running the forwarder for a duration. May be called
+ * iteratively to keep running. Duration is a minimum, actual
+ * runtime may be slightly longer.
+ */
+void dispatcher_RunDuration(Dispatcher *dispatcher, struct timeval *duration);
+
+/**
+ * @header dispatcher_RunCount
+ * @abstract Run the event loop for the given count cycles
+ * @discussion
+ * Runs the event loop for the given number of cycles, blocking
+ * until done. May be called sequentially over and over.
+ *
+ */
+void dispatcher_RunCount(Dispatcher *dispatcher, unsigned count);
+
+typedef int SocketType;
+
+typedef struct evconnlistener Listener;
+
+/**
+ * @typedef ListenerCallback
+ * @abstract Callback function typedef for a stream listener
+ *
+ * @constant listener is the object created by <code>forwarder_NewBind()</code>
+ * that received the client connection
+ * @constant client_socket is the client socket
+ * @constant user_data is the user_data passed to
+ * <code>forwarder_NewBind()</code>
+ * @constant client_addr is the client address
+ * @constant socklen is the length of client_addr
+ * @discussion <#Discussion#>
+ */
+typedef void(ListenerCallback)(Listener *listener, SocketType client_socket,
+ struct sockaddr *client_addr, int socklen,
+ void *user_data);
+
+/**
+ * @header forwarder_NewBind
+ * @abstract Allocate a new stream listener
+ * @discussion
+ * The server socket will be freed when closed and will be reusable.
+ *
+ * @param forwarder that owns the event loop
+ * @param cb is the callback for a new connection
+ * @param user_data is opaque user data passed to the callback
+ * @param backlog is the listen() depth, may use -1 for a default value
+ * @param sa is the socket address to bind to (INET, INET6, LOCAL)
+ * @param socklen is the sizeof the actual sockaddr (e.g. sizeof(sockaddr_un))
+ */
+PARCEventSocket *dispatcher_CreateListener(Dispatcher *dispatcher,
+ PARCEventSocket_Callback *callback,
+ void *user_data, int backlog,
+ const struct sockaddr *sa,
+ int socklen);
+
+void dispatcher_DestroyListener(Dispatcher *dispatcher,
+ PARCEventSocket **listenerPtr);
+
+typedef struct event TimerEvent;
+typedef struct event NetworkEvent;
+typedef struct event SignalEvent;
+
+/**
+ * @typedef EventCallback
+ * @abstract A network event or a timer callback
+ * @constant fd The file descriptor associated with the event, may be -1 for
+ * timers
+ * @constant which_event is a bitmap of the EventType
+ * @constant user_data is the user_data passed to
+ * <code>Forwarder_CreateEvent()</code>
+ */
+typedef void(EventCallback)(SocketType fd, short which_event, void *user_data);
+
+/**
+ * @function dispatcher_CreateTimer
+ * @abstract Creates a Event for use as a timer.
+ * @discussion
+ *
+ * When created, the timer is idle and you need to call
+ * <code>forwarder_StartTimer()</code>
+ *
+ * @param isPeriodic means the timer will fire repeatidly, otherwise it is a
+ * one-shot and needs to be set again with <code>dispatcher_StartTimer()</code>
+ */
+PARCEventTimer *dispatcher_CreateTimer(Dispatcher *dispatcher, bool isPeriodic,
+ PARCEvent_Callback *callback,
+ void *userData);
+
+/**
+ * @function dispatcher_StartTimer
+ * @abstract Starts the timer with the given delay.
+ * @discussion
+ * If the timer is periodic, it will keep firing with the given delay
+ */
+void dispatcher_StartTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent,
+ struct timeval *delay);
+
+void dispatcher_StopTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent);
+
+/**
+ * @function dispatcher_DestroyTimerEvent
+ * @abstract Cancels the timer and frees the event
+ */
+void dispatcher_DestroyTimerEvent(Dispatcher *dispatcher,
+ PARCEventTimer **eventPtr);
+
+/**
+ * @function dispatcher_CreateNetworkEvent
+ * @abstract Creates a network event callback on the socket
+ * @discussion
+ * May be used on any sort of file descriptor or socket. The event is edge
+ * triggered and non-reentrent. This means you need to drain the events off the
+ * socket, as the callback will not be called again until a new event arrives.
+ *
+ * When created, the event is idle and you need to call
+ * <code>forwarder_StartNetworkEvent()</code>
+ *
+ * @param isPersistent means the callback will keep firing with new events,
+ * otherwise its a one-shot
+ * @param fd is the socket to monitor
+ */
+PARCEvent *dispatcher_CreateNetworkEvent(Dispatcher *dispatcher,
+ bool isPersistent,
+ PARCEvent_Callback *callback,
+ void *userData, int fd);
+
+void dispatcher_StartNetworkEvent(Dispatcher *dispatcher, PARCEvent *event);
+void dispatcher_StopNetworkEvent(Dispatcher *dispatcher, PARCEvent *event);
+
+void dispatcher_DestroyNetworkEvent(Dispatcher *dispatcher,
+ PARCEvent **eventPtr);
+
+/**
+ * @function dispatcher_CreateSignalEvent
+ * @abstract Creates a signal trap
+ * @discussion
+ * May be used on catchable signals. The event is edge triggered and
+ * non-reentrent. Signal events are persistent.
+ *
+ * When created, the signal trap is idle and you need to call
+ * <code>forwarder_StartSignalEvent()</code>
+ *
+ * @param signal is the system signal to monitor (e.g. SIGINT).
+ * @return <#return#>
+ */
+PARCEventSignal *dispatcher_CreateSignalEvent(
+ Dispatcher *dispatcher, PARCEventSignal_Callback *callback, void *userData,
+ int signal);
+
+void dispatcher_DestroySignalEvent(Dispatcher *dispatcher,
+ PARCEventSignal **eventPtr);
+
+void dispatcher_StartSignalEvent(Dispatcher *dispatcher,
+ PARCEventSignal *event);
+void dispatcher_StopSignalEvent(Dispatcher *dispatcher, PARCEventSignal *event);
+
+// =============
+// stream buffers
+
+#include <src/core/streamBuffer.h>
+#include <src/io/addressPair.h>
+
+/**
+ * @function dispatcher_CreateStreamBuffer
+ * @abstract Creates a high-function buffer around a stream socket
+ */
+PARCEventQueue *dispatcher_CreateStreamBufferFromSocket(Dispatcher *dispatcher,
+ SocketType fd);
+
+/**
+ * @function dispatcher_StreamBufferConnect
+ * @abstract Create a TCP tunnel to a remote peer
+ * @discussion
+ * For TCP, both address pairs need to be the same address family: both INET
+ * or both INET6. The remote address must have the complete socket information
+ * (address, port). The local socket could be wildcarded or may specify down to
+ * the (address, port) pair.
+ *
+ * If the local address is IPADDR_ANY and the port is 0, then it is a normal
+ * call to "connect" that will use whatever local IP address and whatever local
+ * port for the connection. If either the address or port is set, the local
+ * socket will first be bound (via bind(2)), and then call connect().
+ *
+ * It is unlikely that the buffer will be connected by the time the function
+ * returns. The eventCallback will fire once the remote system accepts the
+ * conneciton.
+ *
+ * @return NULL on error, otherwise a streambuffer.
+ */
+PARCEventQueue *dispatcher_StreamBufferConnect(Dispatcher *dispatcher,
+ const AddressPair *pair);
+#endif // dispatcher_h
diff --git a/hicn-light/src/core/forwarder.c b/hicn-light/src/core/forwarder.c
new file mode 100755
index 000000000..cb94af3b5
--- /dev/null
+++ b/hicn-light/src/core/forwarder.c
@@ -0,0 +1,499 @@
+/*
+ * 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.
+ */
+
+/**
+ * Event based router
+ *
+ * This module is the glue around the event scheduler.
+ * Its the packet i/o module.
+ *
+ * Packet processing is done in dispatcher.c, which is the actual wrapper around
+ * the event scheduler
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <src/config.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <src/core/connectionManager.h>
+#include <src/core/connectionTable.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+#include <src/core/messagePacketType.h>
+#ifdef WITH_MAPME
+#include <src/core/mapMe.h>
+#endif /* WITH_MAPME */
+#include <src/config/configuration.h>
+#include <src/config/configurationFile.h>
+#include <src/config/configurationListeners.h>
+#include <src/processor/messageProcessor.h>
+
+#include <src/core/wldr.h>
+
+#include <parc/assert/parc_Assert.h>
+
+// the router's clock frequency (we now use the monotonic clock)
+#define HZ 1000
+
+// these will all be a little off because its all integer division
+#define MSEC_PER_TICK (1000 / HZ)
+#define USEC_PER_TICK (1000000 / HZ)
+#define NSEC_PER_TICK ((1000000000ULL) / HZ)
+#define MSEC_TO_TICKS(msec) \
+ ((msec < FC_MSEC_PER_TICK) ? 1 : msec / FC_MSEC_PER_TICK)
+#define NSEC_TO_TICKS(nsec) ((nsec < NSEC_PER_TICK) ? 1 : nsec / NSEC_PER_TICK)
+
+struct forwarder {
+ Dispatcher *dispatcher;
+
+ uint16_t server_port;
+
+ PARCEventSignal *signal_int;
+ PARCEventSignal *signal_term;
+ PARCEventSignal *signal_usr1;
+ PARCEventTimer *keepalive_event;
+
+ // will skew the virtual clock forward. In normal operaiton, it is 0.
+ Ticks clockOffset;
+
+ unsigned nextConnectionid;
+ Messenger *messenger;
+ ConnectionManager *connectionManager;
+ ConnectionTable *connectionTable;
+ ListenerSet *listenerSet;
+ Configuration *config;
+
+ // we'll eventually want to setup a threadpool of these
+ MessageProcessor *processor;
+
+ Logger *logger;
+
+ PARCClock *clock;
+
+ hicn_socket_helper_t
+ *hicnSocketHelper; // state required to manage hicn connections
+
+ // used by seed48 and nrand48
+ unsigned short seed[3];
+
+#ifdef WITH_MAPME
+ MapMe *mapme;
+#endif /* WITH_MAPME */
+};
+
+// signal traps through the event scheduler
+static void _signal_cb(int, PARCEventType, void *);
+
+// A no-op keepalive to prevent Libevent from exiting the dispatch loop
+static void _keepalive_cb(int, PARCEventType, void *);
+
+/**
+ * Reseed our pseudo-random number generator.
+ */
+static void forwarder_Seed(Forwarder *forwarder) {
+ int fd;
+ ssize_t res;
+
+ res = -1;
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd != -1) {
+ res = read(fd, forwarder->seed, sizeof(forwarder->seed));
+ close(fd);
+ }
+ if (res != sizeof(forwarder->seed)) {
+ forwarder->seed[1] = (unsigned short)getpid(); /* better than no entropy */
+ forwarder->seed[2] = (unsigned short)time(NULL);
+ }
+ /*
+ * The call to seed48 is needed by cygwin, and should be harmless
+ * on other platforms.
+ */
+ seed48(forwarder->seed);
+}
+
+Logger *forwarder_GetLogger(const Forwarder *forwarder) {
+ return forwarder->logger;
+}
+
+// ============================================================================
+// Setup and destroy section
+
+Forwarder *forwarder_Create(Logger *logger) {
+ Forwarder *forwarder = parcMemory_AllocateAndClear(sizeof(Forwarder));
+ parcAssertNotNull(forwarder, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Forwarder));
+ memset(forwarder, 0, sizeof(Forwarder));
+ forwarder_Seed(forwarder);
+
+ forwarder->clock = parcClock_Monotonic();
+ forwarder->clockOffset = 0;
+
+ if (logger) {
+ forwarder->logger = logger_Acquire(logger);
+ logger_SetClock(forwarder->logger, forwarder->clock);
+ } else {
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ forwarder->logger = logger_Create(reporter, forwarder->clock);
+ parcLogReporter_Release(&reporter);
+ }
+
+ forwarder->nextConnectionid = 1;
+ forwarder->dispatcher = dispatcher_Create(forwarder->logger);
+ forwarder->messenger = messenger_Create(forwarder->dispatcher);
+ forwarder->connectionManager = connectionManager_Create(forwarder);
+ forwarder->connectionTable = connectionTable_Create();
+ forwarder->listenerSet = listenerSet_Create();
+ forwarder->config = configuration_Create(forwarder);
+ forwarder->processor = messageProcessor_Create(forwarder);
+
+ forwarder->signal_term = dispatcher_CreateSignalEvent(
+ forwarder->dispatcher, _signal_cb, forwarder, SIGTERM);
+ dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_term);
+
+ forwarder->signal_int = dispatcher_CreateSignalEvent(
+ forwarder->dispatcher, _signal_cb, forwarder, SIGINT);
+ dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_int);
+
+ forwarder->signal_usr1 = dispatcher_CreateSignalEvent(
+ forwarder->dispatcher, _signal_cb, forwarder, SIGPIPE);
+ dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_usr1);
+
+#ifndef __APPLE__
+ forwarder->hicnSocketHelper = hicn_create();
+ if (forwarder->hicnSocketHelper == NULL) return NULL;
+#endif /* __APPLE__ */
+ /* ignore child */
+ signal(SIGCHLD, SIG_IGN);
+
+ /* ignore tty signals */
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+
+ // We no longer use this for ticks, but we need to have at least one event
+ // schedule to keep Libevent happy.
+
+ struct timeval wtnow_timeout;
+ timerclear(&wtnow_timeout);
+
+ wtnow_timeout.tv_sec = 0;
+ wtnow_timeout.tv_usec = 50000; // 20 Hz keepalive
+
+#ifdef WITH_MAPME
+ if (!(mapMe_Init(&forwarder->mapme, forwarder))) return NULL;
+#endif /* WITH_MAPME */
+
+ PARCEventScheduler *base =
+ dispatcher_GetEventScheduler(forwarder->dispatcher);
+ forwarder->keepalive_event = parcEventTimer_Create(
+ base, PARCEventType_Persist, _keepalive_cb, (void *)forwarder);
+ parcEventTimer_Start(forwarder->keepalive_event, &wtnow_timeout);
+
+ return forwarder;
+}
+
+void forwarder_Destroy(Forwarder **ptr) {
+ parcAssertNotNull(ptr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*ptr, "Parameter must dereference to non-null pointer");
+ Forwarder *forwarder = *ptr;
+#if !defined(__APPLE__) && !defined(__ANDROID__)
+ hicn_destroy();
+#endif
+ parcEventTimer_Destroy(&(forwarder->keepalive_event));
+
+ listenerSet_Destroy(&(forwarder->listenerSet));
+ connectionManager_Destroy(&(forwarder->connectionManager));
+ connectionTable_Destroy(&(forwarder->connectionTable));
+ messageProcessor_Destroy(&(forwarder->processor));
+ configuration_Destroy(&(forwarder->config));
+
+ // the messenger is used by many of the other pieces, so destroy it last
+ messenger_Destroy(&(forwarder->messenger));
+
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_int));
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_term));
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_usr1));
+
+ parcClock_Release(&forwarder->clock);
+ logger_Release(&forwarder->logger);
+
+ // do the dispatcher last
+ dispatcher_Destroy(&(forwarder->dispatcher));
+
+ parcMemory_Deallocate((void **)&forwarder);
+ *ptr = NULL;
+}
+
+void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port,
+ const char *localPath) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+
+ configurationListeners_SetupAll(forwarder->config, port, localPath);
+}
+
+void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename) {
+ ConfigurationFile *configFile = configurationFile_Create(forwarder, filename);
+ if (configFile) {
+ configurationFile_Process(configFile);
+ configurationFile_Release(&configFile);
+ }
+}
+
+Configuration *forwarder_GetConfiguration(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return forwarder->config;
+}
+
+// ============================================================================
+
+unsigned forwarder_GetNextConnectionId(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return forwarder->nextConnectionid++;
+}
+
+Messenger *forwarder_GetMessenger(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return forwarder->messenger;
+}
+
+Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return forwarder->dispatcher;
+}
+
+ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return forwarder->connectionTable;
+}
+
+ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return forwarder->listenerSet;
+}
+
+void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ messageProcessor_SetCacheStoreFlag(forwarder->processor, val);
+}
+
+bool forwarder_GetChacheStoreFlag(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return messageProcessor_GetCacheStoreFlag(forwarder->processor);
+}
+
+void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ messageProcessor_SetCacheServeFlag(forwarder->processor, val);
+}
+
+bool forwarder_GetChacheServeFlag(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return messageProcessor_GetCacheServeFlag(forwarder->processor);
+}
+
+void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command,
+ struct iovec *message, unsigned ingressId) {
+ configuration_ReceiveCommand(forwarder->config, command, message, ingressId);
+}
+
+void forwarder_Receive(Forwarder *forwarder, Message *message) {
+ parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+
+ // this takes ownership of the message, so we're done here
+
+ // this are the checks needed to implement WLDR. We set wldr only on the STAs
+ // and we let the AP to react according to choise of the client.
+ // if the STA enables wldr using the set command, the AP enable wldr as well
+ // otherwise, if the STA disable it the AP remove wldr
+ // WLDR should be enabled only on the STAs using the command line
+ // TODO
+ // disable WLDR command line on the AP
+ const Connection *conn = connectionTable_FindById(
+ forwarder->connectionTable, message_GetIngressConnectionId(message));
+
+ if (!conn) {
+ return;
+ }
+
+ if (message_HasWldr(message)) {
+ if (connection_HasWldr(conn)) {
+ // case 1: WLDR is enabled
+ connection_DetectLosses((Connection *)conn, message);
+ } else if (!connection_HasWldr(conn) &&
+ connection_WldrAutoStartAllowed(conn)) {
+ // case 2: We are on an AP. We enable WLDR
+ connection_EnableWldr((Connection *)conn);
+ connection_DetectLosses((Connection *)conn, message);
+ }
+ // case 3: Ignore WLDR
+ } else {
+ if (connection_HasWldr(conn) && connection_WldrAutoStartAllowed(conn)) {
+ // case 1: STA do not use WLDR, we disable it
+ connection_DisableWldr((Connection *)conn);
+ }
+ }
+
+ messageProcessor_Receive(forwarder->processor, message);
+}
+
+Ticks forwarder_GetTicks(const Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+ return parcClock_GetTime(forwarder->clock) + forwarder->clockOffset;
+}
+
+Ticks forwarder_NanosToTicks(uint64_t nanos) { return NSEC_TO_TICKS(nanos); }
+
+uint64_t forwarder_TicksToNanos(Ticks ticks) {
+ return (1000000000ULL) * ticks / HZ;
+}
+
+bool forwarder_AddOrUpdateRoute(Forwarder *forwarder,
+ add_route_command *control, unsigned ifidx) {
+ parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+ parcAssertNotNull(control, "Parameter route must be non-null");
+
+ // we only have one message processor
+ bool res =
+ messageProcessor_AddOrUpdateRoute(forwarder->processor, control, ifidx);
+
+ return res;
+}
+
+bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control,
+ unsigned ifidx) {
+ parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+ parcAssertNotNull(control, "Parameter route must be non-null");
+
+ // we only have one message processor
+ return messageProcessor_RemoveRoute(forwarder->processor, control, ifidx);
+}
+
+void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder,
+ unsigned connectionId) {
+ parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+ messageProcessor_RemoveConnectionIdFromRoutes(forwarder->processor,
+ connectionId);
+}
+
+void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix,
+ strategy_type strategy) {
+ parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+ parcAssertNotNull(prefix, "Parameter prefix must be non-null");
+
+ // if (strategy == NULL) {
+ // strategy = SET_STRATEGY_RANDOM;
+ // }
+
+ processor_SetStrategy(forwarder->processor, prefix, strategy);
+}
+
+FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder) {
+ return messageProcessor_GetFibEntries(forwarder->processor);
+}
+
+void forwarder_SetContentObjectStoreSize(Forwarder *forwarder,
+ size_t maximumContentStoreSize) {
+ messageProcessor_SetContentObjectStoreSize(forwarder->processor,
+ maximumContentStoreSize);
+}
+
+void forwarder_ClearCache(Forwarder *forwarder) {
+ messageProcessor_ClearCache(forwarder->processor);
+}
+
+PARCClock *forwarder_GetClock(const Forwarder *forwarder) {
+ return forwarder->clock;
+}
+
+hicn_socket_helper_t *forwarder_GetHIcnSocketHelper(Forwarder *forwarder) {
+ return forwarder->hicnSocketHelper;
+}
+
+// =======================================================
+
+static void _signal_cb(int sig, PARCEventType events, void *user_data) {
+ Forwarder *forwarder = (Forwarder *)user_data;
+
+ logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
+ __func__, "signal %d events %d", sig, events);
+
+ switch ((int)sig) {
+ case SIGTERM:
+ logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
+ __func__, "Caught an terminate signal; exiting cleanly.");
+ dispatcher_Stop(forwarder->dispatcher);
+ break;
+
+ case SIGINT:
+ logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
+ __func__, "Caught an interrupt signal; exiting cleanly.");
+ dispatcher_Stop(forwarder->dispatcher);
+ break;
+
+ case SIGUSR1:
+ // dump stats
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void _keepalive_cb(int fd, PARCEventType what, void *user_data) {
+ parcAssertTrue(what & PARCEventType_Timeout, "Got unexpected tick_cb: %d",
+ what);
+ // function is just a keepalive for hicn-light, does not do anything
+}
+
+#ifdef WITH_MAPME
+FIB *forwarder_getFib(Forwarder *forwarder) {
+ return messageProcessor_getFib(forwarder->processor);
+}
+
+void forwarder_onConnectionAdded(Forwarder *forwarder, const Connection *conn) {
+ mapMe_onConnectionAdded(forwarder->mapme, conn);
+}
+
+void forwarder_onConnectionRemoved(Forwarder *forwarder,
+ const Connection *conn) {}
+
+void forwarder_ProcessMapMe(Forwarder *forwarder, uint8_t *msgBuffer,
+ unsigned conn_id) {
+ mapMe_Process(forwarder->mapme, msgBuffer, conn_id);
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/core/forwarder.h b/hicn-light/src/core/forwarder.h
new file mode 100755
index 000000000..ad3f9756b
--- /dev/null
+++ b/hicn-light/src/core/forwarder.h
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+/*
+ * The methods in this header are for the non-threaded forwarder. They should
+ * only be called within the forwarders thread of execution.
+ */
+
+#ifndef forwarder_h
+#define forwarder_h
+
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <src/core/connectionTable.h>
+#include <src/core/dispatcher.h>
+#include <src/messenger/messenger.h>
+
+#include <src/core/message.h>
+
+#include <src/config/configuration.h>
+
+#ifdef WITH_MAPME
+#include <src/processor/fib.h>
+#endif /* WITH_MAPME */
+
+#include <src/core/logger.h>
+#include <src/core/ticks.h>
+#include <src/io/listenerSet.h>
+
+#include <src/processor/fibEntryList.h>
+
+#include <parc/algol/parc_Clock.h>
+
+#include <src/socket/api.h>
+
+#define PORT_NUMBER 9695
+#define PORT_NUMBER_AS_STRING "9695"
+
+#include <src/utils/commands.h>
+
+// ==============================================
+
+struct forwarder;
+typedef struct forwarder Forwarder;
+
+
+/**
+ * @function forwarder_Create
+ * @abstract Create the forwarder and use the provided logger for diagnostic
+ * output
+ * @discussion
+ * If the logger is null, hicn-light will create a STDOUT logger.
+ *
+ * @param logger may be NULL
+ */
+Forwarder *forwarder_Create(Logger *logger);
+
+/**
+ * @function forwarder_Destroy
+ * @abstract Destroys the forwarder, stopping all traffic and freeing all memory
+ */
+void forwarder_Destroy(Forwarder **ptr);
+
+/**
+ * @function forwarder_SetupAllListeners
+ * @abstract Setup all listeners (tcp, udp, local, ether, ip multicast) on all
+ * interfaces
+ * @discussion
+ * Sets up all listeners on all running interfaces. This provides a quick and
+ * easy startup, rather than providing a configuration file or programmatic
+ * commands.
+ *
+ * @param port is used by TCP and UDP listeners, in host byte order
+ * @param localPath is the AF_UNIX path to use, if NULL no AF_UNIX listener is
+ * setup
+ */
+void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port,
+ const char *localPath);
+
+/**
+ * Configure hicn-light via a configuration file
+ *
+ * The configuration file is a set of lines, just like used in hicnLightControl.
+ * You need to have "add listener" lines in the file to receive connections. No
+ * default listeners are configured.
+ *
+ * @param [in] forwarder An alloated Forwarder
+ * @param [in] filename The path to the configuration file
+ */
+void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename);
+
+/**
+ * Returns the logger used by this forwarder
+ *
+ * If you will store the logger, you should acquire a reference to it.
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ *
+ * @retval non-null The logger used by hicn-light
+ * @retval null An error
+ */
+Logger *forwarder_GetLogger(const Forwarder *forwarder);
+
+/**
+ * @function forwarder_SetLogLevel
+ * @abstract Sets the minimum level to log
+ */
+void forwarder_SetLogLevel(Forwarder *forwarder, PARCLogLevel level);
+
+/**
+ * @function forwarder_GetNextConnectionId
+ * @abstract Get the next identifier for a new connection
+ */
+unsigned forwarder_GetNextConnectionId(Forwarder *forwarder);
+
+Messenger *forwarder_GetMessenger(Forwarder *forwarder);
+
+Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder);
+
+/**
+ * Returns the set of currently active listeners
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ *
+ * @retval non-null The set of active listeners
+ * @retval null An error
+ */
+ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder);
+
+/**
+ * Returns the forwrder's connection table
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ *
+ * @retval non-null The connection tabler
+ * @retval null An error
+ *
+ */
+ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder);
+
+/**
+ * Returns a Tick-based clock
+ *
+ * Runs at approximately 1 msec per tick (see HZ in forwarder.c).
+ * Do not Release this clock. If you save a copy of it, create your own
+ * reference to it with parcClock_Acquire().
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ *
+ * @retval non-null An allocated hicn-light Clock based on the Tick counter
+ * @retval null An error
+ */
+PARCClock *forwarder_GetClock(const Forwarder *forwarder);
+
+/**
+ * Direct call to get the Tick clock
+ *
+ * Runs at approximately 1 msec per tick (see HZ in forwarder.c)
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ */
+Ticks forwarder_GetTicks(const Forwarder *forwarder);
+
+/**
+ * Convert nano seconds to Ticks
+ *
+ * Converts nano seconds to Ticks, based on HZ (in forwarder.c)
+ */
+Ticks forwarder_NanosToTicks(uint64_t nanos);
+
+uint64_t forwarder_TicksToNanos(Ticks ticks);
+
+void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command,
+ struct iovec *message, unsigned ingressId);
+
+void forwarder_Receive(Forwarder *forwarder, Message *mesage);
+
+/**
+ * @function forwarder_AddOrUpdateRoute
+ * @abstract Adds or updates a route on all the message processors
+ */
+bool forwarder_AddOrUpdateRoute(Forwarder *forwarder,
+ add_route_command *control, unsigned ifidx);
+
+/**
+ * @function forwarder_RemoveRoute
+ * @abstract Removes a route from all the message processors
+ */
+bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control,
+ unsigned ifidx);
+
+/**
+ * Removes a connection id from all routes
+ */
+void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder,
+ unsigned connectionId);
+
+/**
+ * @function forwarder_GetConfiguration
+ * @abstract The configuration object
+ * @discussion
+ * The configuration contains all user-issued commands. It does not include
+ * dynamic state.
+ */
+Configuration *forwarder_GetConfiguration(Forwarder *forwarder);
+
+FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder);
+
+/**
+ * Sets the maximum number of content objects in the content store
+ *
+ * Implementation dependent - may wipe the cache.
+ */
+void forwarder_SetContentObjectStoreSize(Forwarder *forwarder,
+ size_t maximumContentStoreSize);
+
+void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val);
+
+bool forwarder_GetChacheStoreFlag(Forwarder *forwarder);
+
+void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val);
+
+bool forwarder_GetChacheServeFlag(Forwarder *forwarder);
+
+void forwarder_ClearCache(Forwarder *forwarder);
+
+void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix,
+ strategy_type strategy);
+
+hicn_socket_helper_t *forwarder_GetHIcnSocketHelper(Forwarder *forwarder);
+
+#ifdef WITH_MAPME
+
+/**
+ * @function forwarder_getFib
+ * @abstract Returns the hICN forwarder's FIB.
+ * @param [in] forwarder - Pointer to the hICN forwarder.
+ * @returns Pointer to the hICN FIB.
+ */
+FIB *forwarder_getFib(Forwarder *forwarder);
+
+/**
+ * @function forwarder_onConnectionAdded
+ * @abstract Callback fired upon addition of a new connection through the
+ * control protocol.
+ * @param [in] forwarder - Pointer to the hICN forwarder.
+ * @param [in] conn - Pointer to the newly added connection.
+ */
+void forwarder_onConnectionAdded(Forwarder *forwarder, const Connection *conn);
+
+/**
+ * @function forwarder_onConnectionRemoved
+ * @abstract Callback fired upon removal of a connection through the control
+ * protocol.
+ * @param [in] forwarder - Pointer to the hICN forwarder.
+ * @param [in] conn - Pointer to the removed connection.
+ */
+void forwarder_onConnectionRemoved(Forwarder *forwarder,
+ const Connection *conn);
+
+/**
+ * @function forwarder_ProcessMapMe
+ * @abstract Callback fired by an hICN listener upon reception of a MAP-Me
+ * message.
+ * @param [in] forwarder - Pointer to the hICN forwarder.
+ * @param [in] msgBuffer - MAP-Me buffer
+ * @param [in] conn_id - Ingress connection id
+ */
+void forwarder_ProcessMapMe(Forwarder *forwarder, uint8_t *msgBuffer,
+ unsigned conn_id);
+
+#endif /* WITH_MAPME */
+
+#endif // forwarder_h
diff --git a/hicn-light/src/core/logger.c b/hicn-light/src/core/logger.c
new file mode 100755
index 000000000..cac3000e2
--- /dev/null
+++ b/hicn-light/src/core/logger.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <errno.h>
+#include <src/config.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/logging/parc_Log.h>
+
+#include <src/core/forwarder.h>
+#include <src/core/logger.h>
+
+struct logger {
+ PARCClock *clock;
+
+ PARCLogReporter *reporter;
+ PARCLog *loggerArray[LoggerFacility_END];
+};
+
+static const struct facility_to_string {
+ LoggerFacility facility;
+ const char *string;
+} _facilityToString[] = {
+ {.facility = LoggerFacility_Config, .string = "Config"},
+ {.facility = LoggerFacility_Core, .string = "Core"},
+ {.facility = LoggerFacility_IO, .string = "IO"},
+ {.facility = LoggerFacility_Message, .string = "Message"},
+ {.facility = LoggerFacility_Processor, .string = "Processor"},
+ {.facility = 0, .string = NULL}};
+
+const char *logger_FacilityString(LoggerFacility facility) {
+ for (int i = 0; _facilityToString[i].string != NULL; i++) {
+ if (_facilityToString[i].facility == facility) {
+ return _facilityToString[i].string;
+ }
+ }
+ return "Unknown";
+}
+
+static void _allocateLoggers(Logger *logger, PARCLogReporter *reporter) {
+ parcTrapUnexpectedStateIf(
+ logger->reporter != NULL,
+ "Trying to allocate a reporter when the previous one is not null");
+ logger->reporter = parcLogReporter_Acquire(reporter);
+
+ char hostname[255];
+ int gotHostName = gethostname(hostname, 255);
+ if (gotHostName < 0) {
+ snprintf(hostname, 255, "unknown");
+ }
+
+ for (int i = 0; i < LoggerFacility_END; i++) {
+ logger->loggerArray[i] = parcLog_Create(hostname, logger_FacilityString(i),
+ "forwarder", logger->reporter);
+ parcLog_SetLevel(logger->loggerArray[i], PARCLogLevel_Error);
+ }
+}
+
+static void _releaseLoggers(Logger *logger) {
+ for (int i = 0; i < LoggerFacility_END; i++) {
+ parcLog_Release(&logger->loggerArray[i]);
+ }
+ parcLogReporter_Release(&logger->reporter);
+}
+
+static void _destroyer(Logger **loggerPtr) {
+ Logger *logger = *loggerPtr;
+ _releaseLoggers(logger);
+ parcClock_Release(&(*loggerPtr)->clock);
+}
+
+parcObject_ExtendPARCObject(Logger, _destroyer, NULL, NULL, NULL, NULL, NULL,
+ NULL);
+
+parcObject_ImplementAcquire(logger, Logger);
+
+parcObject_ImplementRelease(logger, Logger);
+
+Logger *logger_Create(PARCLogReporter *reporter, const PARCClock *clock) {
+ parcAssertNotNull(reporter, "Parameter reporter must be non-null");
+ parcAssertNotNull(clock, "Parameter clock must be non-null");
+
+ Logger *logger = parcObject_CreateAndClearInstance(Logger);
+ if (logger) {
+ logger->clock = parcClock_Acquire(clock);
+ _allocateLoggers(logger, reporter);
+ }
+
+ return logger;
+}
+
+void logger_SetReporter(Logger *logger, PARCLogReporter *reporter) {
+ parcAssertNotNull(logger, "Parameter logger must be non-null");
+
+ // save the log level state
+ PARCLogLevel savedLevels[LoggerFacility_END];
+ for (int i = 0; i < LoggerFacility_END; i++) {
+ savedLevels[i] = parcLog_GetLevel(logger->loggerArray[i]);
+ }
+
+ _releaseLoggers(logger);
+
+ _allocateLoggers(logger, reporter);
+
+ // restore log level state
+ for (int i = 0; i < LoggerFacility_END; i++) {
+ parcLog_SetLevel(logger->loggerArray[i], savedLevels[i]);
+ }
+}
+
+void logger_SetClock(Logger *logger, PARCClock *clock) {
+ parcAssertNotNull(logger, "Parameter logger must be non-null");
+ parcClock_Release(&logger->clock);
+ logger->clock = parcClock_Acquire(clock);
+}
+
+static void _assertInvariants(const Logger *logger, LoggerFacility facility) {
+ parcAssertNotNull(logger, "Parameter logger must be non-null");
+ parcTrapOutOfBoundsIf(facility >= LoggerFacility_END, "Invalid facility %d",
+ facility);
+}
+
+void logger_SetLogLevel(Logger *logger, LoggerFacility facility,
+ PARCLogLevel minimumLevel) {
+ _assertInvariants(logger, facility);
+ PARCLog *log = logger->loggerArray[facility];
+ parcLog_SetLevel(log, minimumLevel);
+}
+
+bool logger_IsLoggable(const Logger *logger, LoggerFacility facility,
+ PARCLogLevel level) {
+ _assertInvariants(logger, facility);
+ PARCLog *log = logger->loggerArray[facility];
+ return parcLog_IsLoggable(log, level);
+}
+
+void logger_Log(Logger *logger, LoggerFacility facility, PARCLogLevel level,
+ const char *module, const char *format, ...) {
+ if (logger_IsLoggable(logger, facility, level)) {
+ // this is logged as the messageid
+ uint64_t logtime = parcClock_GetTime(logger->clock);
+
+ // logger_IsLoggable asserted invariants so we know facility is in bounds
+ PARCLog *log = logger->loggerArray[facility];
+
+ va_list va;
+ va_start(va, format);
+
+ parcLog_MessageVaList(log, level, logtime, format, va);
+
+ va_end(va);
+ }
+}
diff --git a/hicn-light/src/core/logger.h b/hicn-light/src/core/logger.h
new file mode 100755
index 000000000..e2ab7e147
--- /dev/null
+++ b/hicn-light/src/core/logger.h
@@ -0,0 +1,168 @@
+/*
+ * 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 logger.h
+ * @brief Logger for the hicn-light forwarder
+ *
+ * A facility based logger to allow selective logging from different parts of
+ * hicn-light
+ *
+ */
+
+#ifndef logger_h
+#define logger_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/logging/parc_LogLevel.h>
+#include <parc/logging/parc_LogReporter.h>
+#include <stdarg.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_Clock.h>
+
+struct logger;
+typedef struct logger Logger;
+
+/**
+ * CONFIG faciilty concerns anything in the /config directory
+ * CORE concerns anything in the /core directory
+ * IO concerns anything in the /io directory (listeners, connectors, tcp,
+ * ethernet, etc.) PROCESSOR concerns FIB, PIT, CS MESSAGE concerns message
+ * events, like parsing
+ */
+typedef enum {
+ LoggerFacility_Config,
+ LoggerFacility_Core,
+ LoggerFacility_IO,
+ LoggerFacility_Processor,
+ LoggerFacility_Message,
+ LoggerFacility_END // sentinel value
+} LoggerFacility;
+
+/**
+ * Returns a string representation of a facility
+ *
+ * Do not free the returned value.
+ *
+ * @param [in] facility The facility to change to a string
+ *
+ * @retval string A string representation of the facility
+ */
+const char *logger_FacilityString(LoggerFacility facility);
+
+/**
+ * Returns a string representation of a log level
+ *
+ * Do not free the returned value.
+ *
+ * @param [in] level The level to change to a string
+ *
+ * @retval string A string representation of the level
+ */
+const char *logger_LevelString(PARCLogLevel level);
+
+/**
+ * Create a logger that uses a given writer and clock
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] writer The output writer
+ * @param [in] clock The clock to use for log messages
+ *
+ * @retval non-null An allocated logger
+ * @retval null An error
+ */
+Logger *logger_Create(PARCLogReporter *reporter, const PARCClock *clock);
+
+/**
+ * Release logger
+ */
+void logger_Release(Logger **loggerPtr);
+
+/**
+ * Acquire logger
+ */
+Logger *logger_Acquire(const Logger *logger);
+
+/**
+ * Sets the minimum log level for a facility
+ *
+ * The default log level is ERROR. For a message to be logged, it must be of
+ * equal or higher log level.
+ *
+ * @param [in] logger An allocated logger
+ * @param [in] facility The facility to set the log level for
+ * @param [in] The minimum level to log
+ *
+ */
+void logger_SetLogLevel(Logger *logger, LoggerFacility facility,
+ PARCLogLevel minimumLevel);
+
+/**
+ * Tests if the log level would be logged
+ *
+ * If the facility would log the given level, returns true. May be used as a
+ * guard around expensive logging functions.
+ *
+ * @param [in] logger An allocated logger
+ * @param [in] facility The facility to test
+ * @param [in] The level to test
+ *
+ * @retval true The given facility would log the given level
+ * @retval false A message of the given level would not be logged
+ *
+ */
+bool logger_IsLoggable(const Logger *logger, LoggerFacility facility,
+ PARCLogLevel level);
+
+/**
+ * Log a message
+ *
+ * The message will only be logged if it is loggable (logger_IsLoggable returns
+ * true).
+ *
+ * @param [in] logger An allocated Logger
+ * @param [in] facility The facility to log under
+ * @param [in] level The log level of the message
+ * @param [in] module The specific module logging the message
+ * @param [in] format The message with varargs
+ *
+ */
+void logger_Log(Logger *logger, LoggerFacility facility, PARCLogLevel level,
+ const char *module, const char *format, ...);
+
+/**
+ * Switch the logger to a new reporter
+ *
+ * Will close the old reporter and re-setup the internal loggers to use the new
+ * reporter. All current log level settings are preserved.
+ *
+ * @param [in] logger An allocated Logger
+ * @param [in] reporter An allocated PARCLogReporter
+ */
+void logger_SetReporter(Logger *logger, PARCLogReporter *reporter);
+
+/**
+ * Set a new clock to use with the logger
+ *
+ * The logger will start getting the time (logged as the messageid) from the
+ * specified clock
+ *
+ * @param [in] logger An allocated Logger
+ * @param [in] clock An allocated PARCClock
+ */
+void logger_SetClock(Logger *logger, PARCClock *clock);
+#endif // logger_h
diff --git a/hicn-light/src/core/mapMe.c b/hicn-light/src/core/mapMe.c
new file mode 100755
index 000000000..4444bcf15
--- /dev/null
+++ b/hicn-light/src/core/mapMe.c
@@ -0,0 +1,816 @@
+/*
+ * 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 mapMe.c
+ * @brief MAP-Me : AnchorLess Producer Mobility Management.
+ */
+
+#ifdef WITH_MAPME
+
+#include <hicn/hicn.h>
+#include <src/core/mapMe.h>
+#include <stdio.h> // printf
+
+#include <src/core/connectionList.h>
+#include <src/core/forwarder.h>
+#include <src/core/logger.h>
+#include <src/core/message.h>
+#include <src/core/messagePacketType.h> // packet types
+#include <src/core/ticks.h>
+#include <src/processor/fibEntry.h>
+#include <src/processor/pitEntry.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Iterator.h>
+#include <parc/algol/parc_Unsigned.h>
+#include <parc/assert/parc_Assert.h>
+
+#define MS2NS(x) x * 1000000
+#define T2NS(x) forwarder_TicksToNanos(x)
+
+#define MAPME_DEFAULT_TU 5000 /* ms */
+#define MAPME_DEFAULT_RETX 500 /* ms */
+#define MAX_RETX 3
+
+#define NOT_A_NOTIFICATION false
+#define NO_INGRESS 0
+#define TIMER_NO_REPEAT false
+
+#define DO_DISCOVERY 1
+#define MAPME_INVALID_DICOVERY_SEQ -1
+
+#define LOG_FACILITY LoggerFacility_Core
+
+#define LOG(mapme, log_level, fmt, ...) \
+ do { \
+ Logger *logger = forwarder_GetLogger(mapme->forwarder); \
+ if (logger_IsLoggable(logger, LOG_FACILITY, log_level)) { \
+ logger_Log(logger, LOG_FACILITY, log_level, __func__, fmt, \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define WARN(mapme, fmt, ...) \
+ LOG(mapme, PARCLogLevel_Warning, fmt, ##__VA_ARGS__)
+#define ERROR(mapme, fmt, ...) \
+ LOG(mapme, PARCLogLevel_Error, fmt, ##__VA_ARGS__)
+#define INFO(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Info, fmt, ##__VA_ARGS__)
+#define DEBUG(mapme, fmt, ...) \
+ LOG(mapme, PARCLogLevel_Debug, fmt, ##__VA_ARGS__)
+
+/**
+ * MAP-Me state data structure
+ */
+struct mapme {
+ uint32_t retx; /* ms */
+ uint32_t Tu; /* ms */
+ bool removeFibEntries;
+
+ Forwarder *forwarder;
+};
+
+static MapMe MapMeDefault = {.retx = MAPME_DEFAULT_RETX,
+ .Tu = MAPME_DEFAULT_TU,
+ .removeFibEntries = false};
+
+/******************************************************************************/
+
+#include <src/core/connection.h>
+
+bool mapMe_Init(MapMe **mapme, Forwarder *forwarder) {
+ *mapme = malloc(sizeof(MapMe));
+ if (!mapme) goto ERR_MALLOC;
+
+ /* Internal state : set default values */
+ memcpy(*mapme, &MapMeDefault, sizeof(MapMe));
+
+ (*mapme)->forwarder = forwarder;
+
+ /* Install hook on Face events to onConnectionAdded */
+ // see. config/configuration.c
+
+ /* Install hook for signalization processing. See :
+ * - io/hicnListener.c
+ * - src/core/connection.{c,h}
+ */
+
+ ERROR((*mapme), "MapMe");
+
+ return true;
+
+ERR_MALLOC:
+ return false;
+}
+
+/******************************************************************************
+ * TFIB
+ ******************************************************************************/
+
+#define INVALID_SEQ 0
+#define INIT_SEQ 1
+
+typedef struct {
+ uint32_t seq;
+ PARCHashMap *nexthops;
+ /* Update/Notification heuristic */
+ Ticks lastAckedUpdate; // XXX This is only for producer !!!
+} MapMeTFIB;
+
+static MapMeTFIB *mapMeTFIB_Create() {
+ MapMeTFIB *tfib;
+ tfib = malloc(sizeof(MapMeTFIB));
+ if (!tfib) goto ERR_MALLOC;
+ tfib->seq = 0;
+ tfib->lastAckedUpdate = 0;
+ tfib->nexthops = parcHashMap_Create();
+ if (!tfib->nexthops) goto ERR_HASHMAP;
+
+ return tfib;
+
+ERR_HASHMAP:
+ free(tfib);
+ERR_MALLOC:
+ return NULL;
+}
+
+void mapMeTFIB_Release(MapMeTFIB **tfibPtr) {
+ MapMeTFIB *tfib = *tfibPtr;
+ parcHashMap_Release(&tfib->nexthops);
+ free(tfib);
+ *tfibPtr = NULL;
+}
+
+/**
+ * @function mapMe_CreateTFIB
+ * @abstract Associate a new TFIB entry to a FIB entry.
+ * @param [in] - Pointer to the FIB entry.
+ * @return Boolean indicating the success of the operation.
+ */
+static void mapMe_CreateTFIB(FibEntry *fibEntry) {
+ MapMeTFIB *tfib;
+
+ /* Make sure we don't already have an associated TFIB entry */
+ tfib = fibEntry_getUserData(fibEntry);
+ // assertNull(tfib);
+
+ tfib = mapMeTFIB_Create();
+ fibEntry_setUserData(fibEntry, tfib, (void (*)(void **))mapMeTFIB_Release);
+}
+
+#define TFIB(fibEntry) ((MapMeTFIB *)fibEntry_getUserData(fibEntry))
+
+static const PARCEventTimer *mapMeTFIB_Get(const MapMeTFIB *tfib,
+ unsigned conn_id) {
+ const PARCEventTimer *timer;
+ const PARCBuffer *buffer;
+ PARCUnsigned *cid = parcUnsigned_Create(conn_id);
+ buffer = parcHashMap_Get(tfib->nexthops, cid);
+ if (!buffer) return NULL;
+ PARCByteArray *array = parcBuffer_Array(buffer);
+ timer = *((PARCEventTimer **)parcByteArray_Array(array));
+ parcUnsigned_Release(&cid);
+ return timer;
+}
+
+static void mapMeTFIB_Put(MapMeTFIB *tfib, unsigned conn_id,
+ const PARCEventTimer *timer) {
+ /* NOTE: Timers are not objects (the only class not being an object in
+ * fact), and as such, we cannot use them as values for the HashMap.
+ * Just like for unsigned we needed the PARC wrapper.
+ * There is no wrapper for pointers, so we use Arrays, which has an ubly
+ * syntax...
+ */
+ PARCUnsigned *cid = parcUnsigned_Create(conn_id);
+ PARCBuffer *buffer =
+ parcBuffer_CreateFromArray(&timer, sizeof(PARCEventTimer *));
+ parcHashMap_Put(tfib->nexthops, cid, buffer);
+ parcUnsigned_Release(&cid);
+ parcBuffer_Release(&buffer);
+}
+
+static void mapMeTFIB_Remove(MapMeTFIB *tfib, unsigned conn_id) {
+ // Who releases the timer ?
+ PARCUnsigned *cid = parcUnsigned_Create(conn_id);
+ parcHashMap_Remove(tfib->nexthops, cid);
+ parcUnsigned_Release(&cid);
+}
+
+static PARCIterator *mapMeTFIB_CreateKeyIterator(const MapMeTFIB *tfib) {
+ return parcHashMap_CreateKeyIterator(tfib->nexthops);
+}
+
+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);
+
+ /* The name length will be equal to ip address' prefix length */
+ return hicn_prefix_create_from_ip_address(&ip_address, prefix);
+}
+
+static Message *mapMe_createMessage(const MapMe *mapme, const Name *name,
+ mapme_params_t *params) {
+ Ticks now = forwarder_GetTicks(mapme->forwarder);
+ Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder));
+
+ INFO(mapme, "[MAP-Me] CreateMessage type=%d seq=%d", params->type,
+ params->seq);
+
+ size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN
+ : HICN_MAPME_V4_HDRLEN;
+ uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size);
+
+ hicn_prefix_t prefix;
+ int rc = hicn_prefix_from_name(name, &prefix);
+ if (rc < 0) {
+ ERROR(mapme, "[MAP-Me] Failed to create lib's name");
+ goto ERR_NAME;
+ }
+
+ INFO(mapme, "[MAP-Me] Creating MAP-Me packet");
+ size_t len = hicn_mapme_create_packet(icmp_pkt, &prefix, params);
+ if (len != 0) {
+ ERROR(mapme, "[MAP-Me] Failed to create mapme packet through lib");
+ goto ERR_CREATE;
+ }
+
+ // hicn_packet_dump(icmp_pkt, MAPME_HDRLEN);
+
+ return message_CreateFromByteArray(NO_INGRESS, icmp_pkt,
+ MessagePacketType_Interest, now, logger);
+
+ERR_CREATE:
+ERR_NAME:
+ return NULL;
+}
+
+static Message *mapMe_createAckMessage(const MapMe *mapme,
+ const uint8_t *msgBuffer,
+ const mapme_params_t *params) {
+ Ticks now = forwarder_GetTicks(mapme->forwarder);
+ Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder));
+
+ size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN
+ : HICN_MAPME_V4_HDRLEN;
+ uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size);
+ memcpy(icmp_pkt, msgBuffer, size);
+
+ size_t len = hicn_mapme_create_ack(icmp_pkt, params);
+ if (len != size) {
+ ERROR(mapme, "[MAP-Me] Failed to create mapme ack packet through lib");
+ return NULL;
+ }
+
+ return message_CreateFromByteArray(
+ NO_INGRESS, icmp_pkt, MessagePacketType_ContentObject, now, logger);
+}
+
+struct setFacePendingArgs {
+ const MapMe *mapme;
+ const Name *name;
+ FibEntry *fibEntry;
+ unsigned conn_id;
+ bool send;
+ bool is_first;
+ uint32_t num_retx;
+};
+
+static bool mapMe_setFacePending(const MapMe *mapme, const Name *name,
+ FibEntry *fibEntry, unsigned conn_id,
+ bool send, bool is_first, uint32_t num_retx);
+
+static void mapMe_setFacePendingCallback(int fd, PARCEventType which_event,
+ void *data) {
+ struct setFacePendingArgs *args = (struct setFacePendingArgs *)data;
+
+ parcAssertTrue(which_event & PARCEventType_Timeout,
+ "Event incorrect, expecting %X set, got %X",
+ PARCEventType_Timeout, which_event);
+
+ INFO(args->mapme, "Timeout during retransmission. Re-sending");
+ mapMe_setFacePending(args->mapme, args->name, args->fibEntry, args->conn_id,
+ args->send, args->is_first, args->num_retx);
+}
+
+/**
+ * @brief Update/Notification heuristic:
+ *
+ * NOTE: IN are currently disabled until the proper placeholder is agreed in the
+ * interest header.
+ */
+static hicn_mapme_type_t mapMe_getTypeFromHeuristic(const MapMe *mapme,
+ FibEntry *fibEntry) {
+#if 0 /* interplay of IU/IN */
+ if (TFIB(fibEntry)->lastAckedUpdate == 0) {
+ return UPDATE;
+ } else {
+ Ticks interval = now - TFIB(fibEntry)->lastAckedUpdate;
+ return (T2NS(interval) > MS2NS(mapme->Tu)) ? UPDATE : NOTIFICATION;
+ }
+#else /* Always send IU */
+ return UPDATE;
+#endif
+}
+
+static bool mapMe_setFacePending(const MapMe *mapme, const Name *name,
+ FibEntry *fibEntry, unsigned conn_id,
+ bool send, bool is_first, uint32_t num_retx) {
+ int rc;
+
+ INFO(mapme, "[MAP-Me] SetFacePending connection=%d prefix=XX retx=%d",
+ conn_id, num_retx);
+
+ /* NOTE: if the face is pending an we receive an IN, maybe we should not
+ * cancel the timer
+ */
+ Dispatcher *dispatcher = forwarder_GetDispatcher(mapme->forwarder);
+ PARCEventTimer *timer;
+
+ // NOTE
+ // - at producer, send always true, we always send something reliably so we
+ // set the timer.
+ // - in the network, we always forward an IU, and never an IN
+ if (is_first || send) {
+ // XXX
+ mapme_params_t params = {
+ .protocol = IPPROTO_IPV6,
+ .type = is_first ? mapMe_getTypeFromHeuristic(mapme, fibEntry) : UPDATE,
+ .seq = TFIB(fibEntry)->seq};
+ Message *special_interest = mapMe_createMessage(mapme, name, &params);
+ if (!special_interest) {
+ INFO(mapme, "[MAP-Me] Could not create special interest");
+ return false;
+ }
+
+ const ConnectionTable *table =
+ forwarder_GetConnectionTable(mapme->forwarder);
+ const Connection *conn =
+ connectionTable_FindById((ConnectionTable *)table, conn_id);
+ if (conn) {
+ INFO(mapme, "[MAP-Me] Sending MAP-Me packet");
+ connection_ReSend(conn, special_interest, NOT_A_NOTIFICATION);
+ } else {
+ INFO(mapme, "[MAP-Me] Stopped retransmissions as face went down");
+ }
+
+ if (num_retx < MAX_RETX) {
+ INFO(mapme, "[MAP-Me] - Scheduling retransmission\n");
+ /* Schedule retransmission */
+ struct setFacePendingArgs *args =
+ malloc(sizeof(struct setFacePendingArgs));
+ if (!args) goto ERR_MALLOC;
+ args->mapme = mapme;
+ args->name = name;
+ args->fibEntry = fibEntry;
+ args->conn_id = conn_id;
+ args->send = send;
+ args->is_first = is_first;
+ args->num_retx = num_retx + 1;
+
+ timer = dispatcher_CreateTimer(dispatcher, TIMER_NO_REPEAT,
+ mapMe_setFacePendingCallback, args);
+ struct timeval timeout = {mapme->retx / 1000,
+ (mapme->retx % 1000) * 1000};
+ rc = parcEventTimer_Start(timer, &timeout);
+ if (rc < 0) goto ERR_TIMER;
+ } else {
+ INFO(mapme, "[MAP-Me] Last retransmission.");
+ timer = NULL;
+ }
+ } else {
+ INFO(mapme, "[MAP-Me] - not forwarding as send is False");
+ timer = NULL;
+ }
+
+ PARCEventTimer *oldTimer =
+ (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_id);
+ if (oldTimer) {
+ INFO(mapme, "[MAP-Me] - Found old timer, would need to cancel !");
+ // parcEventTimer_Stop(oldTimer);
+ }
+ INFO(mapme, "[MAP-Me] - Putting new timer in TFIB");
+ if (timer) mapMeTFIB_Put(TFIB(fibEntry), conn_id, timer);
+
+ return true;
+
+ERR_MALLOC:
+ERR_TIMER:
+ return false;
+}
+
+/*------------------------------------------------------------------------------
+ * Event handling
+ *----------------------------------------------------------------------------*/
+
+/*
+ * Return true if we have at least one local connection as next hop
+ */
+static bool mapMe_hasLocalNextHops(const MapMe *mapme,
+ const FibEntry *fibEntry) {
+ const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry);
+ const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder);
+
+ for (size_t j = 0; j < fibEntry_NexthopCount(fibEntry); j++) {
+ /* Retrieve Nexthop #j */
+ unsigned conn_id = numberSet_GetItem(nexthops, j);
+ const Connection *conn =
+ connectionTable_FindById((ConnectionTable *)table, conn_id);
+
+ /* Ignore non-local connections */
+ if (!connection_IsLocal(conn)) continue;
+ /* We don't need to test against conn_added since we don't
+ * expect it to have any entry in the FIB */
+
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Callback called everytime a new connection is created by the control protocol
+ */
+void mapMe_onConnectionAdded(const MapMe *mapme, const Connection *conn_added) {
+ /* bool ret; */
+ FibEntryList *fiblist;
+
+ /* Ignore local connections corresponding to applications for now */
+ if (connection_IsLocal(conn_added)) return;
+
+ unsigned conn_added_id = connection_GetConnectionId(conn_added);
+ INFO(mapme, "[MAP-Me] New connection %d", conn_added_id);
+
+ /*
+ * Iterate on FIB to find locally served prefix
+ * Ideally, we want to avoid a FIB scan everytime a face is added/removed
+ */
+ fiblist = forwarder_GetFibEntries(mapme->forwarder);
+ for (size_t i = 0; i < fibEntryList_Length(fiblist); i++) {
+ FibEntry *fibEntry = (FibEntry *)fibEntryList_Get(fiblist, i);
+ const Name *name = fibEntry_GetPrefix(fibEntry);
+
+ /* Skip entries that have no local connection as next hop */
+ if (!mapMe_hasLocalNextHops(mapme, fibEntry)) continue;
+
+ /* This entry corresponds to a locally served prefix, set
+ * Special Interest */
+ if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */
+ mapMe_CreateTFIB(fibEntry);
+ TFIB(fibEntry)->seq++;
+
+ char *name_str = name_ToString(name);
+ INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str,
+ conn_added_id);
+ free(name_str);
+
+ mapMe_setFacePending(mapme, name, fibEntry, conn_added_id, true, true, 0);
+ }
+}
+
+/*------------------------------------------------------------------------------
+ * Special Interest handling
+ *----------------------------------------------------------------------------*/
+
+/**
+ * @discussion This function is way too long and should be cut out
+ */
+static bool mapMe_onSpecialInterest(const MapMe *mapme,
+ const uint8_t *msgBuffer,
+ unsigned conn_in_id, hicn_prefix_t *prefix,
+ mapme_params_t *params) {
+ const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder);
+ /* The cast is needed since connectionTable_FindById miss the
+ * const qualifier for the first parameter */
+ const Connection *conn_in =
+ connectionTable_FindById((ConnectionTable *)table, conn_in_id);
+ seq_t fibSeq, seq = params->seq;
+ bool send = (params->type == UPDATE);
+ bool rv;
+
+ Name *name = name_CreateFromPacket(msgBuffer, MessagePacketType_Interest);
+ char *name_str = name_ToString(name);
+ INFO(mapme,
+ "[MAP-Me] Ack'ed Special Interest on connection %d - prefix=%s type=XX "
+ "seq=%d",
+ conn_in_id, name_str, seq);
+ free(name_str);
+
+ /*
+ * Immediately send an acknowledgement back on the ingress connection
+ * We always ack, even duplicates.
+ */
+ Message *ack = mapMe_createAckMessage(mapme, msgBuffer, params);
+ if (!ack) goto ERR_ACK_CREATE;
+ rv = connection_ReSend(conn_in, ack, NOT_A_NOTIFICATION);
+ if (!rv) goto ERR_ACK_SEND;
+ message_Release(&ack);
+
+ /* EPM on FIB */
+ /* only the processor has access to the FIB */
+ FIB *fib = forwarder_getFib(mapme->forwarder);
+
+ FibEntry *fibEntry = fib_Contains(fib, name);
+ if (!fibEntry) {
+ INFO(mapme,
+ "[MAP-Me] - Re-creating FIB entry with next hop on connection %d",
+ conn_in_id);
+ /*
+ * This might happen for a node hosting a producer which has moved.
+ * Destroying the face has led to removing all corresponding FIB
+ * entries. In that case, we need to correctly restore the FIB entries.
+ */
+ strategy_type fwdStrategy = LAST_STRATEGY_VALUE;
+
+ fibEntry = fibEntry_Create(name, fwdStrategy);
+ fibEntry_AddNexthopByConnectionId(fibEntry, conn_in_id);
+ mapMe_CreateTFIB(fibEntry);
+ TFIB(fibEntry)->seq = seq; // INIT_SEQ;
+ fib_Add(fib, fibEntry);
+ return true; // with proper seq, we are done
+
+ } else if (!TFIB(fibEntry)) {
+ /* Create TFIB associated to FIB entry */
+ INFO(mapme,
+ "[MAP-Me] - Creating TFIB entry with default sequence number");
+ mapMe_CreateTFIB(fibEntry);
+ }
+
+ fibSeq = TFIB(fibEntry)->seq;
+ if (seq > fibSeq) {
+ INFO(mapme,
+ "[MAP-Me] - Higher sequence number than FIB %d, updating seq and "
+ "next hops",
+ fibSeq);
+ /* This has to be done first to allow processing SpecialInterestAck's */
+ TFIB(fibEntry)->seq = seq;
+
+ /* Reliably forward the IU on all prevHops */
+ INFO(mapme, "[MAP-Me] - (1/3) processing prev hops");
+ if (params->type == UPDATE) {
+ PARCIterator *iterator = mapMeTFIB_CreateKeyIterator(TFIB(fibEntry));
+ while (parcIterator_HasNext(iterator)) {
+ PARCUnsigned *cid = parcIterator_Next(iterator);
+ unsigned conn_id = parcUnsigned_GetUnsigned(cid);
+ INFO(mapme, "[MAP-Me] - Re-sending IU to pending connection %d",
+ conn_id);
+ mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
+ conn_id, false, false, 0);
+ }
+ parcIterator_Release(&iterator);
+ }
+
+ /* nextHops -> prevHops
+ *
+ * We add to the list of pendingUpdates the current next hops, and
+ * eventually forward them an IU too.
+ *
+ * Exception: nextHops -> nextHops
+ * Because of retransmission issues, it is possible that a second interest
+ * (with same of higher sequence number) is receive from a next-hop
+ * interface. In that case, the face remains a next hop.
+ */
+ const NumberSet *nexthops_old = fibEntry_GetNexthops(fibEntry);
+
+ /* We make a copy to be able to send IU _after_ updating next hops */
+ NumberSet *nexthops = numberSet_Create();
+ numberSet_AddSet(nexthops, nexthops_old);
+
+ /* We are considering : * -> nextHops
+ *
+ * If inFace was a previous hop, we need to cancel the timer and remove
+ * the entry. Also, the face should be added to next hops.
+ *
+ * Optimization : nextHops -> nextHops
+ * - no next hop to add
+ * - we know that inFace was not a previous hop since it was a next hop and
+ * this forms a partition. No need for a search
+ */
+
+ INFO(mapme, "[MAP-Me] - (3/3) next hops ~~> prev hops");
+ PARCEventTimer *oldTimer =
+ (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_in_id);
+ if (oldTimer) {
+ /* This happens if we receive an IU while we are still sending
+ * one in the other direction
+ */
+ INFO(mapme, "[MAP-Me] - Canceled pending timer");
+ parcEventTimer_Stop(oldTimer);
+ mapMeTFIB_Remove(TFIB(fibEntry), conn_in_id);
+ }
+
+ /* Remove all next hops */
+ for (size_t k = 0; k < numberSet_Length(nexthops_old); k++) {
+ unsigned conn_id = numberSet_GetItem(nexthops_old, k);
+ INFO(mapme, "[MAP-Me] - Replaced next hops by connection %d", conn_id);
+ fibEntry_RemoveNexthopByConnectionId(fibEntry, conn_id);
+ }
+ fibEntry_AddNexthopByConnectionId(fibEntry, conn_in_id);
+
+ INFO(mapme, "[MAP-Me] - (2/3) processing next hops");
+ bool complete = true;
+ for (size_t k = 0; k < numberSet_Length(nexthops); k++) {
+ unsigned conn_id = numberSet_GetItem(nexthops, k);
+ INFO(mapme, " - Next hop connection %d", conn_id);
+ if (conn_id == conn_in_id) {
+ INFO(mapme, " . Ignored this next hop since equal to ingress face");
+ continue;
+ }
+
+ INFO(mapme, "[MAP-Me] - Sending IU on current next hop connection %d",
+ conn_id);
+ mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
+ conn_id, send, false, 0);
+ complete = false;
+ }
+
+ /*
+ * The update is completed when the IU could not be sent to any
+ * other next hop.
+ */
+ if (complete) INFO(mapme, "[MAP-Me] - Update completed !");
+
+ numberSet_Release(&nexthops);
+
+ } else if (seq == fibSeq) {
+ /*
+ * Multipath, multihoming, multiple producers or duplicate interest
+ *
+ * In all cases, we assume the propagation was already done when the first
+ * interest with the same sequence number was received, so we stop here
+ *
+ * It might happen that the previous AP has still a connection to the
+ * producer and that we received back our own IU. In that case, we just
+ * need to Ack and ignore it.
+ */
+ if (mapMe_hasLocalNextHops(mapme, fibEntry)) {
+ INFO(mapme, "[MAP-Me] - Received original interest... Update complete");
+ return true;
+ }
+
+ INFO(mapme, "[MAP-Me] - Adding multipath next hop on connection %d",
+ conn_in_id);
+ fibEntry_AddNexthopByConnectionId(fibEntry, conn_in_id);
+
+ } else { // seq < fibSeq
+ /*
+ * Face is propagating outdated information, we can just
+ * consider it as a prevHops. Send the special interest backwards with
+ * the new sequence number to reconciliate this outdated part of the
+ * arborescence.
+ */
+ INFO(
+ mapme,
+ "[MAP-Me] - Update interest %d -> %d sent backwards on connection %d",
+ seq, fibSeq, conn_in_id);
+ mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
+ conn_in_id, send, false, 0);
+ }
+
+ return true;
+
+ERR_ACK_SEND:
+ message_Release(&ack);
+ERR_ACK_CREATE:
+ return false;
+}
+
+void mapMe_onSpecialInterestAck(const MapMe *mapme, const uint8_t *msgBuffer,
+ unsigned conn_in_id, hicn_prefix_t *prefix,
+ mapme_params_t *params) {
+ INFO(mapme, "[MAP-Me] Receive IU/IN Ack on connection %d", conn_in_id);
+
+ const Name *name =
+ name_CreateFromPacket(msgBuffer, MessagePacketType_Interest);
+
+ FIB *fib = forwarder_getFib(mapme->forwarder);
+ FibEntry *fibEntry = fib_Contains(fib, name);
+ parcAssertNotNull(fibEntry,
+ "No corresponding FIB entry for name contained in IU Ack");
+
+ /* Test if the latest pending update has been ack'ed, otherwise just ignore */
+ seq_t seq = params->seq;
+ if (seq != INVALID_SEQ) {
+ seq_t fibSeq = TFIB(fibEntry)->seq;
+
+ if (seq < fibSeq) {
+ INFO(mapme,
+ "[MAP-Me] - Ignored special interest Ack with seq=%u, expected %u",
+ seq, fibSeq);
+ return;
+ }
+ }
+
+ /*
+ * Ignore the Ack if no TFIB is present, or it has no corresponding entry
+ * with the ingress face.
+ * Note: previously, we were creating the TFIB entry
+ */
+ if (!TFIB(fibEntry)) {
+ INFO(mapme, "[MAP-Me] - Ignored ACK for prefix with no TFIB entry");
+ return;
+ }
+
+ PARCEventTimer *timer =
+ (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_in_id);
+ if (!timer) {
+ INFO(mapme,
+ "[MAP-Me] - Ignored ACK for prefix not having the Connection in "
+ "TFIB entry. Possible duplicate ?");
+ return;
+ }
+
+ /* Stop timer and remove entry from TFIB */
+ parcEventTimer_Stop(timer);
+ mapMeTFIB_Remove(TFIB(fibEntry), conn_in_id);
+
+ INFO(mapme, "[MAP-Me] - Removing TFIB entry for ack on connection %d",
+ conn_in_id);
+
+ /* We need to update the timestamp only for IU Acks, not for IN Acks */
+ if (params->type == UPDATE_ACK) {
+ INFO(mapme, "[MAP-Me] - Updating LastAckedUpdate");
+ TFIB(fibEntry)->lastAckedUpdate = forwarder_GetTicks(mapme->forwarder);
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Overloaded functions
+ *----------------------------------------------------------------------------*/
+
+/*
+ * @abstract returns where to forward a normal interests(nexthops) defined by
+ * mapme, it also set the sequnence number properly if needed
+ */
+
+/******************************************************************************
+ * Public functions (exposed in the .h)
+ ******************************************************************************/
+
+/*
+ * Returns true iif the message corresponds to a MAP-Me packet
+ */
+bool mapMe_isMapMe(const uint8_t *msgBuffer) {
+ uint8_t next_header = messageHandler_NextHeaderType(msgBuffer);
+
+ const uint8_t *icmp_ptr;
+ if (next_header == IPPROTO_ICMP) {
+ icmp_ptr = msgBuffer + IPV4_HDRLEN;
+ } else if (next_header == IPPROTO_ICMPV6) {
+ icmp_ptr = msgBuffer + IPV6_HDRLEN;
+ } else {
+ return false;
+ }
+
+ uint8_t type = ((_icmp_header_t *)icmp_ptr)->type;
+ uint8_t code = ((_icmp_header_t *)icmp_ptr)->code;
+ if (HICN_IS_MAPME(type, code)) return true;
+
+ return false;
+}
+
+/**
+ * @discussion The exact type of the MapMe message is determined after
+ * reception. In hICN, Interest Update and Notifications look like regular
+ * Interest packets, and are first punted from the normal path by the forwarder,
+ * then treated as such in the Listener to reach this function. Acknowledgements
+ * are received as Content (Data) packets and will land here too.
+ *
+ * This function is in charge of abstracting the low-level implementation of
+ * MAP-Me (eg. ICMP packets) and return higher level messages that can be
+ * processed by MAP-Me core.
+ */
+void mapMe_Process(const MapMe *mapme, const uint8_t *msgBuffer,
+ unsigned conn_id) {
+ hicn_prefix_t prefix;
+ mapme_params_t params;
+ hicn_mapme_parse_packet(msgBuffer, &prefix, &params);
+
+ // XXX Dispatch message dependenging on type
+ switch (params.type) {
+ case UPDATE:
+ case NOTIFICATION:
+ mapMe_onSpecialInterest(mapme, msgBuffer, conn_id, &prefix, &params);
+ break;
+ case UPDATE_ACK:
+ case NOTIFICATION_ACK:
+ mapMe_onSpecialInterestAck(mapme, msgBuffer, conn_id, &prefix, &params);
+ break;
+ default:
+ printf("E:Unknown message\n");
+ break;
+ }
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/core/mapMe.h b/hicn-light/src/core/mapMe.h
new file mode 100755
index 000000000..39edd0bd7
--- /dev/null
+++ b/hicn-light/src/core/mapMe.h
@@ -0,0 +1,89 @@
+/*
+ * 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 mapMe.h
+ * @brief MAP-Me : AnchorLess Producer Mobility Management
+ */
+
+#ifndef mapMe_h
+#define mapMe_h
+
+#ifdef WITH_MAPME
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <src/io/hicnListener.h>
+
+#include <hicn/hicn.h>
+#include <src/utils/commands.h>
+
+struct mapme;
+typedef struct mapme MapMe;
+
+/**
+ * @function MapMe_Init
+ * @abstract Initializes MAP-Me state in the forwarder.
+ * @return bool - Boolean informing about the success of MAP-Me initialization.
+ */
+bool mapMe_Init(MapMe **mapme, Forwarder *Forwarder);
+
+/**
+ * @function messageHandler_isMapMe
+ * @abstract Identifies MAP-Me messages
+ * @discussion This function can be used by the forwarder to dispatch MAP-Me
+ * message to the appropriate processing function. Ideally this would be
+ * done through hooks defined in the Init function.
+ * @param [in] msgBuffer - The buffer to match
+ * @return A boolean indicating whether message is a MAP-Me control message.
+ */
+bool mapMe_isMapMe(const uint8_t *msgBuffer);
+
+/**
+ * @function mapMe_handleMapMeMessage
+ * @abstract Process a MAP-Me message.
+ * @param [in] mapme - Pointer to the MAP-Me data structure.
+ * @param [in] message - MAP-Me buffer
+ * @param [in] conn_id - Ingress connection id
+ */
+void mapMe_Process(const MapMe *mapme, const uint8_t *msgBuffer,
+ unsigned conn_id);
+
+/**
+ * @function mapMe_onConnectionAdded
+ * @abstract Callback following the addition of the face though the control
+ * protocol.
+ * @discussion This callback triggers the sending of control packets by MAP-Me.
+ * @param [in] mapme - Pointer to the MAP-Me data structure.
+ * @param [in] conn - The newly added connection.
+ */
+void mapMe_onConnectionAdded(const MapMe *mapme, const Connection *conn);
+
+/**
+ * @function mapMe_getNextHops
+ * @abstract return the nexthops to forward interests defined by mapme, it
+ * covers also the case where local discovery mechanisms are trriggered.
+ */
+NumberSet *mapMe_getNextHops(const MapMe *mapme, FibEntry *fibEntry,
+ const Message *interest);
+
+hicn_mapme_type_t mapMe_PktType_To_LibHicnPktType(MessagePacketType type);
+
+MessagePacketType mapMe_LibHicnPktType_To_PktType(hicn_mapme_type_t type);
+
+#endif /* WITH_MAPME */
+
+#endif // mapMe_h
diff --git a/hicn-light/src/core/message.c b/hicn-light/src/core/message.c
new file mode 100755
index 000000000..6c0e916d2
--- /dev/null
+++ b/hicn-light/src/core/message.c
@@ -0,0 +1,297 @@
+/*
+ * 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 <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+#include <src/core/wldr.h>
+
+#include <src/core/messageHandler.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <src/core/messagePacketType.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_EventBuffer.h>
+
+struct message {
+ Logger *logger;
+
+ Ticks receiveTime;
+ unsigned ingressConnectionId;
+
+ Name *name;
+
+ uint8_t *messageHead;
+
+ unsigned length;
+
+ uint8_t packetType;
+
+ unsigned refcount;
+};
+
+Message *message_Acquire(const Message *message) {
+ Message *copy = (Message *)message;
+ copy->refcount++;
+ return copy;
+}
+
+Message *message_CreateFromEventBuffer(PARCEventBuffer *data, size_t dataLength,
+ unsigned ingressConnectionId,
+ Ticks receiveTime, Logger *logger) {
+ // used by applications, we can get only interest or data packets
+ Message *message = parcMemory_AllocateAndClear(sizeof(Message));
+ parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Message));
+
+ message->logger = logger_Acquire(logger);
+ message->receiveTime = receiveTime;
+ message->ingressConnectionId = ingressConnectionId;
+ message->length = dataLength;
+
+ message->messageHead = parcMemory_AllocateAndClear(dataLength);
+ parcAssertNotNull(message->messageHead,
+ "parcMemory_AllocateAndClear(%zu) returned NULL",
+ dataLength);
+
+ // copy the data because *data is destroyed in the connection.
+ int res = parcEventBuffer_Read(data, message->messageHead, dataLength);
+ if (res == -1) {
+ return NULL;
+ }
+
+ if (messageHandler_IsInterest(message->messageHead)) {
+ message->packetType = MessagePacketType_Interest;
+ } else if (messageHandler_IsData(message->messageHead)) {
+ message->packetType = MessagePacketType_ContentObject;
+ } else {
+ printf("Got a packet that is not a data nor an interest, drop it!\n");
+ return NULL;
+ }
+ message->name =
+ name_CreateFromPacket(message->messageHead, message->packetType);
+
+ message->refcount = 1;
+
+ return message;
+}
+
+Message *message_CreateFromByteArray(unsigned connid, uint8_t *pckt,
+ MessagePacketType type, Ticks receiveTime,
+ Logger *logger) {
+ Message *message = parcMemory_AllocateAndClear(sizeof(Message));
+ parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Message));
+
+ message->logger = logger_Acquire(logger);
+ message->receiveTime = receiveTime;
+ message->ingressConnectionId = connid;
+ message->messageHead = pckt;
+ message->length = messageHandler_GetTotalPacketLength(pckt);
+ message->packetType = type;
+
+ if (messageHandler_IsWldrNotification(pckt)) {
+ message->name = NULL;
+ } else {
+ message->name =
+ name_CreateFromPacket(message->messageHead, message->packetType);
+ }
+
+ message->refcount = 1;
+
+ return message;
+}
+
+void message_Release(Message **messagePtr) {
+ parcAssertNotNull(messagePtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*messagePtr,
+ "Parameter must dereference to non-null pointer");
+
+ Message *message = *messagePtr;
+ parcAssertTrue(
+ message->refcount > 0,
+ "Invalid state: message_Release called on message with 0 references %p",
+ (void *)message);
+
+ message->refcount--;
+ if (message->refcount == 0) {
+ if (logger_IsLoggable(message->logger, LoggerFacility_Message,
+ PARCLogLevel_Debug)) {
+ logger_Log(message->logger, LoggerFacility_Message, PARCLogLevel_Debug,
+ __func__, "Message %p destroyed", (void *)message);
+ }
+
+ logger_Release(&message->logger);
+ if (message->name != NULL) name_Release(&message->name);
+ parcMemory_Deallocate((void **)&message->messageHead);
+ parcMemory_Deallocate((void **)&message);
+ }
+ *messagePtr = NULL;
+}
+
+bool message_Write(PARCEventQueue *parcEventQueue, const Message *message) {
+ parcAssertNotNull(message, "Message parameter must be non-null");
+ parcAssertNotNull(parcEventQueue, "Buffer parameter must be non-null");
+
+ return parcEventQueue_Write(parcEventQueue, message->messageHead,
+ message_Length(message));
+}
+
+size_t message_Length(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return message->length;
+}
+
+bool message_HasWldr(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return messageHandler_HasWldr(message->messageHead);
+}
+
+bool message_IsWldrNotification(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return messageHandler_IsWldrNotification(message->messageHead);
+}
+
+void message_ResetWldrLabel(Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return messageHandler_ResetWldrLabel(message->messageHead);
+}
+
+unsigned message_GetWldrLabel(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return messageHandler_GetWldrLabel(message->messageHead);
+}
+
+unsigned message_GetWldrExpectedLabel(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return messageHandler_GetExpectedWldrLabel(message->messageHead);
+}
+
+unsigned message_GetWldrLastReceived(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return messageHandler_GetWldrLastReceived(message->messageHead);
+}
+
+void message_SetWldrLabel(Message *message, uint16_t label) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ messageHandler_SetWldrLabel(message->messageHead, label);
+}
+
+Message *message_CreateWldrNotification(Message *original, uint16_t expected,
+ uint16_t lastReceived) {
+ parcAssertNotNull(original, "Parameter original must be non-null");
+ Message *message = parcMemory_AllocateAndClear(sizeof(Message));
+ parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Message));
+ message->receiveTime = original->receiveTime;
+ message->ingressConnectionId = original->ingressConnectionId;
+ message->refcount = 1;
+ message->logger = logger_Acquire(original->logger);
+
+ message->length = messageHandler_GetICMPPacketSize(
+ messageHandler_GetIPPacketType(original->messageHead));
+ message->messageHead = parcMemory_AllocateAndClear(message->length);
+ parcAssertNotNull(message->messageHead,
+ "parcMemory_AllocateAndClear returned NULL");
+
+ message->packetType = MessagePacketType_WldrNotification;
+ message->name = NULL; // nobody will use the name in a notification packet,
+ // so we can simply set it to NULL
+
+ // set notification stuff.
+ messageHandler_SetWldrNotification(
+ message->messageHead, original->messageHead, expected, lastReceived);
+ // XXX: what about the checksum?
+ return message;
+}
+
+unsigned message_GetIngressConnectionId(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return message->ingressConnectionId;
+}
+
+void message_SetIngressConnectionId(Message *message, unsigned conn) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ message->ingressConnectionId = conn;
+}
+
+Ticks message_GetReceiveTime(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return message->receiveTime;
+}
+
+uint32_t message_GetPathLabel(const Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return messageHandler_GetPathLabel(message->messageHead);
+}
+
+void message_SetPathLabel(Message *message, uint32_t label) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ return messageHandler_SetPathLabel(message->messageHead, label);
+}
+
+void message_UpdatePathLabel(Message *message, uint8_t outFace) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ messageHandler_UpdatePathLabel(message->messageHead, outFace);
+}
+
+void message_ResetPathLabel(Message *message) {
+ parcAssertNotNull(message, "Parameter must be non-null");
+ messageHandler_ResetPathLabel(message->messageHead);
+}
+
+MessagePacketType message_GetType(const Message *message) {
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ return message->packetType;
+}
+
+Name *message_GetName(const Message *message) {
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ return message->name;
+}
+
+bool message_HasInterestLifetime(const Message *message) {
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ return messageHandler_HasInterestLifetime(message->messageHead);
+}
+
+uint64_t message_GetInterestLifetimeTicks(const Message *message) {
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ uint64_t lifetime = messageHandler_GetInterestLifetime(message->messageHead);
+ return forwarder_NanosToTicks(lifetime * 1000000ULL);
+}
+
+bool message_HasContentExpiryTime(const Message *message) {
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ return messageHandler_HasContentExpiryTime(message->messageHead);
+}
+
+uint64_t message_GetContentExpiryTimeTicks(const Message *message) {
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ uint64_t expire = messageHandler_GetContentExpiryTime(message->messageHead);
+ return message->receiveTime + forwarder_NanosToTicks(expire * 1000000ULL);
+}
+
+const uint8_t *message_FixedHeader(const Message *message) {
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ return message->messageHead;
+}
diff --git a/hicn-light/src/core/message.h b/hicn-light/src/core/message.h
new file mode 100755
index 000000000..88aa32480
--- /dev/null
+++ b/hicn-light/src/core/message.h
@@ -0,0 +1,180 @@
+/*
+ * 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 message.h
+ * @brief Message is the unit of forwarding, i.e. the packets being switched
+ *
+ */
+#ifndef message_h
+#define message_h
+
+#include <src/config.h>
+#include <src/core/logger.h>
+#include <src/core/messagePacketType.h>
+#include <src/core/streamBuffer.h>
+
+#include <src/core/name.h>
+
+#include <parc/algol/parc_EventBuffer.h>
+#include <parc/algol/parc_EventQueue.h>
+
+#include <src/utils/address.h>
+
+#include <src/core/ticks.h>
+
+struct message;
+typedef struct message Message;
+
+/**
+ * @function message_CreateFromBuffer
+ * @abstract Takes ownership of the input buffer, which comprises one complete
+ * message
+ */
+
+Message *message_CreateFromEventBuffer(PARCEventBuffer *data, size_t dataLength,
+ unsigned ingressConnectionId,
+ Ticks receiveTime, Logger *logger);
+
+/**
+ * @function message_CreateFromByteArray
+ * @abstract create a message from a byte array
+ */
+
+Message *message_CreateFromByteArray(unsigned connid, uint8_t *pckt,
+ MessagePacketType type, Ticks receiveTime,
+ Logger *logger);
+
+/**
+ * @function message_Copy
+ * @abstract Get a reference counted copy
+ */
+
+Message *message_Acquire(const Message *message);
+
+/**
+ * Releases the message and frees the memory
+ */
+void message_Release(Message **messagePtr);
+
+/**
+ * Writes the message to the queue
+ */
+
+bool message_Write(PARCEventQueue *parcEventQueue, const Message *message);
+
+/**
+ * Returns the total byte length of the message
+ */
+size_t message_Length(const Message *message);
+
+bool message_HasWldr(const Message *message);
+
+bool message_IsWldrNotification(const Message *message);
+
+void message_ResetWldrLabel(Message *message);
+
+unsigned message_GetWldrLabel(const Message *message);
+
+unsigned message_GetWldrExpectedLabel(const Message *message);
+
+unsigned message_GetWldrLastReceived(const Message *message);
+
+void message_SetWldrLabel(Message *message, uint16_t label);
+
+Message *message_CreateWldrNotification(Message *original, uint16_t expected,
+ uint16_t lastReceived);
+/**
+ * Returns the connection id of the packet input
+ */
+unsigned message_GetIngressConnectionId(const Message *message);
+
+void message_SetIngressConnectionId(Message *message, unsigned conn);
+
+/**
+ * Returns the receive time (in router ticks) of the message
+ */
+Ticks message_GetReceiveTime(const Message *message);
+
+/**
+ * Returns the PacketType
+ */
+MessagePacketType message_GetType(const Message *message);
+
+uint32_t message_GetPathLabel(const Message *message);
+void message_SetPathLabel(Message *message, uint32_t label);
+void message_UpdatePathLabel(Message *message, uint8_t outFace);
+void message_ResetPathLabel(Message *message);
+
+// ===========================================================
+// Accessors used to index and compare messages
+
+/**
+ * @function message_GetName
+ * @abstract The name in the message
+ * @discussion
+ * The name of the Interest or Content Object. If the caller will store the
+ * name, he should make a reference counted copy.
+ * @return The name as stored in the message object.
+ */
+
+Name *message_GetName(const Message *message);
+
+/**
+ * Determines if the message has an Interest Lifetime parameter
+ *
+ * @param [in] message An allocated and parsed Message
+ *
+ * @retval true If an Intrerest Lifetime field exists
+ * @retval false If no Interest Lifetime exists
+ */
+
+bool message_HasInterestLifetime(const Message *message);
+
+/**
+ * Returns the Interest lifetime in hicn-light Ticks
+ *
+ * the interest expires after now + returned ticks
+ *
+ * @param [in] message An allocated and parsed Message
+ *
+ * @retval integer Lifetime in forwarder Ticks
+ *
+ */
+
+uint64_t message_GetInterestLifetimeTicks(const Message *message);
+
+/**
+ * checks if the expiry time is set inside the content object
+ */
+bool message_HasContentExpiryTime(const Message *message);
+
+/**
+ * returns the moment (in hicn-light ticks) when the content object will expire
+ */
+uint64_t message_GetContentExpiryTimeTicks(const Message *message);
+
+/**
+ * Returns a pointer to the beginning of the FixedHeader
+ *
+ * @param [in] message An allocated and parsed Message
+ *
+ * @return non-null The fixed header memory
+ * @return null No fixed header or an error
+ */
+
+const uint8_t *message_FixedHeader(const Message *message);
+
+#endif // message_h
diff --git a/hicn-light/src/core/messageHandler.h b/hicn-light/src/core/messageHandler.h
new file mode 100755
index 000000000..d63656461
--- /dev/null
+++ b/hicn-light/src/core/messageHandler.h
@@ -0,0 +1,580 @@
+/*
+ * 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 messageHandler
+#define messageHandler
+
+#include <stdlib.h>
+
+#include <hicn/hicn.h>
+#include <src/core/messagePacketType.h>
+
+#define H(packet) ((hicn_header_t *)packet)
+#define H6(packet) (H(packet)->v6.ip)
+#define H6T(packet) (H(packet)->v6.tcp)
+#define H4(packet) (H(packet)->v4.ip)
+#define H4T(packet) (H(packet)->v4.tcp)
+
+#define HICN_V6_LEN(packet) (H6(packet).len)
+#define HICN_V4_LEN(packet) (H4(packet).len)
+
+/*** codes and types ***/
+#define IPv6_TYPE 6
+#define IPv4_TYPE 4
+#define ICMP_WLDR_TYPE 42
+#define ICMP_WLDR_CODE 0
+#define ICMP_LB_TYPE 43
+
+/*** masks and constants ***/
+#define PATH_LABEL_MASK 0x8000 // 1000 0000 0000 0000
+#define NOT_PATH_LABEL_MASK 0x7fff // 0111 0000 0000 0000
+#define UINT16_T_MASK 0x0000ffff // 1111 1111 1111 1111
+#define NEVER_EXPIRE \
+ 16777216 // 2^16 (max urgent pointer) * 2^8 (max reserved + NS bits)
+
+/*** HICN ALLOWED PORTS ***/
+#define CONTROL_PORT 9695
+#define HTTP_PORT 8080
+
+#define IPV6_DEFAULT_VERSION 6
+#define IPV6_DEFAULT_TRAFFIC_CLASS 0
+#define IPV6_DEFAULT_FLOW_LABEL 0
+
+#define expected_lbl wldr_notification_lbl.expected_lbl
+#define received_lbl wldr_notification_lbl.received_lbl
+
+static inline uint8_t messageHandler_GetIPPacketType(const uint8_t *message) {
+ return HICN_IP_VERSION(message);
+}
+
+static inline void messageHandler_UpdateTCPCheckSum(uint8_t *message,
+ uint16_t *old_val,
+ uint16_t *new_val,
+ uint8_t size) {
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv4_TYPE:
+ for (uint8_t i = 0; i < size; i++) {
+ uint16_t old_csum = ~(H4T(message).csum);
+ uint16_t not_old_val = ~(*old_val);
+ uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val;
+
+ while (sum >> 16) {
+ sum = (sum >> 16) + (sum & UINT16_T_MASK);
+ }
+
+ H4T(message).csum = ~sum;
+ ++old_val;
+ ++new_val;
+ }
+ break;
+ case IPv6_TYPE:
+ for (uint8_t i = 0; i < size; i++) {
+ uint16_t old_csum = ~(H6T(message).csum);
+ uint16_t not_old_val = ~(*old_val);
+ uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val;
+
+ while (sum >> 16) {
+ sum = (sum >> 16) + (sum & UINT16_T_MASK);
+ }
+
+ H6T(message).csum = ~sum;
+ ++old_val;
+ ++new_val;
+ }
+ break;
+ default:
+ return;
+ }
+}
+
+static inline void messageHandler_UpdateIPv4CheckSum(uint8_t *message,
+ uint16_t *old_val,
+ uint16_t *new_val,
+ uint8_t size) {
+ for (uint8_t i = 0; i < size; i++) {
+ uint16_t old_csum = ~(H4(message).csum);
+ uint16_t not_old_val = ~(*old_val);
+ uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val;
+
+ while (sum >> 16) {
+ sum = (sum >> 16) + (sum & UINT16_T_MASK);
+ }
+
+ H4(message).csum = ~sum;
+ ++old_val;
+ ++new_val;
+ }
+}
+
+static inline size_t messageHandler_GetEmptyTCPPacketSize(unsigned ipVersion) {
+ if (ipVersion == IPv4_TYPE)
+ return IPV4_HDRLEN + TCP_HDRLEN;
+ else if (ipVersion == IPv6_TYPE)
+ return IPV6_HDRLEN + TCP_HDRLEN;
+ else
+ return 0;
+}
+
+static inline size_t messageHandler_GetICMPPacketSize(unsigned ipVersion) {
+ if (ipVersion == IPv4_TYPE)
+ return IPV4_HDRLEN + ICMP_HDRLEN;
+ else if (ipVersion == IPv6_TYPE)
+ return IPV6_HDRLEN + ICMP_HDRLEN;
+ else
+ return 0;
+}
+
+static inline size_t messageHandler_GetIPHeaderLength(unsigned ipVersion) {
+ if (ipVersion == IPv4_TYPE)
+ return IPV4_HDRLEN;
+ else if (ipVersion == IPv6_TYPE)
+ return IPV6_HDRLEN;
+ else
+ return 0;
+}
+
+static inline bool messageHandler_IsValidHIcnPacket(const uint8_t *message) {
+ uint8_t version = messageHandler_GetIPPacketType(message);
+ if (version == IPv6_TYPE || version == IPv4_TYPE) {
+ return true;
+ }
+ return false;
+}
+
+static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) {
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ return (uint8_t)H6(message).nxt;
+ case IPv4_TYPE:
+ return (uint8_t)H4(message).protocol;
+ default:
+ return 0;
+ }
+}
+
+static inline bool messageHandler_IsTCP(const uint8_t *message) {
+ if (messageHandler_NextHeaderType(message) != IPPROTO_TCP) return false;
+ return true;
+}
+
+static inline bool messageHandler_IsInterest(const uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return false;
+
+ bool flag;
+ hicn_packet_test_ece((hicn_header_t *)message,
+ &flag); // ECE flag is set to 0 in interest packets
+ if (flag == false) return true;
+ return false;
+}
+
+static inline bool messageHandler_IsData(const uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return false;
+
+ bool flag;
+ hicn_packet_test_ece((hicn_header_t *)message,
+ &flag); // ECE flag is set to 1 in data packets
+ if (flag == true) return true;
+ return false;
+}
+
+static inline bool messageHandler_IsWldrNotification(const uint8_t *message) {
+ // this function returns true only if the packet is an ICMP packet in Wldr
+ // form. type must be equal to ICMP_WLDR_TYPE and code equal to ICMP_WLDR_CODE
+ uint8_t next_header = messageHandler_NextHeaderType(message);
+
+ const uint8_t *icmp_ptr;
+ if (next_header == IPPROTO_ICMP) {
+ icmp_ptr = message + IPV4_HDRLEN;
+ } else if (next_header == IPPROTO_ICMPV6) {
+ icmp_ptr = message + IPV6_HDRLEN;
+ } else {
+ return false;
+ }
+
+ uint8_t type = ((_icmp_header_t *)icmp_ptr)->type;
+ uint8_t code = ((_icmp_header_t *)icmp_ptr)->code;
+ if (type == ICMP_WLDR_TYPE && code == ICMP_WLDR_CODE) {
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool messageHandler_IsLoadBalancerProbe(const uint8_t *message) {
+ uint8_t next_header = messageHandler_NextHeaderType(message);
+
+ const uint8_t *icmp_ptr;
+ if (next_header == IPPROTO_ICMP) {
+ icmp_ptr = message + IPV4_HDRLEN;
+ } else if (next_header == IPPROTO_ICMPV6) {
+ icmp_ptr = message + IPV6_HDRLEN;
+ } else {
+ return false;
+ }
+
+ uint8_t type = ((_icmp_header_t *)icmp_ptr)->type;
+ if (type == ICMP_LB_TYPE) {
+ return true;
+ }
+
+ return false;
+}
+
+static inline uint16_t messageHandler_GetTotalPacketLength(
+ const uint8_t *message) {
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ return ntohs((uint16_t)HICN_V6_LEN(message)) + IPV6_HDRLEN;
+ case IPv4_TYPE:
+ return ntohs((uint16_t)HICN_V4_LEN(message));
+ default:
+ return 0;
+ }
+}
+
+static inline uint32_t messageHandler_GetSegment(const uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return 0;
+
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ return ntohl((uint32_t)H6T(message).seq);
+ case IPv4_TYPE:
+ return ntohl((uint32_t)H4T(message).seq);
+ default:
+ return 0;
+ }
+}
+
+static inline uint16_t messageHandler_GetExpectedWldrLabel(
+ const uint8_t *message) {
+ const uint8_t *icmp_ptr;
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ icmp_ptr = message + IPV6_HDRLEN;
+ break;
+ case IPv4_TYPE:
+ icmp_ptr = message + IPV4_HDRLEN;
+ break;
+ default:
+ return 0;
+ }
+
+ return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->expected_lbl);
+}
+
+static inline uint16_t messageHandler_GetWldrLastReceived(
+ const uint8_t *message) {
+ const uint8_t *icmp_ptr;
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ icmp_ptr = message + IPV6_HDRLEN;
+ break;
+ case IPv4_TYPE:
+ icmp_ptr = message + IPV4_HDRLEN;
+ break;
+ default:
+ return 0;
+ }
+
+ return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->received_lbl);
+}
+
+static inline uint16_t messageHandler_GetWldrLabel(const uint8_t *message) {
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ return ntohs((uint16_t)H6T(message).window);
+ case IPv4_TYPE:
+ return ntohs((uint16_t)H4T(message).window);
+ default:
+ return 0;
+ }
+}
+
+static inline void messageHandler_SetWldrLabel(uint8_t *message,
+ uint16_t label) {
+ uint16_t old_val = messageHandler_GetWldrLabel(message);
+
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ H6T(message).window = htons(label);
+ break;
+ case IPv4_TYPE:
+ H4T(message).window = htons(label);
+ break;
+ default:
+ break;
+ }
+
+ messageHandler_UpdateTCPCheckSum(message, &old_val, &label, 1);
+}
+
+static inline void messageHandler_ResetWldrLabel(uint8_t *message) {
+ messageHandler_SetWldrLabel(message, 0);
+}
+
+static inline bool messageHandler_HasWldr(const uint8_t *message) {
+ if (messageHandler_IsTCP(message)) {
+ uint16_t lbl = messageHandler_GetWldrLabel(message);
+ if (lbl != 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline uint8_t messageHandler_GetProbePacketType(
+ const uint8_t *message) {
+ const uint8_t *icmp_ptr;
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ icmp_ptr = message + IPV6_HDRLEN;
+ break;
+ case IPv4_TYPE:
+ icmp_ptr = message + IPV4_HDRLEN;
+ break;
+ default:
+ return 0;
+ }
+
+ return ((_icmp_header_t *)icmp_ptr)->code;
+}
+
+static inline uint32_t messageHandler_GetPathLabel(const uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return 0;
+
+ uint32_t path_label;
+ int res = hicn_data_get_path_label((hicn_header_t *)message, &path_label);
+ if (res < 0) return 0;
+ return path_label;
+}
+
+static inline void messageHandler_SetPathLabel(uint8_t *message,
+ uint32_t new_path_label) {
+ if (!messageHandler_IsTCP(message)) return;
+
+ uint32_t old_path_label;
+ int res = hicn_data_get_path_label((hicn_header_t *)message, &old_path_label);
+ if (res < 0) return;
+
+ hicn_data_set_path_label((hicn_header_t *)message, new_path_label);
+
+ messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&old_path_label,
+ (uint16_t *)&new_path_label, 2);
+}
+
+static inline void messageHandler_UpdatePathLabel(uint8_t *message,
+ uint8_t outFace) {
+ if (!messageHandler_IsTCP(message)) return;
+
+ uint32_t pl_old_32bit = messageHandler_GetPathLabel(message);
+ uint8_t pl_old_8bit = (uint8_t)(pl_old_32bit >> 24UL);
+ uint32_t pl_new_32bit =
+ (uint32_t)((((pl_old_8bit << 1) | (pl_old_8bit >> 7)) ^ outFace) << 24UL);
+
+ hicn_data_set_path_label((hicn_header_t *)message, pl_new_32bit);
+
+ messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&pl_old_32bit,
+ (uint16_t *)&pl_new_32bit, 2);
+}
+
+static inline void messageHandler_ResetPathLabel(uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return;
+
+ uint32_t pl_old_32bit = messageHandler_GetPathLabel(message);
+ uint32_t pl_new_32bit = 0;
+ hicn_data_set_path_label((hicn_header_t *)message, pl_new_32bit);
+ messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&pl_old_32bit,
+ (uint16_t *)&pl_new_32bit, 2);
+}
+
+static inline uint16_t messageHandler_GetInterestLifetime(
+ const uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return 0;
+
+ hicn_lifetime_t lifetime;
+ int res = hicn_interest_get_lifetime((hicn_header_t *)message, &lifetime);
+ if (res < 0) return 0;
+ return lifetime;
+}
+
+static inline bool messageHandler_HasInterestLifetime(const uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return false;
+
+ if (messageHandler_GetInterestLifetime(message) == 0) return false;
+ return true;
+}
+
+static inline uint32_t messageHandler_GetContentExpiryTime(
+ const uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return 0;
+
+ uint32_t expirationTime;
+ int res =
+ hicn_data_get_expiry_time((hicn_header_t *)message, &expirationTime);
+ if (res < 0) return 0;
+ return expirationTime;
+}
+
+static inline bool messageHandler_HasContentExpiryTime(const uint8_t *message) {
+ if (!messageHandler_IsTCP(message)) return 0;
+
+ uint32_t expirationTime;
+ int res =
+ hicn_data_get_expiry_time((hicn_header_t *)message, &expirationTime);
+ if (res < 0) return false;
+
+ if (expirationTime == NEVER_EXPIRE) return false;
+
+ return true;
+}
+
+static inline void *messageHandler_GetSource(const uint8_t *message) {
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ return &H6(message).saddr;
+ break;
+ case IPv4_TYPE:
+ return &H4(message).saddr;
+ break;
+ default:
+ return NULL;
+ }
+}
+
+static inline void *messageHandler_GetDestination(const uint8_t *message) {
+ switch (messageHandler_GetIPPacketType(message)) {
+ case IPv6_TYPE:
+ return &H6(message).daddr;
+ break;
+ case IPv4_TYPE:
+ return &H4(message).daddr;
+ break;
+ default:
+ return NULL;
+ }
+}
+
+static inline void messageHandler_SetSource_IPv6(uint8_t *message,
+ struct in6_addr *address) {
+ if (messageHandler_IsTCP(message)) {
+ uint16_t *old_src = (uint16_t *)messageHandler_GetSource(message);
+ messageHandler_UpdateTCPCheckSum(message, old_src, (uint16_t *)address, 8);
+ }
+ H6(message).saddr.as_in6addr = *address;
+}
+
+static inline void messageHandler_SetDestination_IPv6(
+ uint8_t *message, struct in6_addr *address) {
+ if (messageHandler_IsTCP(message)) {
+ uint16_t *old_dst = (uint16_t *)messageHandler_GetDestination(message);
+ messageHandler_UpdateTCPCheckSum(message, old_dst, (uint16_t *)address, 8);
+ }
+ H6(message).daddr.as_in6addr = *address;
+}
+
+static inline void messageHandler_SetSource_IPv4(uint8_t *message,
+ uint32_t *address) {
+ // update tcp checksum
+ uint16_t *old_src = (uint16_t *)messageHandler_GetSource(message);
+ if (messageHandler_IsTCP(message)) {
+ messageHandler_UpdateTCPCheckSum(message, old_src, (uint16_t *)address, 2);
+ }
+ // update IPv4 cheksum
+ // the IPv4 checksum is not part of the psudo header for TCP checksum
+ // calculation we can update them separetelly
+ messageHandler_UpdateIPv4CheckSum(message, old_src, (uint16_t *)address, 2);
+
+ H4(message).saddr.as_u32 = *address;
+}
+
+static inline void messageHandler_SetDestination_IPv4(uint8_t *message,
+ uint32_t *address) {
+ uint16_t *old_dst = (uint16_t *)messageHandler_GetDestination(message);
+ if (messageHandler_IsTCP(message)) {
+ messageHandler_UpdateTCPCheckSum(message, old_dst, (uint16_t *)address, 2);
+ }
+ messageHandler_UpdateIPv4CheckSum(message, old_dst, (uint16_t *)address, 2);
+ H4(message).daddr.as_u32 = *address;
+}
+
+static inline void messageHandler_SetWldrNotification(uint8_t *notification,
+ uint8_t *original,
+ uint16_t expected,
+ uint16_t received) {
+ hicn_header_t *h = (hicn_header_t *)notification;
+ switch (messageHandler_GetIPPacketType(original)) {
+ case IPv6_TYPE: {
+ *h = (hicn_header_t){.v6 = {
+ .ip =
+ {
+ .version_class_flow = htonl(
+ (IPV6_DEFAULT_VERSION << 28) |
+ (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |
+ (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)),
+ .len = htons(ICMP_HDRLEN),
+ .nxt = IPPROTO_ICMPV6,
+ .hlim = 5,
+ },
+ .wldr =
+ {
+ .type = ICMP_WLDR_TYPE,
+ .code = ICMP_WLDR_CODE,
+ .expected_lbl = htons(expected),
+ .received_lbl = htons(received),
+ },
+ }};
+ messageHandler_SetSource_IPv6(
+ notification,
+ (struct in6_addr *)messageHandler_GetDestination(original));
+ messageHandler_SetDestination_IPv6(
+ notification, (struct in6_addr *)messageHandler_GetSource(original));
+ break;
+ }
+ case IPv4_TYPE: {
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static inline void messageHandler_SetProbePacket(uint8_t *message,
+ uint8_t probeType,
+ struct in6_addr *src,
+ struct in6_addr *dst) {
+ hicn_header_t *h = (hicn_header_t *)message;
+ *h = (hicn_header_t){
+ .v6 = {
+ .ip =
+ {
+ .version_class_flow =
+ htonl((IPV6_DEFAULT_VERSION << 28) |
+ (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |
+ (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)),
+ .len = htons(ICMP_HDRLEN),
+ .nxt = IPPROTO_ICMPV6,
+ .hlim = 5, // this should be 1, but ... just to be safe
+ },
+ .icmp =
+ {
+ .type = ICMP_LB_TYPE,
+ .code = probeType,
+ },
+ }};
+ messageHandler_SetSource_IPv6(message, src);
+ messageHandler_SetDestination_IPv6(message, dst);
+}
+
+#endif // Metis_metis_MessageHandler
diff --git a/hicn-light/src/core/messagePacketType.h b/hicn-light/src/core/messagePacketType.h
new file mode 100755
index 000000000..dfbb12342
--- /dev/null
+++ b/hicn-light/src/core/messagePacketType.h
@@ -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.
+ */
+
+/**
+ * @file message_packet_type_h
+ * @brief Defines the packet type for a HICN message
+ *
+ */
+
+#ifndef message_packet_type_h
+#define message_packet_type_h
+
+typedef enum message_type {
+ MessagePacketType_Unknown,
+ MessagePacketType_Interest,
+ MessagePacketType_ContentObject,
+ MessagePacketType_WldrNotification
+} MessagePacketType;
+
+#endif // message_packet_type_h
diff --git a/hicn-light/src/core/name.c b/hicn-light/src/core/name.c
new file mode 100755
index 000000000..f6a452d27
--- /dev/null
+++ b/hicn-light/src/core/name.c
@@ -0,0 +1,236 @@
+/*
+ * 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 <limits.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/core/messageHandler.h>
+#include <src/core/name.h>
+
+#include <parc/algol/parc_Hash.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#define IPv6_TYPE 6
+#define IPv4_TYPE 4
+
+// assumption: the IPv6 address is the name, the TCP segment number is the ICN
+// segment
+
+struct name {
+ NameBitvector *content_name;
+ uint32_t segment;
+ uint32_t name_hash;
+ // the refcount is shared between all copies
+ unsigned *refCountPtr;
+};
+
+// =====================================================
+
+static unsigned _getRefCount(const Name *name) { return *name->refCountPtr; }
+
+static void _incrementRefCount(Name *name) {
+ parcAssertTrue(*name->refCountPtr > 0,
+ "Illegal State: Trying to increment a 0 refcount!");
+ (*name->refCountPtr)++;
+}
+
+static void _decrementRefCount(Name *name) {
+ parcAssertTrue(*name->refCountPtr > 0,
+ "Illegal State: Trying to decrement a 0 refcount!");
+ (*name->refCountPtr)--;
+}
+
+static uint32_t _computeHash(Name *name) {
+ parcAssertNotNull(name, "Parameter must be non-null pointer");
+
+ uint32_t hash1 = nameBitvector_GetHash32(name->content_name);
+ return parcHash32_Data_Cumulative((const uint8_t *)&name->segment, 4, hash1);
+}
+
+// ============================================================================
+
+Name *name_CreateFromPacket(const uint8_t *packet, MessagePacketType type) {
+ Name *name = parcMemory_AllocateAndClear(sizeof(Name));
+ parcAssertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Name));
+
+ if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) {
+ if (type == MessagePacketType_Interest) {
+ name->content_name = nameBitvector_CreateFromIn6Addr(
+ (struct in6_addr *)messageHandler_GetDestination(packet), 128);
+ } else if (type == MessagePacketType_ContentObject) {
+ name->content_name = nameBitvector_CreateFromIn6Addr(
+ (struct in6_addr *)messageHandler_GetSource(packet), 128);
+ } else {
+ parcMemory_Deallocate((void **)&name);
+ return NULL;
+ }
+ } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) {
+ if (type == MessagePacketType_Interest) {
+ name->content_name = nameBitvector_CreateFromInAddr(
+ *((uint32_t *)messageHandler_GetDestination(packet)), 32);
+ } else if (type == MessagePacketType_ContentObject) {
+ name->content_name = nameBitvector_CreateFromInAddr(
+ *((uint32_t *)messageHandler_GetSource(packet)), 32);
+ } else {
+ parcMemory_Deallocate((void **)&name);
+ return NULL;
+ }
+ } else {
+ printf("Error: unknown message type\n");
+ parcMemory_Deallocate((void **)&name);
+ return NULL;
+ }
+
+ name->segment = messageHandler_GetSegment(packet);
+ name->name_hash = _computeHash(name);
+
+ name->refCountPtr = parcMemory_Allocate(sizeof(unsigned));
+ parcAssertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL",
+ sizeof(unsigned));
+ *name->refCountPtr = 1;
+ return name;
+}
+
+Name *name_CreateFromAddress(address_type addressType, union commandAddr addr,
+ uint8_t len) {
+ Name *name = parcMemory_AllocateAndClear(sizeof(Name));
+ parcAssertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Name));
+ if (addressType == ADDR_INET) {
+ name->content_name = nameBitvector_CreateFromInAddr(addr.ipv4, len);
+ } else if (addressType == ADDR_INET6) {
+ name->content_name = nameBitvector_CreateFromIn6Addr(&addr.ipv6, len);
+ } else {
+ parcTrapNotImplemented("Unkown packet type");
+ }
+
+ name->segment = 0;
+ name->name_hash = _computeHash(name);
+
+ name->refCountPtr = parcMemory_Allocate(sizeof(unsigned));
+ parcAssertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL",
+ sizeof(unsigned));
+ *name->refCountPtr = 1;
+
+ return name;
+}
+
+void name_Release(Name **namePtr) {
+ parcAssertNotNull(namePtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*namePtr, "Parameter must dereference to non-null pointer");
+
+ Name *name = *namePtr;
+ _decrementRefCount(name);
+ if (_getRefCount(name) == 0) {
+ parcMemory_Deallocate((void **)&(name->refCountPtr));
+ nameBitvector_Destroy(&(name->content_name));
+ }
+ parcMemory_Deallocate((void **)&name);
+ *namePtr = NULL;
+}
+
+Name *name_Acquire(const Name *original) {
+ parcAssertNotNull(original, "Parameter must be non-null");
+ Name *copy = parcMemory_AllocateAndClear(sizeof(Name));
+ parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Name));
+
+ memcpy(copy, original, sizeof(Name));
+ _incrementRefCount(copy);
+
+ return copy;
+}
+
+uint32_t name_HashCode(const Name *name) {
+ parcAssertNotNull(name, "Parameter must be non-null");
+ return name->name_hash;
+}
+
+NameBitvector *name_GetContentName(const Name *name) {
+ parcAssertNotNull(name, "Parameter must be non-null");
+ return name->content_name;
+}
+
+bool name_Equals(const Name *a, const Name *b) {
+ parcAssertNotNull(a, "Parameter a must be non-null");
+ parcAssertNotNull(b, "Parameter b must be non-null");
+
+ if ((nameBitvector_Equals(a->content_name, b->content_name) &&
+ a->segment == b->segment))
+ return true;
+ return false;
+}
+
+int name_Compare(const Name *a, const Name *b) {
+ parcAssertNotNull(a, "Parameter a must be non-null");
+ parcAssertNotNull(b, "Parameter b must be non-null");
+
+ if (a == NULL && b == NULL) {
+ return 0;
+ }
+ if (a == NULL) {
+ return -1;
+ }
+ if (b == NULL) {
+ return +1;
+ }
+
+ int res = nameBitvector_Compare(a->content_name, b->content_name);
+
+ if (res != 0) {
+ return res;
+ } else {
+ if (a->segment < b->segment) {
+ return -1;
+ } else if (a->segment > b->segment) {
+ return +1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+bool name_StartsWith(const Name *name, const Name *prefix) {
+ parcAssertNotNull(name, "Parameter name must be non-null");
+ parcAssertNotNull(prefix, "Parameter prefix must be non-null");
+
+ return nameBitvector_StartsWith(name->content_name, prefix->content_name);
+}
+
+char *name_ToString(const Name *name) {
+ char *output = malloc(128);
+
+ Address *packetAddr = nameBitvector_ToAddress(name_GetContentName(name));
+
+ sprintf(output, "name: %s seq: %u", addressToString(packetAddr),
+ name->segment);
+
+ addressDestroy(&packetAddr);
+
+ return output;
+}
+
+void name_setLen(const Name *name, uint8_t len) {
+ nameBitvector_setLen(name->content_name, len);
+}
diff --git a/hicn-light/src/core/name.h b/hicn-light/src/core/name.h
new file mode 100755
index 000000000..fb4ad7a56
--- /dev/null
+++ b/hicn-light/src/core/name.h
@@ -0,0 +1,105 @@
+/*
+ * 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 name_h
+#define name_h
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <src/core/messagePacketType.h>
+#include <src/core/nameBitvector.h>
+#include <src/utils/address.h>
+
+#include <src/utils/commands.h>
+
+struct name;
+typedef struct name Name;
+
+/**
+ * Creates a name from packet
+ *
+ */
+Name *name_CreateFromPacket(const uint8_t *memory, MessagePacketType type);
+
+/**
+ * Releases one reference count, and frees memory after last reference
+ */
+void name_Release(Name **namePtr);
+
+/**
+ * Acquires a reference to the name so that a reference count increments.
+ * Notice however that this * function is used only when a new fib entry is
+ * created (mostly configuration time) probably here performance are not
+ * critical.
+ */
+Name *name_Acquire(const Name *original);
+
+/**
+ * A hash value for use in hash tables
+ *
+ */
+uint32_t name_HashCode(const Name *name);
+
+/**
+ * Returns the content name without the segment value
+ *
+ */
+NameBitvector *name_GetContentName(const Name *name);
+
+/**
+ * Determine if two HicnName instances are equal.
+ */
+bool name_Equals(const Name *a, const Name *b);
+
+/**
+ * Compares two names and returns their ordering
+ *
+ */
+int name_Compare(const Name *a, const Name *b);
+
+/**
+ * @function metsName_StartsWith
+ * @abstract Checks if name starts with prefix
+ * @discussion
+ * Byte-by-byte prefix comparison
+ *
+ * @return True if the name is equal to or begins with prefix
+ */
+
+bool name_StartsWith(const Name *name, const Name *prefix);
+
+/**
+ * return the name in string format (bitvector + segment number)
+ *
+ */
+char *name_ToString(const Name *name);
+
+/**
+ * @function message_setNameLen
+ * @abstract Sets a message name length
+ * @param [in] message - Interest message
+ * @param [in] len - Name length
+ */
+void name_setLen(const Name *name, uint8_t len);
+
+/**
+ * Creates a name from a Address
+ *
+ */
+Name *name_CreateFromAddress(address_type addressType, union commandAddr addr,
+ uint8_t len);
+
+#endif // name_h
diff --git a/hicn-light/src/core/nameBitvector.c b/hicn-light/src/core/nameBitvector.c
new file mode 100755
index 000000000..66f3eae20
--- /dev/null
+++ b/hicn-light/src/core/nameBitvector.c
@@ -0,0 +1,383 @@
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/core/messageHandler.h>
+#include <src/core/nameBitvector.h>
+
+#include <parc/algol/parc_Hash.h>
+
+#include <src/utils/commands.h>
+
+#define BLOCKS 2
+
+const uint64_t BLOCK_SIZE = 64;
+const uint64_t WIDTH = 128;
+const uint64_t BLOCK_ONE = 0x1;
+
+// the bits are encoded in the following order:
+// 00100101001---101010 00100011---110100100
+// [bits[0] (uint64_t)] [bits[1] (uint64_t)]
+// ^ ^ ^ ^
+// 0 63 64 127
+// address 2200::0011 is encoded as:
+// 1000 1000 0000 0010 00000 ....0100 0100
+// ^ ^
+// 0 127
+
+struct name_bitvector {
+ uint64_t bits[BLOCKS];
+ uint8_t len;
+ uint8_t IPversion;
+};
+
+NameBitvector *nameBitvector_CreateFromInAddr(uint32_t s_addr, uint8_t len) {
+ NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector));
+ parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(NameBitvector));
+
+ bitvector->bits[0] = 0;
+ bitvector->bits[1] = 0;
+
+ uint8_t addr_1 = (s_addr & 0xff000000) >> 24;
+ uint8_t addr_2 = (s_addr & 0x00ff0000) >> 16;
+ uint8_t addr_3 = (s_addr & 0x0000ff00) >> 8;
+ uint8_t addr_4 = (s_addr & 0x000000ff);
+
+ bitvector->bits[1] = (bitvector->bits[1] | addr_4) << 8;
+ bitvector->bits[1] = (bitvector->bits[1] | addr_3) << 8;
+ bitvector->bits[1] = (bitvector->bits[1] | addr_2) << 8;
+ bitvector->bits[1] = (bitvector->bits[1] | addr_1);
+ bitvector->bits[1] = bitvector->bits[1] << 32;
+
+ bitvector->len = len;
+
+ bitvector->IPversion = IPv4_TYPE;
+
+ return bitvector;
+}
+
+NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr,
+ uint8_t len) {
+ parcAssertNotNull(addr, "addr cannot be null");
+
+ NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector));
+ parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(NameBitvector));
+
+ bitvector->bits[0] = 0;
+ bitvector->bits[1] = 0;
+
+ for (int i = 0; i < 8; ++i) {
+ bitvector->bits[1] = (bitvector->bits[1] << 8) | addr->s6_addr[i];
+ }
+
+ for (int i = 8; i < 16; ++i) {
+ bitvector->bits[0] = (bitvector->bits[0] << 8) | addr->s6_addr[i];
+ }
+
+ bitvector->len = len;
+
+ bitvector->IPversion = IPv6_TYPE;
+
+ return bitvector;
+}
+
+NameBitvector *nameBitvector_CreateFromAddress(const Address *prefix,
+ uint8_t len) {
+ parcAssertNotNull(prefix, "prefix cannot be null");
+
+ NameBitvector *bitvector = NULL;
+ switch (addressGetType(prefix)) {
+ case ADDR_INET: {
+ struct sockaddr_in addr;
+ addressGetInet(prefix, &addr);
+ bitvector = nameBitvector_CreateFromInAddr(addr.sin_addr.s_addr, len);
+ break;
+ }
+ case ADDR_INET6: {
+ struct sockaddr_in6 addr;
+ addressGetInet6(prefix, &addr);
+ bitvector = nameBitvector_CreateFromIn6Addr(&addr.sin6_addr, len);
+ break;
+ }
+ default:
+ parcTrapNotImplemented("Unkown packet type");
+ break;
+ }
+
+ return bitvector;
+}
+
+NameBitvector *nameBitvector_Copy(const NameBitvector *original) {
+ parcAssertNotNull(original, "original cannot be null");
+
+ NameBitvector *copy = parcMemory_AllocateAndClear(sizeof(NameBitvector));
+ parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(NameBitvector));
+
+ copy->bits[0] = original->bits[0];
+ copy->bits[1] = original->bits[1];
+ copy->len = original->len;
+
+ return copy;
+}
+
+void nameBitvector_Destroy(NameBitvector **bitvectorPtr) {
+ parcAssertNotNull(bitvectorPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*bitvectorPtr,
+ "Parameter must dereference to non-null pointer");
+
+ NameBitvector *bv = *bitvectorPtr;
+ parcMemory_Deallocate((void **)&(bv));
+ *bitvectorPtr = NULL;
+}
+
+uint8_t nameBitvector_GetLength(const NameBitvector *name) { return name->len; }
+
+uint32_t nameBitvector_GetHash32(const NameBitvector *name) {
+ return parcHash32_Data_Cumulative((const uint8_t *)name->bits, 16, 0);
+}
+
+bool nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b) {
+ if (a->bits[0] == b->bits[0] && a->bits[1] == b->bits[1] && a->len == b->len)
+ return true;
+ return false;
+}
+
+int nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b) {
+ if (a == NULL && b == NULL) {
+ return 0;
+ }
+ if (a == NULL) {
+ return -1;
+ }
+ if (b == NULL) {
+ return +1;
+ }
+
+ if (a->bits[0] < b->bits[0]) {
+ return -1;
+ } else if (a->bits[0] > b->bits[0]) {
+ return +1;
+ } else if (a->bits[1] < b->bits[1]) {
+ return -1;
+ } else if (a->bits[1] > b->bits[1]) {
+ return +1;
+ } else if (a->len < b->len) {
+ return -1;
+ } else if (a->len > b->len) {
+ return +1;
+ } else {
+ return 0;
+ }
+}
+
+bool nameBitvector_StartsWith(const NameBitvector *name,
+ const NameBitvector *prefix) {
+ parcAssertNotNull(name, "name cannot be NULL");
+ parcAssertNotNull(prefix, "prefix cannot be NULL");
+ parcAssertTrue(prefix->len > 0, "prefix length can not be 0");
+
+ if (prefix->len > BLOCK_SIZE)
+ return (name->bits[1] == prefix->bits[1]) &&
+ ((name->bits[0] ^ prefix->bits[0]) >>
+ (BLOCK_SIZE - (prefix->len - BLOCK_SIZE)) ==
+ 0);
+
+ return ((name->bits[1] ^ prefix->bits[1]) >> (BLOCK_SIZE - prefix->len) == 0);
+}
+
+bool nameBitvector_testBit(const NameBitvector *name, uint8_t pos) {
+ if (pos == WIDTH) pos = 127;
+
+ uint8_t final_pos = WIDTH - name->len;
+
+ // the bit to test is inside the name/prefix len
+ if (pos > final_pos) {
+ return (name->bits[pos / BLOCK_SIZE] & (BLOCK_ONE << (pos % BLOCK_SIZE)));
+ }
+
+ // the bit to test is outside the name/prefix len
+ if (pos < final_pos) {
+ return false;
+ }
+
+ // pos is equal to the name/prefix len
+ return true;
+}
+
+uint64_t _diff_bit_log2(uint64_t val) {
+ // base 2 log of an uint64_t. This is the same as get the position of
+ // the highest bit set (or most significant bit set, MSB)
+ uint64_t result = 0;
+
+ if (val & 0xFFFFFFFF00000000) {
+ val = val >> 32;
+ result = result | 32;
+ }
+ if (val & 0xFFFF0000) {
+ val = val >> 16;
+ result = result | 16;
+ }
+ if (val & 0xFF00) {
+ val = val >> 8;
+ result = result | 8;
+ }
+ if (val & 0xF0) {
+ val = val >> 4;
+ result = result | 4;
+ }
+ if (val & 0xC) {
+ val = val >> 2;
+ result = result | 2;
+ }
+ if (val & 0x2) {
+ val = val >> 1;
+ result = result | 1;
+ }
+ return result;
+}
+
+uint8_t nameBitvector_firstDiff(const NameBitvector *a,
+ const NameBitvector *b) {
+ uint8_t res = 0;
+ uint64_t diff = a->bits[1] ^ b->bits[1];
+ if (diff)
+ res = 64 + _diff_bit_log2(diff);
+ else
+ res = _diff_bit_log2(a->bits[0] ^ b->bits[0]);
+
+ // res is computed over the bitvector which is composed by 128 bit all the
+ // times however the prefixes may be diffrent just because the have different
+ // lengths example: prefix 1: 0::/30 prefix 2: 0::/20 at this point of the
+ // function res would be 0 since both the bitvectors are composed by 0s but the
+ // function will return 127-20, which is the position at which the two prefix
+ // are different, since prefix 2 has only 20 bits
+
+ uint8_t len_diff;
+ if (a->len < b->len)
+ len_diff = WIDTH - a->len;
+ else
+ len_diff = WIDTH - b->len;
+
+ if (len_diff > res) res = len_diff;
+
+ return res;
+}
+
+int nameBitvector_ToIPAddress(const NameBitvector *name,
+ ip_address_t *ip_address) {
+ 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;
+
+ uint32_t tmp_addr = name->bits[1] >> 32ULL;
+ uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
+ uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16;
+ uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8;
+ uint8_t addr_4 = (tmp_addr & 0x000000ff);
+
+ addr->s_addr = 0;
+ addr->s_addr = (addr->s_addr | addr_4) << 8;
+ addr->s_addr = (addr->s_addr | addr_3) << 8;
+ addr->s_addr = (addr->s_addr | addr_2) << 8;
+ 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;
+
+ for (int i = 0; i < 8; i++) {
+ addr->s6_addr[i] = (uint8_t)((name->bits[1] >> 8 * (7 - i)) & 0xFF);
+ }
+
+ int x = 0;
+ for (int i = 8; i < 16; ++i) {
+ addr->s6_addr[i] = (uint8_t)((name->bits[0] >> 8 * (7 - x)) & 0xFF);
+ x++;
+ }
+ }
+ return true;
+}
+
+void nameBitvector_setLen(NameBitvector *name, uint8_t len) { name->len = len; }
+
+Address *nameBitvector_ToAddress(const NameBitvector *name) {
+ if (name->IPversion == IPv4_TYPE) {
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(1234);
+
+ uint32_t tmp_addr = name->bits[1] >> 32ULL;
+ uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
+ uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16;
+ uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8;
+ uint8_t addr_4 = (tmp_addr & 0x000000ff);
+
+ addr.sin_addr.s_addr = 0;
+ addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_4) << 8;
+ addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_3) << 8;
+ addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_2) << 8;
+ addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_1);
+
+ Address *packetAddr = addressCreateFromInet(&addr);
+
+ return packetAddr;
+
+ } else {
+ struct sockaddr_in6 addr;
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(1234);
+ addr.sin6_scope_id = 0;
+ addr.sin6_flowinfo = 0;
+
+ for (int i = 0; i < 8; i++) {
+ addr.sin6_addr.s6_addr[i] =
+ (uint8_t)((name->bits[1] >> 8 * (7 - i)) & 0xFF);
+ }
+
+ int x = 0;
+ for (int i = 8; i < 16; ++i) {
+ addr.sin6_addr.s6_addr[i] =
+ (uint8_t)((name->bits[0] >> 8 * (7 - x)) & 0xFF);
+ x++;
+ }
+
+ Address *packetAddr = addressCreateFromInet6(&addr);
+
+ return packetAddr;
+ }
+}
+
+char *nameBitvector_ToString(const NameBitvector *name) {
+ char *output = malloc(WIDTH);
+
+ Address *packetAddr = nameBitvector_ToAddress(name);
+
+ sprintf(output, "prefix: %s len: %u", addressToString(packetAddr), name->len);
+
+ addressDestroy(&packetAddr);
+
+ return output;
+} \ No newline at end of file
diff --git a/hicn-light/src/core/nameBitvector.h b/hicn-light/src/core/nameBitvector.h
new file mode 100755
index 000000000..28a31dc26
--- /dev/null
+++ b/hicn-light/src/core/nameBitvector.h
@@ -0,0 +1,63 @@
+/*
+ * 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 name_bitvector_h
+#define name_bitvector_h
+
+#include <hicn/hicn.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <src/utils/address.h>
+
+struct name_bitvector;
+typedef struct name_bitvector NameBitvector;
+
+NameBitvector *nameBitvector_CreateFromInAddr(uint32_t s_addr, uint8_t len);
+
+NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr,
+ uint8_t len);
+
+NameBitvector *nameBitvector_CreateFromAddress(const Address *prefix,
+ uint8_t len);
+
+NameBitvector *nameBitvector_Copy(const NameBitvector *original);
+
+void nameBitvector_Destroy(NameBitvector **bitvectorPtr);
+
+uint8_t nameBitvector_GetLength(const NameBitvector *name);
+
+uint32_t nameBitvector_GetHash32(const NameBitvector *name);
+
+bool nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b);
+
+int nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b);
+
+bool nameBitvector_StartsWith(const NameBitvector *name,
+ const NameBitvector *prefix);
+
+bool nameBitvector_testBit(const NameBitvector *name, uint8_t pos);
+
+uint8_t nameBitvector_firstDiff(const NameBitvector *a, const NameBitvector *b);
+
+int nameBitvector_ToIPAddress(const NameBitvector *name,
+ ip_address_t *ip_address);
+void nameBitvector_setLen(NameBitvector *name, uint8_t len);
+
+Address *nameBitvector_ToAddress(const NameBitvector *name);
+
+char *nameBitvector_ToString(const NameBitvector *name);
+
+#endif // name_bitvector_h
diff --git a/hicn-light/src/core/numberSet.c b/hicn-light/src/core/numberSet.c
new file mode 100755
index 000000000..75fec1524
--- /dev/null
+++ b/hicn-light/src/core/numberSet.c
@@ -0,0 +1,203 @@
+/*
+ * 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 <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <src/config.h>
+#include <src/core/numberSet.h>
+#include <stdio.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct number_set {
+ Number *arrayOfNumbers;
+ size_t length;
+ size_t limit;
+ unsigned refcount;
+};
+
+static void numberSet_Expand(NumberSet *set);
+
+NumberSet *numberSet_Create() {
+ NumberSet *set = parcMemory_AllocateAndClear(sizeof(NumberSet));
+ parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(NumberSet));
+ set->arrayOfNumbers = parcMemory_AllocateAndClear(sizeof(Number) * 16);
+ parcAssertNotNull((set->arrayOfNumbers),
+ "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Number) * 16);
+ set->length = 0;
+ set->limit = 16;
+ set->refcount = 1;
+ return set;
+}
+
+NumberSet *numberSet_Acquire(const NumberSet *original) {
+ parcAssertNotNull(original, "Parameter original must be non-null");
+ NumberSet *copy = (NumberSet *)original;
+ copy->refcount++;
+ return copy;
+}
+
+void numberSet_Release(NumberSet **setPtr) {
+ parcAssertNotNull(setPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer");
+
+ NumberSet *set = *setPtr;
+ parcAssertTrue(
+ set->refcount > 0,
+ "Invalid state: calling destroy on an object with 0 reference count");
+ set->refcount--;
+
+ if (set->refcount == 0) {
+ parcMemory_Deallocate((void **)&(set->arrayOfNumbers));
+ parcMemory_Deallocate((void **)&set);
+ *setPtr = NULL;
+ }
+}
+
+/**
+ * @function numberSet_AddNoChecks
+ * @abstract Add a number we know is not already in the set
+ * @discussion
+ * Used by other functions that already know the number is unique in the set,
+ * Does not do the expensive Contains check.
+ */
+static void numberSet_AddNoChecks(NumberSet *set, Number number) {
+ if (set->length == set->limit) {
+ numberSet_Expand(set);
+ }
+
+ set->arrayOfNumbers[set->length] = number;
+ set->length++;
+}
+
+bool numberSet_Add(NumberSet *set, Number number) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ if (numberSet_Contains(set, number)) {
+ return false;
+ }
+
+ numberSet_AddNoChecks(set, number);
+ return true;
+}
+
+size_t numberSet_Length(const NumberSet *set) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ return set->length;
+}
+
+Number numberSet_GetItem(const NumberSet *set, size_t ordinalIndex) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ parcAssertTrue(ordinalIndex < set->length,
+ "Limit beyond end of set, length %zu got %zu", set->length,
+ ordinalIndex);
+
+ return set->arrayOfNumbers[ordinalIndex];
+}
+
+bool numberSet_Contains(const NumberSet *set, Number number) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ for (size_t i = 0; i < set->length; i++) {
+ if (set->arrayOfNumbers[i] == number) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void numberSet_AddSet(NumberSet *destinationSet, const NumberSet *setToAdd) {
+ parcAssertNotNull(destinationSet,
+ "Parameter destinationSet must be non-null");
+ parcAssertNotNull(setToAdd, "Parameter setToAdd must be non-null");
+
+ for (size_t i = 0; i < setToAdd->length; i++) {
+ numberSet_Add(destinationSet, setToAdd->arrayOfNumbers[i]);
+ }
+}
+
+NumberSet *numberSet_Subtract(const NumberSet *minuend,
+ const NumberSet *subtrahend) {
+ // because the underlying ADT is not sorted, this is pretty ineffient, could
+ // be O(n^2).
+
+ NumberSet *difference = numberSet_Create();
+
+ for (size_t i = 0; i < minuend->length; i++) {
+ bool unique = true;
+ for (size_t j = 0; j < subtrahend->length && unique; j++) {
+ if (minuend->arrayOfNumbers[i] == subtrahend->arrayOfNumbers[j]) {
+ unique = false;
+ }
+ }
+
+ if (unique) {
+ numberSet_AddNoChecks(difference, minuend->arrayOfNumbers[i]);
+ }
+ }
+ return difference;
+}
+
+bool numberSet_Equals(const NumberSet *a, const NumberSet *b) {
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->length == b->length) {
+ for (size_t i = 0; i < a->length; i++) {
+ bool found = false;
+ for (size_t j = 0; j < b->length && !found; j++) {
+ if (a->arrayOfNumbers[i] == b->arrayOfNumbers[j]) {
+ found = true;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void numberSet_Remove(NumberSet *set, Number number) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ for (size_t i = 0; i < set->length; i++) {
+ if (set->arrayOfNumbers[i] == number) {
+ set->length--;
+ if (set->length > 0) {
+ // move the last element to the removed element to keep the array
+ // packed.
+ set->arrayOfNumbers[i] = set->arrayOfNumbers[set->length];
+ }
+ return;
+ }
+ }
+}
+
+// =====================================================
+
+static void numberSet_Expand(NumberSet *set) {
+ size_t newlimit = set->limit * 2;
+ size_t newbytes = newlimit * sizeof(Number);
+
+ set->arrayOfNumbers = parcMemory_Reallocate(set->arrayOfNumbers, newbytes);
+ set->limit = newlimit;
+}
diff --git a/hicn-light/src/core/numberSet.h b/hicn-light/src/core/numberSet.h
new file mode 100755
index 000000000..91a965d7b
--- /dev/null
+++ b/hicn-light/src/core/numberSet.h
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+/**
+ * @brief Stores a set of numbers.
+ *
+ * Useful for things like the reverse path of a PIT
+ * or the forward paths of a FIB. Does not allow duplicates.
+ *
+ */
+
+#ifndef numberSet_h
+#define numberSet_h
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+struct number_set;
+typedef struct number_set NumberSet;
+
+typedef uint32_t Number;
+
+/**
+ * @function numberList_Create
+ * @abstract A new list of numbers
+ */
+NumberSet *numberSet_Create(void);
+
+/**
+ * Obtains a reference counted copy of the original
+ * The reference count is increased by one. It must be released with
+ * NumberSet_Release().
+ * @param [in] original An allocated NumberSet
+ * @return non-null The reference counted copy
+ */
+NumberSet *numberSet_Acquire(const NumberSet *original);
+
+/**
+ * Releases one reference count and destroys the memory after last release
+ * The pointer will be NULLed after release regardless if the memory was
+ * destroyed.
+ * @param [in,out] setPtr A pointer to a NumberSet. Will be NULL'd after
+ * release.
+ */
+void numberSet_Release(NumberSet **setPtr);
+
+/**
+ * @function numberList_Append
+ * @abstract Add a number to the end of the list
+ * @discussion
+ * No check for duplicates is done
+ * @return true if added, false if a duplicate
+ */
+bool numberSet_Add(NumberSet *set, Number number);
+
+/**
+ * @function numberList_Length
+ * @abstract The count of numbers in the list
+ */
+size_t numberSet_Length(const NumberSet *set);
+
+/**
+ * @function numberSet_GetItem
+ * @abstract Retrieves an item based on the ordinal index
+ * @discussion
+ * Will assert if the ordinalIndex is out of bounds.
+ */
+Number numberSet_GetItem(const NumberSet *set, size_t ordinalIndex);
+
+/**
+ * @function numberSet_Contains
+ * @abstract Checks for set membership
+ * @return true if the set contains the number, false otherwise
+ */
+bool numberSet_Contains(const NumberSet *set, Number number);
+
+/**
+ * @function numberSet_AddSet
+ * @abstract Adds one set to another set
+ * @discussion
+ * Adds <code>setToAdd</code> to <code>destinationSet</code>
+ * @return true if the set contains the number, false otherwise
+ */
+void numberSet_AddSet(NumberSet *destinationSet, const NumberSet *setToAdd);
+
+/**
+ * @function numberSet_Subtract
+ * @abstract Computes set difference <code>difference = minuend -
+ * subtrahend</code>, returns a new number set.
+ * @discussion
+ * <code>minuend</code> and <code>subtrahend</code> are not modified. A new
+ * difference set is created.
+ *
+ * Returns the elements in <code>minuend</code> that are not in
+ * <code>subtrahend</code>.
+ *
+ * @param minuend The set from which to subtract
+ * @param subrahend The set begin removed from minuend
+ * @return The set difference. May be empty, but will not be NULL.
+ */
+NumberSet *numberSet_Subtract(const NumberSet *minuend,
+ const NumberSet *subtrahend);
+
+/**
+ * Determine if two NumberSet instances are equal.
+ *
+ * Two NumberSet instances are equal if, and only if,
+ * they are the same size and contain the same elements. Empty sets are
+ * equal. NULL equals NULL, but does not equal non-NULL.
+ *
+ * The following equivalence relations on non-null `NumberSet` instances are
+ * maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `NumberSet_Equals(x,
+ * x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `numberSet_Equals(x, y)` must return true if and only if
+ * `numberSet_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `numberSet_Equals(x, y)` returns true and
+ * `numberSet_Equals(y, z)` returns true,
+ * then `numberSet_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `numberSet_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `numberSet_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `NumberSet` instance.
+ * @param b A pointer to a `NumberSet` instance.
+ * @return true if the two `NumberSet` instances are equal.
+ */
+bool numberSet_Equals(const NumberSet *a, const NumberSet *b);
+
+/**
+ * @function numberSet_Remove
+ * @abstract Removes the number from the set
+ */
+void numberSet_Remove(NumberSet *set, Number number);
+#endif // numberSet_h
diff --git a/hicn-light/src/core/streamBuffer.c b/hicn-light/src/core/streamBuffer.c
new file mode 100755
index 000000000..7aebb5edb
--- /dev/null
+++ b/hicn-light/src/core/streamBuffer.c
@@ -0,0 +1,142 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/core/streamBuffer.h>
+
+void streamBuffer_Destroy(PARCEventQueue **bufferPtr) {
+ parcAssertNotNull(bufferPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*bufferPtr,
+ "Parameter must dereference to non-null pointer");
+ parcEventQueue_Destroy(bufferPtr);
+ *bufferPtr = NULL;
+}
+
+void streamBuffer_SetWatermark(PARCEventQueue *buffer, bool setRead,
+ bool setWrite, size_t low, size_t high) {
+ parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+ short flags = 0;
+ if (setRead) {
+ flags |= PARCEventType_Read;
+ }
+
+ if (setWrite) {
+ flags |= PARCEventType_Write;
+ }
+
+ parcEventQueue_SetWatermark(buffer, flags, low, high);
+}
+
+int streamBuffer_Flush(PARCEventQueue *buffer, bool flushRead,
+ bool flushWrite) {
+ parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+ short flags = 0;
+ if (flushRead) {
+ flags |= PARCEventType_Read;
+ }
+
+ if (flushWrite) {
+ flags |= PARCEventType_Write;
+ }
+
+ return parcEventQueue_Flush(buffer, flags);
+}
+
+int streamBuffer_FlushCheckpoint(PARCEventQueue *buffer, bool flushRead,
+ bool flushWrite) {
+ parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+ short flags = 0;
+ if (flushRead) {
+ flags |= PARCEventType_Read;
+ }
+
+ if (flushWrite) {
+ flags |= PARCEventType_Write;
+ }
+
+ return parcEventQueue_Flush(buffer, flags);
+}
+
+int streamBuffer_FlushFinished(PARCEventQueue *buffer, bool flushRead,
+ bool flushWrite) {
+ parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+ short flags = 0;
+ if (flushRead) {
+ flags |= PARCEventType_Read;
+ }
+
+ if (flushWrite) {
+ flags |= PARCEventType_Write;
+ }
+
+ return parcEventQueue_Flush(buffer, flags);
+}
+
+void streamBuffer_SetCallbacks(PARCEventQueue *buffer,
+ PARCEventQueue_Callback *readCallback,
+ PARCEventQueue_Callback *writeCallback,
+ PARCEventQueue_EventCallback *eventCallback,
+ void *user_data) {
+ parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+ parcEventQueue_SetCallbacks(buffer, readCallback, writeCallback,
+ eventCallback, user_data);
+}
+
+void streamBuffer_EnableCallbacks(PARCEventQueue *buffer, bool enableRead,
+ bool enableWrite) {
+ parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+ short flags = 0;
+ if (enableRead) {
+ flags |= PARCEventType_Read;
+ }
+ if (enableWrite) {
+ flags |= PARCEventType_Write;
+ }
+
+ parcEventQueue_Enable(buffer, flags);
+}
+
+/**
+ * @function StreamBuffer_DisableCallbacks
+ * @abstract Disables specified callbacks. Does not affect others.
+ * @discussion
+ * Disables enabled callbacks. If a callback is already disabled, has no
+ * effect. A "false" value does not enable it.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+void streamBuffer_DisableCallbacks(PARCEventQueue *buffer, bool disableRead,
+ bool disableWrite) {
+ parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+ short flags = 0;
+ if (disableRead) {
+ flags |= PARCEventType_Read;
+ }
+ if (disableWrite) {
+ flags |= PARCEventType_Write;
+ }
+
+ parcEventQueue_Disable(buffer, flags);
+}
diff --git a/hicn-light/src/core/streamBuffer.h b/hicn-light/src/core/streamBuffer.h
new file mode 100755
index 000000000..27e793176
--- /dev/null
+++ b/hicn-light/src/core/streamBuffer.h
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+/**
+ * Wrapper around event scheduler
+ */
+
+#ifndef streamBuffer_h
+#define streamBuffer_h
+
+#include <parc/algol/parc_EventQueue.h>
+#include <stdbool.h>
+
+void streamBuffer_Destroy(PARCEventQueue **bufferPtr);
+
+/**
+ * @function streamBuffer_SetWatermark
+ * @abstract Sets the read and/or write watermarks
+ * @discussion
+ * For a read watermark, when there is at least <code>low</code> bytes
+ * available to read, the read callback will be fired. If the bytes in the
+ * buffer exceed <code>high</code>, the stream buffer will stop reading from the
+ * network.
+ *
+ * For a write watermark, when the bytes in the buffer fall below
+ * <code>low</code>, the write callback is fired. The <code>high</code>
+ * watermark limits stream filters and shapers from exceeding that threashold on
+ * what they write to the buffer.
+ *
+ */
+void streamBuffer_SetWatermark(PARCEventQueue *buffer, bool setRead,
+ bool setWrite, size_t low, size_t high);
+
+/**
+ * @function streamBuffer_Flush
+ * @abstract The buffer will read/write more data if available
+ *
+ * @return -1 error, 0 no more data, 1 more data
+ */
+int streamBuffer_Flush(PARCEventQueue *buffer, bool flushRead, bool flushWrite);
+
+/**
+ * @function streamBuffer_FlushCheckpoint
+ * @abstract Flushes the stream, checkpointing all data in the buffer
+ */
+int streamBuffer_FlushCheckpoint(PARCEventQueue *buffer, bool flushRead,
+ bool flushWrite);
+
+/**
+ * @function streamBuffer_FlushFinished
+ * @abstract Flush the stream and indicate the end of new data
+ */
+int streamBuffer_FlushFinished(PARCEventQueue *buffer, bool flushRead,
+ bool flushWrite);
+
+/**
+ * @typedef StreamBufferReadWriteCallback
+ * @abstract Callback when data is available or write space available
+ * @constant user_data opaque data passed to
+ * <code>StreamBuffer_SetCallbacks()</code>
+ */
+typedef void(StreamBufferReadWriteCallback)(PARCEventQueue *buffer,
+ void *user_data);
+
+/**
+ * @typedef StreamBufferEventCallback
+ * @abstract Callback on error or other event on the stream buffer
+ * @constant what logical or of STREAM events. STREAM_READING and
+ * STREAM_WRITING indicate if the error was on the read or write direction. The
+ * conditions may be STREAM_ERROR, STREAM_EOF, STREAM_TIMEOUT, or
+ * STREAM_CONNECTED.
+ * @constant user_data opaque data passed to
+ * <code>StreamBuffer_SetCallbacks()</code>
+ */
+typedef void(StreamBufferEventCallback)(PARCEventQueue *buffer, short what,
+ void *user_data);
+
+/**
+ * Changes the callbacks for a buffer event.
+ *
+ * @param bufev the buffer event object for which to change callbacks
+ * @param readcb callback to invoke when there is data to be read, or NULL if
+ * no callback is desired
+ * @param writecb callback to invoke when the file descriptor is ready for
+ * writing, or NULL if no callback is desired
+ * @param eventcb callback to invoke when there is an event on the file
+ * descriptor
+ * @param cbarg an argument that will be supplied to each of the callbacks
+ * (readcb, writecb, and errorcb)
+ * @see parcEventQueue_Create()
+ */
+void streamBuffer_SetCallbacks(PARCEventQueue *buffer,
+ PARCEventQueue_Callback *readCallback,
+ PARCEventQueue_Callback *writeCallback,
+ PARCEventQueue_EventCallback *eventCallback,
+ void *user_data);
+
+/**
+ * @function StreamBuffer_EnableCallbacks
+ * @abstract Enables specified callbacks. Does not affect others.
+ * @discussion
+ * Enables disabled callbacks. If a callback is already enabled, has no
+ * effect. A "false" value does not disable it.
+ */
+void streamBuffer_EnableCallbacks(PARCEventQueue *buffer, bool enableRead,
+ bool enableWrite);
+
+/**
+ * @function StreamBuffer_DisableCallbacks
+ * @abstract Disables specified callbacks. Does not affect others.
+ * @discussion
+ * Disables enabled callbacks. If a callback is already disabled, has no
+ * effect. A "false" value does not enable it.
+ */
+void streamBuffer_DisableCallbacks(PARCEventQueue *buffer, bool disableRead,
+ bool disableWrite);
+#endif // streamBuffer_h
diff --git a/hicn-light/src/core/system.h b/hicn-light/src/core/system.h
new file mode 100755
index 000000000..3c5c8cba2
--- /dev/null
+++ b/hicn-light/src/core/system.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header system.h
+ * @abstract System-level properties
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+
+#ifndef system_h
+#define system_h
+
+#include <src/core/forwarder.h>
+#include <src/utils/interfaceSet.h>
+
+/**
+ * @function system_Interfaces
+ * @abstract The system network interfaces
+ */
+InterfaceSet *system_Interfaces(Forwarder *forwarder);
+
+/**
+ * Returns the MTU of the named interface
+ *
+ * @param [in] an allocated hicn-light forwarder
+ * @param [in] interfaceName The system interface name, e.g. "eth0"
+ *
+ * @return 0 Interface does not exist
+ * @return positive the MTU the kernel reports
+ *
+ */
+unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName);
+
+/**
+ * Returns the LINK address of the specified interface
+ *
+ * @param [in] an allocated hicn-light forwarder
+ * @param [in] interfaceName The system interface name, e.g. "eth0"
+ *
+ * @retval non-null The MAC address of the interface
+ * @retval null The interface does not exist
+ *
+ */
+Address *system_GetMacAddressByName(Forwarder *forwarder,
+ const char *interfaceName);
+#endif
diff --git a/hicn-light/src/core/ticks.h b/hicn-light/src/core/ticks.h
new file mode 100755
index 000000000..8750abde5
--- /dev/null
+++ b/hicn-light/src/core/ticks.h
@@ -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.
+ */
+
+/**
+ * @brief The router periodically measures time in units of Ticks
+ *
+ * See forwarder.c HZ which specifies the tick rate. forwarder.h has functions
+ * to convert between ticks and milliseconds.
+ *
+ */
+#ifndef ticks_h
+#define ticks_h
+
+#define __STDC_FORMAT_MACROS
+#include <stdint.h>
+
+typedef uint64_t Ticks;
+
+#endif // ticks_h
diff --git a/hicn-light/src/core/wldr.c b/hicn-light/src/core/wldr.c
new file mode 100755
index 000000000..b94ae76e5
--- /dev/null
+++ b/hicn-light/src/core/wldr.c
@@ -0,0 +1,182 @@
+/*
+ * 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 <parc/assert/parc_Assert.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+#include <src/core/wldr.h>
+#include <stdint.h>
+#include <stdio.h>
+
+struct wldr_buffer {
+ Message *message;
+ uint8_t rtx_counter;
+};
+
+typedef struct wldr_buffer WldrBuffer;
+
+struct wldr_state {
+ uint16_t expected_label;
+ uint16_t next_label;
+ WldrBuffer *buffer[BUFFER_SIZE];
+};
+
+Wldr *wldr_Init() {
+ Wldr *wldr = parcMemory_AllocateAndClear(sizeof(Wldr));
+ parcAssertNotNull(wldr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Wldr));
+ wldr->expected_label = 1;
+ wldr->next_label = 1;
+ for (int i = 0; i < BUFFER_SIZE; i++) {
+ WldrBuffer *entry = parcMemory_AllocateAndClear(sizeof(WldrBuffer));
+ parcAssertNotNull(
+ entry,
+ "WldrBuffer init: parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(WldrBuffer));
+ entry->message = NULL;
+ entry->rtx_counter = 0;
+ wldr->buffer[i] = entry;
+ }
+ return wldr;
+}
+
+void wldr_ResetState(Wldr *wldr) {
+ wldr->expected_label = 1;
+ wldr->next_label = 1;
+ for (int i = 0; i < BUFFER_SIZE; i++) {
+ wldr->buffer[i]->message = NULL;
+ wldr->buffer[i]->rtx_counter = 0;
+ }
+}
+
+void wldr_Destroy(Wldr **wldrPtr) {
+ Wldr *wldr = *wldrPtr;
+ for (unsigned i = 0; i < BUFFER_SIZE; i++) {
+ if (wldr->buffer[i]->message != NULL) {
+ message_Release(&(wldr->buffer[i]->message));
+ parcMemory_Deallocate((void **)&(wldr->buffer[i]));
+ }
+ }
+ parcMemory_Deallocate((void **)&wldr);
+ *wldrPtr = NULL;
+}
+
+static void _wldr_RetransmitPacket(Wldr *wldr, const Connection *conn,
+ uint16_t label) {
+ if (wldr->buffer[label % BUFFER_SIZE]->message == NULL) {
+ // the required message for retransmission is not in the buffer
+ return;
+ }
+
+ if (wldr->buffer[label % BUFFER_SIZE]->rtx_counter < MAX_RTX) {
+ Message *msg = wldr->buffer[label % BUFFER_SIZE]->message;
+ message_SetWldrLabel(msg, wldr->next_label);
+
+ if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->message != NULL) {
+ message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message));
+ }
+
+ wldr->buffer[wldr->next_label % BUFFER_SIZE]->message = msg;
+ wldr->buffer[wldr->next_label % BUFFER_SIZE]->rtx_counter =
+ wldr->buffer[label % BUFFER_SIZE]->rtx_counter + 1;
+ message_Acquire(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message);
+ wldr->next_label++;
+ connection_ReSend(conn, msg, false);
+ }
+}
+
+static void _wldr_SendWldrNotificaiton(Wldr *wldr, const Connection *conn,
+ Message *message, uint16_t expected_lbl,
+ uint16_t received_lbl) {
+ // here we need to create a new packet that is used to send the wldr
+ // notification to the prevoius hop. the destionation address of the
+ // notification is the source address of the message for which we want to
+ // create a notification. in fact, if message is an interest the prevoius hop
+ // is identified by the src. if message is a data, we need to send the
+ // notification message with the content name has a source address in this way
+ // the message will be trapped by the pounting rules in the next hop We define
+ // the notification as an interest message so that the NAT in the send function
+ // will set the src address of the local connection. Notice that in this way
+ // the notification packet will be dispaced to the right connection at the next
+ // hop.
+
+ Message *notification =
+ message_CreateWldrNotification(message, expected_lbl, received_lbl);
+ parcAssertNotNull(notification, "Got null from CreateWldrNotification");
+ connection_ReSend(conn, notification, true);
+}
+
+void wldr_SetLabel(Wldr *wldr, Message *message) {
+ // in this function we send the packet for the first time
+ // 1) we set the wldr label
+ message_SetWldrLabel(message, wldr->next_label);
+
+ // 2) we store the pointer to packet in the buffer
+ if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->message != NULL) {
+ // release an old message if necessary
+ message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message));
+ }
+
+ // we need to acquire the message to avoid that it gets destroyed
+ message_Acquire(message);
+
+ wldr->buffer[wldr->next_label % BUFFER_SIZE]->message = message;
+ wldr->buffer[wldr->next_label % BUFFER_SIZE]->rtx_counter = 0;
+ wldr->next_label++;
+ if (wldr->next_label ==
+ 0) // we alwasy skip label 0 beacause it means that wldr is not active
+ wldr->next_label++;
+}
+
+void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message) {
+ if (message_HasWldr(message)) {
+ // this is a normal wldr packet
+ uint16_t pkt_lbl = (uint16_t)message_GetWldrLabel(message);
+ if (pkt_lbl != wldr->expected_label) {
+ // if the received packet label is 1 and the expected packet label >
+ // pkt_lbl usually we are in the case where a remote note disconnected for
+ // a while and reconnected on this same connection, so the two nodes are
+ // out of synch for this reason we do not send any notification, we just
+ // synch the labels
+
+ if ((pkt_lbl != 1) || (wldr->expected_label < pkt_lbl)) {
+ _wldr_SendWldrNotificaiton(wldr, conn, message, wldr->expected_label,
+ pkt_lbl);
+ }
+
+ // here we always synch
+ wldr->expected_label = (uint16_t)(pkt_lbl + 1);
+ } else {
+ wldr->expected_label++;
+ if (wldr->expected_label == 0)
+ wldr->expected_label++; // for the next_label we want to skip 0
+ }
+ }
+}
+
+void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn,
+ Message *message) {
+ uint16_t expected_lbl = (uint16_t)message_GetWldrExpectedLabel(message);
+ uint16_t received_lbl = (uint16_t)message_GetWldrLastReceived(message);
+ if ((wldr->next_label - expected_lbl) > BUFFER_SIZE) {
+ // the packets are not in the buffer anymore
+ return;
+ }
+ while (expected_lbl < received_lbl) {
+ _wldr_RetransmitPacket(wldr, conn, expected_lbl);
+ expected_lbl++;
+ }
+}
diff --git a/hicn-light/src/core/wldr.h b/hicn-light/src/core/wldr.h
new file mode 100755
index 000000000..1666b4d3f
--- /dev/null
+++ b/hicn-light/src/core/wldr.h
@@ -0,0 +1,52 @@
+/*
+ * 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 wldr_h
+#define wldr_h
+
+#include <src/config.h>
+#include <src/core/connection.h>
+#include <src/core/message.h>
+
+#define BUFFER_SIZE 8192
+#define MAX_RTX 3
+#define WLDR_LBL 13
+#define WLDR_NOTIFICATION 14
+#define WLDR_UNKNOWN 15
+
+// NORMAL PACKET or RETRASMISSION
+// WLDR_LBL: label = window size in the TCP header
+// NOTIFICATION
+// WLDR_NOTIFICATION: expected_label = window size in the TCP header,
+// last_received_label = urgent pointer in the TCP header
+// ATTENTION!!! in order to detect a notificaiton the
+// source and destination ports must be set to 0
+
+struct wldr_state;
+typedef struct wldr_state Wldr;
+
+Wldr *wldr_Init();
+
+void wldr_Destroy(Wldr **wldrPtr);
+
+void wldr_ResetState(Wldr *wldr);
+
+void wldr_SetLabel(Wldr *wldr, Message *message);
+
+void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message);
+
+void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn,
+ Message *message);
+#endif // wldr_h
diff --git a/hicn-light/src/io/CMakeLists.txt b/hicn-light/src/io/CMakeLists.txt
new file mode 100755
index 000000000..f65f0b580
--- /dev/null
+++ b/hicn-light/src/io/CMakeLists.txt
@@ -0,0 +1,53 @@
+# 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/addressPair.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/ioOperations.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/listener.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/listenerSet.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/tcpListener.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicnListener.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/udpTunnel.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/tcpTunnel.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/udpConnection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/udpListener.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/streamConnection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicnTunnel.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicnConnection.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/addressPair.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/ioOperations.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/listenerSet.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/streamConnection.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tcpListener.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tcpTunnel.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/udpConnection.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/udpListener.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/udpTunnel.c
+)
+
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+ list(APPEND SOURCE_FILES
+ io/hicnTunnel.c
+ io/hicnConnection.c
+ io/hicnListener.c
+ )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/hicn-light/src/io/addressPair.c b/hicn-light/src/io/addressPair.c
new file mode 100755
index 000000000..5d2017a3d
--- /dev/null
+++ b/hicn-light/src/io/addressPair.c
@@ -0,0 +1,129 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/io/addressPair.h>
+
+struct address_pair {
+ Address *local;
+ Address *remote;
+};
+
+static void _addressPair_Destroy(AddressPair **addressPairPtr) {
+ AddressPair *pair = *addressPairPtr;
+
+ addressDestroy(&pair->local);
+ addressDestroy(&pair->remote);
+}
+
+parcObject_ExtendPARCObject(AddressPair, _addressPair_Destroy, NULL,
+ addressPair_ToString, addressPair_Equals, NULL,
+ addressPair_HashCode, NULL);
+
+parcObject_ImplementAcquire(addressPair, AddressPair);
+
+parcObject_ImplementRelease(addressPair, AddressPair);
+
+AddressPair *addressPair_Create(const Address *local, const Address *remote) {
+ parcAssertNotNull(local, "Parameter local must be non-null");
+ parcAssertNotNull(remote, "Parameter remote must be non-null");
+
+ AddressPair *pair = parcObject_CreateInstance(AddressPair);
+ parcAssertNotNull(pair, "Got null from parcObject_Create()");
+
+ pair->local = addressCopy(local);
+ pair->remote = addressCopy(remote);
+
+ return pair;
+}
+
+bool addressPair_Equals(const AddressPair *a, const AddressPair *b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (addressEquals(a->local, b->local)) {
+ if (addressEquals(a->remote, b->remote)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool addressPair_EqualsAddresses(const AddressPair *a, const Address *local,
+ const Address *remote) {
+ if (a == NULL || local == NULL || remote == NULL) {
+ return false;
+ }
+
+ if (addressEquals(a->local, local)) {
+ if (addressEquals(a->remote, remote)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+char *addressPair_ToString(const AddressPair *pair) {
+ parcAssertNotNull(pair, "Parameter pair must be non-null");
+
+ char *local = addressToString(pair->local);
+ char *remote = addressToString(pair->remote);
+
+ char *output;
+ int failure = asprintf(&output, "{ .local=%s, .remote=%s }", local, remote);
+ parcAssertTrue(failure > -1, "Error on asprintf");
+
+ parcMemory_Deallocate((void **)&local);
+ parcMemory_Deallocate((void **)&remote);
+
+ return output;
+}
+
+const Address *addressPair_GetLocal(const AddressPair *pair) {
+ parcAssertNotNull(pair, "Parameter pair must be non-null");
+ return pair->local;
+}
+
+const Address *addressPair_GetRemote(const AddressPair *pair) {
+ parcAssertNotNull(pair, "Parameter pair must be non-null");
+ return pair->remote;
+}
+
+/**
+ * @function addressPair_HashCode
+ * @abstract Hash useful for tables. Consistent with Equals.
+ * @discussion
+ * Returns a non-cryptographic hash that is consistent with equals. That is,
+ * if a == b, then hash(a) == hash(b).
+ *
+ */
+PARCHashCode addressPair_HashCode(const AddressPair *pair) {
+ PARCHashCode hashpair[2];
+ hashpair[0] = addressHashCode(pair->local);
+ hashpair[1] = addressHashCode(pair->remote);
+ return parcHashCode_Hash((const uint8_t *)hashpair, sizeof(hashpair));
+}
diff --git a/hicn-light/src/io/addressPair.h b/hicn-light/src/io/addressPair.h
new file mode 100755
index 000000000..5152267b6
--- /dev/null
+++ b/hicn-light/src/io/addressPair.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+/**
+ * Used to identify a connection between a specific local address and
+ * a specific remote address.
+ */
+
+#ifndef address_Pair_h
+#define address_Pair_h
+
+#include <src/utils/address.h>
+
+struct address_pair;
+typedef struct address_pair AddressPair;
+
+/**
+ * @function addressPair_Create
+ * @abstract Creates and address pair. There is no restriction on the address
+ * types.
+ * @discussion
+ * Creates an ordered pair of addresses, where the first is considered the
+ * "local" address and the second is the "remote" address. Those designations
+ * are purely a convention used to name them, and does not imply any specifici
+ * types of operations.
+ *
+ * The two addresses may be of any address types (e.g. IPv4, IPv6, Local,
+ * Ethernet). However, some functions that use an AddressPair may require that
+ * the local and remote addresses be the same type.
+ *
+ */
+AddressPair *addressPair_Create(const Address *local, const Address *remote);
+
+/**
+ * Returns a reference counted copy of the address pair
+ *
+ * Increments the reference count and returns the same address pair
+ *
+ * @param [in] addressPair An allocated address pair
+ *
+ * @retval non-null A reference counted copy
+ * @retval null An error
+ */
+AddressPair *addressPair_Acquire(const AddressPair *addressPair);
+
+/**
+ * Releases a reference count to the object
+ *
+ * Decrements the reference count and destroys the object when it reaches 0.
+ */
+void addressPair_Release(AddressPair **pairPtr);
+
+/**
+ * Determine if two AddressPair instances are equal.
+ *
+ * Two AddressPair instances are equal if, and only if, the local and remote
+ * addresses are identical. Equality is determined by addressEquals(a->local,
+ * b->local) and Adress_Equals(a->remote, b->remote).
+ *
+ * The following equivalence relations on non-null `AddressPair` instances are
+ * maintained:
+ *
+ * * It is reflexive: for any non-null reference value x,
+ * `AddressPair_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `addressPair_Equals(x, y)` must return true if and only if
+ * `addressPair_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `addressPair_Equals(x, y)` returns true and
+ * `addressPair_Equals(y, z)` returns true,
+ * then `addressPair_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `addressPair_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `addressPair_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `AddressPair` instance.
+ * @param b A pointer to a `AddressPair` instance.
+ * @return true if the two `AddressPair` instances are equal.
+ */
+bool addressPair_Equals(const AddressPair *a, const AddressPair *b);
+
+/**
+ * @function addressPair_EqualsAddresses
+ * @abstract As AddressEquals, but "b" is broken out
+ * @discussion
+ * Equality is determined by addressEquals(a->local, local) and
+ * Adress_Equals(a->remote, remote).
+ */
+bool addressPair_EqualsAddresses(const AddressPair *a, const Address *local,
+ const Address *remote);
+
+const Address *addressPair_GetLocal(const AddressPair *pair);
+
+const Address *addressPair_GetRemote(const AddressPair *pair);
+
+/**
+ * @function addressPair_HashCode
+ * @abstract Hash useful for tables. Consistent with Equals.
+ * @discussion
+ * Returns a non-cryptographic hash that is consistent with equals. That is,
+ * if a == b, then hash(a) == hash(b).
+ */
+PARCHashCode addressPair_HashCode(const AddressPair *pair);
+
+/**
+ * @function addressPair_ToString
+ * @abstract Human readable string representation. Caller must use free(3).
+ */
+char *addressPair_ToString(const AddressPair *pair);
+#endif // address_Pair_h
diff --git a/hicn-light/src/io/hicnConnection.c b/hicn-light/src/io/hicnConnection.c
new file mode 100755
index 000000000..85cf50921
--- /dev/null
+++ b/hicn-light/src/io/hicnConnection.c
@@ -0,0 +1,517 @@
+/*
+ * 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.
+ */
+
+/**
+ * Embodies the reader/writer for a HIcn connection
+ *
+ * NB The Send() function may overflow the output buffer
+ *
+ */
+
+#include <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <src/core/message.h>
+#include <src/io/hicnConnection.h>
+
+#include <src/core/messageHandler.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+
+typedef struct hicn_state {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ // the hicn listener socket we receive packets on
+ int hicnListenerSocket;
+
+ AddressPair *addressPair;
+
+ // We need to access this all the time, so grab it out
+ // of the addressPair;
+ struct sockaddr *peerAddress;
+ socklen_t peerAddressLength;
+
+ struct sockaddr *localAddress;
+ socklen_t localAddressLength;
+
+ // this address contains one of the content names reachable
+ // throught the connection peer. We need this address beacuse it is
+ // the only way we have to conntact the next hop, since the main tun
+ // does not have address. Notice that a connection that sends probes
+ // is a connection that sends interest. In a "data" connection this
+ // value will remain NULL. We refresh the content address every time
+ // we send a probe, in this way we don't need to waste to much time in
+ // copy the address, but we can also react to the routing changes
+ struct sockaddr *probeDestAddress;
+ socklen_t probeDestAddressLength;
+ bool refreshProbeDestAddress;
+
+ bool isLocal;
+ bool isUp;
+ unsigned id;
+
+ unsigned delay;
+} _HicnState;
+
+// Prototypes
+static bool _send(IoOperations *ops, const Address *nexthop, Message *message);
+static const Address *_getRemoteAddress(const IoOperations *ops);
+static const AddressPair *_getAddressPair(const IoOperations *ops);
+static unsigned _getConnectionId(const IoOperations *ops);
+static bool _isUp(const IoOperations *ops);
+static bool _isLocal(const IoOperations *ops);
+static void _destroy(IoOperations **opsPtr);
+static list_connections_type _getConnectionType(const IoOperations *ops);
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+ uint8_t *message);
+
+/*
+ * This assigns a unique pointer to the void * which we use
+ * as a GUID for this class.
+ */
+static const void *_ioOperationsGuid = __FILE__;
+
+/*
+ * Return our GUID
+ */
+static const void *_streamConnection_Class(const IoOperations *ops) {
+ return _ioOperationsGuid;
+}
+
+static IoOperations _template = {.closure = NULL,
+ .send = &_send,
+ .getRemoteAddress = &_getRemoteAddress,
+ .getAddressPair = &_getAddressPair,
+ .getConnectionId = &_getConnectionId,
+ .isUp = &_isUp,
+ .isLocal = &_isLocal,
+ .destroy = &_destroy,
+ .class = &_streamConnection_Class,
+ .getConnectionType = &_getConnectionType,
+ .sendProbe = &_sendProbe};
+
+// =================================================================
+
+static void _setConnectionState(_HicnState *HIcn, bool isUp);
+static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair);
+static void _refreshProbeDestAddress(_HicnState *hicnConnState,
+ const uint8_t *message);
+
+IoOperations *hicnConnection_Create(Forwarder *forwarder, int fd,
+ const AddressPair *pair, bool isLocal) {
+ IoOperations *io_ops = NULL;
+
+ _HicnState *hicnConnState = parcMemory_AllocateAndClear(sizeof(_HicnState));
+ parcAssertNotNull(hicnConnState,
+ "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(_HicnState));
+
+ hicnConnState->forwarder = forwarder;
+ hicnConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+ bool saved = _saveSockaddr(hicnConnState, pair);
+ if (saved) {
+ hicnConnState->hicnListenerSocket = fd;
+ hicnConnState->id = forwarder_GetNextConnectionId(forwarder);
+ hicnConnState->addressPair = addressPair_Acquire(pair);
+ hicnConnState->isLocal = isLocal;
+
+ // allocate a connection
+ io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations));
+ parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(IoOperations));
+ memcpy(io_ops, &_template, sizeof(IoOperations));
+ io_ops->closure = hicnConnState;
+
+ _setConnectionState(hicnConnState, true);
+
+ if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO,
+ PARCLogLevel_Info)) {
+ char *str = addressPair_ToString(hicnConnState->addressPair);
+ logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Info,
+ __func__,
+ "HIcnConnection %p created for address %s (isLocal %d)",
+ (void *)hicnConnState, str, hicnConnState->isLocal);
+ free(str);
+ }
+
+ messenger_Send(
+ forwarder_GetMessenger(forwarder),
+ missive_Create(MissiveType_ConnectionCreate, hicnConnState->id));
+ messenger_Send(forwarder_GetMessenger(forwarder),
+ missive_Create(MissiveType_ConnectionUp, hicnConnState->id));
+ } else {
+ // _saveSockaddr will already log an error, no need for extra log message
+ // here
+ logger_Release(&hicnConnState->logger);
+ parcMemory_Deallocate((void **)&hicnConnState);
+ }
+
+ return io_ops;
+}
+
+// =================================================================
+// I/O Operations implementation
+
+static void _destroy(IoOperations **opsPtr) {
+ parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer");
+ parcAssertNotNull(*opsPtr,
+ "Parameter opsPtr must dereference to non-null pointer");
+
+ IoOperations *ops = *opsPtr;
+ parcAssertNotNull(ioOperations_GetClosure(ops),
+ "ops->context must not be null");
+
+ _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops);
+ addressPair_Release(&hicnConnState->addressPair);
+ parcMemory_Deallocate((void **)&(hicnConnState->peerAddress));
+ parcMemory_Deallocate((void **)&(hicnConnState->localAddress));
+ if (hicnConnState->probeDestAddress != NULL)
+ parcMemory_Deallocate((void **)&(hicnConnState->probeDestAddress));
+
+ messenger_Send(
+ forwarder_GetMessenger(hicnConnState->forwarder),
+ missive_Create(MissiveType_ConnectionDestroyed, hicnConnState->id));
+
+ if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO,
+ PARCLogLevel_Info)) {
+ logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Info,
+ __func__, "HIcnConnection %p destroyed", (void *)hicnConnState);
+ }
+
+ // XXX
+ // do not close hicListenerSocket, the listener will close
+ // that when its done
+ // should I say something to libhicn?
+
+ logger_Release(&hicnConnState->logger);
+ parcMemory_Deallocate((void **)&hicnConnState);
+ parcMemory_Deallocate((void **)&ops);
+
+ *opsPtr = NULL;
+}
+
+static bool _isUp(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _HicnState *hicnConnState =
+ (const _HicnState *)ioOperations_GetClosure(ops);
+ return hicnConnState->isUp;
+}
+
+static bool _isLocal(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _HicnState *hicnConnState =
+ (const _HicnState *)ioOperations_GetClosure(ops);
+ return hicnConnState->isLocal;
+}
+
+static const Address *_getRemoteAddress(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _HicnState *hicnConnState =
+ (const _HicnState *)ioOperations_GetClosure(ops);
+ return addressPair_GetRemote(hicnConnState->addressPair);
+}
+
+static const AddressPair *_getAddressPair(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _HicnState *hicnConnState =
+ (const _HicnState *)ioOperations_GetClosure(ops);
+ return hicnConnState->addressPair;
+}
+
+static unsigned _getConnectionId(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _HicnState *hicnConnState =
+ (const _HicnState *)ioOperations_GetClosure(ops);
+ return hicnConnState->id;
+}
+
+/**
+ * @function hicnConnection_Send
+ * @abstract Non-destructive send of the message.
+ * @discussion
+ * sends a message to the peer.
+ *
+ * @param dummy is ignored. .
+ * @return <#return#>
+ */
+static bool _send(IoOperations *ops, const Address *dummy, Message *message) {
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops);
+
+ // NAT for HICN
+ // XXX
+ if (message_GetType(message) == MessagePacketType_ContentObject) {
+ // this is a data packet. We need to put the remote address in the
+ // destination field
+
+ if (messageHandler_GetIPPacketType(message_FixedHeader(message)) ==
+ IPv6_TYPE) {
+ messageHandler_SetDestination_IPv6(
+ (uint8_t *)message_FixedHeader(message),
+ &((struct sockaddr_in6 *)hicnConnState->peerAddress)->sin6_addr);
+ } else {
+ messageHandler_SetDestination_IPv4(
+ (uint8_t *)message_FixedHeader(message),
+ &(((struct sockaddr_in *)hicnConnState->peerAddress)
+ ->sin_addr.s_addr));
+ }
+ } else if (message_GetType(message) == MessagePacketType_Interest) {
+ // this si an interest packet. We need to put the local address in the
+ // source field
+ if (messageHandler_GetIPPacketType(message_FixedHeader(message)) ==
+ IPv6_TYPE) {
+ messageHandler_SetSource_IPv6(
+ (uint8_t *)message_FixedHeader(message),
+ &((struct sockaddr_in6 *)hicnConnState->localAddress)->sin6_addr);
+ } else {
+ messageHandler_SetSource_IPv4(
+ (uint8_t *)message_FixedHeader(message),
+ &(((struct sockaddr_in *)hicnConnState->localAddress)
+ ->sin_addr.s_addr));
+ }
+
+ // only in this case we may need to set the probeDestAddress
+ if (hicnConnState->refreshProbeDestAddress) {
+ _refreshProbeDestAddress(hicnConnState, message_FixedHeader(message));
+ }
+
+ } else if (message_GetType(message) == MessagePacketType_WldrNotification) {
+ // here we don't need to do anything for now
+ } else {
+ // unkown packet
+ if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO,
+ PARCLogLevel_Debug)) {
+ logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Debug,
+ __func__, "connid %u can't parse the message",
+ hicnConnState->id);
+ }
+ return false;
+ }
+
+ ssize_t writeLength =
+ write(hicnConnState->hicnListenerSocket, message_FixedHeader(message),
+ message_Length(message));
+
+ if (writeLength < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return false;
+ } else {
+ // this print is for debugging
+ printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLength,
+ message_Length(message), errno, strerror(errno));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static list_connections_type _getConnectionType(const IoOperations *ops) {
+ return CONN_HICN;
+}
+
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+ uint8_t *message) {
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops);
+
+ if ((hicnConnState->peerAddressLength == sizeof(struct sockaddr_in)) ||
+ (hicnConnState->localAddressLength == sizeof(struct sockaddr_in)))
+ return false;
+
+ if (hicnConnState->probeDestAddress == NULL &&
+ probeType == PACKET_TYPE_PROBE_REPLY) {
+ uint8_t *pkt = parcMemory_AllocateAndClear(
+ messageHandler_GetICMPPacketSize(IPv6_TYPE));
+ messageHandler_SetProbePacket(
+ pkt, probeType,
+ (struct in6_addr *)messageHandler_GetDestination(message),
+ (struct in6_addr *)messageHandler_GetSource(message));
+
+ ssize_t writeLength = write(hicnConnState->hicnListenerSocket, pkt,
+ messageHandler_GetICMPPacketSize(IPv6_TYPE));
+
+ parcMemory_Deallocate((void **)&pkt);
+
+ if (writeLength < 0) {
+ return 0;
+ }
+
+ } else if (hicnConnState->probeDestAddress != NULL &&
+ probeType == PACKET_TYPE_PROBE_REQUEST) {
+ hicnConnState->refreshProbeDestAddress = true;
+
+ uint8_t *pkt = parcMemory_AllocateAndClear(
+ messageHandler_GetICMPPacketSize(IPv6_TYPE));
+ messageHandler_SetProbePacket(
+ pkt, probeType,
+ &((struct sockaddr_in6 *)hicnConnState->localAddress)->sin6_addr,
+ &((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_addr);
+
+ ssize_t writeLength = write(hicnConnState->hicnListenerSocket, pkt,
+ messageHandler_GetICMPPacketSize(IPv6_TYPE));
+
+ parcMemory_Deallocate((void **)&pkt);
+
+ if (writeLength < 0) {
+ return 0;
+ }
+
+ } else {
+ if (hicnConnState->probeDestAddress == NULL &&
+ probeType == PACKET_TYPE_PROBE_REQUEST) {
+ // this happen for the first probe
+ hicnConnState->refreshProbeDestAddress = true;
+ }
+ // do nothing
+ return 0;
+ }
+
+ return forwarder_GetTicks(hicnConnState->forwarder);
+}
+
+// =================================================================
+// Internal API
+
+static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair) {
+ bool success = false;
+ const Address *remoteAddress = addressPair_GetRemote(pair);
+ const Address *localAddress = addressPair_GetLocal(pair);
+ switch (addressGetType(remoteAddress)) { // local must be of the same type
+
+ case ADDR_INET: {
+ size_t bytes = sizeof(struct sockaddr_in);
+ hicnConnState->peerAddress = parcMemory_Allocate(bytes);
+ parcAssertNotNull(hicnConnState->peerAddress,
+ "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+ addressGetInet(remoteAddress,
+ (struct sockaddr_in *)hicnConnState->peerAddress);
+ hicnConnState->peerAddressLength = (socklen_t)bytes;
+
+ hicnConnState->localAddress = parcMemory_Allocate(bytes);
+ parcAssertNotNull(hicnConnState->localAddress,
+ "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+ addressGetInet(localAddress,
+ (struct sockaddr_in *)hicnConnState->localAddress);
+ hicnConnState->localAddressLength = (socklen_t)bytes;
+
+ hicnConnState->probeDestAddress = NULL;
+ hicnConnState->probeDestAddressLength = (socklen_t)bytes;
+ hicnConnState->refreshProbeDestAddress = false;
+
+ success = true;
+ break;
+ }
+
+ case ADDR_INET6: {
+ size_t bytes = sizeof(struct sockaddr_in6);
+ hicnConnState->peerAddress = parcMemory_Allocate(bytes);
+ parcAssertNotNull(hicnConnState->peerAddress,
+ "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+ addressGetInet6(remoteAddress,
+ (struct sockaddr_in6 *)hicnConnState->peerAddress);
+ hicnConnState->peerAddressLength = (socklen_t)bytes;
+
+ hicnConnState->localAddress = parcMemory_Allocate(bytes);
+ parcAssertNotNull(hicnConnState->localAddress,
+ "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+ addressGetInet6(localAddress,
+ (struct sockaddr_in6 *)hicnConnState->localAddress);
+ hicnConnState->localAddressLength = (socklen_t)bytes;
+
+ hicnConnState->probeDestAddress = NULL;
+ hicnConnState->probeDestAddressLength = (socklen_t)bytes;
+ hicnConnState->refreshProbeDestAddress = false;
+
+ success = true;
+ break;
+ }
+
+ default:
+ if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO,
+ PARCLogLevel_Error)) {
+ char *str = addressToString(remoteAddress);
+ logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Error,
+ __func__, "Remote address is not INET or INET6: %s", str);
+ parcMemory_Deallocate((void **)&str);
+ }
+ break;
+ }
+ return success;
+}
+
+static void _refreshProbeDestAddress(_HicnState *hicnConnState,
+ const uint8_t *message) {
+ if ((hicnConnState->peerAddressLength == sizeof(struct sockaddr_in)) ||
+ (hicnConnState->localAddressLength == sizeof(struct sockaddr_in)))
+ return;
+
+ if (hicnConnState->probeDestAddress == NULL) {
+ hicnConnState->probeDestAddress =
+ parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+ parcAssertNotNull(hicnConnState->probeDestAddress,
+ "parcMemory_Allocate(%zu) returned NULL",
+ sizeof(struct sockaddr_in6));
+ }
+
+ ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_family =
+ AF_INET6;
+ ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_port =
+ htons(1234);
+ ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_scope_id = 0;
+ ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_flowinfo = 0;
+ ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_addr =
+ *((struct in6_addr *)messageHandler_GetDestination(message));
+ hicnConnState->refreshProbeDestAddress = false;
+}
+
+static void _setConnectionState(_HicnState *hicnConnState, bool isUp) {
+ parcAssertNotNull(hicnConnState, "Parameter HICN must be non-null");
+
+ Messenger *messenger = forwarder_GetMessenger(hicnConnState->forwarder);
+
+ bool oldStateIsUp = hicnConnState->isUp;
+ hicnConnState->isUp = isUp;
+
+ if (oldStateIsUp && !isUp) {
+ // bring connection DOWN
+ Missive *missive =
+ missive_Create(MissiveType_ConnectionDown, hicnConnState->id);
+ messenger_Send(messenger, missive);
+ return;
+ }
+
+ if (!oldStateIsUp && isUp) {
+ // bring connection UP
+ Missive *missive =
+ missive_Create(MissiveType_ConnectionUp, hicnConnState->id);
+ messenger_Send(messenger, missive);
+ return;
+ }
+}
diff --git a/hicn-light/src/io/hicnConnection.h b/hicn-light/src/io/hicnConnection.h
new file mode 100755
index 000000000..757e534ba
--- /dev/null
+++ b/hicn-light/src/io/hicnConnection.h
@@ -0,0 +1,53 @@
+/*
+ * 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 hicnConnection.h
+ * @brief Represents a HIcn connection for the connection table
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef hicnConnection_h
+#define hicnConnection_h
+
+#include <src/core/forwarder.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+#include <src/utils/address.h>
+
+/**
+ * Creates a HIcn connection that can send to the remote address
+ *
+ * The address pair must both be same type (i.e. INET or INET6).
+ *
+ * @param [in] an allocated hicn-light Forwarder (saves reference)
+ * @param [in] fd The socket to use
+ * @param [in] pair An allocated address pair for the connection (saves
+ * reference)
+ * @param [in] isLocal determines if the remote address is on the current system
+ *
+ * @retval non-null An allocated Io operations
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+IoOperations *hicnConnection_Create(Forwarder *forwarder, int fd,
+ const AddressPair *pair, bool isLocal);
+#endif // hicnConnection_h
diff --git a/hicn-light/src/io/hicnListener.c b/hicn-light/src/io/hicnListener.c
new file mode 100755
index 000000000..161f5b317
--- /dev/null
+++ b/hicn-light/src/io/hicnListener.c
@@ -0,0 +1,725 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <unistd.h>
+
+#include <src/io/hicnConnection.h>
+#include <src/io/hicnListener.h>
+
+#include <src/core/connection.h>
+#include <src/core/connectionTable.h>
+#include <src/core/forwarder.h>
+#ifdef WITH_MAPME
+#include <src/config/symbolicNameTable.h>
+#include <src/core/mapMe.h>
+#include <src/core/message.h>
+#include <src/io/hicnTunnel.h>
+#endif /* WITH_MAPME */
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/mapMe.h>
+#include <src/core/messagePacketType.h>
+#include <src/io/listener.h>
+#include <src/socket/api.h>
+
+#define IPv6 6
+#define IPv4 4
+#define MTU_SIZE 1500 // bytes
+#define MAX_HICN_RETRY 5
+
+struct hicn_listener {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ PARCEvent *hicn_event;
+ int hicn_fd; // this is the file descriptor got from hicn library
+
+ Address *localAddress; // this is the local address or 0::0 in case of the
+ // main listener this is the address used inside
+ // forwarder to identify the listener. Notice that this
+ // address is the same as the fisical interfaces on
+ // which we create the TUN. it is NOT the TUN address
+ // which is given by libhicn after the bind operation
+ // However the user alway uses this address since is
+ // the only one available at configuration time
+
+ unsigned inetFamily;
+
+ int connection_id; // this is used only if the listener is used to receive
+ // data packets we assume that 1 connection is associated
+ // to one listener in this case so we set the connection_id
+ // we the connection is create. if this id is not set and a
+ // data packet is received, the packet is dropped
+
+ unsigned conn_id;
+};
+
+static void _destroy(ListenerOps **listenerOpsPtr);
+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 ListenerOps _hicnTemplate = {.context = NULL,
+ .destroy = &_destroy,
+ .getInterfaceIndex = &_getInterfaceIndex,
+ .getListenAddress = &_getListenAddress,
+ .getEncapType = &_getEncapType,
+ .getSocket = &_getSocket};
+
+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));
+ parcAssertNotNull(addr6, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(addr6));
+
+ addressGetInet6(address, addr6);
+
+ bool res = true;
+ for (int i = 0; i < 16; ++i) {
+ if (addr6->sin6_addr.s6_addr[i] != 0) {
+ res = false;
+ }
+ }
+
+ parcMemory_Deallocate((void **)&addr6);
+
+ return res;
+}
+
+static bool _isEmptyAddressIPv4(Address *address) {
+ bool res = false;
+
+ if (strcmp("inet4://0.0.0.0:1234", addressToString(address)) == 0) res = true;
+ return res;
+}
+
+ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic,
+ Address *address) {
+ HIcnListener *hicn = parcMemory_AllocateAndClear(sizeof(HIcnListener));
+ parcAssertNotNull(hicn, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(HIcnListener));
+
+ hicn->forwarder = forwarder;
+ hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+ hicn->conn_id = forwarder_GetNextConnectionId(forwarder);
+ hicn->localAddress = addressCopy(address);
+
+ hicn->inetFamily = IPv4;
+
+ hicn->connection_id = -1;
+
+ hicn_socket_helper_t *hicnSocketHelper =
+ forwarder_GetHIcnSocketHelper(forwarder);
+
+ if (_isEmptyAddressIPv4(address)) {
+ hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, NULL);
+ } else {
+ struct sockaddr_in *tmpAddr =
+ parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+ parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(tmpAddr));
+ addressGetInet(address, tmpAddr);
+ char *local_addr = parcMemory_AllocateAndClear(INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &(tmpAddr->sin_addr), local_addr, INET_ADDRSTRLEN);
+ parcMemory_Deallocate((void **)&tmpAddr);
+
+ hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, local_addr);
+
+ parcMemory_Deallocate((void **)&local_addr);
+ }
+
+ if (hicn->hicn_fd < 0) {
+ if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+ PARCLogLevel_Debug)) {
+ logger_Log(
+ hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "HIcnListener %s: error while creating an hicn listener in lib_hicn",
+ symbolic);
+ }
+ logger_Release(&hicn->logger);
+ addressDestroy(&hicn->localAddress);
+ parcMemory_Deallocate((void **)&hicn);
+ return NULL;
+ }
+
+ // Set non-blocking flag
+ int flags = fcntl(hicn->hicn_fd, F_GETFL, NULL);
+ parcAssertTrue(flags != -1,
+ "fcntl failed to obtain file descriptor flags (%d)", errno);
+ int failure = fcntl(hicn->hicn_fd, F_SETFL, flags | O_NONBLOCK);
+ parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)",
+ errno);
+
+ hicn->hicn_event = dispatcher_CreateNetworkEvent(
+ forwarder_GetDispatcher(forwarder), true, _hicnListener_readcb,
+ (void *)hicn, hicn->hicn_fd);
+ dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder),
+ hicn->hicn_event);
+
+ ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+ parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListenerOps));
+
+ memcpy(ops, &_hicnTemplate, sizeof(ListenerOps));
+ ops->context = hicn;
+
+ if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "HIcnListener %s created", symbolic);
+ }
+
+ return ops;
+ return NULL;
+}
+
+ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic,
+ Address *address) {
+ HIcnListener *hicn = parcMemory_AllocateAndClear(sizeof(HIcnListener));
+ parcAssertNotNull(hicn, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(HIcnListener));
+
+ hicn->forwarder = forwarder;
+ hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+ hicn->conn_id = forwarder_GetNextConnectionId(forwarder);
+ hicn->localAddress = addressCopy(address);
+
+ hicn->inetFamily = IPv6;
+
+ hicn->connection_id = -1;
+
+ // the call to libhicn is the same both for the main and the normal listeners
+ // in both cases we need to set only the identifier. In the case of normal
+ // listener (listener for data packet) we let the library select the right ip
+ //address we just need to set the right type of packet
+
+ hicn_socket_helper_t *hicnSocketHelper =
+ forwarder_GetHIcnSocketHelper(forwarder);
+
+ if (_isEmptyAddressIPv6(address)) {
+ // create main listener
+ hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, NULL);
+ } else {
+ // create listener for the connetion
+ struct sockaddr_in6 *tmpAddr =
+ parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+
+ parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(tmpAddr));
+ addressGetInet6(address, tmpAddr);
+
+ char *local_addr = parcMemory_AllocateAndClear(INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &(tmpAddr->sin6_addr), local_addr, INET6_ADDRSTRLEN);
+
+ parcMemory_Deallocate((void **)&tmpAddr);
+
+ hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, local_addr);
+
+ parcMemory_Deallocate((void **)&local_addr);
+ }
+
+ if (hicn->hicn_fd < 0) {
+ if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+ PARCLogLevel_Debug)) {
+ logger_Log(
+ hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "HIcnListener %s: error while creating an hicn listener in lib_hicn",
+ symbolic);
+ }
+ logger_Release(&hicn->logger);
+ addressDestroy(&hicn->localAddress);
+ parcMemory_Deallocate((void **)&hicn);
+ return NULL;
+ }
+
+ // Set non-blocking flag
+ int flags = fcntl(hicn->hicn_fd, F_GETFL, NULL);
+ parcAssertTrue(flags != -1,
+ "fcntl failed to obtain file descriptor flags (%d)", errno);
+ int failure = fcntl(hicn->hicn_fd, F_SETFL, flags | O_NONBLOCK);
+ parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)",
+ errno);
+
+ hicn->hicn_event = dispatcher_CreateNetworkEvent(
+ forwarder_GetDispatcher(forwarder), true, _hicnListener_readcb,
+ (void *)hicn, hicn->hicn_fd);
+ dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder),
+ hicn->hicn_event);
+
+ ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+ parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListenerOps));
+
+ memcpy(ops, &_hicnTemplate, sizeof(ListenerOps));
+ ops->context = hicn;
+
+ if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "HIcnListener %s created", symbolic);
+ }
+
+ return ops;
+}
+
+bool _hicnListener_BindInet6(ListenerOps *ops, const Address *remoteAddress) {
+ HIcnListener *hicn = (HIcnListener *)ops->context;
+ hicn_socket_helper_t *hicnSocketHelper =
+ forwarder_GetHIcnSocketHelper(hicn->forwarder);
+
+ struct sockaddr_in6 *tmpAddr =
+ parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+ parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(tmpAddr));
+ addressGetInet6(remoteAddress, tmpAddr);
+ char *remote_addr = parcMemory_AllocateAndClear(INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &(tmpAddr->sin6_addr), remote_addr, INET6_ADDRSTRLEN);
+ parcMemory_Deallocate((void **)&tmpAddr);
+
+ int res = hicn_bind(hicnSocketHelper, hicn->hicn_fd, remote_addr);
+
+ bool result = false;
+ if (res < 0) {
+ 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));
+ }
+ } else {
+ result = true;
+ }
+
+ parcMemory_Deallocate((void **)&remote_addr);
+
+ return result;
+}
+
+bool _hicnListener_BindInet(ListenerOps *ops, const Address *remoteAddress) {
+ HIcnListener *hicn = (HIcnListener *)ops->context;
+ hicn_socket_helper_t *hicnSocketHelper =
+ forwarder_GetHIcnSocketHelper(hicn->forwarder);
+
+ struct sockaddr_in *tmpAddr =
+ parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+ parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(tmpAddr));
+ addressGetInet(remoteAddress, tmpAddr);
+ char *remote_addr = parcMemory_AllocateAndClear(INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &(tmpAddr->sin_addr), remote_addr, INET_ADDRSTRLEN);
+ parcMemory_Deallocate((void **)&tmpAddr);
+
+ int res = hicn_bind(hicnSocketHelper, hicn->hicn_fd, remote_addr);
+ bool result = false;
+
+ if (res < 0) {
+ 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));
+ }
+ } else {
+ result = true;
+ }
+
+ parcMemory_Deallocate((void **)&remote_addr);
+
+ return result;
+}
+
+bool hicnListener_Bind(ListenerOps *ops, const Address *remoteAddress) {
+ if (addressGetType(remoteAddress) == ADDR_INET) {
+ return _hicnListener_BindInet(ops, remoteAddress);
+ } else if (addressGetType(remoteAddress) == ADDR_INET6) {
+ return _hicnListener_BindInet6(ops, remoteAddress);
+ } else {
+ printf("Bind failed: Invalid address\n");
+ return false;
+ }
+}
+
+bool hicnListener_Punting(ListenerOps *ops, const char *prefix) {
+ HIcnListener *hicn = (HIcnListener *)ops->context;
+ hicn_socket_helper_t *hicnSocketHelper =
+ forwarder_GetHIcnSocketHelper(hicn->forwarder);
+
+ int res = hicn_listen(hicnSocketHelper, hicn->hicn_fd, prefix);
+ int retry = 0;
+
+ while (res < 0 && retry < MAX_HICN_RETRY) {
+ sleep(1);
+ res = hicn_listen(hicnSocketHelper, hicn->hicn_fd, prefix);
+ retry++;
+ }
+
+ if (res < 0) {
+ if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+ PARCLogLevel_Debug)) {
+ logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "hicn_listen failed %d %s", res, hicn_socket_strerror(res));
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool hicnListener_SetConnectionId(ListenerOps *ops, unsigned connId) {
+ HIcnListener *hicn = (HIcnListener *)ops->context;
+ if (hicn) {
+ hicn->connection_id = connId;
+ return true;
+ }
+ return false;
+}
+
+static void _hicnListener_Destroy(HIcnListener **listenerPtr) {
+ parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*listenerPtr,
+ "Parameter must derefernce to non-null pointer");
+
+ HIcnListener *hicn = *listenerPtr;
+
+ // close(hicn->hicn_fd); //XXX close the fd in the hicnlib (detroy listener?)
+ dispatcher_DestroyNetworkEvent(forwarder_GetDispatcher(hicn->forwarder),
+ &hicn->hicn_event);
+ logger_Release(&hicn->logger);
+ addressDestroy(&hicn->localAddress);
+ parcMemory_Deallocate((void **)&hicn);
+ *listenerPtr = NULL;
+}
+
+static void _destroy(ListenerOps **listenerOpsPtr) {
+ ListenerOps *ops = *listenerOpsPtr;
+ HIcnListener *hicn = (HIcnListener *)ops->context;
+ _hicnListener_Destroy(&hicn);
+ parcMemory_Deallocate((void **)&ops);
+ *listenerOpsPtr = NULL;
+}
+
+static unsigned _getInterfaceIndex(const ListenerOps *ops) {
+ HIcnListener *hicn = (HIcnListener *)ops->context;
+ return hicn->conn_id;
+}
+
+static const Address *_getListenAddress(const ListenerOps *ops) {
+ HIcnListener *hicn = (HIcnListener *)ops->context;
+ return hicn->localAddress;
+}
+
+static EncapType _getEncapType(const ListenerOps *ops) { return ENCAP_HICN; }
+
+static int _getSocket(const ListenerOps *ops) {
+ HIcnListener *hicn = (HIcnListener *)ops->context;
+ return hicn->hicn_fd;
+}
+
+// ===============================
+
+static void _readFrameToDiscard(HIcnListener *hicn, int fd) {
+ // we need to discard the frame. Read 1 byte. This will clear it off the
+ // stack.
+ uint8_t buffer;
+ int nread = read(fd, &buffer, 1);
+
+ if (nread > 0) {
+ if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+ PARCLogLevel_Debug)) {
+ logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "Discarded frame from fd %d", fd);
+ }
+ } else if (nread < 0) {
+ printf("Error trying to discard frame from fd %d: (%d) %s", fd, errno,
+ strerror(errno));
+ if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+ PARCLogLevel_Error)) {
+ logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Error trying to discard frame from fd %d: (%d) %s", fd, errno,
+ strerror(errno));
+ }
+ }
+}
+
+static unsigned _createNewConnection(HIcnListener *hicn, int fd,
+ const AddressPair *pair) {
+ bool isLocal = false;
+
+ // udpConnection_Create takes ownership of the pair
+ IoOperations *ops = hicnConnection_Create(hicn->forwarder, fd, pair, isLocal);
+ Connection *conn = connection_Create(ops);
+
+ connectionTable_Add(forwarder_GetConnectionTable(hicn->forwarder), conn);
+ unsigned connid = ioOperations_GetConnectionId(ops);
+
+ return connid;
+}
+
+const Connection *_findConnectionFromPacket(HIcnListener *hicn,
+ Address *packetSourceAddress) {
+ const Connection *conn = NULL;
+ if (hicn->connection_id != -1) {
+ conn = connectionTable_FindById(
+ forwarder_GetConnectionTable(hicn->forwarder), hicn->connection_id);
+ } else {
+ if (packetSourceAddress != NULL) {
+ // in this first check we try to retrieve the standard connection
+ // generated by the hicn-light
+ AddressPair *pair =
+ addressPair_Create(hicn->localAddress, packetSourceAddress);
+ conn = connectionTable_FindByAddressPair(
+ forwarder_GetConnectionTable(hicn->forwarder), pair);
+ addressPair_Release(&pair);
+ }
+ }
+
+ return conn;
+}
+
+static Address *_createAddressFromPacket(uint8_t *msgBuffer) {
+ Address *packetAddr = NULL;
+ if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) {
+ struct sockaddr_in6 addr_in6;
+ addr_in6.sin6_family = AF_INET6;
+ addr_in6.sin6_port = htons(1234);
+ addr_in6.sin6_flowinfo = 0;
+ addr_in6.sin6_scope_id = 0;
+ memcpy(&addr_in6.sin6_addr,
+ (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16);
+ packetAddr = addressCreateFromInet6(&addr_in6);
+ } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) {
+ struct sockaddr_in addr_in;
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = htons(1234);
+ memcpy(&addr_in.sin_addr,
+ (struct in_addr *)messageHandler_GetSource(msgBuffer), 4);
+ packetAddr = addressCreateFromInet(&addr_in);
+ }
+ return packetAddr;
+}
+
+static void _handleProbeMessage(HIcnListener *hicn, uint8_t *msgBuffer) {
+ Address *packetAddr = _createAddressFromPacket(msgBuffer);
+
+ if (packetAddr != NULL) {
+ const Connection *conn = _findConnectionFromPacket(hicn, packetAddr);
+ if (conn != NULL) {
+ // we drop all the probes for a connection that does not exists
+ connection_HandleProbe((Connection *)conn, msgBuffer,
+ forwarder_GetTicks(hicn->forwarder));
+ }
+ }
+
+ addressDestroy(&packetAddr);
+ parcMemory_Deallocate((void **)&msgBuffer);
+}
+
+static void _handleWldrNotification(HIcnListener *hicn, uint8_t *msgBuffer) {
+ Address *packetAddr = _createAddressFromPacket(msgBuffer);
+
+ if (packetAddr == NULL) {
+ parcMemory_Deallocate((void **)&msgBuffer);
+ return;
+ }
+
+ const Connection *conn = _findConnectionFromPacket(hicn, packetAddr);
+ if (conn == NULL) {
+ addressDestroy(&packetAddr);
+ return;
+ }
+
+ addressDestroy(&packetAddr);
+
+ Message *message = message_CreateFromByteArray(
+ connection_GetConnectionId(conn), msgBuffer,
+ MessagePacketType_WldrNotification, forwarder_GetTicks(hicn->forwarder),
+ forwarder_GetLogger(hicn->forwarder));
+
+ connection_HandleWldrNotification((Connection *)conn, message);
+
+ message_Release(&message);
+}
+
+#ifdef WITH_MAPME
+static void _handleMapMe(HIcnListener *hicn, int fd, uint8_t *msgBuffer) {
+ Address *packetAddr = _createAddressFromPacket(msgBuffer);
+
+ if (packetAddr == NULL) {
+ parcMemory_Deallocate((void **)&msgBuffer);
+ return;
+ }
+
+ const Connection *conn = _findConnectionFromPacket(hicn, packetAddr);
+ unsigned conn_id;
+ if (conn == NULL) {
+ /* Unlike the interest path, we don't create virtual connections bound
+ * on the listener, whose only interest is to send data, but full
+ * tunnels to be able to route interests
+ *
+ * packetAddr is the remote address, we need to ask the lib for our
+ * local address
+ * hicn->localAddress is None as the interest is received by the main
+ * listener.
+ */
+ printf("MapMe, connection did not exist, creating\n");
+
+ /* Populate remote_address through packetAddr */
+ struct sockaddr_in6 sockaddr; // XXX IPv6 only
+ addressGetInet6(packetAddr, &sockaddr);
+ ip_address_t remote_address = {.family = AF_INET6,
+ .prefix_len = IPV6_ADDR_LEN_BITS};
+ memcpy(&remote_address.buffer, &sockaddr.sin6_addr,
+ ip_address_len(&remote_address));
+
+ /* Get local address through libhicn */
+ ip_address_t local_address;
+ int rc = hicn_get_local_address(&remote_address, &local_address);
+ if (rc < 0) {
+ printf("Error getting local address. Discarded mapme packet.\n");
+ return;
+ }
+
+ struct sockaddr_in6 addr_in6;
+ addr_in6.sin6_family = AF_INET6;
+ addr_in6.sin6_port = htons(1234);
+ addr_in6.sin6_flowinfo = 0;
+ addr_in6.sin6_scope_id = 0;
+ memcpy(&addr_in6.sin6_addr, (struct in6_addr *)&(local_address.buffer), 16);
+
+ Address *localAddr = addressCreateFromInet6(&addr_in6);
+ IoOperations *ops =
+ hicnTunnel_Create(hicn->forwarder, localAddr, packetAddr);
+
+ if (!ops) {
+ printf("Error creating tunnel. Discarded mapme packet.\n");
+ return;
+ }
+
+ conn = connection_Create(ops);
+
+ connectionTable_Add(forwarder_GetConnectionTable(hicn->forwarder),
+ (Connection *)conn);
+ }
+ conn_id = connection_GetConnectionId(conn);
+
+ addressDestroy(&packetAddr);
+
+ forwarder_ProcessMapMe(hicn->forwarder, msgBuffer, conn_id);
+}
+#endif /* WITH_MAPME */
+
+static Message *_readMessage(HIcnListener *hicn, int fd, uint8_t *msgBuffer) {
+ 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);
+ const Connection *conn = _findConnectionFromPacket(hicn, packetAddr);
+
+ if (conn == NULL) {
+ AddressPair *pair = addressPair_Create(hicn->localAddress, packetAddr);
+ connid = _createNewConnection(hicn, 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(hicn, msgBuffer);
+ } else if (messageHandler_IsLoadBalancerProbe(msgBuffer)) {
+ _handleProbeMessage(hicn, msgBuffer);
+ }
+#ifdef WITH_MAPME
+ else if (mapMe_isMapMe(msgBuffer)) {
+ /* This function triggers the handling of the MAP-Me message, and we
+ * will return NULL so as to terminate the processing of this
+ * msgBuffer. */
+ _handleMapMe(hicn, fd, msgBuffer);
+ }
+#endif /* WITH_MAPME */
+
+ return message;
+}
+
+static void _receivePacket(HIcnListener *hicn, int fd) {
+ Message *msg = NULL;
+ uint8_t *msgBuffer = parcMemory_AllocateAndClear(MTU_SIZE);
+ msg = _readMessage(hicn, fd, msgBuffer);
+
+ if (msg) {
+ forwarder_Receive(hicn->forwarder, msg);
+ }
+}
+
+static void _hicnListener_readcb(int fd, PARCEventType what, void *hicnVoid) {
+ HIcnListener *hicn = (HIcnListener *)hicnVoid;
+
+ if (hicn->inetFamily == IPv4 || hicn->inetFamily == IPv6) {
+ if (what & PARCEventType_Read) {
+ _receivePacket(hicn, fd);
+ }
+ } else {
+ _readFrameToDiscard(hicn, fd);
+ }
+}
diff --git a/hicn-light/src/io/hicnListener.h b/hicn-light/src/io/hicnListener.h
new file mode 100755
index 000000000..98c5387c9
--- /dev/null
+++ b/hicn-light/src/io/hicnListener.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 hicnListener.h
+ * @brief Listens for in coming HIcn connections
+ *
+ *
+ */
+
+#ifndef hicnListener_h
+#define hicnListener_h
+
+#include <src/core/forwarder.h>
+#include <src/core/messageHandler.h>
+#include <src/io/listener.h>
+#include <stdlib.h>
+
+struct hicn_listener;
+typedef struct hicn_listener HIcnListener;
+
+ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic,
+ Address *address);
+ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic,
+ Address *address);
+bool hicnListener_Punting(ListenerOps *ops, const char *prefix);
+bool hicnListener_Bind(ListenerOps *ops, const Address *remoteAddress);
+bool hicnListener_SetConnectionId(ListenerOps *ops, unsigned connId);
+// const Address *hicnListener_GetTunAddress(const ListenerOps *ops);
+#endif // hicnListener_h
diff --git a/hicn-light/src/io/hicnTunnel.c b/hicn-light/src/io/hicnTunnel.c
new file mode 100755
index 000000000..e55393137
--- /dev/null
+++ b/hicn-light/src/io/hicnTunnel.c
@@ -0,0 +1,106 @@
+/*
+ * 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 <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/io/hicnConnection.h>
+#include <src/io/hicnListener.h>
+#include <src/io/hicnTunnel.h>
+
+IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder,
+ ListenerOps *localListener,
+ const Address *remoteAddress) {
+ parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+ parcAssertNotNull(localListener, "Parameter localListener must be non-null");
+ parcAssertNotNull(remoteAddress, "Parameter remoteAddress must be non-null");
+
+ Logger *logger = forwarder_GetLogger(forwarder);
+
+ IoOperations *ops = NULL;
+ if (localListener->getEncapType(localListener) == ENCAP_HICN) {
+ const Address *localAddress =
+ localListener->getListenAddress(localListener);
+ address_type localType = addressGetType(localAddress);
+ address_type remoteType = addressGetType(remoteAddress);
+
+ if (localType == remoteType) {
+ bool res = hicnListener_Bind(localListener, remoteAddress);
+ if (res == false) {
+ if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+ logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Unable to bind local listener to remote node");
+ }
+ return ops;
+ }
+
+ // localAddress = hicnListener_GetTunAddress(localListener); //This is the
+ // true local address
+
+ AddressPair *pair = addressPair_Create(localAddress, remoteAddress);
+ bool isLocal = false;
+ int fd = localListener->getSocket(localListener);
+ ops = hicnConnection_Create(forwarder, fd, pair, isLocal);
+
+ addressPair_Release(&pair);
+ } else {
+ if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+ logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Local listener of type %s and remote type %s, cannot "
+ "establish tunnel",
+ addressTypeToString(localType),
+ addressTypeToString(remoteType));
+ }
+ }
+ } else {
+ if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+ logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Local listener %p is not type UDP, cannot establish tunnel",
+ (void *)localListener);
+ }
+ }
+
+ return ops;
+}
+
+IoOperations *hicnTunnel_Create(Forwarder *forwarder,
+ const Address *localAddress,
+ const Address *remoteAddress) {
+ ListenerSet *set = forwarder_GetListenerSet(forwarder);
+ ListenerOps *listener = listenerSet_Find(set, ENCAP_HICN, localAddress);
+ IoOperations *ops = NULL;
+ if (listener) {
+ ops = hicnTunnel_CreateOnListener(forwarder, listener, remoteAddress);
+ } else {
+ if (logger_IsLoggable(forwarder_GetLogger(forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error)) {
+ char *str = addressToString(localAddress);
+ logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error, __func__,
+ "Could not find listener to match address %s", str);
+ parcMemory_Deallocate((void **)&str);
+ }
+ }
+
+ if (ops) {
+ hicnListener_SetConnectionId(listener, ops->getConnectionId(ops));
+ }
+
+ return ops;
+}
diff --git a/hicn-light/src/io/hicnTunnel.h b/hicn-light/src/io/hicnTunnel.h
new file mode 100755
index 000000000..70295797c
--- /dev/null
+++ b/hicn-light/src/io/hicnTunnel.h
@@ -0,0 +1,65 @@
+/*
+ * 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 hicnTunnel.h
+ * @brief Establish a tunnel to a remote system
+ *
+ * Creates a "hicn tunnel" to a remote system. There must already be a local
+ * HICN listener for the local side of the connection.
+ *
+ */
+
+#ifndef hicnTunnel_h
+#define hicnTunnel_h
+
+#include <src/core/forwarder.h>
+#include <src/io/ioOperations.h>
+#include <src/io/listener.h>
+#include <src/utils/address.h>
+
+/**
+ * Establishes a connection to a remote system over HICN
+ *
+ * The remoteAddress must be of the same type (i.e. v4 or v6) as the
+ * localAddress. There must be an existing HICN listener on the local address.
+ * If either of these are not true, will return NULL.
+ *
+ * The connection will go in the table immediately, and will be in the "up"
+ * state.
+ *
+ * @param [in] an allocated hicn-light Forwarder
+ * @param [in] localAddress The local IP address and port to use for the
+ * connection
+ * @param [in] remote Address the remote IP address for the connection, must
+ * include a destination port.
+ *
+ * @retval non-null An allocated Io Operations structure for the connection
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+IoOperations *hicnTunnel_Create(Forwarder *forwarder,
+ const Address *localAddress,
+ const Address *remoteAddress);
+
+IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder,
+ ListenerOps *localListener,
+ const Address *remoteAddress);
+
+#endif // hicnTunnel_h
diff --git a/hicn-light/src/io/ioOperations.c b/hicn-light/src/io/ioOperations.c
new file mode 100755
index 000000000..bbc8cec91
--- /dev/null
+++ b/hicn-light/src/io/ioOperations.c
@@ -0,0 +1,63 @@
+/*
+ * 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 <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <src/io/ioOperations.h>
+#include <stdio.h>
+
+void *ioOperations_GetClosure(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ return ops->closure;
+}
+
+bool ioOperations_Send(IoOperations *ops, const Address *nexthop,
+ Message *message) {
+ return ops->send(ops, nexthop, message);
+}
+
+const Address *ioOperations_GetRemoteAddress(const IoOperations *ops) {
+ return ops->getRemoteAddress(ops);
+}
+
+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); }
+
+unsigned ioOperations_GetConnectionId(const IoOperations *ops) {
+ return ops->getConnectionId(ops);
+}
+
+void ioOperations_Release(IoOperations **opsPtr) {
+ IoOperations *ops = *opsPtr;
+ ops->destroy(opsPtr);
+}
+
+const void *ioOperations_Class(const IoOperations *ops) {
+ return ops->class(ops);
+}
+
+list_connections_type ioOperations_GetConnectionType(const IoOperations *ops) {
+ return ops->getConnectionType(ops);
+}
+
+Ticks ioOperations_SendProbe(IoOperations *ops, unsigned probeType,
+ uint8_t *message) {
+ return ops->sendProbe(ops, probeType, message);
+}
diff --git a/hicn-light/src/io/ioOperations.h b/hicn-light/src/io/ioOperations.h
new file mode 100755
index 000000000..dee66030d
--- /dev/null
+++ b/hicn-light/src/io/ioOperations.h
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ */
+
+/**
+ * Defines the interface all connections use to communicate with the forwarder.
+ *
+ * @code
+ *
+ * static IoOperations _template = {
+ * .closure = NULL,
+ * .send = &_etherConnection_Send,
+ * .getRemoteAddress = &_etherConnection_GetRemoteAddress,
+ * .getAddressPair = &_etherConnection_GetAddressPair,
+ * .getConnectionId = &_etherConnection_GetConnectionId,
+ * .isUp = &_etherConnection_IsUp,
+ * .isLocal = &_etherConnection_IsLocal,
+ * .destroy = &_etherConnection_DestroyOperations,
+ * .class = &_etherConnection_Class,
+ * .getConnectionType = &_etherConnection_getConnectionType
+ * };
+ *
+ * IoOperations *
+ * etherConnection_Create(Forwarder *forwarder, GenericEther *ether,
+ * AddressPair *pair)
+ * {
+ * _EtherState *etherConnState = parcMemory_Allocate(sizeof(_EtherState));
+ * // Fill in etherConnState with instance variables
+ *
+ * IoOperations *io_ops = parcMemory_Allocate(sizeof(IoOperations));
+ * memcpy(io_ops, &_template, sizeof(IoOperations));
+ * io_ops->closure = etherConnState;
+ * // Add to connection table, send missives about connection state
+ *
+ * return op_ops;
+ * }
+ * @endcode
+ *
+ */
+
+/**
+ * I/O is built around a callback structure. The connection table contains an
+ * operations structure built around function pointers. These allow the
+ * connection table to be agnostic about underlying connections.
+ */
+
+#ifndef io_h
+#define io_h
+
+#include <src/core/message.h>
+#include <src/core/ticks.h>
+#include <src/io/addressPair.h>
+#include <src/utils/address.h>
+
+// packet types for probing
+#define PACKET_TYPE_PROBE_REQUEST 5
+#define PACKET_TYPE_PROBE_REPLY 6
+
+struct io_ops;
+typedef struct io_ops IoOperations;
+
+/**
+ * @typedef IoOperations
+ * @abstract The IO Operations structure abstracts an connection's properties
+ * and send() method
+ * @constant context Implementation specific opaque data, passed back on each
+ * call
+ * @constant send function pointer to send a message, does not destroy the
+ * message
+ * @constant getRemoteAddress function pointer to return the "to" address
+ * associated with the connection. Some connections might not have a specific
+ * peer, such as multicast, where its the group address.
+ * @constant isUp test if the connection is up, ready to send a message.
+ * @constant isLocal test if the connection is local to the host.
+ * @constant getConnectionId returns the hicn-light id for the connection.
+ * @constant destroy releases a refernce count on the connection and possibly
+ * destroys the connection.
+ * @constant class A unique identifier for each class that instantiates
+ * IoOperations.
+ * @constant getConnectionType Returns the type of connection (TCP, UDP, L2,
+ * etc.) of the underlying connection.
+ * @discussion <#Discussion#>
+ */
+struct io_ops {
+ void *closure;
+ bool (*send)(IoOperations *ops, const Address *nexthop, Message *message);
+ const Address *(*getRemoteAddress)(const IoOperations *ops);
+ const AddressPair *(*getAddressPair)(const IoOperations *ops);
+ bool (*isUp)(const IoOperations *ops);
+ bool (*isLocal)(const IoOperations *ops);
+ unsigned (*getConnectionId)(const IoOperations *ops);
+ void (*destroy)(IoOperations **opsPtr);
+ const void *(*class)(const IoOperations *ops);
+ list_connections_type (*getConnectionType)(const IoOperations *ops);
+ Ticks (*sendProbe)(IoOperations *ops, unsigned probeType, uint8_t *message);
+};
+
+/**
+ * Returns the closure of the interface
+ *
+ * The creator of the closure sets this parameter to store its state.
+ *
+ * @param [in] ops A concrete instance of the interface
+ *
+ * @return The value set by the concrete instance of the interface.
+ *
+ * Example:
+ * @clode
+ * {
+
+ * }
+ * @endcode
+ */
+void *ioOperations_GetClosure(const IoOperations *ops);
+
+/**
+ * Release all memory related to the interface and implementation
+ *
+ * This function must release all referenced memory in the concrete
+ * implementation and memory related to the IoOperations. It should NULL the
+ * input parameter.
+ *
+ * @param [in,out] opsPtr Pointer to interface. Will be NULLed.
+ *
+ * Example:
+ * @code
+ *
+ * static void
+ * _etherConnection_InternalRelease(_EtherState *etherConnState)
+ * {
+ * // release internal state of _EtherState
+ * }
+ *
+ * static void
+ * _etherConnection_Release(IoOperations **opsPtr)
+ * {
+ * IoOperations *ops = *opsPtr;
+ *
+ * _EtherState *etherConnState = (_EtherState *)
+ * ioOperations_GetClosure(ops);
+ * _etherConnection_InternalRelease(etherConnState);
+ *
+ * parcMemory_Deallocate((void **) &ops);
+ * }
+ *
+ * IoOperations *
+ * etherConnection_Create(Forwarder *forwarder, GenericEther *ether,
+ * AddressPair *pair)
+ * {
+ * size_t allocationSize = sizeof(_EtherState) + sizeof(IoOperations);
+ * IoOperations *ops = parcMemory_AllocateAndClear(allocationSize);
+ * if (ops) {
+ * // fill in other interface functions
+ * ops->destroy = &_etherConnection_Release;
+ * ops->closure = (uint8_t *) ops + sizeof(IoOperations);
+ *
+ * _EtherState *etherConnState = ioOperations_GetClosure(ops);
+ * // fill in Ethernet state
+ * }
+ * return ops;
+ * }
+ * @endcode
+ */
+void ioOperations_Release(IoOperations **opsPtr);
+
+/**
+ * Sends the specified Message out this connection
+ *
+ * The the implementation of send may queue the message, it must acquire a
+ * reference to it.
+ *
+ * @param [in] ops The connection implementation.
+ * @param [in] nexthop On multiple access networks, this parameter might be
+ * used, usually NULL.
+ * @param [in] message The message to send. If the message will be queued, it
+ * will be acquired.
+ *
+ * @return true The message was sent or queued
+ * @retrun false An error occured and the message will not be sent or queued
+ *
+ * Example:
+ * @code
+ * {
+ * if (ioOperations_IsUp(conn->ops)) {
+ * return ioOperations_Send(conn->ops, NULL, message);
+ * }
+ * }
+ * @endcode
+ */
+bool ioOperations_Send(IoOperations *ops, const Address *nexthop,
+ Message *message);
+
+/**
+ * A connection is made up of a local and a remote address. This function
+ * returns the remote address.
+ *
+ * Represents the destination endpoint of the communication.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return non-null The remote address
+ * @return null The connection does not have a remote address
+ *
+ * Example:
+ * @code
+ * {
+ * Address *local = addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03,
+ * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t [])
+ * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair =
+ * addressPair_Create(local, remote); IoOperations *ops =
+ * etherConnection_Create(forwarder, ether, pair);
+ *
+ * const Address *test = ioOperations_GetRemoteAddress(ops);
+ * parcAssertTrue(addressEquals(test, remote), "Wrong remote address");
+ * ioOperations_Release(&ops);
+ * addressPair_Release(&pair);
+ * addressDestroy(&local);
+ * addressDestroy(&remote);
+ * }
+ * @endcode
+ */
+const Address *ioOperations_GetRemoteAddress(const IoOperations *ops);
+
+/**
+ * A connection is made up of a local and a remote address. This function
+ * returns the address pair.
+ *
+ * Represents the destination endpoint of the communication.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return non-null The address pair
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ * Address *local = addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03,
+ * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t [])
+ * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair =
+ * addressPair_Create(local, remote); IoOperations *ops =
+ * etherConnection_Create(forwarder, ether, pair);
+ *
+ * const AddressPair *test = ioOperations_GetAddressPair(ops);
+ * parcAssertTrue(addressPair(test, pair), "Wrong address pair");
+ * ioOperations_Release(&ops);
+ * addressPair_Release(&pair);
+ * addressDestroy(&local);
+ * addressDestroy(&remote);
+ * }
+ * @endcode
+ */
+const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops);
+
+/**
+ * Returns true if the underlying connection is in operation
+ *
+ * An UP connection is able to send and receive packets. If a subsystem needs to
+ * take actions when a connection goes UP or DOWN, it should subscribe as a
+ * Missive listener.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return true The connection is UP
+ * @return false The connection is not UP
+ *
+ * Example:
+ * @code
+ * {
+ * if (ioOperations_IsUp(conn->ops)) {
+ * return ioOperations_Send(conn->ops, NULL, message);
+ * }
+ * }
+ * @endcode
+ */
+bool ioOperations_IsUp(const IoOperations *ops);
+
+/**
+ * If the remote address is local to this system, returns true
+ *
+ * Will return true if an INET or INET6 connection is on localhost. Will return
+ * true for AF_UNIX. An Ethernet connection is not local.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return true The remote address is local to the system
+ * @return false The remote address is not local
+ *
+ * Example:
+ * @code
+ * {
+ * // Is the ingress connection remote? If so check for non-zero and
+ * decrement if (!ioOperations(ingressConnectionOps) { uint8_t hoplimit =
+ * message_GetHopLimit(interestMessage); if (hoplimit == 0) {
+ * // error
+ * } else {
+ * hoplimit--;
+ * }
+ * // take actions on hoplimit
+ * }
+ * }
+ * @endcode
+ */
+bool ioOperations_IsLocal(const IoOperations *ops);
+
+/**
+ * Returns the connection ID represented by this IoOperations in the
+ * ConnectionTable.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return number The connection ID in the connection table.
+ *
+ * Example:
+ * @code
+ * {
+ * unsigned id = ioOperations_GetConnectionId(ingressIoOps);
+ * const Connection *conn =
+ * connectionTable_FindById(forwarder->connectionTable, id);
+ * }
+ * @endcode
+ */
+unsigned ioOperations_GetConnectionId(const IoOperations *ops);
+
+/**
+ * A pointer that represents the class of the connection
+ *
+ * Each concrete implementation has a class pointer that is unique to the
+ * implementation (not instance). Each implementation is free to choose how to
+ * determine the value, so long as it is unique on the system. This is a
+ * system-local value.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return non-null A pointer value unique to the implementation (not instance).
+ *
+ * Example:
+ * @code
+ * bool
+ * etherConnection_IsInstanceOf(const Connection *conn)
+ * {
+ * bool result = false;
+ * if (conn != NULL) {
+ * IoOperations *ops = connection_GetIoOperations(conn);
+ * const void *class = ioOperations_Class(ops);
+ * result = (class == _etherConnection_Class(ops));
+ * }
+ * return result;
+ * }
+ * @endcode
+ */
+const void *ioOperations_Class(const IoOperations *ops);
+
+/**
+ * Returns the transport type of the connection (TCP, UDP, L2, etc.).
+ *
+ * TCP and AF_UNIX are both stream connections and will both return
+ * "Connection_TCP". Ethernet will return "Connection_L2".
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return Connection_TCP A TCP4, TCP6, or AF_UNIX connection
+ * @return Connection_UDP A UDP4 or UDP6 connection
+ * @return Connection_L2 An Ethernet connection
+ *
+ * Example:
+ * @code
+ * {
+ * ConnectionType type =
+ * ioOperations_GetConnectionType(connection_GetIoOperations(connection));
+ * Connection *Conn =
+ * Connection_Create(connection_GetConnectionId(connection), localAddress,
+ * remoteAddress, type);
+ * }
+ * @endcode
+ */
+list_connections_type ioOperations_GetConnectionType(const IoOperations *ops);
+
+Ticks ioOperations_SendProbe(IoOperations *ops, unsigned probeType,
+ uint8_t *message);
+#endif // io_h
diff --git a/hicn-light/src/io/listener.h b/hicn-light/src/io/listener.h
new file mode 100755
index 000000000..ffbb513fa
--- /dev/null
+++ b/hicn-light/src/io/listener.h
@@ -0,0 +1,105 @@
+/*
+ * 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 listener.h
+ * @brief Provides the function abstraction of all Listeners.
+ *
+ * A listener accepts in coming packets. A Stream listener will accept the
+ * connection then pass it off to the {@link StreamConnection} class. A
+ * datagram listener will have to have its own way to multiplex packets.
+ *
+ */
+
+#ifndef listener_h
+#define listener_h
+
+#include <src/utils/address.h>
+
+struct listener_ops;
+typedef struct listener_ops ListenerOps;
+
+typedef enum {
+ ENCAP_TCP, /**< TCP encapsulation type */
+ ENCAP_UDP, /**< UDP encapsulation type */
+ ENCAP_ETHER, /**< Ethernet encapsulation type */
+ ENCAP_LOCAL, /**< A connection to a local protocol stack */
+ ENCAP_HICN
+} EncapType;
+
+struct listener_ops {
+ /**
+ * A user-defined parameter
+ */
+ void *context;
+
+ /**
+ * Called to destroy the Listener.
+ *
+ * @param [in] listenerOpsPtr Double pointer to this structure
+ */
+ void (*destroy)(ListenerOps **listenerOpsPtr);
+
+ /**
+ * Returns the interface index of the listener.
+ *
+ * @param [in] ops Pointer to this structure
+ *
+ * @return the interface index of the listener
+ */
+ unsigned (*getInterfaceIndex)(const ListenerOps *ops);
+
+ /**
+ * Returns the address pair that defines the listener (local, remote)
+ *
+ * @param [in] ops Pointer to this structure
+ *
+ * @return the (local, remote) pair of addresses
+ */
+ const Address *(*getListenAddress)(const ListenerOps *ops);
+
+ /**
+ * Returns the encapsulation type of the listener (e.g. TCP, UDP, HICN)
+ *
+ * @param [in] ops Pointer to this structure
+ *
+ * @return the listener encapsulation type
+ */
+ EncapType (*getEncapType)(const ListenerOps *ops);
+
+ /**
+ * Returns the underlying socket associated with the listener
+ *
+ * Not all listeners are capable of returning a useful socket. In those
+ * cases, this function pointer is NULL.
+ *
+ * TCP does not support this operation (function is NULL). UDP returns its
+ * local socket.
+ *
+ * The caller should never close this socket, the listener will do that when
+ * its destroy method is called.
+ *
+ * @param [in] ops Pointer to this structure
+ *
+ * @retval integer The socket descriptor
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ int (*getSocket)(const ListenerOps *ops);
+};
+#endif // listener_h
diff --git a/hicn-light/src/io/listenerSet.c b/hicn-light/src/io/listenerSet.c
new file mode 100755
index 000000000..a890cd5b8
--- /dev/null
+++ b/hicn-light/src/io/listenerSet.c
@@ -0,0 +1,132 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/io/listenerSet.h>
+
+struct listener_set {
+ PARCArrayList *listOfListeners;
+};
+
+static void listenerSet_DestroyListenerOps(void **opsPtr) {
+ ListenerOps *ops = *((ListenerOps **)opsPtr);
+ ops->destroy(&ops);
+}
+
+ListenerSet *listenerSet_Create() {
+ ListenerSet *set = parcMemory_AllocateAndClear(sizeof(ListenerSet));
+ parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListenerSet));
+ set->listOfListeners = parcArrayList_Create(listenerSet_DestroyListenerOps);
+
+ return set;
+}
+
+void listenerSet_Destroy(ListenerSet **setPtr) {
+ parcAssertNotNull(setPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer");
+
+ ListenerSet *set = *setPtr;
+ parcArrayList_Destroy(&set->listOfListeners);
+ parcMemory_Deallocate((void **)&set);
+ *setPtr = NULL;
+}
+
+/**
+ * @function listenerSet_Add
+ * @abstract Adds the listener to the set
+ * @discussion
+ * Unique set based on pair (EncapType, localAddress)
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+bool listenerSet_Add(ListenerSet *set, ListenerOps *ops) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+
+ int opsEncap = ops->getEncapType(ops);
+ const Address *opsAddress = ops->getListenAddress(ops);
+
+ // make sure its not in the set
+ size_t length = parcArrayList_Size(set->listOfListeners);
+ for (size_t i = 0; i < length; i++) {
+ ListenerOps *entry = parcArrayList_Get(set->listOfListeners, i);
+
+ int entryEncap = entry->getEncapType(entry);
+ const Address *entryAddress = entry->getListenAddress(entry);
+
+ if (opsEncap == entryEncap && addressEquals(opsAddress, entryAddress)) {
+ // duplicate
+ return false;
+ }
+ }
+
+ parcArrayList_Add(set->listOfListeners, ops);
+ return true;
+}
+
+size_t listenerSet_Length(const ListenerSet *set) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ return parcArrayList_Size(set->listOfListeners);
+}
+
+/**
+ * Returns the listener at the given index
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] index The index position (0 <= index < listenerSet_Count)
+ *
+ * @retval non-null The listener at index
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ return parcArrayList_Get(set->listOfListeners, index);
+}
+
+ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType,
+ const Address *localAddress) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ parcAssertNotNull(localAddress, "Parameter localAddress 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->getEncapType(ops) == encapType) {
+ if (addressEquals(localAddress, ops->getListenAddress(ops))) {
+ match = ops;
+ }
+ }
+ }
+
+ return match;
+}
diff --git a/hicn-light/src/io/listenerSet.h b/hicn-light/src/io/listenerSet.h
new file mode 100755
index 000000000..671e68479
--- /dev/null
+++ b/hicn-light/src/io/listenerSet.h
@@ -0,0 +1,137 @@
+/*
+ * 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 listenerSet.h
+ * @brief A listener set is unique on (EncapType, localAddress)
+ *
+ * Keeps track of all the running listeners. The set is unique on the
+ * encapsulation type and the local address. For example, with TCP
+ * encapsulation and local address 127.0.0.1 or Ethernet encapsulation and MAC
+ * address 00:11:22:33:44:55.
+ *
+ * NOTE: This does not allow multiple EtherType on the same interface because
+ * the Address for a LINK address does not include an EtherType.
+ *
+ */
+
+#ifndef listenerSet_h
+#define listenerSet_h
+
+#include <src/io/listener.h>
+
+struct listener_set;
+typedef struct listener_set ListenerSet;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ListenerSet *listenerSet_Create(void);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void listenerSet_Destroy(ListenerSet **setPtr);
+
+/**
+ * @function listenerSet_Add
+ * @abstract Adds the listener to the set
+ * @discussion
+ * Unique set based on pair (EncapType, localAddress).
+ * Takes ownership of the ops memory if added.
+ *
+ * @param <#param1#>
+ * @return true if added, false if not
+ */
+bool listenerSet_Add(ListenerSet *set, ListenerOps *ops);
+
+/**
+ * The number of listeners in the set
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t listenerSet_Length(const ListenerSet *set);
+size_t listenerSet_Length(const ListenerSet *set);
+
+/**
+ * Returns the listener at the given index
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] index The index position (0 <= index < listenerSet_Lenght)
+ *
+ * @retval non-null The listener at index
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index);
+
+/**
+ * Looks up a listener by its key (EncapType, LocalAddress)
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] encapType the listener type
+ * @param [in] localAddress The local bind address (e.g. MAC address or TCP
+ * socket)
+ *
+ * @retval non-null The listener matching the query
+ * @retval null Does not exist
+ *
+ * Example:
+ * @code
+ *
+ * @endcode
+ */
+ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType,
+ const Address *localAddress);
+#endif
diff --git a/hicn-light/src/io/streamConnection.c b/hicn-light/src/io/streamConnection.c
new file mode 100755
index 000000000..fedbb157a
--- /dev/null
+++ b/hicn-light/src/io/streamConnection.c
@@ -0,0 +1,714 @@
+/*
+ * 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.
+ */
+
+/**
+ * Common activity for STREAM based listeners.
+ */
+
+#include <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+#include <src/io/streamConnection.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/messageHandler.h>
+
+#include <src/utils/commands.h>
+
+#include <hicn/hicn.h>
+// 128 KB output queue
+#define OUTPUT_QUEUE_BYTES (128 * 1024)
+
+static void _conn_readcb(PARCEventQueue *bufferEventVector, PARCEventType type,
+ void *ioOpsVoid);
+
+static void _conn_eventcb(PARCEventQueue *bufferEventVector,
+ PARCEventQueueEventType events, void *ioOpsVoid);
+
+typedef struct stream_state {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ int fd;
+
+ AddressPair *addressPair;
+ PARCEventQueue *bufferEventVector;
+
+ bool isLocal;
+ bool isUp;
+ bool isClosed;
+ unsigned id;
+
+ size_t nextMessageLength;
+} _StreamState;
+
+// Prototypes
+static bool _streamConnection_Send(IoOperations *ops, const Address *nexthop,
+ Message *message);
+static const Address *_streamConnection_GetRemoteAddress(
+ const IoOperations *ops);
+static const AddressPair *_streamConnection_GetAddressPair(
+ const IoOperations *ops);
+static unsigned _streamConnection_GetConnectionId(const IoOperations *ops);
+static bool _streamConnection_IsUp(const IoOperations *ops);
+static bool _streamConnection_IsLocal(const IoOperations *ops);
+static void _streamConnection_DestroyOperations(IoOperations **opsPtr);
+
+static void _setConnectionState(_StreamState *stream, bool isUp);
+static list_connections_type _streamConnection_GetConnectionType(
+ const IoOperations *ops);
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+ uint8_t *message);
+
+// REMINDER: when a new_command is added, the following array has to be updated
+// with the sizeof(new_command). It allows to allocate the buffer for receiving
+// the payload of the CONTROLLER REQUEST after the header has beed read. Each
+// command identifier (typedef enum command_id) corresponds to a position in the
+// following array.
+static int payloadLengthDaemon[LAST_COMMAND_VALUE] = {
+ sizeof(add_listener_command),
+ sizeof(add_connection_command),
+ 0, // list connections: payload always 0 when get controller request
+ sizeof(add_route_command),
+ 0, // list routes: payload always 0 when get controller request
+ sizeof(remove_connection_command),
+ sizeof(remove_route_command),
+ sizeof(cache_store_command),
+ sizeof(cache_serve_command),
+ 0, // cache clear
+ sizeof(set_strategy_command),
+ sizeof(set_wldr_command),
+ sizeof(add_punting_command),
+ 0, // list listeners: payload always 0 when get controller request
+ sizeof(mapme_activator_command),
+ sizeof(mapme_activator_command),
+ sizeof(mapme_timing_command),
+ sizeof(mapme_timing_command)};
+
+/*
+ * This assigns a unique pointer to the void * which we use
+ * as a GUID for this class.
+ */
+static const void *_ioOperationsGuid = __FILE__;
+
+/*
+ * Return our GUID
+ */
+static const void *_streamConnection_Class(const IoOperations *ops) {
+ return _ioOperationsGuid;
+}
+
+static IoOperations _template = {
+ .closure = NULL,
+ .send = &_streamConnection_Send,
+ .getRemoteAddress = &_streamConnection_GetRemoteAddress,
+ .getAddressPair = &_streamConnection_GetAddressPair,
+ .getConnectionId = &_streamConnection_GetConnectionId,
+ .isUp = &_streamConnection_IsUp,
+ .isLocal = &_streamConnection_IsLocal,
+ .destroy = &_streamConnection_DestroyOperations,
+ .class = &_streamConnection_Class,
+ .getConnectionType = &_streamConnection_GetConnectionType,
+ .sendProbe = &_sendProbe,
+};
+
+IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd,
+ AddressPair *pair,
+ bool isLocal) {
+ _StreamState *stream = parcMemory_AllocateAndClear(sizeof(_StreamState));
+ parcAssertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(_StreamState));
+
+ Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder);
+ PARCEventScheduler *eventBase = dispatcher_GetEventScheduler(dispatcher);
+ stream->bufferEventVector = parcEventQueue_Create(
+ eventBase, fd,
+ PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks);
+
+ stream->forwarder = forwarder;
+ stream->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ stream->fd = fd;
+ stream->id = forwarder_GetNextConnectionId(forwarder);
+ stream->addressPair = pair;
+ stream->isClosed = false;
+
+ // allocate a connection
+ IoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations));
+ parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(IoOperations));
+ memcpy(io_ops, &_template, sizeof(IoOperations));
+ io_ops->closure = stream;
+ stream->isLocal = isLocal;
+
+ parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL,
+ _conn_eventcb, (void *)io_ops);
+ parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read);
+
+ messenger_Send(forwarder_GetMessenger(stream->forwarder),
+ missive_Create(MissiveType_ConnectionCreate, stream->id));
+
+ // As we are acceting a connection, we begin in the UP state
+ _setConnectionState(stream, true);
+
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+ PARCLogLevel_Debug)) {
+ char *pair_str = addressPair_ToString(pair);
+ logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "StreamConnection %p accept for address pair %s", (void *)stream,
+ pair_str);
+ free(pair_str);
+ }
+
+ return io_ops;
+}
+
+IoOperations *streamConnection_OpenConnection(Forwarder *forwarder,
+ AddressPair *pair, bool isLocal) {
+ parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+ parcAssertNotNull(pair, "Parameter pair must be non-null");
+
+ // if there's an error on the bind or connect, will return NULL
+ PARCEventQueue *bufferEventVector =
+ dispatcher_StreamBufferConnect(forwarder_GetDispatcher(forwarder), pair);
+ if (bufferEventVector == NULL) {
+ // error opening connection
+ return NULL;
+ }
+
+ _StreamState *stream = parcMemory_AllocateAndClear(sizeof(_StreamState));
+ parcAssertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(_StreamState));
+
+ stream->forwarder = forwarder;
+ stream->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ stream->fd = parcEventQueue_GetFileDescriptor(bufferEventVector);
+ stream->bufferEventVector = bufferEventVector;
+ stream->id = forwarder_GetNextConnectionId(forwarder);
+ stream->addressPair = pair;
+ stream->isClosed = false;
+
+ // allocate a connection
+ IoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations));
+ parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(IoOperations));
+ memcpy(io_ops, &_template, sizeof(IoOperations));
+ io_ops->closure = stream;
+ stream->isLocal = isLocal;
+
+ parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL,
+ _conn_eventcb, (void *)io_ops);
+ parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read);
+
+ // we start in DOWN state, until remote side answers
+ messenger_Send(forwarder_GetMessenger(stream->forwarder),
+ missive_Create(MissiveType_ConnectionCreate, stream->id));
+ _setConnectionState(stream, false);
+
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO, PARCLogLevel_Info)) {
+ char *pair_str = addressPair_ToString(pair);
+ logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__,
+ "StreamConnection %p connect for address pair %s",
+ (void *)stream, pair_str);
+ free(pair_str);
+ }
+
+ return io_ops;
+}
+
+static void _streamConnection_DestroyOperations(IoOperations **opsPtr) {
+ parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer");
+ parcAssertNotNull(*opsPtr,
+ "Parameter opsPtr must dereference to non-null pointer");
+
+ IoOperations *ops = *opsPtr;
+ parcAssertNotNull(ioOperations_GetClosure(ops),
+ "ops->context must not be null");
+
+ _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops);
+
+ parcEventQueue_Destroy(&stream->bufferEventVector);
+
+ addressPair_Release(&stream->addressPair);
+
+ if (!stream->isClosed) {
+ stream->isClosed = true;
+ messenger_Send(forwarder_GetMessenger(stream->forwarder),
+ missive_Create(MissiveType_ConnectionClosed, stream->id));
+ }
+
+ messenger_Send(forwarder_GetMessenger(stream->forwarder),
+ missive_Create(MissiveType_ConnectionDestroyed, stream->id));
+
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO, PARCLogLevel_Info)) {
+ logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__,
+ "StreamConnection %p destroyed", (void *)stream);
+ }
+
+ logger_Release(&stream->logger);
+ parcMemory_Deallocate((void **)&stream);
+ parcMemory_Deallocate((void **)&ops);
+
+ *opsPtr = NULL;
+}
+
+static bool _streamConnection_IsUp(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _StreamState *stream =
+ (const _StreamState *)ioOperations_GetClosure(ops);
+ return stream->isUp;
+}
+
+static bool _streamConnection_IsLocal(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _StreamState *stream =
+ (const _StreamState *)ioOperations_GetClosure(ops);
+ return stream->isLocal;
+}
+
+static const Address *_streamConnection_GetRemoteAddress(
+ const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _StreamState *stream =
+ (const _StreamState *)ioOperations_GetClosure(ops);
+ return addressPair_GetRemote(stream->addressPair);
+}
+
+static const AddressPair *_streamConnection_GetAddressPair(
+ const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _StreamState *stream =
+ (const _StreamState *)ioOperations_GetClosure(ops);
+ return stream->addressPair;
+}
+
+static unsigned _streamConnection_GetConnectionId(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _StreamState *stream =
+ (const _StreamState *)ioOperations_GetClosure(ops);
+ return stream->id;
+}
+
+bool streamState_SendCommandResponse(IoOperations *ops,
+ struct iovec *response) {
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ parcAssertNotNull(response, "Parameter message must be non-null");
+ _StreamState *conn = (_StreamState *)ioOperations_GetClosure(ops);
+
+ bool success = false;
+ if (conn->isUp) {
+ PARCEventBuffer *buffer =
+ parcEventBuffer_GetQueueBufferOutput(conn->bufferEventVector);
+ size_t buffer_backlog = parcEventBuffer_GetLength(buffer);
+ parcEventBuffer_Destroy(&buffer);
+
+ if (buffer_backlog < OUTPUT_QUEUE_BYTES) {
+ if (logger_IsLoggable(conn->logger, LoggerFacility_IO,
+ PARCLogLevel_Debug)) {
+ logger_Log(
+ conn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "connid %u Writing %zu bytes to buffer with backlog %zu bytes",
+ conn->id,
+ (response[0].iov_len +
+ response[1].iov_len), // NEW: take total lenght
+ buffer_backlog);
+ }
+
+ // NEW: write directly ino the parcEventQueue without passing through
+ // message
+ int failure =
+ parcEventQueue_Write(conn->bufferEventVector, response[0].iov_base,
+ response[0].iov_len) +
+ parcEventQueue_Write(conn->bufferEventVector, response[1].iov_base,
+ response[1].iov_len);
+
+ if (failure == 0) {
+ success = true;
+ }
+ } else {
+ if (logger_IsLoggable(conn->logger, LoggerFacility_IO,
+ PARCLogLevel_Warning)) {
+ logger_Log(conn->logger, LoggerFacility_IO, PARCLogLevel_Warning,
+ __func__,
+ "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE",
+ conn->id, buffer_backlog);
+ }
+ }
+ } else {
+ if (logger_IsLoggable(conn->logger, LoggerFacility_IO,
+ PARCLogLevel_Error)) {
+ logger_Log(
+ conn->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "connid %u tried to send to down connection (isUp %d isClosed %d)",
+ conn->id, conn->isUp, conn->isClosed);
+ }
+ }
+
+ return success;
+}
+
+/**
+ * @function streamConnection_Send
+ * @abstract Non-destructive send of the message.
+ * @discussion
+ * Send uses message_CopyToStreamBuffer, which is a non-destructive write.
+ * The send may fail if there's no buffer space in the output queue.
+ *
+ * @param dummy is ignored. A stream has only one peer.
+ * @return <#return#>
+ */
+static bool _streamConnection_Send(IoOperations *ops, const Address *dummy,
+ Message *message) {
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops);
+
+ bool success = false;
+ if (stream->isUp) {
+ PARCEventBuffer *buffer =
+ parcEventBuffer_GetQueueBufferOutput(stream->bufferEventVector);
+ size_t buffer_backlog = parcEventBuffer_GetLength(buffer);
+ parcEventBuffer_Destroy(&buffer);
+
+ if (buffer_backlog < OUTPUT_QUEUE_BYTES) {
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+ PARCLogLevel_Debug)) {
+ logger_Log(
+ stream->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "connid %u Writing %zu bytes to buffer with backlog %zu bytes",
+ stream->id, message_Length(message), buffer_backlog);
+ }
+
+ int failure = message_Write(stream->bufferEventVector, message);
+ if (failure == 0) {
+ success = true;
+ }
+ } else {
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+ PARCLogLevel_Warning)) {
+ logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Warning,
+ __func__,
+ "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE",
+ stream->id, buffer_backlog);
+ }
+ }
+ } else {
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+ PARCLogLevel_Error)) {
+ logger_Log(
+ stream->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "connid %u tried to send to down connection (isUp %d isClosed %d)",
+ stream->id, stream->isUp, stream->isClosed);
+ }
+ }
+
+ return success;
+}
+
+list_connections_type _streamConnection_GetConnectionType(
+ const IoOperations *ops) {
+ return CONN_TCP;
+}
+
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+ uint8_t *message) {
+ // we don't need to implemet this here, it is a local connection
+ return 0;
+}
+
+// =================================================================
+// the actual I/O functions
+
+int _isACommand(PARCEventBuffer *input) {
+ size_t bytesAvailable = parcEventBuffer_GetLength(input);
+ parcAssertTrue(bytesAvailable >= sizeof(header_control_message),
+ "Called with too short an input: %zu", bytesAvailable);
+
+ uint8_t *msg = parcEventBuffer_Pullup(input, bytesAvailable);
+ // read first byte of the header
+
+ // first byte: must be a REQUEST_LIGHT
+ if (msg[0] != 100) {
+ return LAST_COMMAND_VALUE;
+ }
+
+ // second byte: must be a command_id
+ if (msg[1] < 0 || msg[1] >= LAST_COMMAND_VALUE) {
+ return LAST_COMMAND_VALUE;
+ }
+
+ return msg[1];
+}
+
+PARCEventBuffer *_tryReadControlMessage(_StreamState *stream,
+ PARCEventBuffer *input,
+ command_id command,
+ struct iovec **request) {
+ size_t bytesAvailable = parcEventBuffer_GetLength(input);
+
+ if (stream->nextMessageLength == 0) {
+ stream->nextMessageLength =
+ sizeof(header_control_message) +
+ payloadLengthDaemon[command]; // consider the whole packet.
+ }
+
+ if (bytesAvailable >= stream->nextMessageLength) {
+ PARCEventBuffer *message = parcEventBuffer_Create();
+ int bytesRead = parcEventBuffer_ReadIntoBuffer(input, message,
+ stream->nextMessageLength);
+ parcAssertTrue(bytesRead == stream->nextMessageLength,
+ "Partial read, expected %zu got %d",
+ stream->nextMessageLength, bytesRead);
+
+ uint8_t *control =
+ parcEventBuffer_Pullup(message, stream->nextMessageLength);
+ if (!(*request = (struct iovec *)parcMemory_AllocateAndClear(
+ sizeof(struct iovec) * 2))) {
+ return NULL;
+ }
+ (*request)[0].iov_base = control; // header
+ (*request)[0].iov_len = sizeof(header_control_message);
+ if (payloadLengthDaemon[command] > 0) {
+ (*request)[1].iov_base =
+ control + sizeof(header_control_message); // payload
+ } else {
+ (*request)[1].iov_base = NULL;
+ }
+ (*request)[1].iov_len = payloadLengthDaemon[command];
+ // now reset message length for next packet
+
+ stream->nextMessageLength = 0;
+
+ return message;
+ }
+
+ return NULL;
+}
+
+static bool _isAnHIcnPacket(PARCEventBuffer *input) {
+ size_t bytesAvailable = parcEventBuffer_GetLength(input);
+ parcAssertTrue(bytesAvailable >= sizeof(header_control_message),
+ "Called with too short an input: %zu", bytesAvailable);
+
+ uint8_t *fh = parcEventBuffer_Pullup(input, sizeof(header_control_message));
+ return messageHandler_IsValidHIcnPacket(fh);
+}
+
+static Message *_readMessage(_StreamState *stream, Ticks time,
+ PARCEventBuffer *input) {
+ Message *message = message_CreateFromEventBuffer(
+ input, stream->nextMessageLength, stream->id, time, stream->logger);
+
+ return message;
+}
+
+static void _startNewMessage(_StreamState *stream, PARCEventBuffer *input,
+ size_t inputBytesAvailable) {
+ parcAssertTrue(stream->nextMessageLength == 0,
+ "Invalid state, nextMessageLength not zero: %zu",
+ stream->nextMessageLength);
+ parcAssertTrue(inputBytesAvailable >= sizeof(header_control_message),
+ "read_length not a whole fixed header!: %zd",
+ inputBytesAvailable);
+
+ // this linearizes the first messageHandler_GetIPv6HeaderLength() bytes of the
+ // input buffer's iovecs and returns a pointer to it.
+ uint8_t *fh = parcEventBuffer_Pullup(input, sizeof(header_control_message));
+
+ // Calculate the total message size based on the fixed header
+ stream->nextMessageLength = messageHandler_GetTotalPacketLength(fh);
+}
+
+static Message *_tryReadMessage(PARCEventBuffer *input, _StreamState *stream) {
+ size_t bytesAvailable = parcEventBuffer_GetLength(input);
+ parcAssertTrue(bytesAvailable >= sizeof(header_control_message),
+ "Called with too short an input: %zu", bytesAvailable);
+
+ if (stream->nextMessageLength == 0) {
+ _startNewMessage(stream, input, bytesAvailable);
+ }
+
+ // This is not an ELSE statement. We can both start a new message then
+ // check if there's enough bytes to read the whole thing.
+
+ if (bytesAvailable >= stream->nextMessageLength) {
+ Message *message =
+ _readMessage(stream, forwarder_GetTicks(stream->forwarder), input);
+
+ // now reset message length for next packet
+ stream->nextMessageLength = 0;
+
+ return message;
+ }
+
+ return NULL;
+}
+
+/**
+ * @function conn_readcb
+ * @abstract Event callback for reads
+ * @discussion
+ * Will read messages off the input. Continues reading as long as we
+ * can get a header to determine the next message length or as long as we
+ * can read a complete message.
+ *
+ * This function manipulates the read low water mark. (1) read a fixed header
+ * plus complete message, then set the low water mark to FIXED_HEADER_LEN. (2)
+ * read a fixed header, but not a complete message, then set low water mark to
+ * the total mesage length. Using the low water mark like this means the buffer
+ * event will only trigger on meaningful byte boundaries when we can get actual
+ * work done.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static void _conn_readcb(PARCEventQueue *event, PARCEventType type,
+ void *ioOpsVoid) {
+ command_id command;
+ IoOperations *ops = (IoOperations *)ioOpsVoid;
+ _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops);
+
+ PARCEventBuffer *input = parcEventBuffer_GetQueueBufferInput(event);
+
+ // drain the input buffer
+
+ // notice that we always try to read at least 8 bytes
+ // (sizeof(header_control_message)). This is enough to read the length of all
+ // 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
+ PARCEventBuffer *message =
+ _tryReadControlMessage(stream, input, command, &rx);
+ // If received correctly the whole message, send to dispatcher
+ if (message) {
+ forwarder_ReceiveCommand(stream->forwarder, command, rx, stream->id);
+ parcEventBuffer_Destroy(&message);
+ }
+
+ } else if (_isAnHIcnPacket(input)) {
+ // this is an HIcn packet (here we should distinguish between IPv4 and
+ // IPv6 tryReadMessage may set nextMessageLength
+ Message *message = _tryReadMessage(input, stream);
+
+ if (message) {
+ forwarder_Receive(stream->forwarder, message);
+ }
+
+ } else {
+ parcAssertTrue(false,
+ "(Local stream connection) malformend packet received");
+ }
+ }
+
+ if (stream->nextMessageLength == 0) {
+ // we don't have the next header, so set it to the header length
+ streamBuffer_SetWatermark(event, true, false,
+ sizeof(header_control_message), 0);
+ } else {
+ // set it to the packet length
+ streamBuffer_SetWatermark(event, true, false, stream->nextMessageLength, 0);
+ }
+ parcEventBuffer_Destroy(&input);
+}
+
+static void _setConnectionState(_StreamState *stream, bool isUp) {
+ parcAssertNotNull(stream, "Parameter stream must be non-null");
+
+ Messenger *messenger = forwarder_GetMessenger(stream->forwarder);
+
+ bool oldStateIsUp = stream->isUp;
+ stream->isUp = isUp;
+
+ if (oldStateIsUp && !isUp) {
+ // bring connection DOWN
+ Missive *missive = missive_Create(MissiveType_ConnectionDown, stream->id);
+ messenger_Send(messenger, missive);
+ return;
+ }
+
+ if (!oldStateIsUp && isUp) {
+ // bring connection UP
+ Missive *missive = missive_Create(MissiveType_ConnectionUp, stream->id);
+ messenger_Send(messenger, missive);
+ return;
+ }
+}
+
+static void _conn_eventcb(PARCEventQueue *event, PARCEventQueueEventType events,
+ void *ioOpsVoid) {
+ IoOperations *ops = (IoOperations *)ioOpsVoid;
+ _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops);
+
+ if (events & PARCEventQueueEventType_Connected) {
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+ PARCLogLevel_Info)) {
+ logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__,
+ "Connection %u is connected", stream->id);
+ }
+
+ // if the stream was closed, do not transition to an UP state
+ if (!stream->isClosed) {
+ _setConnectionState(stream, true);
+ }
+ } else if (events & PARCEventQueueEventType_EOF) {
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+ PARCLogLevel_Info)) {
+ logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__,
+ "connid %u closed.", stream->id);
+ }
+
+ parcEventQueue_Disable(stream->bufferEventVector, PARCEventType_Read);
+
+ _setConnectionState(stream, false);
+
+ if (!stream->isClosed) {
+ stream->isClosed = true;
+ // this will cause the connection manager to destroy the connection later
+ messenger_Send(forwarder_GetMessenger(stream->forwarder),
+ missive_Create(MissiveType_ConnectionClosed, stream->id));
+ }
+ } else if (events & PARCEventQueueEventType_Error) {
+ if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+ PARCLogLevel_Error)) {
+ logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Error,
+ __func__, "Got an error on the connection %u: %s", stream->id,
+ strerror(errno));
+ }
+
+ parcEventQueue_Disable(stream->bufferEventVector,
+ PARCEventType_Read | PARCEventType_Write);
+
+ _setConnectionState(stream, false);
+
+ if (!stream->isClosed) {
+ stream->isClosed = true;
+ // this will cause the connection manager to destroy the connection later
+ messenger_Send(forwarder_GetMessenger(stream->forwarder),
+ missive_Create(MissiveType_ConnectionClosed, stream->id));
+ }
+ }
+ /* None of the other events can happen here, since we haven't enabled
+ * timeouts */
+}
diff --git a/hicn-light/src/io/streamConnection.h b/hicn-light/src/io/streamConnection.h
new file mode 100755
index 000000000..8eb63a094
--- /dev/null
+++ b/hicn-light/src/io/streamConnection.h
@@ -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.
+ */
+
+/**
+ * Methods common to TCP and PF_LOCAL stream-based listeners
+ */
+
+#ifndef streamConnection_h
+#define streamConnection_h
+
+#include <src/core/forwarder.h>
+#include <src/core/messagePacketType.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+#include <src/utils/address.h>
+
+/**
+ * @function streamConnection_AcceptConnection
+ * @abstract Receive a connection from a remote peer
+ * @discussion
+ * We are the "server side" of the stream connection, so we need to accept the
+ * client connection and setup state for her.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd,
+ AddressPair *pair,
+ bool isLocal);
+
+/**
+ * @function streamConnection_OpenConnection
+ * @abstract Initiate a connection to a remote peer
+ * @discussion
+ * We are the "client side" of the stream connection. We'll create state for
+ * the peer, but it will be in the "down" state until the connection
+ * establishes.
+ *
+ * For TCP, both address pairs need to be the same address family: both INET
+ * or both INET6. The remote address must have the complete socket information
+ * (address, port). The local socket could be wildcarded or may specify down to
+ * the (address, port) pair.
+ *
+ * If the local address is IPADDR_ANY and the port is 0, then it is a normal
+ * call to "connect" that will use whatever local IP address and whatever local
+ * port for the connection. If either the address or port is set, the local
+ * socket will first be bound (via bind(2)), and then call connect().
+ *
+ * AF_UNIX is not yet supported
+ *
+ * If there's an error binding to the specified address or connecting to the
+ * remote address, will return NULL.
+ *
+ * @param pair (takes ownership of this) is the complete socket pair of
+ * (address, port) for each end, if INET or INET6.
+ * @return NULL on error, otherwise the connections IO operations.
+ */
+IoOperations *streamConnection_OpenConnection(Forwarder *forwarder,
+ AddressPair *pair, bool isLocal);
+
+bool streamState_SendCommandResponse(IoOperations *ops, struct iovec *response);
+
+#endif // streamConnection_h
diff --git a/hicn-light/src/io/tcpListener.c b/hicn-light/src/io/tcpListener.c
new file mode 100755
index 000000000..6f0477f5b
--- /dev/null
+++ b/hicn-light/src/io/tcpListener.c
@@ -0,0 +1,233 @@
+/*
+ * 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 <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <src/core/connectionTable.h>
+#include <src/core/forwarder.h>
+#include <src/io/listener.h>
+#include <src/io/streamConnection.h>
+#include <src/io/tcpListener.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/assert/parc_Assert.h>
+
+typedef struct tcp_listener {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ PARCEventSocket *listener;
+
+ Address *localAddress;
+
+ unsigned id;
+
+ // is the localAddress as 127.0.0.0 address?
+ bool isLocalAddressLocal;
+} _TcpListener;
+
+static void _tcpListener_Destroy(_TcpListener **listenerPtr);
+
+static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr);
+static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops);
+static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops);
+static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops);
+
+static ListenerOps _tcpTemplate = {
+ .context = NULL,
+ .destroy = &_tcpListener_OpsDestroy,
+ .getInterfaceIndex = &_tcpListener_OpsGetInterfaceIndex,
+ .getListenAddress = &_tcpListener_OpsGetListenAddress,
+ .getEncapType = &_tcpListener_OpsGetEncapType,
+ .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) {
+ _TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener));
+ parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(_TcpListener));
+
+ tcp->forwarder = forwarder;
+ tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+ tcp->listener = dispatcher_CreateListener(
+ forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1,
+ (struct sockaddr *)&sin6, sizeof(sin6));
+
+ if (tcp->listener == NULL) {
+ logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "dispatcher_CreateListener failed to create listener (%d) %s",
+ errno, strerror(errno));
+ logger_Release(&tcp->logger);
+ parcMemory_Deallocate((void **)&tcp);
+ return NULL;
+ }
+
+ tcp->localAddress = addressCreateFromInet6(&sin6);
+ tcp->id = forwarder_GetNextConnectionId(forwarder);
+ tcp->isLocalAddressLocal =
+ parcNetwork_IsSocketLocal((struct sockaddr *)&sin6);
+
+ ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+ parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListenerOps));
+
+ memcpy(ops, &_tcpTemplate, sizeof(ListenerOps));
+ ops->context = tcp;
+
+ if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ char *str = addressToString(tcp->localAddress);
+ logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "TcpListener %p created for address %s (isLocal %d)",
+ (void *)tcp, str, tcp->isLocalAddressLocal);
+ parcMemory_Deallocate((void **)&str);
+ }
+
+ return ops;
+}
+
+ListenerOps *tcpListener_CreateInet(Forwarder *forwarder,
+ struct sockaddr_in sin) {
+ _TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener));
+ parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(_TcpListener));
+
+ tcp->forwarder = forwarder;
+ tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ tcp->listener = dispatcher_CreateListener(
+ forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1,
+ (struct sockaddr *)&sin, sizeof(sin));
+
+ if (tcp->listener == NULL) {
+ logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "dispatcher_CreateListener failed to create listener (%d) %s",
+ errno, strerror(errno));
+
+ logger_Release(&tcp->logger);
+ parcMemory_Deallocate((void **)&tcp);
+ return NULL;
+ }
+
+ tcp->localAddress = addressCreateFromInet(&sin);
+ tcp->id = forwarder_GetNextConnectionId(forwarder);
+ tcp->isLocalAddressLocal = parcNetwork_IsSocketLocal((struct sockaddr *)&sin);
+
+ ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+ parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListenerOps));
+
+ memcpy(ops, &_tcpTemplate, sizeof(ListenerOps));
+ ops->context = tcp;
+
+ if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ char *str = addressToString(tcp->localAddress);
+ logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "TcpListener %p created for address %s (isLocal %d)",
+ (void *)tcp, str, tcp->isLocalAddressLocal);
+ parcMemory_Deallocate((void **)&str);
+ }
+
+ return ops;
+}
+
+static void _tcpListener_Destroy(_TcpListener **listenerPtr) {
+ parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*listenerPtr,
+ "Parameter must derefernce to non-null pointer");
+ _TcpListener *tcp = *listenerPtr;
+
+ if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ char *str = addressToString(tcp->localAddress);
+ logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "TcpListener %p destroyed", (void *)tcp);
+ parcMemory_Deallocate((void **)&str);
+ }
+
+ logger_Release(&tcp->logger);
+ dispatcher_DestroyListener(forwarder_GetDispatcher(tcp->forwarder),
+ &tcp->listener);
+ addressDestroy(&tcp->localAddress);
+ parcMemory_Deallocate((void **)&tcp);
+ *listenerPtr = NULL;
+}
+
+// ==================================================
+
+static void _tcpListener_Listen(int fd, struct sockaddr *sa, int socklen,
+ void *tcpVoid) {
+ _TcpListener *tcp = (_TcpListener *)tcpVoid;
+
+ Address *remote;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ remote = addressCreateFromInet((struct sockaddr_in *)sa);
+ break;
+
+ case AF_INET6:
+ remote = addressCreateFromInet6((struct sockaddr_in6 *)sa);
+ break;
+
+ default:
+ parcTrapIllegalValue(sa, "Expected INET or INET6, got %d", sa->sa_family);
+ abort();
+ }
+
+ AddressPair *pair = addressPair_Create(tcp->localAddress, remote);
+
+ IoOperations *ops = streamConnection_AcceptConnection(
+ tcp->forwarder, fd, pair, tcp->isLocalAddressLocal);
+ Connection *conn = connection_Create(ops);
+
+ connectionTable_Add(forwarder_GetConnectionTable(tcp->forwarder), conn);
+
+ if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "TcpListener %p listen started", (void *)tcp);
+ }
+
+ addressDestroy(&remote);
+}
+
+static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr) {
+ ListenerOps *ops = *listenerOpsPtr;
+ _TcpListener *tcp = (_TcpListener *)ops->context;
+ _tcpListener_Destroy(&tcp);
+ parcMemory_Deallocate((void **)&ops);
+ *listenerOpsPtr = NULL;
+}
+
+static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops) {
+ _TcpListener *tcp = (_TcpListener *)ops->context;
+ return tcp->id;
+}
+
+static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops) {
+ _TcpListener *tcp = (_TcpListener *)ops->context;
+ return tcp->localAddress;
+}
+
+static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops) {
+ return ENCAP_TCP;
+}
diff --git a/hicn-light/src/io/tcpListener.h b/hicn-light/src/io/tcpListener.h
new file mode 100755
index 000000000..c5d1e33af
--- /dev/null
+++ b/hicn-light/src/io/tcpListener.h
@@ -0,0 +1,37 @@
+/*
+ * 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 tcpListener.h
+ * @brief Listens for in coming TCP connections
+ *
+ * This is the "server socket" of hicn-light for TCP connections. The actual
+ * I/O is handled by {@link StreamConnection}.
+ *
+ */
+
+#ifndef tcpListener_h
+#define tcpListener_h
+
+#include <netinet/in.h>
+#include <src/core/forwarder.h>
+#include <src/io/listener.h>
+#include <stdlib.h>
+
+ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder,
+ struct sockaddr_in6 sin6);
+ListenerOps *tcpListener_CreateInet(Forwarder *forwarder,
+ struct sockaddr_in sin);
+#endif // tcpListener_h
diff --git a/hicn-light/src/io/tcpTunnel.c b/hicn-light/src/io/tcpTunnel.c
new file mode 100755
index 000000000..a2bf2bd30
--- /dev/null
+++ b/hicn-light/src/io/tcpTunnel.c
@@ -0,0 +1,43 @@
+/*
+ * 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 <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/io/streamConnection.h>
+#include <src/io/tcpListener.h>
+#include <src/io/tcpTunnel.h>
+
+IoOperations *tcpTunnel_Create(Forwarder *forwarder,
+ const Address *localAddress,
+ const Address *remoteAddress) {
+ IoOperations *ops = NULL;
+
+ address_type localType = addressGetType(localAddress);
+ address_type remoteType = addressGetType(remoteAddress);
+
+ if (localType == remoteType) {
+ AddressPair *pair = addressPair_Create(localAddress, remoteAddress);
+ bool isLocal = false;
+
+ ops = streamConnection_OpenConnection(forwarder, pair, isLocal);
+ }
+
+ return ops;
+}
diff --git a/hicn-light/src/io/tcpTunnel.h b/hicn-light/src/io/tcpTunnel.h
new file mode 100755
index 000000000..4daa7d032
--- /dev/null
+++ b/hicn-light/src/io/tcpTunnel.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 tcpTunnel.h
+ * @brief Establish a tunnel to a remote system
+ *
+ */
+
+#ifndef tcpTunnel_h
+#define tcpTunnel_h
+
+#include <src/core/forwarder.h>
+#include <src/io/ioOperations.h>
+#include <src/io/listener.h>
+#include <src/utils/address.h>
+
+/**
+ */
+// IoOperations *tcpTunnel_CreateOnListener(Forwarder *forwarder,
+// ListenerOps *localListener,
+// const Address *remoteAddress);
+
+/**
+ */
+IoOperations *tcpTunnel_Create(Forwarder *forwarder,
+ const Address *localAddress,
+ const Address *remoteAddress);
+
+#endif // tcpTunnel_h
diff --git a/hicn-light/src/io/udpConnection.c b/hicn-light/src/io/udpConnection.c
new file mode 100755
index 000000000..2aa6edc51
--- /dev/null
+++ b/hicn-light/src/io/udpConnection.c
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ */
+
+/**
+ * Embodies the reader/writer for a UDP connection
+ *
+ * NB The Send() function may overflow the output buffer
+ *
+ */
+
+#include <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <src/core/messageHandler.h>
+#include <src/io/udpConnection.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+
+typedef struct udp_state {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ // the udp listener socket we receive packets on
+ int udpListenerSocket;
+
+ AddressPair *addressPair;
+
+ // We need to access this all the time, so grab it out
+ // of the addressPair;
+ struct sockaddr *peerAddress;
+ socklen_t peerAddressLength;
+
+ bool isLocal;
+ bool isUp;
+ unsigned id;
+
+ unsigned delay;
+} _UdpState;
+
+// Prototypes
+static bool _send(IoOperations *ops, const Address *nexthop, Message *message);
+static const Address *_getRemoteAddress(const IoOperations *ops);
+static const AddressPair *_getAddressPair(const IoOperations *ops);
+static unsigned _getConnectionId(const IoOperations *ops);
+static bool _isUp(const IoOperations *ops);
+static bool _isLocal(const IoOperations *ops);
+static void _destroy(IoOperations **opsPtr);
+static list_connections_type _getConnectionType(const IoOperations *ops);
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+ uint8_t *message);
+/*
+ * This assigns a unique pointer to the void * which we use
+ * as a GUID for this class.
+ */
+static const void *_IoOperationsGuid = __FILE__;
+
+/*
+ * Return our GUID
+ */
+static const void *_streamConnection_Class(const IoOperations *ops) {
+ return _IoOperationsGuid;
+}
+
+static IoOperations _template = {.closure = NULL,
+ .send = &_send,
+ .getRemoteAddress = &_getRemoteAddress,
+ .getAddressPair = &_getAddressPair,
+ .getConnectionId = &_getConnectionId,
+ .isUp = &_isUp,
+ .isLocal = &_isLocal,
+ .destroy = &_destroy,
+ .class = &_streamConnection_Class,
+ .getConnectionType = &_getConnectionType,
+ .sendProbe = &_sendProbe};
+
+// =================================================================
+
+static void _setConnectionState(_UdpState *Udp, bool isUp);
+static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair);
+
+IoOperations *udpConnection_Create(Forwarder *forwarder, int fd,
+ const AddressPair *pair, bool isLocal) {
+ IoOperations *io_ops = NULL;
+
+ _UdpState *udpConnState = parcMemory_AllocateAndClear(sizeof(_UdpState));
+ parcAssertNotNull(udpConnState,
+ "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(_UdpState));
+
+ udpConnState->forwarder = forwarder;
+ udpConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+ bool saved = _saveSockaddr(udpConnState, pair);
+ if (saved) {
+ udpConnState->udpListenerSocket = fd;
+ udpConnState->id = forwarder_GetNextConnectionId(forwarder);
+ udpConnState->addressPair = addressPair_Acquire(pair);
+ udpConnState->isLocal = isLocal;
+
+ // allocate a connection
+ io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations));
+ parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(IoOperations));
+ memcpy(io_ops, &_template, sizeof(IoOperations));
+ io_ops->closure = udpConnState;
+
+ _setConnectionState(udpConnState, true);
+
+ if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO,
+ PARCLogLevel_Info)) {
+ char *str = addressPair_ToString(udpConnState->addressPair);
+ logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Info,
+ __func__,
+ "UdpConnection %p created for address %s (isLocal %d)",
+ (void *)udpConnState, str, udpConnState->isLocal);
+ free(str);
+ }
+
+ messenger_Send(
+ forwarder_GetMessenger(forwarder),
+ missive_Create(MissiveType_ConnectionCreate, udpConnState->id));
+ messenger_Send(forwarder_GetMessenger(forwarder),
+ missive_Create(MissiveType_ConnectionUp, udpConnState->id));
+ } else {
+ // _saveSockaddr will already log an error, no need for extra log message
+ // here
+ logger_Release(&udpConnState->logger);
+ parcMemory_Deallocate((void **)&udpConnState);
+ }
+
+ return io_ops;
+}
+
+// =================================================================
+// I/O Operations implementation
+
+static void _destroy(IoOperations **opsPtr) {
+ parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer");
+ parcAssertNotNull(*opsPtr,
+ "Parameter opsPtr must dereference to non-null pointer");
+
+ IoOperations *ops = *opsPtr;
+ parcAssertNotNull(ioOperations_GetClosure(ops),
+ "ops->context must not be null");
+
+ _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops);
+ addressPair_Release(&udpConnState->addressPair);
+ parcMemory_Deallocate((void **)&(udpConnState->peerAddress));
+
+ messenger_Send(
+ forwarder_GetMessenger(udpConnState->forwarder),
+ missive_Create(MissiveType_ConnectionDestroyed, udpConnState->id));
+
+ if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO,
+ PARCLogLevel_Info)) {
+ logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Info,
+ __func__, "UdpConnection %p destroyed", (void *)udpConnState);
+ }
+
+ // do not close udp->udpListenerSocket, the listener will close
+ // that when its done
+
+ logger_Release(&udpConnState->logger);
+ parcMemory_Deallocate((void **)&udpConnState);
+ parcMemory_Deallocate((void **)&ops);
+
+ *opsPtr = NULL;
+}
+
+static bool _isUp(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _UdpState *udpConnState =
+ (const _UdpState *)ioOperations_GetClosure(ops);
+ return udpConnState->isUp;
+}
+
+static bool _isLocal(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _UdpState *udpConnState =
+ (const _UdpState *)ioOperations_GetClosure(ops);
+ return udpConnState->isLocal;
+}
+
+static const Address *_getRemoteAddress(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _UdpState *udpConnState =
+ (const _UdpState *)ioOperations_GetClosure(ops);
+ return addressPair_GetRemote(udpConnState->addressPair);
+}
+
+static const AddressPair *_getAddressPair(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _UdpState *udpConnState =
+ (const _UdpState *)ioOperations_GetClosure(ops);
+ return udpConnState->addressPair;
+}
+
+static unsigned _getConnectionId(const IoOperations *ops) {
+ parcAssertNotNull(ops, "Parameter must be non-null");
+ const _UdpState *udpConnState =
+ (const _UdpState *)ioOperations_GetClosure(ops);
+ return udpConnState->id;
+}
+
+/**
+ * @function metisUdpConnection_Send
+ * @abstract Non-destructive send of the message.
+ * @discussion
+ * sends a message to the peer.
+ *
+ * @param dummy is ignored. A udp connection has only one peer.
+ * @return <#return#>
+ */
+static bool _send(IoOperations *ops, const Address *dummy, Message *message) {
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+ _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops);
+
+ // NAT for HICN
+ // in this particular connection we don't need natting beacause we send the
+ // packet to the next hop using upd connection
+
+#if 0
+ if((hicnConnState->peerAddressLength == sizeof(struct sockaddr_in)) || (hicnConnState->localAddressLength == sizeof(struct sockaddr_in)))
+ return false;
+
+ if(message_GetType(message) = MessagePacketType_ContentObject){
+ //this is a data packet. We need to put the remote address in the destination field
+ messageHandler_SetDestination_IPv6((uint8_t *) message_FixedHeader(message),
+ &((struct sockaddr_in6 *) hicnConnState->peerAddress)->sin6_addr);
+
+ } else if (message_GetType(message) == MessagePacketType_Interest) {
+ //this si an interest packet. We need to put the local address in the source field
+ messageHandler_SetSource_IPv6((uint8_t *) message_FixedHeader(message),
+ &((struct sockaddr_in6 *) hicnConnState->localAddress)->sin6_addr);
+
+ //only in this case we may need to set the probeDestAddress
+ if(hicnConnState->refreshProbeDestAddress){
+ _refreshProbeDestAddress(hicnConnState, message_FixedHeader(message));
+ }
+
+ } else if (message_GetType(message) == MessagePacketType_WldrNotification) {
+ //here we don't need to do anything for now
+ }else{
+ //unkown packet
+ if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "connid %u can't parse the message",
+ hicnConnState->id);
+ }
+ return false;
+ }
+#endif
+
+ ssize_t writeLength =
+ sendto(udpConnState->udpListenerSocket, message_FixedHeader(message),
+ message_Length(message), 0, udpConnState->peerAddress,
+ udpConnState->peerAddressLength);
+
+ if (writeLength < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return false;
+ } else {
+ // this print is for debugging
+ printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLength,
+ message_Length(message), errno, strerror(errno));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static list_connections_type _getConnectionType(const IoOperations *ops) {
+ return CONN_UDP;
+}
+
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+ uint8_t *message) {
+#if 0
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ _MetisUdpState *udpConnState = (_MetisUdpState *) metisIoOperations_GetClosure(ops);
+
+
+ uint8_t *pkt;
+ size_t pkt_size = 8;
+ pkt = (uint8_t *) malloc(sizeof(uint8_t) * pkt_size);
+ for (unsigned i = 0; i < pkt_size; i++) {
+ pkt[i] = 0;
+ }
+ pkt[0] = 1; //type
+ pkt[1] = probeType; //packet type
+ pkt[6] = 8; //header len (16bit, network order)
+
+ ssize_t writeLen = sendto(udpConnState->udpListenerSocket, pkt, pkt_size, 0, udpConnState->peerAddress, udpConnState->peerAddressLength);
+
+ if (writeLen < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ free(pkt);
+ return 0;
+ } else {
+ //this print is for debugging
+ printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLen, pkt_size, errno, strerror(errno));
+ free(pkt);
+ return 0;
+ }
+ }
+
+ free(pkt);
+ return metisForwarder_GetTicks(udpConnState->metis);
+#endif
+ return 0;
+}
+
+// =================================================================
+// Internal API
+
+static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair) {
+ bool success = false;
+ const Address *remoteAddress = addressPair_GetRemote(pair);
+
+ switch (addressGetType(remoteAddress)) {
+ case ADDR_INET: {
+ size_t bytes = sizeof(struct sockaddr_in);
+ udpConnState->peerAddress = parcMemory_Allocate(bytes);
+ parcAssertNotNull(udpConnState->peerAddress,
+ "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+ addressGetInet(remoteAddress,
+ (struct sockaddr_in *)udpConnState->peerAddress);
+ udpConnState->peerAddressLength = (socklen_t)bytes;
+
+ success = true;
+ break;
+ }
+
+ case ADDR_INET6: {
+ size_t bytes = sizeof(struct sockaddr_in6);
+ udpConnState->peerAddress = parcMemory_Allocate(bytes);
+ parcAssertNotNull(udpConnState->peerAddress,
+ "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+ addressGetInet6(remoteAddress,
+ (struct sockaddr_in6 *)udpConnState->peerAddress);
+ udpConnState->peerAddressLength = (socklen_t)bytes;
+
+ success = true;
+ break;
+ }
+
+ default:
+ if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO,
+ PARCLogLevel_Error)) {
+ char *str = addressToString(remoteAddress);
+ logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Error,
+ __func__, "Remote address is not INET or INET6: %s", str);
+ parcMemory_Deallocate((void **)&str);
+ }
+ break;
+ }
+ return success;
+}
+
+static void _setConnectionState(_UdpState *udpConnState, bool isUp) {
+ parcAssertNotNull(udpConnState, "Parameter Udp must be non-null");
+
+ Messenger *messenger = forwarder_GetMessenger(udpConnState->forwarder);
+
+ bool oldStateIsUp = udpConnState->isUp;
+ udpConnState->isUp = isUp;
+
+ if (oldStateIsUp && !isUp) {
+ // bring connection DOWN
+ Missive *missive =
+ missive_Create(MissiveType_ConnectionDown, udpConnState->id);
+ messenger_Send(messenger, missive);
+ return;
+ }
+
+ if (!oldStateIsUp && isUp) {
+ // bring connection UP
+ Missive *missive =
+ missive_Create(MissiveType_ConnectionUp, udpConnState->id);
+ messenger_Send(messenger, missive);
+ return;
+ }
+}
diff --git a/hicn-light/src/io/udpConnection.h b/hicn-light/src/io/udpConnection.h
new file mode 100755
index 000000000..122f332d5
--- /dev/null
+++ b/hicn-light/src/io/udpConnection.h
@@ -0,0 +1,53 @@
+/*
+ * 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 udpConnection.h
+ * @brief Represents a UDP connection (socket) for the connection table
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef udpConnection_h
+#define udpConnection_h
+
+#include <src/core/forwarder.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+#include <src/utils/address.h>
+
+/**
+ * Creates a UDP connection that can send to the remote address
+ *
+ * The address pair must both be same type (i.e. INET or INET6).
+ *
+ * @param [in] metis An allocated MetisForwarder (saves reference)
+ * @param [in] fd The socket to use
+ * @param [in] pair An allocated address pair for the connection (saves
+ * reference)
+ * @param [in] isLocal determines if the remote address is on the current system
+ *
+ * @retval non-null An allocated Io operations
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+IoOperations *udpConnection_Create(Forwarder *forwarder, int fd,
+ const AddressPair *pair, bool isLocal);
+#endif // udpConnection_h
diff --git a/hicn-light/src/io/udpListener.c b/hicn-light/src/io/udpListener.c
new file mode 100755
index 000000000..31c0e673b
--- /dev/null
+++ b/hicn-light/src/io/udpListener.c
@@ -0,0 +1,533 @@
+/*
+ * 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 <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <src/core/messageHandler.h>
+
+#include <src/io/udpConnection.h>
+#include <src/io/udpListener.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+#include <src/core/messagePacketType.h>
+
+#ifdef WITH_MAPME
+#include <src/core/mapMe.h>
+#endif /* WITH_MAPME */
+
+#define IPv4 4
+#define IPv6 6
+
+struct udp_listener {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ PARCEvent *udp_event;
+ SocketType udp_socket;
+ uint16_t port;
+
+ unsigned id;
+ Address *localAddress;
+};
+
+static void _destroy(ListenerOps **listenerOpsPtr);
+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 ListenerOps udpTemplate = {.context = NULL,
+ .destroy = &_destroy,
+ .getInterfaceIndex = &_getInterfaceIndex,
+ .getListenAddress = &_getListenAddress,
+ .getEncapType = &_getEncapType,
+ .getSocket = &_getSocket};
+
+static void _readcb(int fd, PARCEventType what, void *udpVoid);
+
+ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
+ struct sockaddr_in6 sin6) {
+ ListenerOps *ops = NULL;
+
+ UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener));
+ parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(UdpListener));
+ udp->forwarder = forwarder;
+ udp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ udp->localAddress = addressCreateFromInet6(&sin6);
+ udp->id = forwarder_GetNextConnectionId(forwarder);
+
+ udp->udp_socket = socket(AF_INET6, SOCK_DGRAM, 0);
+ parcAssertFalse(udp->udp_socket < 0, "Error opening UDP socket: (%d) %s",
+ errno, strerror(errno));
+
+ // Set non-blocking flag
+ int flags = fcntl(udp->udp_socket, F_GETFL, NULL);
+ parcAssertTrue(flags != -1,
+ "fcntl failed to obtain file descriptor flags (%d)", errno);
+ int failure = fcntl(udp->udp_socket, F_SETFL, flags | O_NONBLOCK);
+ parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)",
+ errno);
+
+ int one = 1;
+ // don't hang onto address after listener has closed
+ failure = setsockopt(udp->udp_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&one,
+ (socklen_t)sizeof(one));
+ parcAssertFalse(failure, "failed to set REUSEADDR on socket(%d)", errno);
+
+ failure = bind(udp->udp_socket, (struct sockaddr *)&sin6, sizeof(sin6));
+ if (failure == 0) {
+ udp->udp_event =
+ dispatcher_CreateNetworkEvent(forwarder_GetDispatcher(forwarder), true,
+ _readcb, (void *)udp, udp->udp_socket);
+ dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder),
+ udp->udp_event);
+
+ ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+ parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListenerOps));
+ memcpy(ops, &udpTemplate, sizeof(ListenerOps));
+ ops->context = udp;
+
+ if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ char *str = addressToString(udp->localAddress);
+ logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "UdpListener %p created for address %s", (void *)udp, str);
+ parcMemory_Deallocate((void **)&str);
+ }
+ } else {
+ if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+ int myerrno = errno;
+ char *str = addressToString(udp->localAddress);
+ logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Error binding UDP socket to address %s: (%d) %s", str,
+ myerrno, strerror(myerrno));
+ parcMemory_Deallocate((void **)&str);
+ }
+
+ close(udp->udp_socket);
+ addressDestroy(&udp->localAddress);
+ logger_Release(&udp->logger);
+ parcMemory_Deallocate((void **)&udp);
+ }
+
+ return ops;
+}
+
+ListenerOps *udpListener_CreateInet(Forwarder *forwarder,
+ struct sockaddr_in sin) {
+ ListenerOps *ops = NULL;
+
+ UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener));
+ parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(UdpListener));
+ udp->forwarder = forwarder;
+ udp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ udp->localAddress = addressCreateFromInet(&sin);
+ udp->id = forwarder_GetNextConnectionId(forwarder);
+
+ udp->udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ parcAssertFalse(udp->udp_socket < 0, "Error opening UDP socket: (%d) %s",
+ errno, strerror(errno));
+
+ // Set non-blocking flag
+ int flags = fcntl(udp->udp_socket, F_GETFL, NULL);
+ parcAssertTrue(flags != -1,
+ "fcntl failed to obtain file descriptor flags (%d)", errno);
+ int failure = fcntl(udp->udp_socket, F_SETFL, flags | O_NONBLOCK);
+ parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)",
+ errno);
+
+ int one = 1;
+ // don't hang onto address after listener has closed
+ failure = setsockopt(udp->udp_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&one,
+ (socklen_t)sizeof(one));
+ parcAssertFalse(failure, "failed to set REUSEADDR on socket(%d)", errno);
+
+ failure = bind(udp->udp_socket, (struct sockaddr *)&sin, sizeof(sin));
+ if (failure == 0) {
+ udp->udp_event =
+ dispatcher_CreateNetworkEvent(forwarder_GetDispatcher(forwarder), true,
+ _readcb, (void *)udp, udp->udp_socket);
+ dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder),
+ udp->udp_event);
+
+ ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+ parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(ListenerOps));
+ memcpy(ops, &udpTemplate, sizeof(ListenerOps));
+ ops->context = udp;
+
+ if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ char *str = addressToString(udp->localAddress);
+ logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "UdpListener %p created for address %s", (void *)udp, str);
+ parcMemory_Deallocate((void **)&str);
+ }
+ } else {
+ if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+ int myerrno = errno;
+ char *str = addressToString(udp->localAddress);
+ logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Error binding UDP socket to address %s: (%d) %s", str,
+ myerrno, strerror(myerrno));
+ parcMemory_Deallocate((void **)&str);
+ }
+
+ close(udp->udp_socket);
+ addressDestroy(&udp->localAddress);
+ logger_Release(&udp->logger);
+ parcMemory_Deallocate((void **)&udp);
+ }
+
+ return ops;
+}
+
+static void udpListener_Destroy(UdpListener **listenerPtr) {
+ parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*listenerPtr,
+ "Parameter must derefernce to non-null pointer");
+
+ UdpListener *udp = *listenerPtr;
+
+ if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "UdpListener %p destroyed", (void *)udp);
+ }
+
+ close(udp->udp_socket);
+ addressDestroy(&udp->localAddress);
+ dispatcher_DestroyNetworkEvent(forwarder_GetDispatcher(udp->forwarder),
+ &udp->udp_event);
+ logger_Release(&udp->logger);
+ parcMemory_Deallocate((void **)&udp);
+ *listenerPtr = NULL;
+}
+
+static void _destroy(ListenerOps **listenerOpsPtr) {
+ ListenerOps *ops = *listenerOpsPtr;
+ UdpListener *udp = (UdpListener *)ops->context;
+ udpListener_Destroy(&udp);
+ parcMemory_Deallocate((void **)&ops);
+ *listenerOpsPtr = NULL;
+}
+
+static unsigned _getInterfaceIndex(const ListenerOps *ops) {
+ UdpListener *udp = (UdpListener *)ops->context;
+ return udp->id;
+}
+
+static const Address *_getListenAddress(const ListenerOps *ops) {
+ UdpListener *udp = (UdpListener *)ops->context;
+ return udp->localAddress;
+}
+
+static EncapType _getEncapType(const ListenerOps *ops) { return ENCAP_UDP; }
+
+static int _getSocket(const ListenerOps *ops) {
+ UdpListener *udp = (UdpListener *)ops->context;
+ return (int)udp->udp_socket;
+}
+
+// void
+// udpListener_SetPacketType(ListenerOps *ops, MessagePacketType type)
+//{
+// return;
+//}
+
+// =====================================================================
+
+/**
+ * @function peekMesageLength
+ * @abstract Peek at the next packet to learn its length by reading the fixed
+ * header
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static size_t _peekMessageLength(UdpListener *udp, int fd,
+ struct sockaddr *peerIpAddress,
+ socklen_t *peerIpAddressLengthPtr) {
+ // to be fast I try to use just ipv6, this needs to be validated for ipv4
+
+ size_t packetLength = 0;
+
+ uint8_t fixedHeader[messageHandler_GetIPHeaderLength(IPv6)];
+
+ // peek at the UDP packet and read in the fixed header.
+ // Also returns the socket information for the remote peer
+
+ ssize_t res = recvfrom(
+ fd, fixedHeader, messageHandler_GetIPHeaderLength(IPv6), MSG_PEEK,
+ (struct sockaddr *)peerIpAddress, peerIpAddressLengthPtr);
+
+ if (res == messageHandler_GetIPHeaderLength(IPv6)) {
+ packetLength =
+ messageHandler_GetTotalPacketLength((const uint8_t *)&fixedHeader);
+ } else {
+ if (res < 0) {
+ printf("error while readin packet\n");
+ }
+ }
+
+ return packetLength;
+}
+
+/**
+ * @function _constructAddressPair
+ * @abstract Creates the address pair that uniquely identifies the connection
+ * @discussion
+ * The peerIpAddress must be of AF_INET or AF_INET6 family.
+ *
+ * @param <#param1#>
+ * @return Allocated MetisAddressPair, must be destroyed
+ */
+static AddressPair *_constructAddressPair(UdpListener *udp,
+ struct sockaddr *peerIpAddress,
+ socklen_t peerIpAddressLength) {
+ Address *remoteAddress;
+
+ switch (peerIpAddress->sa_family) {
+ case AF_INET:
+ remoteAddress =
+ addressCreateFromInet((struct sockaddr_in *)peerIpAddress);
+ break;
+
+ case AF_INET6:
+ remoteAddress =
+ addressCreateFromInet6((struct sockaddr_in6 *)peerIpAddress);
+ break;
+
+ default:
+ parcTrapIllegalValue(peerIpAddress,
+ "Peer address unrecognized family for IP: %d",
+ peerIpAddress->sa_family);
+ }
+
+ AddressPair *pair = addressPair_Create(udp->localAddress, remoteAddress);
+ addressDestroy(&remoteAddress);
+
+ return pair;
+}
+
+/**
+ * @function _lookupConnectionId
+ * @abstract Lookup a connection in the connection table
+ * @discussion
+ * Looks up the connection in the connection table and returns the connection
+ * id if it exists.
+ *
+ * @param outputConnectionIdPtr is the output parameter
+ * @return true if connection found and outputConnectionIdPtr set
+ */
+static bool _lookupConnectionId(UdpListener *udp, AddressPair *pair,
+ unsigned *outputConnectionIdPtr) {
+ ConnectionTable *connTable = forwarder_GetConnectionTable(udp->forwarder);
+
+ const Connection *conn = connectionTable_FindByAddressPair(connTable, pair);
+ if (conn) {
+ *outputConnectionIdPtr = connection_GetConnectionId(conn);
+ return true;
+ } else {
+ *outputConnectionIdPtr = 0;
+ return false;
+ }
+}
+
+/**
+ * @function _createNewConnection
+ * @abstract Creates a new Metis connection for the peer
+ * @discussion
+ * PRECONDITION: you know there's not an existing connection with the address
+ * pair
+ *
+ * Creates a new connection and adds it to the connection table.
+ *
+ * @param <#param1#>
+ * @return The connection id for the new connection
+ */
+
+static unsigned _createNewConnection(UdpListener *udp, int fd,
+ const AddressPair *pair) {
+ bool isLocal = false;
+
+ // metisUdpConnection_Create takes ownership of the pair
+ IoOperations *ops = udpConnection_Create(udp->forwarder, fd, pair, isLocal);
+ Connection *conn = connection_Create(ops);
+ // connection_AllowWldrAutoStart(conn);
+
+ connectionTable_Add(forwarder_GetConnectionTable(udp->forwarder), conn);
+ unsigned connid = ioOperations_GetConnectionId(ops);
+
+ return connid;
+}
+
+static void _handleProbeMessage(UdpListener *udp, uint8_t *msgBuffer) {
+ // TODO
+ parcMemory_Deallocate((void **)&msgBuffer);
+}
+
+static void _handleWldrNotification(UdpListener *udp, unsigned connId,
+ uint8_t *msgBuffer) {
+ const Connection *conn = connectionTable_FindById(
+ forwarder_GetConnectionTable(udp->forwarder), connId);
+ if (conn == NULL) {
+ return;
+ }
+
+ Message *message = message_CreateFromByteArray(
+ connId, msgBuffer, MessagePacketType_WldrNotification,
+ forwarder_GetTicks(udp->forwarder), forwarder_GetLogger(udp->forwarder));
+
+ connection_HandleWldrNotification((Connection *)conn, message);
+
+ message_Release(&message);
+}
+
+static Message *_readMessage(UdpListener *udp, int fd, size_t packetLength,
+ AddressPair *pair) {
+ uint8_t *msgBuffer = parcMemory_AllocateAndClear(packetLength);
+
+ ssize_t readLength = read(fd, msgBuffer, packetLength);
+
+ Message *message = NULL;
+
+ if (readLength < 0) {
+ printf("read failed %d: (%d) %s\n", fd, errno, strerror(errno));
+ return message;
+ }
+
+ unsigned connid = 0;
+ bool foundConnection = _lookupConnectionId(udp, pair, &connid);
+
+ if (readLength == packetLength) {
+ // we need to check if it is a valid packet
+ if (messageHandler_IsTCP(msgBuffer)) {
+ MessagePacketType pktType;
+
+ if (messageHandler_IsData(msgBuffer)) {
+ pktType = MessagePacketType_ContentObject;
+ if (!foundConnection) {
+ parcMemory_Deallocate((void **)&msgBuffer);
+ return message;
+ }
+ } else if (messageHandler_IsInterest(msgBuffer)) {
+ pktType = MessagePacketType_Interest;
+ if (!foundConnection) {
+ connid = _createNewConnection(udp, fd, pair);
+ }
+ } 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(udp->forwarder),
+ forwarder_GetLogger(udp->forwarder));
+
+ if (message == NULL) {
+ parcMemory_Deallocate((void **)&msgBuffer);
+ }
+ } else if (messageHandler_IsWldrNotification(msgBuffer)) {
+ _handleWldrNotification(udp, connid, msgBuffer);
+ } else if (messageHandler_IsLoadBalancerProbe(msgBuffer)) {
+ _handleProbeMessage(udp, msgBuffer);
+ }
+#ifdef WITH_MAPME
+ else if (mapMe_isMapMe(msgBuffer)) {
+ forwarder_ProcessMapMe(udp->forwarder, msgBuffer, connid);
+ }
+#endif /* WITH_MAPME */
+ }
+
+ return message;
+}
+
+static void _receivePacket(UdpListener *udp, int fd, size_t packetLength,
+ struct sockaddr_storage *peerIpAddress,
+ socklen_t peerIpAddressLength) {
+ AddressPair *pair = _constructAddressPair(
+ udp, (struct sockaddr *)peerIpAddress, peerIpAddressLength);
+
+ Message *message = _readMessage(udp, fd, packetLength, pair);
+ addressPair_Release(&pair);
+
+ if (message) {
+ forwarder_Receive(udp->forwarder, message);
+ } else {
+ return;
+ }
+}
+
+static void _readFrameToDiscard(UdpListener *udp, int fd) {
+ // we need to discard the frame. Read 1 byte. This will clear it off the
+ // stack.
+ uint8_t buffer;
+ ssize_t nread = read(fd, &buffer, 1);
+
+ if (nread == 1) {
+ if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "Discarded frame from fd %d", fd);
+ }
+ } else if (nread < 0) {
+ if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+ logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Error trying to discard frame from fd %d: (%d) %s", fd, errno,
+ strerror(errno));
+ }
+ }
+}
+
+static void _readcb(int fd, PARCEventType what, void *udpVoid) {
+ UdpListener *udp = (UdpListener *)udpVoid;
+
+ if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "%s socket %d what %s%s%s%s data %p", __func__, fd,
+ (what & PARCEventType_Timeout) ? " timeout" : "",
+ (what & PARCEventType_Read) ? " read" : "",
+ (what & PARCEventType_Write) ? " write" : "",
+ (what & PARCEventType_Signal) ? " signal" : "", udpVoid);
+ }
+
+ if (what & PARCEventType_Read) {
+ struct sockaddr_storage peerIpAddress;
+ socklen_t peerIpAddressLength = sizeof(peerIpAddress);
+
+ size_t packetLength = _peekMessageLength(
+ udp, fd, (struct sockaddr *)&peerIpAddress, &peerIpAddressLength);
+
+ if (packetLength > 0) {
+ _receivePacket(udp, fd, packetLength, &peerIpAddress,
+ peerIpAddressLength);
+ } else {
+ _readFrameToDiscard(udp, fd);
+ }
+ }
+}
diff --git a/hicn-light/src/io/udpListener.h b/hicn-light/src/io/udpListener.h
new file mode 100755
index 000000000..1cf3bd887
--- /dev/null
+++ b/hicn-light/src/io/udpListener.h
@@ -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.
+ */
+
+#ifndef udpListener_h
+#define udpListener_h
+
+#include <netinet/in.h>
+#include <src/core/forwarder.h>
+#include <src/io/listener.h>
+#include <stdlib.h>
+
+struct udp_listener;
+typedef struct udp_listener UdpListener;
+
+ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
+ struct sockaddr_in6 sin6);
+ListenerOps *udpListener_CreateInet(Forwarder *forwarder,
+ struct sockaddr_in sin);
+// void udpListener_SetPacketType(ListenerOps *ops, MessagePacketType type);
+#endif // udpListener_h
diff --git a/hicn-light/src/io/udpTunnel.c b/hicn-light/src/io/udpTunnel.c
new file mode 100755
index 000000000..d06a35ce6
--- /dev/null
+++ b/hicn-light/src/io/udpTunnel.c
@@ -0,0 +1,91 @@
+/*
+ * 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 <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/io/udpConnection.h>
+#include <src/io/udpListener.h>
+#include <src/io/udpTunnel.h>
+
+IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder,
+ ListenerOps *localListener,
+ const Address *remoteAddress) {
+ parcAssertNotNull(forwarder, "Parameter metis must be non-null");
+ parcAssertNotNull(localListener, "Parameter localListener must be non-null");
+ parcAssertNotNull(remoteAddress, "Parameter remoteAddress must be non-null");
+
+ Logger *logger = forwarder_GetLogger(forwarder);
+
+ IoOperations *ops = NULL;
+ if (localListener->getEncapType(localListener) == ENCAP_UDP) {
+ const Address *localAddress =
+ localListener->getListenAddress(localListener);
+ address_type localType = addressGetType(localAddress);
+ address_type remoteType = addressGetType(remoteAddress);
+
+ if (localType == remoteType) {
+ AddressPair *pair = addressPair_Create(localAddress, remoteAddress);
+ bool isLocal = false;
+ int fd = localListener->getSocket(localListener);
+ // udpListener_SetPacketType(localListener,
+ // MessagePacketType_ContentObject);
+ ops = udpConnection_Create(forwarder, fd, pair, isLocal);
+
+ addressPair_Release(&pair);
+ } else {
+ if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+ logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Local listener of type %s and remote type %s, cannot "
+ "establish tunnel",
+ addressTypeToString(localType),
+ addressTypeToString(remoteType));
+ }
+ }
+ } else {
+ if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+ logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+ "Local listener %p is not type UDP, cannot establish tunnel",
+ (void *)localListener);
+ }
+ }
+
+ return ops;
+}
+
+IoOperations *udpTunnel_Create(Forwarder *forwarder,
+ const Address *localAddress,
+ const Address *remoteAddress) {
+ ListenerSet *set = forwarder_GetListenerSet(forwarder);
+ ListenerOps *listener = listenerSet_Find(set, ENCAP_UDP, localAddress);
+ IoOperations *ops = NULL;
+ if (listener) {
+ ops = udpTunnel_CreateOnListener(forwarder, listener, remoteAddress);
+ } else {
+ if (logger_IsLoggable(forwarder_GetLogger(forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error)) {
+ char *str = addressToString(localAddress);
+ logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_IO,
+ PARCLogLevel_Error, __func__,
+ "Could not find listener to match address %s", str);
+ parcMemory_Deallocate((void **)&str);
+ }
+ }
+ return ops;
+}
diff --git a/hicn-light/src/io/udpTunnel.h b/hicn-light/src/io/udpTunnel.h
new file mode 100755
index 000000000..a79ca4a4e
--- /dev/null
+++ b/hicn-light/src/io/udpTunnel.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 udpTunnel.h
+ * @brief Establish a tunnel to a remote system
+ *
+ */
+
+#ifndef udpTunnel_h
+#define udpTunnel_h
+
+#include <src/core/forwarder.h>
+#include <src/io/ioOperations.h>
+#include <src/io/listener.h>
+#include <src/utils/address.h>
+
+/**
+ */
+IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder,
+ ListenerOps *localListener,
+ const Address *remoteAddress);
+
+/**
+ */
+IoOperations *udpTunnel_Create(Forwarder *forwarder,
+ const Address *localAddress,
+ const Address *remoteAddress);
+
+#endif // udpTunnel_h
diff --git a/hicn-light/src/messenger/CMakeLists.txt b/hicn-light/src/messenger/CMakeLists.txt
new file mode 100755
index 000000000..92bc13b5b
--- /dev/null
+++ b/hicn-light/src/messenger/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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/missiveDeque.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/missive.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/missiveType.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/messenger.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/messengerRecipient.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/messenger.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/messengerRecipient.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/missive.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/missiveDeque.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/hicn-light/src/messenger/messenger.c b/hicn-light/src/messenger/messenger.c
new file mode 100755
index 000000000..26c7a85e2
--- /dev/null
+++ b/hicn-light/src/messenger/messenger.c
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * The messenger is contructued with a reference to the forwarder's dispatcher
+ * so it can schedule future events. When someone calls messenger_Send(...), it
+ * will put the message on a queue. If the queue was empty, it will scheudle
+ * itself to be run. By running the queue in a future dispatcher slice, it
+ * guarantees that there will be no re-entrant behavior between callers and
+ * message listeners.
+ *
+ * A recipient will receive a reference counted copy of the missive, so it must
+ * call
+ * {@link missive_Release} on it.
+ *
+ */
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/messenger/messenger.h>
+#include <src/messenger/missiveDeque.h>
+
+struct messenger {
+ PARCArrayList *callbacklist;
+ Dispatcher *dispatcher;
+ MissiveDeque *eventQueue;
+
+ PARCEventTimer *timerEvent;
+};
+
+static void messenger_Dequeue(int fd, PARCEventType which_event,
+ void *messengerVoidPtr);
+
+// =========================================
+// Public API
+
+Messenger *messenger_Create(Dispatcher *dispatcher) {
+ Messenger *messenger = parcMemory_AllocateAndClear(sizeof(Messenger));
+ parcAssertNotNull(messenger, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Messenger));
+
+ // NULL destroyer because we're storing structures owned by the caller
+ messenger->dispatcher = dispatcher;
+ messenger->callbacklist = parcArrayList_Create(NULL);
+ messenger->eventQueue = missiveDeque_Create();
+
+ // creates the timer, but does not start it
+ messenger->timerEvent =
+ dispatcher_CreateTimer(dispatcher, false, messenger_Dequeue, messenger);
+
+ return messenger;
+}
+
+void messenger_Destroy(Messenger **messengerPtr) {
+ parcAssertNotNull(messengerPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*messengerPtr,
+ "Parameter must dereference to non-null pointer");
+
+ Messenger *messenger = *messengerPtr;
+ parcArrayList_Destroy(&messenger->callbacklist);
+ missiveDeque_Release(&messenger->eventQueue);
+ dispatcher_DestroyTimerEvent(messenger->dispatcher, &messenger->timerEvent);
+ parcMemory_Deallocate((void **)&messenger);
+ *messengerPtr = NULL;
+}
+
+void messenger_Send(Messenger *messenger, Missive *missive) {
+ parcAssertNotNull(messenger, "Parameter messenger must be non-null");
+ parcAssertNotNull(missive, "Parameter event must be non-null");
+
+ missiveDeque_Append(messenger->eventQueue, missive);
+ if (missiveDeque_Size(messenger->eventQueue) == 1) {
+ // We need to scheudle ourself when an event is added to an empty queue
+
+ // precondition: timer should not be running.
+ struct timeval immediateTimeout = {0, 0};
+ dispatcher_StartTimer(messenger->dispatcher, messenger->timerEvent,
+ &immediateTimeout);
+ }
+}
+
+static void removeRecipient(Messenger *messenger,
+ const MessengerRecipient *recipient) {
+ // don't increment i in the loop
+ for (size_t i = 0; i < parcArrayList_Size(messenger->callbacklist);) {
+ const void *p = parcArrayList_Get(messenger->callbacklist, i);
+ if (p == recipient) {
+ // removing will compact the list, so next element will also be at i.
+ parcArrayList_RemoveAndDestroyAtIndex(messenger->callbacklist, i);
+ } else {
+ i++;
+ }
+ }
+}
+
+/**
+ * @function eventMessenger_Register
+ * @abstract Receive all event messages
+ */
+void messenger_Register(Messenger *messenger,
+ const MessengerRecipient *recipient) {
+ parcAssertNotNull(messenger, "Parameter messenger must be non-null");
+ parcAssertNotNull(recipient, "Parameter recipient must be non-null");
+
+ // do not allow duplicates
+ removeRecipient(messenger, recipient);
+
+ parcArrayList_Add(messenger->callbacklist, recipient);
+}
+
+/**
+ * @function eventMessenger_Unregister
+ * @abstract Stop receiving event messages
+ */
+void messenger_Unregister(Messenger *messenger,
+ const MessengerRecipient *recipient) {
+ parcAssertNotNull(messenger, "Parameter messenger must be non-null");
+ parcAssertNotNull(recipient, "Parameter recipient must be non-null");
+
+ removeRecipient(messenger, recipient);
+}
+
+/**
+ * Called by event scheduler to give us a slice in which to dequeue events
+ *
+ * Called inside an event callback, so we now have exclusive access to the
+ * system. Dequeues all pending events and calls all the listeners for each one.
+ *
+ * @param [in] fd unused, required for compliance with function prototype
+ * @param [in] which_event unused, required for compliance with function
+ * prototype
+ * @param [in] messengerVoidPtr A void* to Messenger
+ */
+static void messenger_Dequeue(int fd, PARCEventType which_event,
+ void *messengerVoidPtr) {
+ Messenger *messenger = (Messenger *)messengerVoidPtr;
+ parcAssertNotNull(messenger, "Called with null messenger pointer");
+
+ Missive *missive;
+ while ((missive = missiveDeque_RemoveFirst(messenger->eventQueue)) != NULL) {
+ for (size_t i = 0; i < parcArrayList_Size(messenger->callbacklist); i++) {
+ MessengerRecipient *recipient =
+ parcArrayList_Get(messenger->callbacklist, i);
+ parcAssertTrue(recipient, "Recipient is null at index %zu", i);
+
+ messengerRecipient_Deliver(recipient, missive_Acquire(missive));
+ }
+
+ // now let go of our reference to the missive
+ missive_Release(&missive);
+ }
+}
diff --git a/hicn-light/src/messenger/messenger.h b/hicn-light/src/messenger/messenger.h
new file mode 100755
index 000000000..f945e7e72
--- /dev/null
+++ b/hicn-light/src/messenger/messenger.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+/**
+ * The EventMessenger is the system that messages events between
+ * producers and consumers.
+ *
+ * Events are delivered in a deferred event cycle to avoid event callbacks
+ * firing when the event generator is still running.
+ */
+
+#ifndef messenger_h
+#define messenger_h
+
+#include <src/core/dispatcher.h>
+#include <src/messenger/messengerRecipient.h>
+#include <src/messenger/missive.h>
+
+struct messenger;
+typedef struct messenger Messenger;
+
+/**
+ * @function eventmessenger_Create
+ * @abstract Creates an event notification system
+ * @discussion
+ * Typically there's only one of these managed by forwarder.
+ *
+ * @param dispatcher is the event dispatcher to use to schedule events.
+ */
+Messenger *messenger_Create(Dispatcher *dispatcher);
+
+/**
+ * @function eventMessenger_Destroy
+ * @abstract Destroys the messenger system, no notification is sent
+ */
+void messenger_Destroy(Messenger **messengerPtr);
+
+/**
+ * @function eventMessenger_Send
+ * @abstract Send an event message, takes ownership of the event memory
+ */
+void messenger_Send(Messenger *messenger, Missive *missive);
+
+/**
+ * @function eventMessenger_Register
+ * @abstract Receive all event messages
+ */
+void messenger_Register(Messenger *messenger,
+ const MessengerRecipient *recipient);
+
+/**
+ * @function eventMessenger_Unregister
+ * @abstract Stop receiving event messages
+ */
+void messenger_Unregister(Messenger *messenger,
+ const MessengerRecipient *recipient);
+#endif // messenger_h
diff --git a/hicn-light/src/messenger/messengerRecipient.c b/hicn-light/src/messenger/messengerRecipient.c
new file mode 100755
index 000000000..14251f8eb
--- /dev/null
+++ b/hicn-light/src/messenger/messengerRecipient.c
@@ -0,0 +1,62 @@
+/*
+ * 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 <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/messenger/messenger.h>
+#include <src/messenger/messengerRecipient.h>
+
+struct messenger_recipient {
+ void *context;
+ MessengerRecipientCallback *notify;
+};
+
+MessengerRecipient *messengerRecipient_Create(
+ void *recipientContext, MessengerRecipientCallback *recipientCallback) {
+ parcAssertNotNull(recipientCallback,
+ "Parameter recipientCallback must be non-null");
+
+ MessengerRecipient *recipient =
+ parcMemory_AllocateAndClear(sizeof(MessengerRecipient));
+ parcAssertNotNull(recipient, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(MessengerRecipient));
+ recipient->context = recipientContext;
+ recipient->notify = recipientCallback;
+ return recipient;
+}
+
+void messengerRecipient_Destroy(MessengerRecipient **recipientPtr) {
+ parcAssertNotNull(recipientPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*recipientPtr,
+ "Parameter must dereference to non-null pointer");
+
+ parcMemory_Deallocate((void **)recipientPtr);
+ *recipientPtr = NULL;
+}
+
+void *messengerRecipient_GetRecipientContext(MessengerRecipient *recipient) {
+ parcAssertNotNull(recipient, "Parameter must be non-null");
+
+ return recipient->context;
+}
+
+void messengerRecipient_Deliver(MessengerRecipient *recipient,
+ Missive *missive) {
+ parcAssertNotNull(recipient, "Parameter must be non-null");
+ recipient->notify(recipient, missive);
+}
diff --git a/hicn-light/src/messenger/messengerRecipient.h b/hicn-light/src/messenger/messengerRecipient.h
new file mode 100755
index 000000000..66d8f40f5
--- /dev/null
+++ b/hicn-light/src/messenger/messengerRecipient.h
@@ -0,0 +1,104 @@
+/*
+ * 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 messengerRecipient.h
+ * @brief A recipient represents the entity that will recieve a Missive from the
+ * Messenger.
+ *
+ * A recipient is identified by the pair (contenxt, callback). The context is
+ * the recipients context, such as it's object pointer. The callback is the
+ * function the recipient uses to receive a Missive.
+ *
+ * If the receiver is going to do a lot of work or potentially send other
+ * missives, the receiver should queue the received notifications and process
+ * them in its own slice.
+ *
+ * A recipient will receive a reference counted copy of the missive, so it must
+ * call
+ * {@link missive_Release} on it.
+ *
+ *
+ */
+
+#ifndef messengerRecipient_h
+#define messengerRecipient_h
+
+#include <src/messenger/missive.h>
+
+struct messenger_recipient;
+typedef struct messenger_recipient MessengerRecipient;
+
+/**
+ * @typedef MessengerRecipientCallback
+ * @abstract A recipient implements a callback to receive Missives.
+ * @constant recipient The recipient to recieve the missive
+ * @constant missive The missive, recipient must call {@link missive_Release} on
+ * it
+ */
+typedef void(MessengerRecipientCallback)(MessengerRecipient *recipient,
+ Missive *missive);
+
+/**
+ * Creates a Recipient, which represents a reciever of missives.
+ *
+ * Creates a Recipient that can be registerd with the Messenger using {@link
+ * messenger_Register}.
+ *
+ * @param [in] recipientContext This pointer will be passed back to the
+ * recipient with each missive, may be NULL
+ * @param [in] recipientCallback The function that receives the missive, must be
+ * non-NULL.
+ *
+ * @return non-null A recipient object
+ */
+MessengerRecipient *messengerRecipient_Create(
+ void *recipientContext, MessengerRecipientCallback *recipientCallback);
+
+/**
+ * Destroys a recipient. You should unregister it first.
+ *
+ * Destroying a recipient does not unregister it, so be sure to call
+ * {@link messenger_Unregister} first.
+ *
+ * @param [in,out] recipientPtr Double pointer to the recipient to destroy, will
+ * be NULL'd.
+ */
+void messengerRecipient_Destroy(MessengerRecipient **recipientPtr);
+
+/**
+ * Returns the recipient context passed on Create
+ *
+ * @param [in] recipient The recipient object
+ *
+ * @return pointer The context pointer used to create the object, maybe NULL
+ */
+void *messengerRecipient_GetRecipientContext(MessengerRecipient *recipient);
+
+/**
+ * Delivers a Missive to the recipient
+ *
+ * Passes the missive to the recipients callback.
+ *
+ * A recipient will receive a reference counted copy of the missive, so it must
+ * call
+ * {@link missive_Release} on it.
+ *
+ * @param [in] recipient The receiver
+ * @param [in] missive The message to send
+ */
+void messengerRecipient_Deliver(MessengerRecipient *recipient,
+ Missive *missive);
+#endif // messengerRecipient_h
diff --git a/hicn-light/src/messenger/missive.c b/hicn-light/src/messenger/missive.c
new file mode 100755
index 000000000..a8bcb0282
--- /dev/null
+++ b/hicn-light/src/messenger/missive.c
@@ -0,0 +1,54 @@
+/*
+ * 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 <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/messenger/missive.h>
+
+struct missive {
+ MissiveType missiveType;
+ unsigned connectionid;
+};
+
+parcObject_Override(Missive, PARCObject, .isLockable = false);
+
+Missive *missive_Create(MissiveType missiveType, unsigned connectionid) {
+ Missive *missive = parcObject_CreateInstance(Missive);
+ missive->missiveType = missiveType;
+ missive->connectionid = connectionid;
+ return missive;
+}
+
+Missive *missive_Acquire(const Missive *missive) {
+ return parcObject_Acquire(missive);
+}
+
+void missive_Release(Missive **missivePtr) {
+ parcObject_Release((void **)missivePtr);
+}
+
+MissiveType missive_GetType(const Missive *missive) {
+ parcAssertNotNull(missive, "Parameter missive must be non-null");
+ return missive->missiveType;
+}
+
+unsigned missive_GetConnectionId(const Missive *missive) {
+ parcAssertNotNull(missive, "Parameter missive must be non-null");
+ return missive->connectionid;
+}
diff --git a/hicn-light/src/messenger/missive.h b/hicn-light/src/messenger/missive.h
new file mode 100755
index 000000000..33f3ef8b8
--- /dev/null
+++ b/hicn-light/src/messenger/missive.h
@@ -0,0 +1,89 @@
+/*
+ * 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 missive.h
+ * @brief A Missive is a status message sent over a broadcast channel inside
+ * hicn-light
+ *
+ * Recipients use {@link messenger_Register} to receive missives. They are
+ * broadcast to all recipients.
+ *
+ */
+#ifndef missive_h
+#define missive_h
+
+#include <src/messenger/missiveType.h>
+
+struct missive;
+typedef struct missive Missive;
+
+/**
+ * Creates a Missive and sets the reference count to 1
+ *
+ * A Missive may be sent to listeners of the Messenger to inform them of events
+ * on a connection id.
+ *
+ * @param [in] MissiveType The event type
+ * @param [in] connectionid The relevant conneciton id
+ *
+ * @return non-null A message
+ * @retrun null An error
+ */
+Missive *missive_Create(MissiveType missiveType, unsigned connectionid);
+
+/**
+ * Acquire a reference counted copy
+ *
+ * Increases the reference count by 1 and returns the original object.
+ *
+ * @param [in] missive An allocated missive
+ *
+ * @return non-null The original missive with increased reference count
+ */
+Missive *missive_Acquire(const Missive *missive);
+
+/**
+ * Releases a reference counted copy.
+ *
+ * If it is the last reference, the missive is freed.
+ *
+ * @param [in,out] missivePtr Double pointer to a missive, will be nulled.
+ */
+void missive_Release(Missive **missivePtr);
+
+/**
+ * Returns the type of the missive
+ *
+ * Returns the type of event the missive represents
+ *
+ * @param [in] missive An allocated missive
+ *
+ * @return MissiveType The event type
+ */
+MissiveType missive_GetType(const Missive *missive);
+
+/**
+ * Returns the connection ID of the missive
+ *
+ * An event is usually associated with a connection id (i.e. the I/O channel
+ * that originaged the event).
+ *
+ * @param [in] missive An allocated missive
+ *
+ * @return number The relevant connection id.
+ */
+unsigned missive_GetConnectionId(const Missive *missive);
+#endif // missive_h
diff --git a/hicn-light/src/messenger/missiveDeque.c b/hicn-light/src/messenger/missiveDeque.c
new file mode 100755
index 000000000..418027d7a
--- /dev/null
+++ b/hicn-light/src/messenger/missiveDeque.c
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/**
+ * A type-safe wrapper for Missives around a {@link PARCDeque}. We only
+ * implement the subset of functions used.
+ *
+ */
+
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/messenger/missive.h>
+#include <src/messenger/missiveDeque.h>
+
+struct missive_deque {
+ PARCDeque *queue;
+};
+
+MissiveDeque *missiveDeque_Create(void) {
+ MissiveDeque *missiveDeque =
+ parcMemory_AllocateAndClear(sizeof(MissiveDeque));
+ parcAssertNotNull(missiveDeque,
+ "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(MissiveDeque));
+ missiveDeque->queue = parcDeque_Create();
+ return missiveDeque;
+}
+
+void missiveDeque_Release(MissiveDeque **dequePtr) {
+ parcAssertNotNull(dequePtr, "Double pointer must be non-null");
+ parcAssertNotNull(*dequePtr, "Double pointer must dereference to non-null");
+ MissiveDeque *missiveDeque = *dequePtr;
+
+ // flush the queue
+ while (!parcDeque_IsEmpty(missiveDeque->queue)) {
+ Missive *missive = missiveDeque_RemoveFirst(missiveDeque);
+ missive_Release(&missive);
+ }
+
+ parcDeque_Release(&missiveDeque->queue);
+ parcMemory_Deallocate((void **)&missiveDeque);
+ *dequePtr = NULL;
+}
+
+MissiveDeque *missiveDeque_Append(MissiveDeque *deque, Missive *missive) {
+ parcAssertNotNull(deque, "Parameter deque must be non-null");
+ parcAssertNotNull(missive, "Parameter missive must be non-null");
+
+ parcDeque_Append(deque->queue, missive);
+ return deque;
+}
+
+Missive *missiveDeque_RemoveFirst(MissiveDeque *deque) {
+ parcAssertNotNull(deque, "Parameter deque must be non-null");
+ return (Missive *)parcDeque_RemoveFirst(deque->queue);
+}
+
+size_t missiveDeque_Size(const MissiveDeque *deque) {
+ parcAssertNotNull(deque, "Parameter deque must be non-null");
+ return parcDeque_Size(deque->queue);
+}
diff --git a/hicn-light/src/messenger/missiveDeque.h b/hicn-light/src/messenger/missiveDeque.h
new file mode 100755
index 000000000..c6f955ce0
--- /dev/null
+++ b/hicn-light/src/messenger/missiveDeque.h
@@ -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.
+ */
+
+/**
+ * @file missiveDeque
+ * @brief Double ended queue of Missives
+ *
+ * Used to queue Missives. This is a type-safe wrapper around {@link PARCDeque}
+ *
+ */
+
+#ifndef missiveDeque_h
+#define missiveDeque_h
+
+struct missive_deque;
+
+typedef struct missive_deque MissiveDeque;
+
+/**
+ * Create a `PARCDeque` instance with the default element equals function.
+ *
+ * The queue is created with no elements.
+ *
+ * The default element equals function is used by the `parcDeque_Equals`
+ * function and simply compares the values using the `==` operator. Users that
+ * need more sophisticated comparisons of the elements need to supply their own
+ * function via the `parcDeque_CreateCustom` function.
+ *
+ * @return non-NULL A pointer to a PARCDeque instance.
+ */
+MissiveDeque *missiveDeque_Create(void);
+
+void missiveDeque_Release(MissiveDeque **dequePtr);
+
+/**
+ * Appends the missive to the queue, taking ownership of the memory
+ */
+MissiveDeque *missiveDeque_Append(MissiveDeque *deque, Missive *missive);
+
+Missive *missiveDeque_RemoveFirst(MissiveDeque *deque);
+
+size_t missiveDeque_Size(const MissiveDeque *deque);
+#endif // missiveDeque_h
diff --git a/hicn-light/src/messenger/missiveType.h b/hicn-light/src/messenger/missiveType.h
new file mode 100755
index 000000000..b0d9c7704
--- /dev/null
+++ b/hicn-light/src/messenger/missiveType.h
@@ -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.
+ */
+
+/**
+ * @file missiveType
+ * @brief Defines what a Missive represents
+ *
+ * Currently, missives only carry information about the state of a connection
+ * (created, up, down, closed, destroyed).
+ *
+ */
+
+#ifndef missiveType_h
+#define missiveType_h
+
+/**
+ * @typedef Represents the state of a connection
+ * @abstract CREATE is the initial state. UP & DOWN are recurrent states.
+ * CLOSED is transient. DESTROYED is the terminal state.
+ * @constant MissiveType_ConnectionCreate Connection created (new)
+ * @constant MissiveType_ConnectionUp Connection is active and passing
+ * data
+ * @constant MissiveType_ConnectionDown Connection is inactive and cannot
+ * pass data
+ * @constant MissiveType_ConnectionClosed Connection closed and will be
+ * destroyed
+ * @constant MissiveType_ConnectionDestroyed Connection destroyed
+ * @discussion State transitions:
+ * initial -> CREATE
+ * CREATE -> (UP | DOWN)
+ * UP -> (DOWN | DESTROYED)
+ * DOWN -> (UP | CLOSED | DESTROYED)
+ * CLOSED -> DESTROYED
+ * DESTROYED -> terminal
+ */
+typedef enum {
+ MissiveType_ConnectionCreate,
+ MissiveType_ConnectionUp,
+ MissiveType_ConnectionDown,
+ MissiveType_ConnectionClosed,
+ MissiveType_ConnectionDestroyed
+} MissiveType;
+#endif // missiveType_h
diff --git a/hicn-light/src/platforms/CMakeLists.txt b/hicn-light/src/platforms/CMakeLists.txt
new file mode 100755
index 000000000..fcb4282ba
--- /dev/null
+++ b/hicn-light/src/platforms/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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+ list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/android/system.c
+ )
+elseif(APPLE)
+ list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/darwin/system.c
+ )
+elseif( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" )
+ list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/linux/system.c
+ )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/hicn-light/src/platforms/README.txt b/hicn-light/src/platforms/README.txt
new file mode 100755
index 000000000..a1293944c
--- /dev/null
+++ b/hicn-light/src/platforms/README.txt
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+
+Operating system dependent modules.
+
diff --git a/hicn-light/src/platforms/android/system.c b/hicn-light/src/platforms/android/system.c
new file mode 100755
index 000000000..68f99424b
--- /dev/null
+++ b/hicn-light/src/platforms/android/system.c
@@ -0,0 +1,183 @@
+/*
+ * 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 <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+//#define __USE_MISC
+#include <net/if.h>
+
+// to get the list of arp types
+#include <net/if_arp.h>
+
+// for the mac address
+#include <netpacket/packet.h>
+
+#include <src/core/forwarder.h>
+#include <src/utils/interfaceSet.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include "ifaddrs.h"
+
+/**
+ * Returns the MTU for a named interface
+ *
+ * On linux, we get the MTU by opening a socket and reading SIOCGIFMTU
+ *
+ * @param [in] ifname Interface name (e.g. "eth0")
+ *
+ * @retval number The MTU in bytes
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static int getMtu(const char *ifname) {
+ struct ifreq ifr;
+ int fd;
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ strcpy(ifr.ifr_name, ifname);
+ ioctl(fd, SIOCGIFMTU, &ifr);
+
+ close(fd);
+ return ifr.ifr_mtu;
+}
+
+InterfaceSet *system_Interfaces(Forwarder *forwarder) {
+ InterfaceSet *set = interfaceSetCreate();
+
+ Logger *logger = forwarder_GetLogger(forwarder);
+
+ // this is the dynamically allocated head of the list
+ struct ifaddrs *ifaddr;
+ int failure = getifaddrs(&ifaddr);
+ parcAssertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno));
+
+ struct ifaddrs *next;
+ for (next = ifaddr; next != NULL; next = next->ifa_next) {
+ if ((next->ifa_addr == NULL) || ((next->ifa_flags & IFF_UP) == 0)) {
+ continue;
+ }
+
+ Interface *iface = interfaceSetGetByName(set, next->ifa_name);
+ if (iface == NULL) {
+ unsigned mtu = (unsigned)getMtu(next->ifa_name);
+
+ iface = interfaceCreate(
+ next->ifa_name, forwarder_GetNextConnectionId(forwarder),
+ next->ifa_flags & IFF_LOOPBACK, next->ifa_flags & IFF_MULTICAST, mtu);
+
+ interfaceSetAdd(set, iface);
+ }
+
+ int family = next->ifa_addr->sa_family;
+ switch (family) {
+ case AF_INET: {
+ Address *address =
+ addressCreateFromInet((struct sockaddr_in *)next->ifa_addr);
+ interfaceAddAddress(iface, address);
+ break;
+ }
+
+ case AF_INET6: {
+ Address *address =
+ addressCreateFromInet6((struct sockaddr_in6 *)next->ifa_addr);
+ interfaceAddAddress(iface, address);
+ break;
+ }
+
+ case AF_PACKET: {
+ struct sockaddr_ll *addr_ll = (struct sockaddr_ll *)next->ifa_addr;
+
+ if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "sockaddr_ll family %d proto %d ifindex %d hatype %d "
+ "pkttype %d halen %d",
+ addr_ll->sll_family, addr_ll->sll_protocol,
+ addr_ll->sll_ifindex, addr_ll->sll_hatype,
+ addr_ll->sll_pkttype, addr_ll->sll_halen);
+ }
+
+ switch (addr_ll->sll_hatype) {
+ // list of the ARP hatypes we can extract a MAC address from
+ case ARPHRD_ETHER:
+ // fallthrough
+ case ARPHRD_IEEE802: {
+ Address *address = addressCreateFromLink(
+ (uint8_t *)addr_ll->sll_addr, addr_ll->sll_halen);
+ interfaceAddAddress(iface, address);
+ break;
+ }
+ default:
+ break;
+ }
+
+ break;
+ }
+ }
+ }
+
+ freeifaddrs(ifaddr);
+ return set;
+}
+
+Address *system_GetMacAddressByName(Forwarder *forwarder,
+ const char *interfaceName) {
+ Address *linkAddress = NULL;
+
+ InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+ Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+ if (interface) {
+ const AddressList *addressList = interfaceGetAddresses(interface);
+
+ size_t length = addressListLength(addressList);
+ for (size_t i = 0; i < length && !linkAddress; i++) {
+ const Address *a = addressListGetItem(addressList, i);
+ if (addressGetType(a) == ADDR_LINK) {
+ linkAddress = addressCopy(a);
+ }
+ }
+ }
+
+ interfaceSetDestroy(&interfaceSet);
+
+ return linkAddress;
+}
+
+unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) {
+ unsigned mtu = 0;
+
+ InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+ Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+ if (interface) {
+ mtu = interfaceGetMTU(interface);
+ }
+
+ interfaceSetDestroy(&interfaceSet);
+
+ return mtu;
+}
diff --git a/hicn-light/src/platforms/darwin/system.c b/hicn-light/src/platforms/darwin/system.c
new file mode 100755
index 000000000..b8ef80c63
--- /dev/null
+++ b/hicn-light/src/platforms/darwin/system.c
@@ -0,0 +1,146 @@
+/*
+ * 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 <errno.h>
+#include <ifaddrs.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <sys/socket.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/interfaceSet.h>
+
+#include <src/core/forwarder.h>
+#include <src/core/system.h>
+
+InterfaceSet *system_Interfaces(Forwarder *forwarder) {
+ InterfaceSet *set = interfaceSetCreate();
+
+ // this is the dynamically allocated head of the list
+ struct ifaddrs *ifaddr;
+ int failure = getifaddrs(&ifaddr);
+ parcAssertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno));
+
+ struct ifaddrs *next;
+ for (next = ifaddr; next != NULL; next = next->ifa_next) {
+ if ((next->ifa_addr == NULL) || ((next->ifa_flags & IFF_UP) == 0)) {
+ continue;
+ }
+
+ // This assumes the LINK address comes first so we can get the MTU
+ // when the interface is created.
+
+ Interface *iface = interfaceSetGetByName(set, next->ifa_name);
+ if (iface == NULL) {
+ unsigned mtu = 0;
+
+ if (next->ifa_data != NULL) {
+ struct if_data *ifdata = (struct if_data *)next->ifa_data;
+ mtu = ifdata->ifi_mtu;
+ }
+
+ iface = interfaceCreate(
+ next->ifa_name, forwarder_GetNextConnectionId(forwarder),
+ next->ifa_flags & IFF_LOOPBACK, next->ifa_flags & IFF_MULTICAST, mtu);
+
+ interfaceSetAdd(set, iface);
+ }
+
+ int family = next->ifa_addr->sa_family;
+ switch (family) {
+ case AF_INET: {
+ Address *address =
+ addressCreateFromInet((struct sockaddr_in *)next->ifa_addr);
+ interfaceAddAddress(iface, address);
+ break;
+ }
+
+ case AF_INET6: {
+ Address *address =
+ addressCreateFromInet6((struct sockaddr_in6 *)next->ifa_addr);
+ interfaceAddAddress(iface, address);
+ break;
+ }
+
+ case AF_LINK: {
+ struct sockaddr_dl *addr_dl = (struct sockaddr_dl *)next->ifa_addr;
+
+ // skip links with 0-length address
+ if (addr_dl->sdl_alen > 0) {
+ // addr_dl->sdl_data[12] contains the interface name followed by the
+ // MAC address, so need to offset in to the array past the interface
+ // name.
+ Address *address = addressCreateFromLink(
+ (uint8_t *)&addr_dl->sdl_data[addr_dl->sdl_nlen],
+ addr_dl->sdl_alen);
+ interfaceAddAddress(iface, address);
+ }
+ break;
+ }
+ }
+ }
+
+ freeifaddrs(ifaddr);
+
+ return set;
+}
+
+Address *system_GetMacAddressByName(Forwarder *forwarder,
+ const char *interfaceName) {
+ Address *linkAddress = NULL;
+
+ InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+ Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+ if (interface) {
+ const AddressList *addressList = interfaceGetAddresses(interface);
+
+ size_t length = addressListLength(addressList);
+ for (size_t i = 0; i < length && !linkAddress; i++) {
+ const Address *a = addressListGetItem(addressList, i);
+ if (addressGetType(a) == ADDR_LINK) {
+ linkAddress = addressCopy(a);
+ }
+ }
+ }
+
+ interfaceSetDestroy(&interfaceSet);
+
+ return linkAddress;
+}
+
+unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) {
+ unsigned mtu = 0;
+
+ if (interfaceName) {
+ InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+ Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+ if (interface) {
+ mtu = interfaceGetMTU(interface);
+ }
+
+ interfaceSetDestroy(&interfaceSet);
+ }
+ return mtu;
+}
diff --git a/hicn-light/src/platforms/linux/system.c b/hicn-light/src/platforms/linux/system.c
new file mode 100755
index 000000000..fcf13becc
--- /dev/null
+++ b/hicn-light/src/platforms/linux/system.c
@@ -0,0 +1,184 @@
+/*
+ * 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 <errno.h>
+#include <ifaddrs.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+//#define __USE_MISC
+#include <net/if.h>
+
+// to get the list of arp types
+#include <net/if_arp.h>
+
+// for the mac address
+#include <netpacket/packet.h>
+
+#include <src/core/forwarder.h>
+#include <src/utils/interfaceSet.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/addressList.h>
+
+/**
+ * Returns the MTU for a named interface
+ *
+ * On linux, we get the MTU by opening a socket and reading SIOCGIFMTU
+ *
+ * @param [in] ifname Interface name (e.g. "eth0")
+ *
+ * @retval number The MTU in bytes
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static int getMtu(const char *ifname) {
+ struct ifreq ifr;
+ int fd;
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ strcpy(ifr.ifr_name, ifname);
+ ioctl(fd, SIOCGIFMTU, &ifr);
+
+ close(fd);
+ return ifr.ifr_mtu;
+}
+
+InterfaceSet *system_Interfaces(Forwarder *forwarder) {
+ InterfaceSet *set = interfaceSetCreate();
+
+ Logger *logger = forwarder_GetLogger(forwarder);
+
+ // this is the dynamically allocated head of the list
+ struct ifaddrs *ifaddr;
+ int failure = getifaddrs(&ifaddr);
+ parcAssertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno));
+
+ struct ifaddrs *next;
+ for (next = ifaddr; next != NULL; next = next->ifa_next) {
+ if ((next->ifa_addr == NULL) || ((next->ifa_flags & IFF_UP) == 0)) {
+ continue;
+ }
+
+ Interface *iface = interfaceSetGetByName(set, next->ifa_name);
+ if (iface == NULL) {
+ unsigned mtu = (unsigned)getMtu(next->ifa_name);
+
+ iface = interfaceCreate(
+ next->ifa_name, forwarder_GetNextConnectionId(forwarder),
+ next->ifa_flags & IFF_LOOPBACK, next->ifa_flags & IFF_MULTICAST, mtu);
+
+ interfaceSetAdd(set, iface);
+ }
+
+ int family = next->ifa_addr->sa_family;
+ switch (family) {
+ case AF_INET: {
+ Address *address =
+ addressCreateFromInet((struct sockaddr_in *)next->ifa_addr);
+ interfaceAddAddress(iface, address);
+ break;
+ }
+
+ case AF_INET6: {
+ Address *address =
+ addressCreateFromInet6((struct sockaddr_in6 *)next->ifa_addr);
+ interfaceAddAddress(iface, address);
+ break;
+ }
+
+ case AF_PACKET: {
+ struct sockaddr_ll *addr_ll = (struct sockaddr_ll *)next->ifa_addr;
+
+ if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+ logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+ "sockaddr_ll family %d proto %d ifindex %d hatype %d "
+ "pkttype %d halen %d",
+ addr_ll->sll_family, addr_ll->sll_protocol,
+ addr_ll->sll_ifindex, addr_ll->sll_hatype,
+ addr_ll->sll_pkttype, addr_ll->sll_halen);
+ }
+
+ switch (addr_ll->sll_hatype) {
+ // list of the ARP hatypes we can extract a MAC address from
+ case ARPHRD_ETHER:
+ // fallthrough
+ case ARPHRD_IEEE802: {
+ Address *address = addressCreateFromLink(
+ (uint8_t *)addr_ll->sll_addr, addr_ll->sll_halen);
+ interfaceAddAddress(iface, address);
+ break;
+ }
+ default:
+ break;
+ }
+
+ break;
+ }
+ }
+ }
+
+ freeifaddrs(ifaddr);
+ return set;
+}
+
+Address *system_GetMacAddressByName(Forwarder *forwarder,
+ const char *interfaceName) {
+ Address *linkAddress = NULL;
+
+ InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+ Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+ if (interface) {
+ const AddressList *addressList = interfaceGetAddresses(interface);
+
+ size_t length = addressListLength(addressList);
+ for (size_t i = 0; i < length && !linkAddress; i++) {
+ const Address *a = addressListGetItem(addressList, i);
+ if (addressGetType(a) == ADDR_LINK) {
+ linkAddress = addressCopy(a);
+ }
+ }
+ }
+
+ interfaceSetDestroy(&interfaceSet);
+
+ return linkAddress;
+}
+
+unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) {
+ unsigned mtu = 0;
+
+ InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+ Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+ if (interface) {
+ mtu = interfaceGetMTU(interface);
+ }
+
+ interfaceSetDestroy(&interfaceSet);
+
+ return mtu;
+}
diff --git a/hicn-light/src/processor/CMakeLists.txt b/hicn-light/src/processor/CMakeLists.txt
new file mode 100755
index 000000000..b7eeabe3b
--- /dev/null
+++ b/hicn-light/src/processor/CMakeLists.txt
@@ -0,0 +1,40 @@
+# 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/fibEntry.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/fibEntryList.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/messageProcessor.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hashTableFunction.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/pit.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/fib.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/pitEntry.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/pitVerdict.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/pitStandard.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/hashTableFunction.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fib.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fibEntry.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fibEntryList.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/messageProcessor.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/pit.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/pitEntry.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/pitStandard.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/hicn-light/src/processor/fib.c b/hicn-light/src/processor/fib.c
new file mode 100755
index 000000000..33d31fd8a
--- /dev/null
+++ b/hicn-light/src/processor/fib.c
@@ -0,0 +1,448 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <src/processor/fib.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#define NULL_POS 128
+#define MSB_POS 127
+
+struct node;
+typedef struct node FibNode;
+
+struct node {
+ FibNode *left;
+ FibNode *right;
+ FibEntry *entry;
+ unsigned pos;
+};
+
+struct fib {
+ FibNode *root;
+ unsigned size;
+};
+
+// =====================================================
+// Public API
+
+FibNode *_createNode(FibNode *left, FibNode *right, FibEntry *entry,
+ unsigned pos) {
+ FibNode *n = parcMemory_AllocateAndClear(sizeof(FibNode));
+ parcAssertNotNull(n, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(FibNode));
+
+ n->left = left;
+ n->right = right;
+ n->entry = entry;
+ n->pos = pos;
+
+ return n;
+}
+
+FIB *fib_Create() {
+ FIB *hicnFib = parcMemory_AllocateAndClear(sizeof(FIB));
+ parcAssertNotNull(hicnFib, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(FIB));
+
+ hicnFib->root =
+ _createNode(NULL, NULL, NULL,
+ NULL_POS); // the pos will decrease going down in the trie
+ hicnFib->root->left = hicnFib->root;
+ hicnFib->root->right = hicnFib->root;
+
+ hicnFib->size = 0;
+
+ return hicnFib;
+}
+
+void _destroyNode(FibNode *n) {
+ fibEntry_Release(&n->entry);
+ parcMemory_Deallocate((void **)&n);
+ n = NULL;
+}
+
+void _destroyFib(FIB *fib) {
+ // XXX
+ // to be done
+ return;
+}
+
+void fib_Destroy(FIB **fibPtr) {
+ parcAssertNotNull(fibPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*fibPtr, "Parameter must dereference to non-null pointer");
+
+ FIB *fib = *fibPtr;
+
+ _destroyFib(fib);
+ parcMemory_Deallocate((void **)&fib);
+ *fibPtr = NULL;
+}
+
+void fib_Add(FIB *fib, FibEntry *entry) {
+ parcAssertNotNull(fib, "Parameter must be non-null");
+ parcAssertNotNull(entry, "Parameter must be non-null");
+
+ NameBitvector *name = name_GetContentName(fibEntry_GetPrefix(entry));
+
+ // search the name
+ FibNode *prev = fib->root;
+ FibNode *curr;
+
+ if (nameBitvector_testBit(name, MSB_POS)) {
+ curr = fib->root->right;
+ } else {
+ curr = fib->root->left;
+ }
+
+ while (prev->pos > curr->pos) {
+ prev = curr;
+ if (nameBitvector_testBit(name, curr->pos)) {
+ curr = curr->right;
+ } else {
+ curr = curr->left;
+ }
+ }
+
+ if (curr->entry != NULL &&
+ nameBitvector_Equals(
+ name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) {
+ // there is already an entry with this name
+ // do nothing. Before call ADD we should check
+ // if the node exists, and, in that case update it
+ return;
+ }
+
+ // if the name is not in the FIB search for the first different bit between
+ // the new name to add and the node found in the trie
+ uint8_t pos = MSB_POS;
+ if (curr->entry != NULL)
+ pos = nameBitvector_firstDiff(
+ name, name_GetContentName(fibEntry_GetPrefix(curr->entry)));
+
+ // reset pointer and search the insertion point
+ prev = fib->root;
+ if (nameBitvector_testBit(name, MSB_POS))
+ curr = fib->root->right;
+ else
+ curr = fib->root->left;
+
+ while (prev->pos > curr->pos && curr->pos > pos) {
+ prev = curr;
+ if (nameBitvector_testBit(name, curr->pos)) {
+ curr = curr->right;
+ } else {
+ curr = curr->left;
+ }
+ }
+
+ // insert the node
+ fib->size++;
+ FibNode *n = _createNode(NULL, NULL, entry, pos);
+
+ if (nameBitvector_testBit(name, pos)) {
+ n->left = curr;
+ n->right = n;
+ } else {
+ n->left = n;
+ n->right = curr;
+ }
+
+ uint8_t new_pos = prev->pos;
+ if (new_pos == NULL_POS) new_pos = MSB_POS;
+
+ if (nameBitvector_testBit(name, new_pos)) {
+ prev->right = n;
+ } else {
+ prev->left = n;
+ }
+}
+
+FibEntry *fib_Contains(const FIB *fib, const Name *prefix) {
+ parcAssertNotNull(fib, "Parameter must be non-null");
+ parcAssertNotNull(prefix, "Parameter must be non-null");
+
+ NameBitvector *name = name_GetContentName(prefix);
+
+ // this is the same as the first part of the add function
+ // we cannnot call this function inside the add because
+ // we need the pointer prev and curr for the insertion
+
+ FibNode *prev = fib->root;
+ FibNode *curr;
+
+ if (nameBitvector_testBit(name, MSB_POS))
+ curr = fib->root->right;
+ else
+ curr = fib->root->left;
+
+ while (prev->pos > curr->pos) {
+ prev = curr;
+
+ if (nameBitvector_testBit(name, curr->pos)) {
+ curr = curr->right;
+ } else {
+ curr = curr->left;
+ }
+ }
+
+ if (curr->entry != NULL &&
+ nameBitvector_Equals(
+ name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) {
+ return curr->entry;
+ } else {
+ return NULL;
+ }
+}
+
+void _removeNode(FIB *fib, const Name *prefix) {
+ parcAssertNotNull(fib, "Parameter must be non-null");
+ parcAssertNotNull(prefix, "Parameter must be non-null");
+
+ FibNode *grand = NULL; // grandparent
+ FibNode *prev =
+ fib->root; // parent: it will points to curr of the next hop in the trie
+ FibNode *curr; // current node: the node to remove
+
+ NameBitvector *name = name_GetContentName(prefix);
+
+ if (nameBitvector_testBit(name, MSB_POS)) {
+ curr = fib->root->right;
+ } else {
+ curr = fib->root->left;
+ }
+
+ // in the first loop we always search the node to remove
+ while (prev->pos > curr->pos) {
+ grand = prev;
+ prev = curr;
+
+ if (nameBitvector_testBit(name, curr->pos)) {
+ curr = curr->right;
+ } else {
+ curr = curr->left;
+ }
+ }
+
+ if (!nameBitvector_Equals(
+ name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) {
+ // the node does not exists
+ return;
+ }
+
+ // search for the real parent of curr (*tmpPrev)
+ // prev points to curr or next node in the trie
+ // this is because of the loopback links
+
+ FibNode *tmpPrev = fib->root;
+ FibNode *tmpCurr;
+
+ if (nameBitvector_testBit(name, MSB_POS)) {
+ tmpCurr = fib->root->right;
+ } else {
+ tmpCurr = fib->root->left;
+ }
+
+ // here we compare pointer so we are sure to stop at the right potion
+ while (tmpCurr != curr) {
+ tmpPrev = tmpCurr;
+
+ if (nameBitvector_testBit(name, tmpCurr->pos)) {
+ tmpCurr = tmpCurr->right;
+ } else {
+ tmpCurr = tmpCurr->left;
+ }
+ }
+
+ // now curr is the node to remove and tmpPrev is the real parent of curr
+
+ if (curr == prev) {
+ // this is the case where curr is a leaf node
+ FibNode *next; // child of curr (the loopback)
+
+ if (nameBitvector_testBit(name, curr->pos)) {
+ next = curr->left;
+ } else {
+ next = curr->right;
+ }
+
+ if (nameBitvector_testBit(name, tmpPrev->pos)) {
+ tmpPrev->right = next;
+ } else {
+ tmpPrev->left = next;
+ }
+
+ } else {
+ // curr is an internal node
+ FibNode *next; // child of prev (loopback)
+
+ if (nameBitvector_testBit(name, prev->pos)) {
+ next = prev->left;
+ } else {
+ next = prev->right;
+ }
+
+ if (nameBitvector_testBit(name, grand->pos)) {
+ grand->right = next;
+ } else {
+ grand->left = next;
+ }
+
+ if (nameBitvector_testBit(name, tmpPrev->pos)) {
+ tmpPrev->right = prev;
+ } else {
+ tmpPrev->left = prev;
+ }
+
+ prev->left = curr->left;
+ prev->right = curr->right;
+ prev->pos = curr->pos;
+ }
+
+ fib->size--;
+ _destroyNode(curr);
+}
+
+void fib_Remove(FIB *fib, const Name *name, unsigned connId) {
+ parcAssertNotNull(fib, "Parameter must be non-null");
+ parcAssertNotNull(name, "Parameter must be non-null");
+
+ FibEntry *entry = fib_Contains(fib, name);
+
+ if (entry == NULL) {
+ return;
+ }
+
+ fibEntry_RemoveNexthopByConnectionId(entry, connId);
+ if (fibEntry_NexthopCount(entry) == 0) {
+ _removeNode(fib, name);
+ }
+}
+
+void _removeConnectionId(FibNode *n, unsigned pos, unsigned connectionId,
+ FibEntryList *list) {
+ if (n->pos < pos) {
+ fibEntry_RemoveNexthopByConnectionId(n->entry, connectionId);
+ if (fibEntry_NexthopCount(n->entry) == 0) {
+ fibEntryList_Append(list, n->entry);
+ }
+ _removeConnectionId(n->left, n->pos, connectionId, list);
+ _removeConnectionId(n->right, n->pos, connectionId, list);
+ }
+}
+
+void fib_RemoveConnectionId(FIB *fib, unsigned connectionId) {
+ parcAssertNotNull(fib, "Parameter must be non-null");
+
+ // 1 - we vist the tree to remove the connection id
+ // 2 - during the visit we collect the fib entry with 0 nexthop
+ // 3 - after the visit we remove this entries
+
+ FibEntryList *list = fibEntryList_Create();
+
+ _removeConnectionId(fib->root->left, fib->root->pos, connectionId, list);
+ _removeConnectionId(fib->root->right, fib->root->pos, connectionId, list);
+
+ 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) {
+ parcAssertNotNull(fib, "Parameter must be non-null");
+ return fib->size;
+}
+
+FibEntry *fib_Match(const FIB *fib, const Message *interestMessage) {
+ parcAssertNotNull(fib, "Parameter must be non-null");
+ parcAssertNotNull(interestMessage, "Parameter must be non-null");
+
+ NameBitvector *name = name_GetContentName(message_GetName(interestMessage));
+
+ FibNode *prev = fib->root;
+ FibNode *curr;
+
+ FibNode *match = NULL;
+ unsigned len = 0;
+
+ if (nameBitvector_testBit(name, MSB_POS))
+ curr = fib->root->right;
+ else
+ curr = fib->root->left;
+
+ while (prev->pos > curr->pos) {
+ prev = curr;
+
+ if (curr->entry != NULL) {
+ if (nameBitvector_StartsWith(
+ name, name_GetContentName(fibEntry_GetPrefix(curr->entry))) &&
+ nameBitvector_GetLength(
+ name_GetContentName(fibEntry_GetPrefix(curr->entry))) > len) {
+ match = curr;
+ len = nameBitvector_GetLength(
+ name_GetContentName(fibEntry_GetPrefix(curr->entry)));
+ }
+ }
+
+ if (nameBitvector_testBit(name, curr->pos))
+ curr = curr->right;
+ else
+ curr = curr->left;
+ }
+
+ if (curr->entry != NULL) {
+ if (nameBitvector_StartsWith(
+ name, name_GetContentName(fibEntry_GetPrefix(curr->entry))) &&
+ nameBitvector_GetLength(
+ name_GetContentName(fibEntry_GetPrefix(curr->entry))) > len) {
+ match = curr;
+ len = nameBitvector_GetLength(
+ name_GetContentName(fibEntry_GetPrefix(curr->entry)));
+ }
+ }
+
+ if (match != NULL && match->entry != NULL) {
+ return match->entry;
+ } else {
+ return NULL;
+ }
+}
+
+void _collectFibEntries(FibNode *n, int pos, FibEntryList *list) {
+ if (n->pos < pos) {
+ fibEntryList_Append(list, n->entry);
+ _collectFibEntries(n->left, n->pos, list);
+ _collectFibEntries(n->right, n->pos, list);
+ }
+}
+
+FibEntryList *fib_GetEntries(const FIB *fib) {
+ parcAssertNotNull(fib, "Parameter must be non-null");
+
+ FibEntryList *list = fibEntryList_Create();
+
+ _collectFibEntries(fib->root->left, fib->root->pos, list);
+ _collectFibEntries(fib->root->right, fib->root->pos, list);
+
+ return list;
+}
diff --git a/hicn-light/src/processor/fib.h b/hicn-light/src/processor/fib.h
new file mode 100755
index 000000000..4409419db
--- /dev/null
+++ b/hicn-light/src/processor/fib.h
@@ -0,0 +1,43 @@
+/*
+ * 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 fib_h
+#define fib_h
+
+#include <src/core/message.h>
+#include <src/core/name.h>
+#include <src/processor/fibEntry.h>
+#include <src/processor/fibEntryList.h>
+
+struct fib;
+typedef struct fib FIB;
+
+FIB *fib_Create();
+
+void fib_Destroy(FIB **fibPtr);
+
+void fib_Add(FIB *fib, FibEntry *node);
+
+FibEntry *fib_Contains(const FIB *fib, const Name *prefix);
+
+void fib_Remove(FIB *fib, const Name *prefix, unsigned connId);
+
+void fib_RemoveConnectionId(FIB *fib, unsigned connectionId);
+
+FibEntry *fib_Match(const FIB *fib, const Message *interestMessage);
+
+size_t fib_Length(const FIB *fib);
+
+FibEntryList *fib_GetEntries(const FIB *fib);
+#endif // fib_h
diff --git a/hicn-light/src/processor/fibEntry.c b/hicn-light/src/processor/fibEntry.c
new file mode 100755
index 000000000..bb877030f
--- /dev/null
+++ b/hicn-light/src/processor/fibEntry.c
@@ -0,0 +1,223 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <src/core/numberSet.h>
+#include <src/processor/fibEntry.h>
+
+#include <src/core/nameBitvector.h>
+
+#include <src/strategies/loadBalancer.h>
+#include <src/strategies/loadBalancerWithPD.h>
+#include <src/strategies/rnd.h>
+#include <src/strategies/rndSegment.h>
+#include <src/strategies/strategyImpl.h>
+#ifdef WITH_MAPME
+#include <parc/algol/parc_HashMap.h>
+#include <src/core/ticks.h>
+#endif /* WITH_MAPME */
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/commands.h>
+
+struct fib_entry {
+ Name *name;
+ unsigned refcount;
+ StrategyImpl *fwdStrategy;
+#ifdef WITH_MAPME
+ void *userData;
+ void (*userDataRelease)(void **userData);
+#endif /* WITH_MAPME */
+};
+
+FibEntry *fibEntry_Create(Name *name, strategy_type fwdStrategy) {
+ FibEntry *fibEntry = parcMemory_AllocateAndClear(sizeof(FibEntry));
+ parcAssertNotNull(fibEntry, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(FibEntry));
+ fibEntry->name = name_Acquire(name);
+
+ if (fwdStrategy) {
+ switch (fwdStrategy) {
+ case SET_STRATEGY_LOADBALANCER:
+ fibEntry->fwdStrategy = strategyLoadBalancer_Create();
+ break;
+
+ case SET_STRATEGY_RANDOM_PER_DASH_SEGMENT:
+ fibEntry->fwdStrategy = strategyRndSegment_Create();
+ break;
+
+ case SET_STRATEGY_LOADBALANCER_WITH_DELAY:
+ fibEntry->fwdStrategy = strategyLoadBalancerWithPD_Create();
+ break;
+
+ default:
+ // LB is the defualt strategy
+ fibEntry->fwdStrategy = strategyLoadBalancer_Create();
+ // the LB strategy is the default one
+ // other strategies can be set using the appropiate function
+ break;
+ }
+
+ } else {
+ fibEntry->fwdStrategy = strategyLoadBalancer_Create();
+ }
+
+ fibEntry->refcount = 1;
+
+#ifdef WITH_MAPME
+ fibEntry->userData = NULL;
+ fibEntry->userDataRelease = NULL;
+#endif /* WITH_MAPME */
+
+ return fibEntry;
+}
+
+FibEntry *fibEntry_Acquire(const FibEntry *fibEntry) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ FibEntry *copy = (FibEntry *)fibEntry;
+ copy->refcount++;
+ return copy;
+}
+
+void fibEntry_Release(FibEntry **fibEntryPtr) {
+ FibEntry *fibEntry = *fibEntryPtr;
+ parcAssertTrue(fibEntry->refcount > 0, "Illegal state: refcount is 0");
+ fibEntry->refcount--;
+ if (fibEntry->refcount == 0) {
+ name_Release(&fibEntry->name);
+ fibEntry->fwdStrategy->destroy(&(fibEntry->fwdStrategy));
+#ifdef WITH_MAPME
+ if (fibEntry->userData) {
+ fibEntry->userDataRelease(&fibEntry->userData);
+ }
+#endif /* WITH_MAPME */
+ parcMemory_Deallocate((void **)&fibEntry);
+ }
+ *fibEntryPtr = NULL;
+}
+
+void fibEntry_SetStrategy(FibEntry *fibEntry, strategy_type strategy) {
+ StrategyImpl *fwdStrategyImpl;
+
+ switch (strategy) {
+ case SET_STRATEGY_LOADBALANCER:
+ fwdStrategyImpl = strategyLoadBalancer_Create();
+ break;
+
+ case SET_STRATEGY_RANDOM_PER_DASH_SEGMENT:
+ fwdStrategyImpl = strategyRndSegment_Create();
+ break;
+
+ case SET_STRATEGY_LOADBALANCER_WITH_DELAY:
+ fwdStrategyImpl = strategyLoadBalancerWithPD_Create();
+ break;
+
+ default:
+ // LB is the defualt strategy
+ fwdStrategyImpl = strategyLoadBalancer_Create();
+ // the LB strategy is the default one
+ // other strategies can be set using the appropiate function
+ break;
+ }
+
+ const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry);
+ unsigned size = fibEntry_NexthopCount(fibEntry);
+ for (unsigned i = 0; i < size; i++) {
+ fwdStrategyImpl->addNexthop(fwdStrategyImpl,
+ numberSet_GetItem(nexthops, i));
+ }
+ fibEntry->fwdStrategy->destroy(&(fibEntry->fwdStrategy));
+ fibEntry->fwdStrategy = fwdStrategyImpl;
+}
+void fibEntry_AddNexthop(FibEntry *fibEntry, unsigned connectionId) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ fibEntry->fwdStrategy->addNexthop(fibEntry->fwdStrategy, connectionId);
+}
+
+void fibEntry_RemoveNexthopByConnectionId(FibEntry *fibEntry,
+ unsigned connectionId) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ fibEntry->fwdStrategy->removeNexthop(fibEntry->fwdStrategy, connectionId);
+}
+
+size_t fibEntry_NexthopCount(const FibEntry *fibEntry) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ return fibEntry->fwdStrategy->countNexthops(fibEntry->fwdStrategy);
+}
+
+const NumberSet *fibEntry_GetNexthops(const FibEntry *fibEntry) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ return fibEntry->fwdStrategy->returnNexthops(fibEntry->fwdStrategy);
+}
+
+const NumberSet *fibEntry_GetNexthopsFromForwardingStrategy(
+ const FibEntry *fibEntry, const Message *interestMessage) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ return fibEntry->fwdStrategy->lookupNexthop(fibEntry->fwdStrategy,
+ interestMessage);
+}
+
+void fibEntry_ReceiveObjectMessage(const FibEntry *fibEntry,
+ const NumberSet *egressId,
+ const Message *objectMessage, Ticks rtt) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ fibEntry->fwdStrategy->receiveObject(fibEntry->fwdStrategy, egressId,
+ objectMessage, rtt);
+}
+
+void fibEntry_OnTimeout(const FibEntry *fibEntry, const NumberSet *egressId) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ fibEntry->fwdStrategy->onTimeout(fibEntry->fwdStrategy, egressId);
+}
+
+Name *fibEntry_GetPrefix(const FibEntry *fibEntry) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ return fibEntry->name;
+ // return metisName_Acquire(fibEntry->name);
+}
+
+strategy_type fibEntry_GetFwdStrategyType(const FibEntry *fibEntry) {
+ return fibEntry->fwdStrategy->getStrategy(fibEntry->fwdStrategy);
+}
+
+StrategyImpl *fibEntry_GetFwdStrategy(const FibEntry *fibEntry) {
+ return fibEntry->fwdStrategy;
+}
+
+#ifdef WITH_MAPME
+
+void fibEntry_AddNexthopByConnectionId(FibEntry *fibEntry,
+ unsigned connectionId) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ fibEntry->fwdStrategy->addNexthop(fibEntry->fwdStrategy, connectionId);
+}
+
+void *fibEntry_getUserData(const FibEntry *fibEntry) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ return fibEntry->userData;
+}
+
+void fibEntry_setUserData(FibEntry *fibEntry, const void *userData,
+ void (*userDataRelease)(void **)) {
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ fibEntry->userData = (void *)userData;
+ fibEntry->userDataRelease = userDataRelease;
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/processor/fibEntry.h b/hicn-light/src/processor/fibEntry.h
new file mode 100755
index 000000000..3bcac3884
--- /dev/null
+++ b/hicn-light/src/processor/fibEntry.h
@@ -0,0 +1,143 @@
+/*
+ * 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 fibEntry.h
+ * @brief A forwarding entry in the FIB table
+ *
+ * A Forwarding Information Base (FIB) entry (FibEntry) is a
+ * set of nexthops for a name. It also indicates the forwarding strategy.
+ *
+ * Each nexthop contains the ConnectionId assocaited with it. This could be
+ * something specific like a MAC address or point-to-point tunnel. Or, it
+ * could be something general like a MAC group address or ip multicast overlay.
+ *
+ * See strategy.h for a description of forwarding strategies.
+ * In short, a strategy is the algorithm used to select one or more nexthops
+ * from the set of available nexthops.
+ *
+ * Each nexthop also contains a void* to a forwarding strategy data container.
+ * This allows a strategy to keep proprietary information about each nexthop.
+ *
+ *
+ */
+
+#ifndef fibEntry_h
+#define fibEntry_h
+
+#include <src/core/name.h>
+#include <src/strategies/strategyImpl.h>
+
+#ifdef WITH_MAPME
+#include <parc/algol/parc_EventTimer.h>
+#include <parc/algol/parc_Iterator.h>
+#endif /* WITH_MAPME */
+
+struct fib_entry;
+typedef struct fib_entry FibEntry;
+
+FibEntry *fibEntry_Create(Name *name, strategy_type fwdStrategy);
+
+/**
+ * Decrements the reference count by one, and destroys the memory after last
+ * release
+ *
+ */
+void fibEntry_Release(FibEntry **fibEntryPtr);
+
+/**
+ * Returns a reference counted copy of the fib entry
+ *
+ * The reference count is increased by one. The returned value must be
+ * released via fibEnty_Release().
+ *
+ * @param [in] fibEntry An allocated FibEntry
+ *
+ * @return non-null A reference counted copy of the fibEntry
+ *
+ */
+FibEntry *fibEntry_Acquire(const FibEntry *fibEntry);
+
+void fibEntry_SetStrategy(FibEntry *fibEntry, strategy_type strategy);
+
+void fibEntry_AddNexthop(FibEntry *fibEntry, unsigned connectionId);
+
+void fibEntry_RemoveNexthopByConnectionId(FibEntry *fibEntry,
+ unsigned connectionId);
+
+size_t fibEntry_NexthopCount(const FibEntry *fibEntry);
+
+/**
+ * @function fibEntry_GetNexthops
+ * @abstract Returns the nexthop set of the FIB entry. You must Acquire if it
+ * will be saved.
+ * @discussion
+ * Returns the next hop set for the FIB entry.
+ */
+const NumberSet *fibEntry_GetNexthops(const FibEntry *fibEntry);
+
+const NumberSet *fibEntry_GetNexthopsFromForwardingStrategy(
+ const FibEntry *fibEntry, const Message *interestMessage);
+
+void fibEntry_ReceiveObjectMessage(const FibEntry *fibEntry,
+ const NumberSet *egressId,
+ const Message *objectMessage, Ticks rtt);
+
+void fibEntry_OnTimeout(const FibEntry *fibEntry, const NumberSet *egressId);
+
+strategy_type fibEntry_GetFwdStrategyType(const FibEntry *fibEntry);
+
+StrategyImpl *fibEntry_GetFwdStrategy(const FibEntry *fibEntry);
+
+/**
+ * @function fibEntry_GetPrefix
+ * @abstract Returns a copy of the prefix.
+ * @return A reference counted copy that you must destroy
+ */
+Name *fibEntry_GetPrefix(const FibEntry *fibEntry);
+
+#ifdef WITH_MAPME
+
+/**
+ * @function fibEntry_AddNexthopByConnectionId
+ * @abstract Adds a next hop directly from the connection id.
+ * @param [in] fibEntry - Pointer to the FIB entry.
+ * @return The sequence number stored in the FIB entry.
+ */
+void fibEntry_AddNexthopByConnectionId(FibEntry *fibEntry,
+ unsigned connectionId);
+
+/**
+ * @function fibEntry_getUserData
+ * @abstract Returns user data associated to the FIB entry.
+ * @param [in] fibEntry - Pointer to the FIB entry.
+ * @return User data as a void pointer
+ */
+void *fibEntry_getUserData(const FibEntry *fibEntry);
+
+/**
+ * @function fibEntry_getUserData
+ * @abstract Associates user data and release callback to a FIB entry.
+ * @param [in] fibEntry - Pointer to the FIB entry.
+ * @param [in] userData - Generic pointer to user data
+ * @param [in@ userDataRelease - Callback used to release user data upon change
+ * of FIB entry removal.
+ */
+void fibEntry_setUserData(FibEntry *fibEntry, const void *userData,
+ void (*userDataRelease)(void **));
+
+#endif /* WITH_MAPME */
+
+#endif // fibEntry_h
diff --git a/hicn-light/src/processor/fibEntryList.c b/hicn-light/src/processor/fibEntryList.c
new file mode 100755
index 000000000..2221fa614
--- /dev/null
+++ b/hicn-light/src/processor/fibEntryList.c
@@ -0,0 +1,72 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/processor/fibEntryList.h>
+
+struct fib_entry_list {
+ PARCArrayList *listOfFibEntries;
+};
+
+static void fibEntryList_ListDestroyer(void **voidPtr) {
+ FibEntry **entryPtr = (FibEntry **)voidPtr;
+ fibEntry_Release(entryPtr);
+}
+
+FibEntryList *fibEntryList_Create() {
+ FibEntryList *fibEntryList =
+ parcMemory_AllocateAndClear(sizeof(FibEntryList));
+ parcAssertNotNull(fibEntryList,
+ "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(FibEntryList));
+ fibEntryList->listOfFibEntries =
+ parcArrayList_Create(fibEntryList_ListDestroyer);
+ return fibEntryList;
+}
+
+void fibEntryList_Destroy(FibEntryList **listPtr) {
+ parcAssertNotNull(listPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*listPtr, "Parameter must dereference to non-null pointer");
+
+ FibEntryList *list = *listPtr;
+ parcArrayList_Destroy(&list->listOfFibEntries);
+ parcMemory_Deallocate((void **)&list);
+ listPtr = NULL;
+}
+
+void fibEntryList_Append(FibEntryList *list, FibEntry *fibEntry) {
+ parcAssertNotNull(list, "Parameter list must be non-null pointer");
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null pointer");
+
+ FibEntry *copy = fibEntry_Acquire(fibEntry);
+ parcArrayList_Add(list->listOfFibEntries, copy);
+}
+
+size_t fibEntryList_Length(const FibEntryList *list) {
+ parcAssertNotNull(list, "Parameter list must be non-null pointer");
+ return parcArrayList_Size(list->listOfFibEntries);
+}
+
+const FibEntry *fibEntryList_Get(const FibEntryList *list, size_t index) {
+ parcAssertNotNull(list, "Parameter list must be non-null pointer");
+ FibEntry *entry = parcArrayList_Get(list->listOfFibEntries, index);
+ return entry;
+}
diff --git a/hicn-light/src/processor/fibEntryList.h b/hicn-light/src/processor/fibEntryList.h
new file mode 100755
index 000000000..0f6066435
--- /dev/null
+++ b/hicn-light/src/processor/fibEntryList.h
@@ -0,0 +1,96 @@
+/*
+ * 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 fibEntryList.h
+ * @brief A typesafe list of FibEntry
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef fibEntryList_h
+#define fibEntryList_h
+
+#include <src/processor/fibEntry.h>
+
+struct fib_entry_list;
+typedef struct fib_entry_list FibEntryList;
+
+/**
+ * Creates an emtpy FIB entry list
+ *
+ * Must be destroyed with fibEntryList_Destroy.
+ *
+ * @retval non-null An allocated FibEntryList
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+FibEntryList *fibEntryList_Create(void);
+
+/**
+ * @function FibEntryList_Detroy
+ * @abstract Destroys the list and all entries.
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ */
+void fibEntryList_Destroy(FibEntryList **listPtr);
+
+/**
+ * @function fibEntryList_Append
+ * @abstract Will store a reference counted copy of the entry.
+ * @discussion
+ * Will create and store a reference counted copy. You keep ownership
+ * of the parameter <code>fibEntry</code>.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+void fibEntryList_Append(FibEntryList *list, FibEntry *fibEntry);
+
+/**
+ * Returns the number of entries in the list
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] list An allocated FibEntryList
+ *
+ * @retval number The number of entries in the list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t fibEntryList_Length(const FibEntryList *list);
+
+/**
+ * @function fibEntryList_Get
+ * @abstract Gets an element. This is the internal reference, do not destroy.
+ * @discussion
+ * Returns an internal reference from the list. You must not destroy it.
+ * Will assert if you go off the end of the list.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+const FibEntry *fibEntryList_Get(const FibEntryList *list, size_t index);
+#endif // fibEntryList_h
diff --git a/hicn-light/src/processor/hashTableFunction.c b/hicn-light/src/processor/hashTableFunction.c
new file mode 100755
index 000000000..6e70ef91a
--- /dev/null
+++ b/hicn-light/src/processor/hashTableFunction.c
@@ -0,0 +1,47 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/core/message.h>
+#include <src/processor/hashTableFunction.h>
+
+#include <parc/assert/parc_Assert.h>
+
+// ======================================================================
+// Hash table key functions
+// We use a Message as the key data type
+
+bool hashTableFunction_MessageNameEquals(const void *messageA,
+ const void *messageB) {
+ const Message *a = (const Message *)messageA;
+ const Message *b = (const Message *)messageB;
+
+ return name_Equals(message_GetName(a), message_GetName(b));
+}
+
+HashCodeType hashTableFunction_MessageNameHashCode(const void *messageA) {
+ const Message *message = (const Message *)messageA;
+ Name *name = message_GetName(message);
+
+ // we want the cumulative hash for the whole name
+ uint32_t hash = name_HashCode(name);
+
+ return hash;
+} \ No newline at end of file
diff --git a/hicn-light/src/processor/hashTableFunction.h b/hicn-light/src/processor/hashTableFunction.h
new file mode 100755
index 000000000..eb9989086
--- /dev/null
+++ b/hicn-light/src/processor/hashTableFunction.h
@@ -0,0 +1,73 @@
+/*
+ * 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 hashTableFunction.h
+ * @brief These functions are used in PARCHashCodeTables by the
+ * MatchingRulesTable and ContentStore and PIT. They perform the equality
+ * and has generation needed by the PARCHashCodeTable.
+ *
+ */
+#ifndef hashTableFunction_h
+#define hashTableFunction_h
+
+#include <parc/algol/parc_HashCodeTable.h>
+
+// ==========================================================
+// These functions operate on a message as the key in the HashTable.
+// The functions use void * rather than message instances in the function
+// signature because it is using generic has code tables from PARC Library
+
+/**
+ * Determine if the Names of two `message` instances are equal.
+ *
+ * The following equivalence relations on non-null `message` instances are
+ * maintained:
+ *
+ * * It is reflexive: for any non-null reference value x,
+ * `hashTableFunction_MessageNameEquals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `message_Equals(x, y)` must return true if and only if
+ * `hashTableFunction_MessageNameEquals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `hashTableFunction_MessageNameEquals(x, y)` returns true and
+ * `hashTableFunction_MessageNameEquals(y, z)` returns true,
+ * then `hashTableFunction_MessageNameEquals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `hashTableFunction_MessageNameEquals(x, y)` consistently
+ * return true or consistently return false.
+ *
+ * * For any non-null reference value x,
+ * `hashTableFunction_MessageNameEquals(x, NULL)` must return false.
+ *
+ * @param a A pointer to a `message` instance.
+ * @param b A pointer to a `message` instance.
+ * @return true if the names of the two `message` instances are equal.
+ */
+bool hashTableFunction_MessageNameEquals(const void *messageA,
+ const void *messageB);
+
+/**
+ * @function hashTableFunction_NameHashCode
+ * @abstract Computes the hash of the entire name in a message
+ *
+ * @param messageA is a message
+ * @return A non-cryptographic hash of Name
+ */
+HashCodeType hashTableFunction_MessageNameHashCode(const void *messageA);
+#endif // hashTableFunction_h \ No newline at end of file
diff --git a/hicn-light/src/processor/matchingRulesTable.c b/hicn-light/src/processor/matchingRulesTable.c
new file mode 100755
index 000000000..56e59c29e
--- /dev/null
+++ b/hicn-light/src/processor/matchingRulesTable.c
@@ -0,0 +1,132 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/processor/hashTableFunction.h>
+#include <src/processor/matchingRulesTable.h>
+
+struct matching_rules_table {
+ // using this wrapper we can manatain multiple hash tables indexed in
+ // different ways
+ // for now we use only a table indexed by name
+
+ PARCHashCodeTable *tableByName;
+ PARCHashCodeTable_Destroyer dataDestroyer;
+};
+
+static PARCHashCodeTable *matchingRulesTable_GetTableForMessage(
+ const MatchingRulesTable *pit, const Message *interestMessage);
+
+// ======================================================================
+
+MatchingRulesTable *matchingRulesTable_Create(
+ PARCHashCodeTable_Destroyer dataDestroyer) {
+ size_t initialSize = 65535;
+
+ MatchingRulesTable *table =
+ parcMemory_AllocateAndClear(sizeof(MatchingRulesTable));
+ parcAssertNotNull(table, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(MatchingRulesTable));
+ table->dataDestroyer = dataDestroyer;
+
+ table->tableByName = parcHashCodeTable_Create_Size(
+ hashTableFunction_MessageNameEquals,
+ hashTableFunction_MessageNameHashCode, NULL, dataDestroyer, initialSize);
+
+ return table;
+}
+
+void matchingRulesTable_Destroy(MatchingRulesTable **tablePtr) {
+ parcAssertNotNull(tablePtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*tablePtr,
+ "Parameter must dereference to non-null pointer");
+
+ MatchingRulesTable *table = *tablePtr;
+
+ parcHashCodeTable_Destroy(&table->tableByName);
+
+ parcMemory_Deallocate((void **)&table);
+ *tablePtr = NULL;
+}
+
+void *matchingRulesTable_Get(const MatchingRulesTable *rulesTable,
+ const Message *message) {
+ parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+
+ PARCHashCodeTable *hashTable =
+ matchingRulesTable_GetTableForMessage(rulesTable, message);
+ return parcHashCodeTable_Get(hashTable, message);
+}
+
+PARCArrayList *matchingRulesTable_GetUnion(const MatchingRulesTable *table,
+ const Message *message) {
+ PARCArrayList *list = parcArrayList_Create_Capacity(NULL, NULL, 3);
+
+ void *dataByName = parcHashCodeTable_Get(table->tableByName, message);
+ if (dataByName) {
+ parcArrayList_Add(list, dataByName);
+ }
+
+ return list;
+}
+
+void matchingRulesTable_RemoveFromBest(MatchingRulesTable *rulesTable,
+ const Message *message) {
+ parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+
+ PARCHashCodeTable *hashTable =
+ matchingRulesTable_GetTableForMessage(rulesTable, message);
+ parcHashCodeTable_Del(hashTable, message);
+}
+
+void matchingRulesTable_RemoveFromAll(MatchingRulesTable *rulesTable,
+ const Message *message) {
+ parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+
+ parcHashCodeTable_Del(rulesTable->tableByName, message);
+}
+
+bool matchingRulesTable_AddToBestTable(MatchingRulesTable *rulesTable,
+ Message *key, void *data) {
+ parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null");
+ parcAssertNotNull(key, "Parameter key must be non-null");
+ parcAssertNotNull(data, "Parameter data must be non-null");
+
+ PARCHashCodeTable *hashTable =
+ matchingRulesTable_GetTableForMessage(rulesTable, key);
+
+ bool success = parcHashCodeTable_Add(hashTable, key, data);
+
+ return success;
+}
+
+// ========================================================================================
+
+static PARCHashCodeTable *matchingRulesTable_GetTableForMessage(
+ const MatchingRulesTable *pit, const Message *interestMessage) {
+ PARCHashCodeTable *table;
+ table = pit->tableByName;
+
+ return table;
+}
diff --git a/hicn-light/src/processor/matchingRulesTable.h b/hicn-light/src/processor/matchingRulesTable.h
new file mode 100755
index 000000000..96d099430
--- /dev/null
+++ b/hicn-light/src/processor/matchingRulesTable.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header matchingRulesTable
+ * @abstract A generic table (void *) that matches a Message
+ * @discussion
+ * Matching is done based on Name
+ *
+ * When used in the PIT, one calls
+ * <code>matchingRulesTable_AddToBestTable()</code> to add an interest to the
+ * "best" (i.e. most restrictive match) table, then calls
+ * <code>matchingRulesTable_GetUnion()</code> on a content object to match
+ * against all of them.
+ *
+ * When used in a ContentStore, one calls
+ * <code>matchingRulesTable_AddToAllTables()</code> to index a Content Object in
+ * all the tables. one then calls <code>matchingRulesTable_Get()</code> with an
+ * Interest to do the "best" matching (i.e by hash first, then keyid, then just
+ * by name).
+ *
+ */
+
+#ifndef matchingRulesTable_h
+#define matchingRulesTable_h
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <src/core/message.h>
+
+struct matching_rules_table;
+typedef struct matching_rules_table MatchingRulesTable;
+
+/**
+ * Creates a MatchigRulesTable and specifies the function to call to de-allocate
+ * an entry
+ *
+ * The datadestroyer will be called when an entry is removed from a table. It
+ * may be NULL.
+ */
+MatchingRulesTable *matchingRulesTable_Create(
+ PARCHashCodeTable_Destroyer dataDestroyer);
+
+/**
+ * Destroys the table and removes all stored elements.
+ *
+ */
+void matchingRulesTable_Destroy(MatchingRulesTable **tablePtr);
+
+/**
+ * @function matchingRulesTable_Get
+ * @abstract Returns the data item that best matches the message.
+ * @discussion
+ * Indexed by NameAndContentObjectHash, NameAndKeyId, and Name, in that order.
+ *
+ * @return NULL if nothing matches, otherwise the stored value
+ */
+void *matchingRulesTable_Get(const MatchingRulesTable *table,
+ const Message *message);
+
+/**
+ * @function matchingRulesTable_GetUnion
+ * @abstract Returns matching data items from all index tables.
+ * @discussion
+ * The PARCArrayList does not have an item destructor, so destroying it will
+ * not affect the underlying data.
+ *
+ * @return Will not be NULL, but may be empty
+ */
+PARCArrayList *matchingRulesTable_GetUnion(const MatchingRulesTable *table,
+ const Message *message);
+
+/**
+ * @function matchingRulesTable_Add
+ * @abstract Adds the data to the best table
+ * @discussion
+ * The key must be derived from the data and destroyed when the data is
+ * destroyed. Only the data destroyer is called.
+ *
+ * No duplicates are allowed, will return false if not added.
+ *
+ * @return true if unique key and added, false if duplicate and no action taken.
+ */
+bool matchingRulesTable_AddToBestTable(MatchingRulesTable *rulesTable,
+ Message *key, void *data);
+
+/**
+ * @function matchingRulesTable_Remove
+ * @abstract Removes the matching entry from the best match table, calling the
+ * destroyer on the data.
+ */
+void matchingRulesTable_RemoveFromBest(MatchingRulesTable *rulesTable,
+ const Message *message);
+
+/**
+ * @function matchingRulesTable_RemoveFromAll
+ * @abstract Removes the message from all tables
+ */
+void matchingRulesTable_RemoveFromAll(MatchingRulesTable *rulesTable,
+ const Message *message);
+#endif // matchingRulesTable_h
diff --git a/hicn-light/src/processor/messageProcessor.c b/hicn-light/src/processor/messageProcessor.c
new file mode 100755
index 000000000..8c03ee739
--- /dev/null
+++ b/hicn-light/src/processor/messageProcessor.c
@@ -0,0 +1,742 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <src/processor/messageProcessor.h>
+
+#include <src/processor/fib.h>
+#include <src/processor/pitStandard.h>
+
+#include <src/content_store/contentStoreInterface.h>
+#include <src/content_store/contentStoreLRU.h>
+
+#include <src/strategies/loadBalancer.h>
+#include <src/strategies/loadBalancerWithPD.h>
+#include <src/strategies/rnd.h>
+#include <src/strategies/rndSegment.h>
+#include <src/strategies/strategyImpl.h>
+
+#include <src/io/streamConnection.h>
+#include <src/io/udpListener.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+#include <src/utils/address.h>
+
+/*
+ * 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.
+ */
+typedef struct processor_stats {
+ uint32_t countReceived;
+ uint32_t countInterestsReceived;
+ uint32_t countObjectsReceived;
+
+ uint32_t countInterestsAggregated;
+
+ uint32_t countDropped;
+ uint32_t countInterestsDropped;
+ uint32_t countDroppedNoRoute;
+ uint32_t countDroppedNoReversePath;
+
+ uint32_t countDroppedConnectionNotFound;
+ uint32_t countObjectsDropped;
+
+ uint32_t countSendFailures;
+ uint32_t countInterestForwarded;
+ uint32_t countObjectsForwarded;
+ uint32_t countInterestsSatisfiedFromStore;
+
+ uint32_t countDroppedNoHopLimit;
+ uint32_t countDroppedZeroHopLimitFromRemote;
+ uint32_t countDroppedZeroHopLimitToRemote;
+} _ProcessorStats;
+
+struct message_processor {
+ Forwarder *forwarder;
+ Logger *logger;
+
+ PIT *pit;
+ ContentStoreInterface *contentStore;
+ FIB *fib;
+
+ bool store_in_cache;
+ bool serve_from_cache;
+
+ _ProcessorStats stats;
+};
+
+static void messageProcessor_Drop(MessageProcessor *processor,
+ Message *message);
+static void messageProcessor_ReceiveInterest(MessageProcessor *processor,
+ Message *interestMessage);
+static void messageProcessor_ReceiveContentObject(MessageProcessor *processor,
+ Message *objectMessage);
+static unsigned messageProcessor_ForwardToNexthops(MessageProcessor *processor,
+ Message *message,
+ const NumberSet *nexthops);
+
+static void messageProcessor_ForwardToInterfaceId(MessageProcessor *processor,
+ Message *message,
+ unsigned interfaceId);
+
+// ============================================================
+// Public API
+
+MessageProcessor *messageProcessor_Create(Forwarder *forwarder) {
+ size_t objectStoreSize =
+ configuration_GetObjectStoreSize(forwarder_GetConfiguration(forwarder));
+
+ MessageProcessor *processor =
+ parcMemory_AllocateAndClear(sizeof(MessageProcessor));
+ parcAssertNotNull(processor, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(MessageProcessor));
+ memset(processor, 0, sizeof(MessageProcessor));
+
+ processor->forwarder = forwarder;
+ processor->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+ processor->pit = pitStandard_Create(forwarder);
+
+ processor->fib = fib_Create();
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "MessageProcessor %p created", (void *)processor);
+ }
+
+ ContentStoreConfig contentStoreConfig = {
+ .objectCapacity = objectStoreSize,
+ };
+
+ processor->contentStore =
+ contentStoreLRU_Create(&contentStoreConfig, processor->logger);
+
+ // the two flags for the cache are set to true by default. If the cache
+ // is active it always work as expected unless the use modifies this
+ // values using controller
+ processor->store_in_cache = true;
+ processor->serve_from_cache = true;
+
+ return processor;
+}
+
+void messageProcessor_SetContentObjectStoreSize(
+ MessageProcessor *processor, size_t maximumContentStoreSize) {
+ parcAssertNotNull(processor, "Parameter processor must be non-null");
+ contentStoreInterface_Release(&processor->contentStore);
+
+ ContentStoreConfig contentStoreConfig = {.objectCapacity =
+ maximumContentStoreSize};
+
+ processor->contentStore =
+ contentStoreLRU_Create(&contentStoreConfig, processor->logger);
+}
+
+void messageProcessor_ClearCache(MessageProcessor *processor) {
+ parcAssertNotNull(processor, "Parameter processor must be non-null");
+ size_t objectStoreSize = configuration_GetObjectStoreSize(
+ forwarder_GetConfiguration(processor->forwarder));
+
+ contentStoreInterface_Release(&processor->contentStore);
+
+ ContentStoreConfig contentStoreConfig = {
+ .objectCapacity = objectStoreSize,
+ };
+
+ processor->contentStore =
+ contentStoreLRU_Create(&contentStoreConfig, processor->logger);
+}
+
+ContentStoreInterface *messageProcessor_GetContentObjectStore(
+ const MessageProcessor *processor) {
+ parcAssertNotNull(processor, "Parameter processor must be non-null");
+ return processor->contentStore;
+}
+
+void messageProcessor_Destroy(MessageProcessor **processorPtr) {
+ parcAssertNotNull(processorPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*processorPtr, "Parameter dereference to non-null pointer");
+
+ MessageProcessor *processor = *processorPtr;
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "MessageProcessor %p destroyed", (void *)processor);
+ }
+
+ logger_Release(&processor->logger);
+ fib_Destroy(&processor->fib);
+ contentStoreInterface_Release(&processor->contentStore);
+ pit_Release(&processor->pit);
+
+ parcMemory_Deallocate((void **)&processor);
+ *processorPtr = NULL;
+}
+
+void messageProcessor_Receive(MessageProcessor *processor, Message *message) {
+ parcAssertNotNull(processor, "Parameter processor must be non-null");
+ parcAssertNotNull(message, "Parameter message must be non-null");
+
+ processor->stats.countReceived++;
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ char *nameString = name_ToString(message_GetName(message));
+ logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "Message %p ingress %3u length %5u received name %s",
+ (void *)message, message_GetIngressConnectionId(message),
+ message_Length(message), nameString);
+ parcMemory_Deallocate((void **)&nameString);
+ }
+
+ switch (message_GetType(message)) {
+ case MessagePacketType_Interest:
+ messageProcessor_ReceiveInterest(processor, message);
+ break;
+
+ case MessagePacketType_ContentObject:
+ messageProcessor_ReceiveContentObject(processor, message);
+ break;
+
+ default:
+ messageProcessor_Drop(processor, message);
+ break;
+ }
+
+ // if someone wanted to save it, they made a copy
+ message_Release(&message);
+}
+
+bool messageProcessor_AddOrUpdateRoute(MessageProcessor *processor,
+ add_route_command *control,
+ unsigned ifidx) {
+ Configuration *config = forwarder_GetConfiguration(processor->forwarder);
+
+ const char *prefixStr = utils_PrefixLenToString(
+ control->addressType, &control->address, &control->len);
+ strategy_type fwdStrategy =
+ configuration_GetForwardingStrategy(config, prefixStr);
+ if (fwdStrategy == LAST_STRATEGY_VALUE) {
+ fwdStrategy = SET_STRATEGY_LOADBALANCER;
+ }
+
+ Name *prefix = name_CreateFromAddress(control->addressType, control->address,
+ control->len);
+ FibEntry *entry = fib_Contains(processor->fib, prefix);
+ bool newEntry = false;
+ if (entry != NULL) {
+ fibEntry_AddNexthop(entry, ifidx);
+ } else {
+ newEntry = true;
+ entry = fibEntry_Create(prefix, fwdStrategy);
+ fibEntry_AddNexthop(entry, ifidx);
+ fib_Add(processor->fib, entry);
+ }
+
+ name_Release(&prefix);
+ if (newEntry && (fwdStrategy == SET_STRATEGY_LOADBALANCER_WITH_DELAY)) {
+ strategyLoadBalancerWithPD_SetConnectionTable(
+ fibEntry_GetFwdStrategy(entry),
+ forwarder_GetConnectionTable(processor->forwarder));
+ }
+
+ return true;
+}
+
+bool messageProcessor_RemoveRoute(MessageProcessor *processor,
+ remove_route_command *control,
+ unsigned ifidx) {
+ Name *name = name_CreateFromAddress(control->addressType, control->address,
+ control->len);
+ fib_Remove(processor->fib, name, ifidx);
+ name_Release(&name);
+
+ return true;
+}
+
+void messageProcessor_RemoveConnectionIdFromRoutes(MessageProcessor *processor,
+ unsigned connectionId) {
+ fib_RemoveConnectionId(processor->fib, connectionId);
+}
+
+void processor_SetStrategy(MessageProcessor *processor, Name *prefix,
+ strategy_type strategy) {
+ FibEntry *entry = fib_Contains(processor->fib, prefix);
+ if (entry != NULL) {
+ fibEntry_SetStrategy(entry, strategy);
+ if (strategy == SET_STRATEGY_LOADBALANCER_WITH_DELAY) {
+ strategyLoadBalancerWithPD_SetConnectionTable(
+ fibEntry_GetFwdStrategy(entry),
+ forwarder_GetConnectionTable(processor->forwarder));
+ }
+ }
+}
+
+FibEntryList *messageProcessor_GetFibEntries(MessageProcessor *processor) {
+ parcAssertNotNull(processor, "Parameter processor must be non-null");
+ return fib_GetEntries(processor->fib);
+}
+
+// ============================================================
+// Internal API
+
+/**
+ * @function messageProcessor_Drop
+ * @abstract Whenever we "drop" a message, increment countes
+ * @discussion
+ * This is a bookkeeping function. It increments the appropriate counters.
+ *
+ * The default action for a message is to destroy it in
+ * <code>messageProcessor_Receive()</code>, so this function does not need to do
+ * that.
+ *
+ */
+static void messageProcessor_Drop(MessageProcessor *processor,
+ Message *message) {
+ processor->stats.countDropped++;
+
+ switch (message_GetType(message)) {
+ case MessagePacketType_Interest:
+ processor->stats.countInterestsDropped++;
+ break;
+
+ case MessagePacketType_ContentObject:
+ processor->stats.countObjectsDropped++;
+ break;
+
+ default:
+ break;
+ }
+
+ // dont destroy message here, its done at end of receive
+}
+
+/**
+ * @function messageProcessor_AggregateInterestInPit
+ * @abstract Try to aggregate the interest in the PIT
+ * @discussion
+ * Tries to aggregate the interest with another interest.
+ *
+ * @return true if interest aggregagted (no more forwarding needed), false if
+ * need to keep processing it.
+ */
+static bool messageProcessor_AggregateInterestInPit(MessageProcessor *processor,
+ Message *interestMessage) {
+ PITVerdict verdict = pit_ReceiveInterest(processor->pit, interestMessage);
+
+ if (verdict == PITVerdict_Aggregate) {
+ // PIT has it, we're done
+ processor->stats.countInterestsAggregated++;
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(
+ processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "Message %p aggregated in PIT (aggregated count %u)",
+ (void *)interestMessage, processor->stats.countInterestsAggregated);
+ }
+
+ return true;
+ }
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(
+ processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "Message %p not aggregated in PIT (aggregated count %u)",
+ (void *)interestMessage, processor->stats.countInterestsAggregated);
+ }
+
+ return false;
+}
+
+static bool _satisfyFromContentStore(MessageProcessor *processor,
+ Message *interestMessage) {
+ bool result = false;
+
+ if (message_GetInterestLifetimeTicks(interestMessage) == 0) {
+ return false;
+ }
+
+ if (!processor->serve_from_cache) {
+ return result;
+ }
+
+ // See if there's a match in the store.
+ Message *objectMessage = contentStoreInterface_MatchInterest(
+ processor->contentStore, interestMessage,
+ forwarder_GetTicks(processor->forwarder));
+
+ if (objectMessage != NULL) {
+ // Remove it from the PIT. nexthops is allocated, so need to destroy
+ NumberSet *nexthops = pit_SatisfyInterest(processor->pit, objectMessage);
+ parcAssertNotNull(
+ nexthops,
+ "Illegal state: got a null nexthops for an interest we just inserted.");
+
+ // send message in reply, then done
+ processor->stats.countInterestsSatisfiedFromStore++;
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug, __func__,
+ "Message %p satisfied from content store (satisfied count %u)",
+ (void *)interestMessage,
+ processor->stats.countInterestsSatisfiedFromStore);
+ }
+
+ message_ResetPathLabel(objectMessage);
+
+ messageProcessor_ForwardToNexthops(processor, objectMessage, nexthops);
+ numberSet_Release(&nexthops);
+
+ result = true;
+ }
+
+ return result;
+}
+
+/**
+ * @function messageProcessor_ForwardViaFib
+ * @abstract Try to forward the interest via the FIB
+ * @discussion
+ * This calls <code>messageProcessor_ForwardToNexthops()</code>, so if we find
+ * any nexthops, the interest will be sent on its way. Depending on the
+ * IoOperations of each nexthop, it may be a deferred write and bump up the
+ * <code>interestMessage</code> refernce count, or it may copy the data out.
+ *
+ * A TRUE return means we did our best to forward it via the routes. If those
+ * routes are actually down or have errors, we still return TRUE. A FALSE
+ * return means there were no routes to try.
+ *
+ * @return true if we found a route and tried to forward it, false if no route
+ */
+static bool messageProcessor_ForwardViaFib(MessageProcessor *processor,
+ Message *interestMessage) {
+ FibEntry *fibEntry = fib_Match(processor->fib, interestMessage);
+ if (fibEntry == NULL) {
+ return false;
+ }
+
+ PitEntry *pitEntry = pit_GetPitEntry(processor->pit, interestMessage);
+ if (pitEntry == NULL) {
+ return false;
+ }
+
+ pitEntry_AddFibEntry(pitEntry, fibEntry);
+
+ NumberSet *nexthops = (NumberSet *)fibEntry_GetNexthopsFromForwardingStrategy(
+ fibEntry, interestMessage);
+ // this requires some additional checks. It may happen that some of the output
+ // faces selected by the forwarding strategy are not usable. So far all the
+ // forwarding strategy return only valid faces (or an empty list)
+ for (unsigned i = 0; i < numberSet_Length(nexthops); i++) {
+ pitEntry_AddEgressId(pitEntry, numberSet_GetItem(nexthops, i));
+ }
+
+ // The function GetPitEntry encreases the ref counter in the pit entry
+ // we need to decrease it
+ pitEntry_Release(&pitEntry);
+
+ if (messageProcessor_ForwardToNexthops(processor, interestMessage, nexthops) >
+ 0) {
+ numberSet_Release(&nexthops);
+ return true;
+ } else {
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug, __func__,
+ "Message %p returned an emtpy next hop set",
+ (void *)interestMessage);
+ }
+ }
+
+ return false;
+}
+
+/**
+ * @function messageProcessor_ReceiveInterest
+ * @abstract Receive an interest from the network
+ * @discussion
+ * (1) if interest in the PIT, aggregate in PIT
+ * (2) if interest in the ContentStore, reply
+ * (3) if in the FIB, forward
+ * (4) drop
+ *
+ */
+static void messageProcessor_ReceiveInterest(MessageProcessor *processor,
+ Message *interestMessage) {
+ processor->stats.countInterestsReceived++;
+
+ // (1) Try to aggregate in PIT
+ if (messageProcessor_AggregateInterestInPit(processor, interestMessage)) {
+ // done
+ return;
+ }
+
+ // At this point, we just created a PIT entry. If we don't forward the
+ // interest, we need to remove the PIT entry.
+
+ // (2) Try to satisfy from content store
+ if (_satisfyFromContentStore(processor, interestMessage)) {
+ // done
+ // If we found a content object in the CS,
+ // messageProcess_SatisfyFromContentStore already cleared the PIT state
+ return;
+ }
+
+ // (3) Try to forward it
+ if (messageProcessor_ForwardViaFib(processor, interestMessage)) {
+ // done
+ return;
+ }
+
+ // Remove the PIT entry?
+ processor->stats.countDroppedNoRoute++;
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "Message %p did not match FIB, no route (count %u)",
+ (void *)interestMessage, processor->stats.countDroppedNoRoute);
+ }
+
+ messageProcessor_Drop(processor, interestMessage);
+}
+
+/**
+ * @function messageProcessor_ReceiveContentObject
+ * @abstract Process an in-bound content object
+ * @discussion
+ * (1) If it does not match anything in the PIT, drop it
+ * (2) Add to Content Store
+ * (3) Reverse path forward via PIT entries
+ *
+ * @param <#param1#>
+ */
+static void messageProcessor_ReceiveContentObject(MessageProcessor *processor,
+ Message *message) {
+ processor->stats.countObjectsReceived++;
+
+ NumberSet *ingressSetUnion = pit_SatisfyInterest(processor->pit, message);
+
+ if (numberSet_Length(ingressSetUnion) == 0) {
+ // (1) If it does not match anything in the PIT, drop it
+ processor->stats.countDroppedNoReversePath++;
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug, __func__,
+ "Message %p did not match PIT, no reverse path (count %u)",
+ (void *)message, processor->stats.countDroppedNoReversePath);
+ }
+
+ // we store the packets in the content store enven in the case where there
+ // is no match in the PIT table in this way the applications can push the
+ // content in the CS of the forwarder. We allow this only for local faces
+ bool isLocal = connection_IsLocal(connectionTable_FindById(
+ forwarder_GetConnectionTable(processor->forwarder),
+ message_GetIngressConnectionId((const Message *)message)));
+ if (processor->store_in_cache && isLocal) {
+ uint64_t currentTimeTicks = forwarder_GetTicks(processor->forwarder);
+ contentStoreInterface_PutContent(processor->contentStore, message,
+ currentTimeTicks);
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug, __func__,
+ "Message %p sotred in the CS anyway", (void *)message);
+ }
+ }
+
+ messageProcessor_Drop(processor, message);
+ } else {
+ // (2) Add to Content Store. Store may remove expired content, if necessary,
+ // depending on store policy.
+ if (processor->store_in_cache) {
+ uint64_t currentTimeTicks = forwarder_GetTicks(processor->forwarder);
+ contentStoreInterface_PutContent(processor->contentStore, message,
+ currentTimeTicks);
+ }
+ // (3) Reverse path forward via PIT entries
+ messageProcessor_ForwardToNexthops(processor, message, ingressSetUnion);
+ }
+
+ numberSet_Release(&ingressSetUnion);
+}
+
+/**
+ * @function messageProcessor_ForwardToNexthops
+ * @abstract Try to forward to each nexthop listed in the NumberSet
+ * @discussion
+ * Will not forward to the ingress connection.
+ *
+ * @return The number of nexthops tried
+ */
+static unsigned messageProcessor_ForwardToNexthops(MessageProcessor *processor,
+ Message *message,
+ const NumberSet *nexthops) {
+ unsigned forwardedCopies = 0;
+
+ size_t length = numberSet_Length(nexthops);
+
+ unsigned ingressId = message_GetIngressConnectionId(message);
+ uint32_t old_path_label = 0;
+
+ if (message_GetType(message) == MessagePacketType_ContentObject) {
+ old_path_label = message_GetPathLabel(message);
+ }
+
+ for (size_t i = 0; i < length; i++) {
+ unsigned egressId = numberSet_GetItem(nexthops, i);
+ if (egressId != ingressId) {
+ forwardedCopies++;
+ messageProcessor_ForwardToInterfaceId(processor, message, egressId);
+
+ if (message_GetType(message) == MessagePacketType_ContentObject) {
+ // everytime we send out a message we need to restore the original path
+ // label of the message this is important because we keep a single copy
+ // of the message (single pointer) and we modify the path label at each
+ // send.
+ message_SetPathLabel(message, old_path_label);
+ }
+ }
+ }
+ return forwardedCopies;
+}
+
+/**
+ * caller has checked that the hop limit is ok. Try to send out the connection.
+ */
+static void messageProcessor_SendWithGoodHopLimit(MessageProcessor *processor,
+ Message *message,
+ unsigned interfaceId,
+ const Connection *conn) {
+ bool success = connection_Send(conn, message);
+ if (success) {
+ switch (message_GetType(message)) {
+ case MessagePacketType_Interest:
+ processor->stats.countInterestForwarded++;
+ break;
+
+ case MessagePacketType_ContentObject:
+ processor->stats.countObjectsForwarded++;
+ break;
+
+ default:
+ break;
+ }
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(
+ processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "forward message %p to interface %u (int %u, obj %u)",
+ (void *)message, interfaceId, processor->stats.countInterestForwarded,
+ processor->stats.countObjectsForwarded);
+ }
+ } else {
+ processor->stats.countSendFailures++;
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug, __func__,
+ "forward message %p to interface %u send failure (count %u)",
+ (void *)message, interfaceId,
+ processor->stats.countSendFailures);
+ }
+ messageProcessor_Drop(processor, message);
+ }
+}
+
+/*
+ * If the hoplimit is equal to 0, then we may only forward it to local
+ * applications. Otherwise, we may forward it off the system.
+ *
+ */
+static void messageProcessor_ForwardToInterfaceId(MessageProcessor *processor,
+ Message *message,
+ unsigned interfaceId) {
+ ConnectionTable *connectionTable =
+ forwarder_GetConnectionTable(processor->forwarder);
+ const Connection *conn =
+ connectionTable_FindById(connectionTable, interfaceId);
+
+ if (conn != NULL) {
+ messageProcessor_SendWithGoodHopLimit(processor, message, interfaceId,
+ conn);
+ } else {
+ processor->stats.countDroppedConnectionNotFound++;
+
+ if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(processor->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug, __func__,
+ "forward message %p to interface %u not found (count %u)",
+ (void *)message, interfaceId,
+ processor->stats.countDroppedConnectionNotFound);
+ }
+
+ messageProcessor_Drop(processor, message);
+ }
+}
+
+void messageProcessor_SetCacheStoreFlag(MessageProcessor *processor, bool val) {
+ processor->store_in_cache = val;
+}
+
+bool messageProcessor_GetCacheStoreFlag(MessageProcessor *processor) {
+ return processor->store_in_cache;
+}
+
+void messageProcessor_SetCacheServeFlag(MessageProcessor *processor, bool val) {
+ processor->serve_from_cache = val;
+}
+
+bool messageProcessor_GetCacheServeFlag(MessageProcessor *processor) {
+ return processor->serve_from_cache;
+}
+
+#ifdef WITH_MAPME
+
+FIB *messageProcessor_getFib(MessageProcessor *processor) {
+ return processor->fib;
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/processor/messageProcessor.h b/hicn-light/src/processor/messageProcessor.h
new file mode 100755
index 000000000..ce3049938
--- /dev/null
+++ b/hicn-light/src/processor/messageProcessor.h
@@ -0,0 +1,166 @@
+/*
+ * 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 messageProcessor.h
+ * @brief Executes the set of rules dictated by the PacketType
+ *
+ * This is a "run-to-completion" handling of a message based on the PacketType.
+ *
+ * The MessageProcessor also owns the PIT and FIB tables.
+ *
+ */
+
+#ifndef messageProcessor_h
+#define messageProcessor_h
+
+#include <src/content_store/contentStoreInterface.h>
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+
+#include <src/utils/commands.h>
+
+struct message_processor;
+typedef struct message_processor MessageProcessor;
+
+/**
+ * Allocates a MessageProcessor along with PIT, FIB and ContentStore tables
+ *
+ * The hicn-light pointer is primarily used for logging (forwarder_Log), getting
+ * the configuration, and accessing the connection table.
+ *
+ * @param [in] Pointer to owning hicn-light process
+ *
+ * @retval non-null An allocated message processor
+ * @retval null An error
+ *
+ */
+MessageProcessor *messageProcessor_Create(Forwarder *forwarder);
+
+/**
+ * Deallocates a message processor an all internal tables
+ *
+ * @param [in,out] processorPtr Pointer to message processor to de-allocate,
+ * will be NULL'd.
+ */
+void messageProcessor_Destroy(MessageProcessor **processorPtr);
+
+/**
+ * @function messageProcessor_Receive
+ * @abstract Process the message, takes ownership of the memory.
+ * @discussion
+ * Will call destroy on the memory when done with it, so if the caller wants
+ * to keep it, make a reference counted copy.
+ *
+ * Receive may modify some fields in the message, such as the HopLimit field.
+ */
+void messageProcessor_Receive(MessageProcessor *procesor, Message *message);
+
+/**
+ * Adds or updates a route in the FIB
+ *
+ * If the route already exists, it is replaced
+ *
+ * @param [in] procesor An allocated message processor
+ * @param [in] route The route to update
+ *
+ * @retval true added or updated
+ * @retval false An error
+ */
+bool messageProcessor_AddOrUpdateRoute(MessageProcessor *processor,
+ add_route_command *control,
+ unsigned ifidx);
+
+/**
+ * Removes a route from the FIB
+ *
+ * Removes a specific nexthop for a route. If there are no nexthops left after
+ * the removal, the entire route is deleted from the FIB.
+ *
+ * @param [in] procesor An allocated message processor
+ * @param [in] route The route to remove
+ *
+ * @retval true Route completely removed
+ * @retval false There is still a nexthop for the route
+ */
+
+bool messageProcessor_RemoveRoute(MessageProcessor *processor,
+ remove_route_command *control,
+ unsigned ifidx);
+
+/**
+ * Removes a given connection id from all FIB entries
+ *
+ * Iterates the FIB and removes the given connection ID from every route.
+ */
+void messageProcessor_RemoveConnectionIdFromRoutes(MessageProcessor *processor,
+ unsigned connectionId);
+
+/**
+ * Returns a list of all FIB entries
+ *
+ * You must destroy the list.
+ *
+ * @retval non-null The list of FIB entries
+ * @retval null An error
+ */
+FibEntryList *messageProcessor_GetFibEntries(MessageProcessor *processor);
+
+/**
+ * Adjusts the ContentStore to the given size.
+ *
+ * This will destroy and re-create the content store, so any cached objects will
+ * be lost.
+ *
+ */
+void messageProcessor_SetContentObjectStoreSize(MessageProcessor *processor,
+ size_t maximumContentStoreSize);
+
+/**
+ * Return the interface to the currently instantiated ContentStore, if any.
+ *
+ * @param [in] processor the `MessageProcessor` from which to return the
+ * ContentStoreInterface.
+ *
+ */
+ContentStoreInterface *messageProcessor_GetContentObjectStore(
+ const MessageProcessor *processor);
+
+void messageProcessor_SetCacheStoreFlag(MessageProcessor *processor, bool val);
+
+bool messageProcessor_GetCacheStoreFlag(MessageProcessor *processor);
+
+void messageProcessor_SetCacheServeFlag(MessageProcessor *processor, bool val);
+
+bool messageProcessor_GetCacheServeFlag(MessageProcessor *processor);
+
+void messageProcessor_ClearCache(MessageProcessor *processor);
+
+void processor_SetStrategy(MessageProcessor *processor, Name *prefix,
+ strategy_type strategy);
+
+#ifdef WITH_MAPME
+
+/**
+ * @function messageProcessor_getFib
+ * @abstract Returns the hICN processor's FIB.
+ * @param [in] forwarder - Pointer to the hICN processor.
+ * @returns Pointer to the hICN FIB.
+ */
+FIB *messageProcessor_getFib(MessageProcessor *processor);
+
+#endif /* WITH_MAPME */
+
+#endif // messageProcessor_h
diff --git a/hicn-light/src/processor/pit.c b/hicn-light/src/processor/pit.c
new file mode 100755
index 000000000..9cae4062e
--- /dev/null
+++ b/hicn-light/src/processor/pit.c
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/**
+ * Generic interface to PIT table
+ *
+ */
+
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/processor/pit.h>
+
+void *pit_Closure(const PIT *pit) { return pit->closure; }
+
+void pit_Release(PIT **pitPtr) { (*pitPtr)->release(pitPtr); }
+
+PITVerdict pit_ReceiveInterest(PIT *pit, Message *interestMessage) {
+ return pit->receiveInterest(pit, interestMessage);
+}
+
+NumberSet *pit_SatisfyInterest(PIT *pit, const Message *objectMessage) {
+ return pit->satisfyInterest(pit, objectMessage);
+}
+
+void pit_RemoveInterest(PIT *pit, const Message *interestMessage) {
+ pit->removeInterest(pit, interestMessage);
+}
+
+PitEntry *pit_GetPitEntry(const PIT *pit, const Message *interestMessage) {
+ return pit->getPitEntry(pit, interestMessage);
+}
diff --git a/hicn-light/src/processor/pit.h b/hicn-light/src/processor/pit.h
new file mode 100755
index 000000000..1f909be3e
--- /dev/null
+++ b/hicn-light/src/processor/pit.h
@@ -0,0 +1,114 @@
+/*
+ * 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 pit.h
+ * @brief The Pending Interest Table interface
+ *
+ * Interface for implementing a PIT table
+ *
+ */
+
+#ifndef pit_h
+#define pit_h
+
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+#include <src/core/numberSet.h>
+#include <src/processor/pitEntry.h>
+#include <src/processor/pitVerdict.h>
+
+struct pit;
+typedef struct pit PIT;
+
+struct pit {
+ void (*release)(PIT **pitPtr);
+ PITVerdict (*receiveInterest)(PIT *pit, Message *interestMessage);
+ NumberSet *(*satisfyInterest)(PIT *pit, const Message *objectMessage);
+ void (*removeInterest)(PIT *pit, const Message *interestMessage);
+ PitEntry *(*getPitEntry)(const PIT *pit, const Message *interestMessage);
+ void *closure;
+};
+
+void *pit_Closure(const PIT *pit);
+
+/**
+ * Destroys the PIT table and all entries contained in it.
+ *
+ * PIT entries are reference counted, so if the user has stored one outside the
+ * PIT table it will still be valid.
+ *
+ * @param [in,out] pitPtr Double pointer to PIT table, will be NULLed
+ */
+void pit_Release(PIT **pitPtr);
+
+/**
+ * @function pit_ReceiveInterest
+ * @abstract Receives an interest and adds to PIT table
+ * @discussion
+ * If not present, adds entry to the PIT table and returns
+ * PIT_VERDICT_NEW_ENTRY. If present and aggregated, returns
+ * PIT_VERDICT_EXISTING_ENTRY.
+ *
+ * Some aggregated interests may return PIT_VERDICT_NEW_ENTRY if the interest
+ * needs to be forwarded again (e.g. the lifetime is extended).
+ *
+ * If the PIT stores the message in its table, it will store a reference
+ * counted copy.
+ *
+ * @return Verdict of receiving the interest
+ */
+PITVerdict pit_ReceiveInterest(PIT *pit, Message *interestMessage);
+
+/**
+ * @function pit_SatisfyInterest
+ * @abstract Tries to satisfy PIT entries based on the message, returning where
+ * to send message
+ * @discussion
+ * If matching interests are in the PIT, will return the set of reverse
+ * paths to use to forward the content object.
+ *
+ * The return value is allocated and must be destroyed.
+ *
+ * @return Set of ConnectionTable id's to forward the message, may be empty or
+ * NULL. Must be destroyed.
+ */
+NumberSet *pit_SatisfyInterest(PIT *pit, const Message *objectMessage);
+
+/**
+ * @function pit_RemoveInterest
+ * @abstract Unconditionally remove the interest from the PIT
+ * @discussion
+ * The PIT may store a specific name in several tables. This function will
+ * remove the interest from the specific table it lives it. It will not
+ * remove PIT entries in different tables with the same name.
+ *
+ * The different tables index interests based on their matching criteria,
+ * such as by name, by name and keyid, etc.
+ *
+ */
+void pit_RemoveInterest(PIT *pit, const Message *interestMessage);
+
+/**
+ * @function pit_GetPitEntry
+ * @abstract Retrieve the best matching PIT entry for the message.
+ * @discussion
+ * Returns a reference counted copy of the entry, must call
+ * <code>pitEntry_Destory()</code> on it.
+ *
+ * @return NULL if not in table, otherwise a reference counted copy of the entry
+ */
+PitEntry *pit_GetPitEntry(const PIT *pit, const Message *interestMessage);
+#endif // pit_h
diff --git a/hicn-light/src/processor/pitEntry.c b/hicn-light/src/processor/pitEntry.c
new file mode 100755
index 000000000..38103cb8e
--- /dev/null
+++ b/hicn-light/src/processor/pitEntry.c
@@ -0,0 +1,142 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <src/core/numberSet.h>
+#include <src/processor/pitEntry.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct pit_entry {
+ Message *message;
+ NumberSet *ingressIdSet;
+ NumberSet *egressIdSet;
+
+ FibEntry *fibEntry;
+
+ Ticks creationTime;
+ Ticks expiryTime;
+
+ unsigned refcount;
+};
+
+PitEntry *pitEntry_Create(Message *message, Ticks expiryTime,
+ Ticks creationTime) {
+ PitEntry *pitEntry = parcMemory_AllocateAndClear(sizeof(PitEntry));
+ parcAssertNotNull(pitEntry, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(PitEntry));
+ pitEntry->message = message;
+ pitEntry->ingressIdSet = numberSet_Create();
+ pitEntry->egressIdSet = numberSet_Create();
+ pitEntry->refcount = 1;
+
+ // add the message to the reverse path set
+ numberSet_Add(pitEntry->ingressIdSet,
+ message_GetIngressConnectionId(message));
+
+ // hack in a 4-second timeout
+ pitEntry->expiryTime = expiryTime;
+ pitEntry->fibEntry = NULL;
+
+ pitEntry->creationTime = creationTime;
+ return pitEntry;
+}
+
+void pitEntry_Release(PitEntry **pitEntryPtr) {
+ parcAssertNotNull(pitEntryPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*pitEntryPtr,
+ "Parameter must dereference to non-null pointer");
+
+ PitEntry *pitEntry = *pitEntryPtr;
+ parcTrapIllegalValueIf(pitEntry->refcount == 0,
+ "Illegal state: has refcount of 0");
+
+ pitEntry->refcount--;
+ if (pitEntry->refcount == 0) {
+ if (pitEntry->fibEntry != NULL) {
+ fibEntry_Release(&pitEntry->fibEntry);
+ }
+ numberSet_Release(&pitEntry->ingressIdSet);
+ numberSet_Release(&pitEntry->egressIdSet);
+ message_Release(&pitEntry->message);
+ parcMemory_Deallocate((void **)&pitEntry);
+ }
+ *pitEntryPtr = NULL;
+}
+
+PitEntry *pitEntry_Acquire(PitEntry *original) {
+ parcAssertNotNull(original, "Parameter original must be non-null");
+ original->refcount++;
+ return original;
+}
+
+void pitEntry_AddIngressId(PitEntry *pitEntry, unsigned ingressId) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ numberSet_Add(pitEntry->ingressIdSet, ingressId);
+}
+
+void pitEntry_AddEgressId(PitEntry *pitEntry, unsigned egressId) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ numberSet_Add(pitEntry->egressIdSet, egressId);
+}
+
+void pitEntry_AddFibEntry(PitEntry *pitEntry, FibEntry *fibEntry) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+ // the fibEntry should be always the same for all the interests in the same
+ // pitEntry
+ if (pitEntry->fibEntry == NULL) {
+ fibEntry_Acquire(fibEntry);
+ pitEntry->fibEntry = fibEntry;
+ }
+}
+
+FibEntry *pitEntry_GetFibEntry(PitEntry *pitEntry) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ return pitEntry->fibEntry;
+}
+
+Ticks pitEntry_GetExpiryTime(const PitEntry *pitEntry) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ return pitEntry->expiryTime;
+}
+
+Ticks pitEntry_GetCreationTime(const PitEntry *pitEntry) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ return pitEntry->creationTime;
+}
+
+void pitEntry_SetExpiryTime(PitEntry *pitEntry, Ticks expiryTime) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ pitEntry->expiryTime = expiryTime;
+}
+
+const NumberSet *pitEntry_GetIngressSet(const PitEntry *pitEntry) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ return pitEntry->ingressIdSet;
+}
+
+const NumberSet *pitEntry_GetEgressSet(const PitEntry *pitEntry) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ return pitEntry->egressIdSet;
+}
+
+Message *pitEntry_GetMessage(const PitEntry *pitEntry) {
+ parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+ return message_Acquire(pitEntry->message);
+}
diff --git a/hicn-light/src/processor/pitEntry.h b/hicn-light/src/processor/pitEntry.h
new file mode 100755
index 000000000..b7d45e6a4
--- /dev/null
+++ b/hicn-light/src/processor/pitEntry.h
@@ -0,0 +1,164 @@
+/*
+ * 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 pitEntry.h
+ * @brief The embodiment of a PIT entry
+ *
+ * Embodies a PIT entry
+ *
+ */
+
+#ifndef pitEntry_h
+#define pitEntry_h
+
+#include <src/core/message.h>
+#include <src/core/numberSet.h>
+#include <src/core/ticks.h>
+#include <src/processor/fibEntry.h>
+
+struct pit_entry;
+typedef struct pit_entry PitEntry;
+
+/**
+ * @function pitEntry_Create
+ * @abstract Takes ownership of the message inside the PitEntry
+ * @discussion
+ * When the PIT entry is destroyed, will call <code>message_Release()</code>
+ * on the message.
+ *
+ */
+PitEntry *pitEntry_Create(Message *message, Ticks expiryTime,
+ Ticks CreationTime);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] pitEntryPtr A pointer to a PitEntry instance pointer, which
+ * will be set to zero on return.
+ *
+ */
+void pitEntry_Release(PitEntry **pitEntryPtr);
+
+/**
+ * @function pitEntry_Acquire
+ * @abstract Returns a reference counted copy
+ * @discussion
+ * A reference counted copy that shares the same state as the original.
+ * Caller must use <code>pitEntry_Release()</code> on it when done.
+ *
+ * @return A reference counted copy, use Destroy on it.
+ */
+PitEntry *pitEntry_Acquire(PitEntry *original);
+
+/**
+ * @function pitEntry_AddIngressId
+ * @abstract Add an ingress connection id to the list of reverse paths
+ * @discussion
+ * A PitEntry has two NumberSets. The first is the set of ingress ports,
+ * which make up the reverse path. The second is the set of egress ports, which
+ * make up its forward path.
+ *
+ * This function tracks which reverse paths have sent us the interest.
+ *
+ * @param ingressId the reverse path
+ */
+void pitEntry_AddIngressId(PitEntry *pitEntry, unsigned ingressId);
+
+/**
+ * @function pitEntry_AddEgressId
+ * @abstract Add an egress connection id to the list of attempted paths
+ * @discussion
+ * A PitEntry has two NumberSets. The first is the set of ingress ports,
+ * which make up the reverse path. The second is the set of egress ports, which
+ * make up its forward path.
+ *
+ * This function tracks which forward paths we've tried for the interest.
+ *
+ * @param egressId the forwarded path
+ */
+void pitEntry_AddEgressId(PitEntry *pitEntry, unsigned egressId);
+
+void pitEntry_AddFibEntry(PitEntry *pitEntry, FibEntry *fibEntry);
+
+FibEntry *pitEntry_GetFibEntry(PitEntry *pitEntry);
+
+/**
+ * @function pitEntry_GetIngressSet
+ * @abstract The Ingress connection id set
+ * @discussion
+ * You must acquire a copy of the number set if you will store the result.
+ * This is the internal reference.
+ *
+ * @return May be empty, will not be null. Must be destroyed.
+ */
+const NumberSet *pitEntry_GetIngressSet(const PitEntry *pitEntry);
+
+/**
+ * @function pitEntry_GetEgressSet
+ * @abstract The Egress connection id set
+ * @discussion
+ * You must acquire a copy of the number set if you will store the result.
+ * This is the internal reference.
+ *
+ * @param <#param1#>
+ * @return May be empty, will not be null. Must be destroyed.
+ */
+const NumberSet *pitEntry_GetEgressSet(const PitEntry *pitEntry);
+
+/**
+ * @function pitEntry_GetMessage
+ * @abstract Gets the interest underpinning the PIT entry
+ * @discussion
+ * A reference counted copy, call <code>Message_Release()</code> on it.
+ *
+ * @return A reference counted copy, call <code>Message_Release()</code> on it.
+ */
+Message *pitEntry_GetMessage(const PitEntry *pitEntry);
+
+/**
+ * Returns the time (in ticks) at which the PIT entry is no longer valid
+ *
+ * The ExpiryTime is computed when the PIT entry is added (or via
+ * pitEntry_SetExpiryTime). It is the aboslute time (in Ticks) at which the Pit
+ * entry is no longer valid.
+ *
+ * @param [in] PitEntry An allocated PIT entry
+ *
+ * @retval number The abosolute time (in Ticks) of the Expiry
+ */
+Ticks pitEntry_GetExpiryTime(const PitEntry *pitEntry);
+
+Ticks pitEntry_GetCreationTime(const PitEntry *pitEntry);
+/**
+ * Sets the ExpriyTime of the PIT entry to the given value
+ *
+ * It is probalby an error to set the expiryTime to a smaller value than
+ * currently set to, but this is not enforced. PIT entries use lazy delete.
+ *
+ * @param [in] pitEntry The allocated PIT entry to modify
+ * @param [in] expiryTime The new expiryTime (UTC in forwarder Ticks)
+ *
+ */
+void pitEntry_SetExpiryTime(PitEntry *pitEntry, Ticks expiryTime);
+
+#endif // pitEntry_h
diff --git a/hicn-light/src/processor/pitStandard.c b/hicn-light/src/processor/pitStandard.c
new file mode 100755
index 000000000..8d507626a
--- /dev/null
+++ b/hicn-light/src/processor/pitStandard.c
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+/**
+ * The pending interest table.
+ *
+ * Interest aggregation strategy:
+ * - The first Interest for a name is forwarded
+ * - A second Interest for a name from a different reverse path may be
+ * aggregated
+ * - A second Interest for a name from an existing Interest is forwarded
+ * - The Interest Lifetime is like a subscription time. A reverse path entry is
+ * removed once the lifetime is exceeded.
+ * - Whan an Interest arrives or is aggregated, the Lifetime for that reverse
+ * hop is extended. As a simplification, we only keep a single lifetime not per
+ * reverse hop.
+ *
+ */
+
+#include <src/config.h>
+#include <stdio.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <src/processor/hashTableFunction.h>
+#include <src/processor/pit.h>
+
+#include <src/core/ticks.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/core/forwarder.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct standard_pit;
+typedef struct standard_pit StandardPIT;
+
+struct standard_pit {
+ Forwarder *forwarder;
+ Logger *logger;
+ PARCHashCodeTable *table; // PIT indexed by name
+};
+
+static void _pit_StoreInTable(StandardPIT *pit, Message *interestMessage);
+
+static void _pit_PitEntryDestroyer(void **dataPtr) {
+ pitEntry_Release((PitEntry **)dataPtr);
+}
+
+static bool _pit_IngressSetContains(PitEntry *pitEntry, unsigned connectionId) {
+ const NumberSet *set = pitEntry_GetIngressSet(pitEntry);
+ bool numberInSet = numberSet_Contains(set, connectionId);
+ return numberInSet;
+}
+
+static Ticks _pit_CalculateLifetime(StandardPIT *pit,
+ Message *interestMessage) {
+ uint64_t interestLifetimeTicks =
+ message_GetInterestLifetimeTicks(interestMessage);
+ if (interestLifetimeTicks == 0) {
+ interestLifetimeTicks = forwarder_NanosToTicks(4000000000ULL);
+ }
+
+ Ticks expiryTime = forwarder_GetTicks(pit->forwarder) + interestLifetimeTicks;
+ return expiryTime;
+}
+
+static void _pit_StoreInTable(StandardPIT *pit, Message *interestMessage) {
+ Message *key = message_Acquire(interestMessage);
+
+ Ticks expiryTime = _pit_CalculateLifetime(pit, interestMessage);
+
+ PitEntry *pitEntry =
+ pitEntry_Create(key, expiryTime, forwarder_GetTicks(pit->forwarder));
+
+ parcHashCodeTable_Add(pit->table, key, pitEntry);
+
+ if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__,
+ "Message %p added to PIT (expiry %" PRIu64 ") ingress %u",
+ (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry),
+ message_GetIngressConnectionId(interestMessage));
+ }
+}
+
+static void _pit_ExtendLifetime(StandardPIT *pit, PitEntry *pitEntry,
+ Message *interestMessage) {
+ Ticks expiryTime = _pit_CalculateLifetime(pit, interestMessage);
+
+ if (expiryTime > pitEntry_GetExpiryTime(pitEntry))
+ pitEntry_SetExpiryTime(pitEntry, expiryTime);
+}
+
+// ======================================================================
+// Interface API
+
+static void _pitStandard_Destroy(PIT **pitPtr) {
+ parcAssertNotNull(pitPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*pitPtr, "Parameter must dereference to non-null pointer");
+
+ StandardPIT *pit = pit_Closure(*pitPtr);
+
+ if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "PIT %p destroyed", (void *)pit);
+ }
+
+ parcHashCodeTable_Destroy(&pit->table);
+ logger_Release(&pit->logger);
+ parcMemory_Deallocate(pitPtr);
+}
+
+static PITVerdict _pitStandard_ReceiveInterest(PIT *generic,
+ Message *interestMessage) {
+ parcAssertNotNull(generic, "Parameter pit must be non-null");
+ parcAssertNotNull(interestMessage,
+ "Parameter interestMessage must be non-null");
+
+ StandardPIT *pit = pit_Closure(generic);
+
+ PitEntry *pitEntry = parcHashCodeTable_Get(pit->table, interestMessage);
+
+ if (pitEntry) {
+ // has it expired?
+ Ticks now = forwarder_GetTicks(pit->forwarder);
+ if (now < pitEntry_GetExpiryTime(pitEntry)) {
+ _pit_ExtendLifetime(pit, pitEntry, interestMessage);
+
+ // Is the reverse path already in the PIT entry?
+ if (_pit_IngressSetContains(
+ pitEntry, message_GetIngressConnectionId(interestMessage))) {
+ // It is already in the PIT entry, so this is a retransmission, so
+ // forward it.
+
+ if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__,
+ "Message %p existing entry (expiry %" PRIu64
+ ") and reverse path, forwarding",
+ (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry));
+ }
+
+ return PITVerdict_Forward;
+ }
+
+ // It is in the PIT but this is the first interest for the reverse path
+ pitEntry_AddIngressId(pitEntry,
+ message_GetIngressConnectionId(interestMessage));
+
+ if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__,
+ "Message %p existing entry (expiry %" PRIu64
+ ") and reverse path is new, aggregate",
+ (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry));
+ }
+
+ return PITVerdict_Aggregate;
+ }
+ // this is a timeout....
+ FibEntry *fibEntry = pitEntry_GetFibEntry(pitEntry);
+ if (fibEntry != NULL) {
+ fibEntry_OnTimeout(fibEntry, pitEntry_GetEgressSet(pitEntry));
+ }
+
+ // it's an old entry, remove it
+ parcHashCodeTable_Del(pit->table, interestMessage);
+ }
+
+ _pit_StoreInTable(pit, interestMessage);
+
+ return PITVerdict_Forward;
+}
+
+static NumberSet *_pitStandard_SatisfyInterest(PIT *generic,
+ const Message *objectMessage) {
+ parcAssertNotNull(generic, "Parameter pit must be non-null");
+ parcAssertNotNull(objectMessage, "Parameter objectMessage must be non-null");
+
+ StandardPIT *pit = pit_Closure(generic);
+
+ NumberSet *ingressSet = numberSet_Create();
+
+ PitEntry *pitEntry = parcHashCodeTable_Get(pit->table, objectMessage);
+ if (pitEntry) {
+ // here we need to check if the PIT entry is expired
+ // if so, remove the PIT entry.
+ Ticks now = forwarder_GetTicks(pit->forwarder);
+ if (now < pitEntry_GetExpiryTime(pitEntry)) {
+ // PIT entry is not expired, use it
+ FibEntry *fibEntry = pitEntry_GetFibEntry(pitEntry);
+ if (fibEntry != NULL) {
+ // this is a rough estimation of the residual RTT
+ Ticks rtt = forwarder_GetTicks(pit->forwarder) -
+ pitEntry_GetCreationTime(pitEntry);
+ fibEntry_ReceiveObjectMessage(fibEntry, pitEntry_GetEgressSet(pitEntry),
+ objectMessage,
+ rtt); // need to implement RTT
+ }
+ const NumberSet *is = pitEntry_GetIngressSet(pitEntry);
+ numberSet_AddSet(ingressSet, is); // with this we do a copy so we can
+ // remove the entry from the PIT
+ }
+ // remove the entry from the PIT. Key is a reference counted copy of the
+ // pit entry message
+ Message *key = pitEntry_GetMessage(pitEntry);
+ parcHashCodeTable_Del(pit->table, key);
+ message_Release(&key);
+ }
+
+ return ingressSet;
+}
+
+static void _pitStandard_RemoveInterest(PIT *generic,
+ const Message *interestMessage) {
+ parcAssertNotNull(generic, "Parameter pit must be non-null");
+ parcAssertNotNull(interestMessage,
+ "Parameter interestMessage must be non-null");
+
+ StandardPIT *pit = pit_Closure(generic);
+
+ if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "Message %p removed from PIT",
+ (void *)interestMessage);
+ }
+
+ parcHashCodeTable_Del(pit->table, interestMessage);
+}
+
+static PitEntry *_pitStandard_GetPitEntry(const PIT *generic,
+ const Message *interestMessage) {
+ parcAssertNotNull(generic, "Parameter pit must be non-null");
+ parcAssertNotNull(interestMessage,
+ "Parameter interestMessage must be non-null");
+
+ StandardPIT *pit = pit_Closure(generic);
+
+ PitEntry *entry = parcHashCodeTable_Get(pit->table, interestMessage);
+ if (entry) {
+ return pitEntry_Acquire(entry);
+ }
+ return NULL;
+}
+
+// ======================================================================
+// Public API
+
+PIT *pitStandard_Create(Forwarder *forwarder) {
+ parcAssertNotNull(forwarder, "Parameter must be non-null");
+
+ size_t allocation = sizeof(PIT) + sizeof(StandardPIT);
+
+ PIT *generic = parcMemory_AllocateAndClear(allocation);
+ parcAssertNotNull(generic, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ allocation);
+ generic->closure = (uint8_t *)generic + sizeof(PIT);
+
+ StandardPIT *pit = pit_Closure(generic);
+ pit->forwarder = forwarder;
+ pit->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+ size_t initialSize = 65535;
+ pit->table =
+ parcHashCodeTable_Create_Size(hashTableFunction_MessageNameEquals,
+ hashTableFunction_MessageNameHashCode, NULL,
+ _pit_PitEntryDestroyer, initialSize);
+
+ if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+ PARCLogLevel_Debug)) {
+ logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+ __func__, "PIT %p created", (void *)pit);
+ }
+
+ generic->getPitEntry = _pitStandard_GetPitEntry;
+ generic->receiveInterest = _pitStandard_ReceiveInterest;
+ generic->release = _pitStandard_Destroy;
+ generic->removeInterest = _pitStandard_RemoveInterest;
+ generic->satisfyInterest = _pitStandard_SatisfyInterest;
+
+ return generic;
+}
diff --git a/hicn-light/src/processor/pitStandard.h b/hicn-light/src/processor/pitStandard.h
new file mode 100755
index 000000000..b9ba026c8
--- /dev/null
+++ b/hicn-light/src/processor/pitStandard.h
@@ -0,0 +1,41 @@
+/*
+ * 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 pitStandard.h
+ * @brief The Pending Interest Table
+ *
+ * Implements the standard Pending Interest Table.
+ *
+ */
+
+#ifndef pitStandard_h
+#define pitStandard_h
+
+#include <src/processor/pit.h>
+
+/**
+ * Creates a PIT table
+ *
+ * Creates and allocates an emtpy PIT table. The Forwarder reference is
+ * used for logging and for time functions.
+ *
+ * @param [in] hicn-light The releated Forwarder
+ *
+ * @return non-null a PIT table
+ * @return null An error
+ */
+PIT *pitStandard_Create(Forwarder *forwarder);
+#endif // pit_h
diff --git a/hicn-light/src/processor/pitVerdict.h b/hicn-light/src/processor/pitVerdict.h
new file mode 100755
index 000000000..16631fa51
--- /dev/null
+++ b/hicn-light/src/processor/pitVerdict.h
@@ -0,0 +1,36 @@
+/*
+ * 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 pitVerdict.h
+ * @brief Adding an entry to the PIT will return NEW or EXISTING
+ *
+ * Adding an entry to the PIT will return NEW or EXISTING
+ *
+ */
+
+#ifndef pitVerdict_h
+#define pitVerdict_h
+
+/**
+ * @typedef PitVerdict
+ * @abstract The verdit of the PIT for receiving a message
+ * @constant PITVerdict_Forward The message made a new PIT entry, the interest
+ * should be forwarded
+ * @constant PITVerdict_Aggregate The Interest was aggregated in the PIT, does
+ * not need to be forwarded
+ */
+typedef enum { PITVerdict_Forward, PITVerdict_Aggregate } PITVerdict;
+#endif // pitVerdict_h
diff --git a/hicn-light/src/socket/CMakeLists.txt b/hicn-light/src/socket/CMakeLists.txt
new file mode 100755
index 000000000..6ea94dcfa
--- /dev/null
+++ b/hicn-light/src/socket/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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+if (UNIX AND NOT APPLE AND NOT ANDROID_API)
+ list(APPEND HEADER_FILES
+ socket/api.h
+ socket/error.h
+ socket/ops.h
+ )
+
+ list(APPEND SOURCE_FILES
+ socket/api.c
+ socket/error.c
+ socket/ops_linux.c
+ )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/hicn-light/src/socket/api.c b/hicn-light/src/socket/api.c
new file mode 100755
index 000000000..aede01efe
--- /dev/null
+++ b/hicn-light/src/socket/api.c
@@ -0,0 +1,604 @@
+#include <arpa/inet.h> // inet_ntop
+#include <netdb.h> // ''
+#include <search.h> // tfind(), tdestroy(), twalk(), preorder...
+#include <stdbool.h>
+#include <stdio.h> // perror
+#include <stdlib.h> // calloc
+#include <string.h> // memcpy
+#include <sys/socket.h> // ''
+#include <sys/types.h> // getaddrinfo
+#include <unistd.h> // close
+
+#include "api.h"
+#include "error.h"
+#include "ops.h"
+
+#define INET_MAX_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#define IF_NAMESIZE 16
+#define MAX_TABLES 256
+
+#define DEFAULT_INTERVAL 1000
+#define DEFAULT_IDENTIFIER "hicn"
+#define DEFAULT_SOCKET_IDENTIFIER "main"
+#define LOCAL_IPV6_PREFIX "fe80"
+
+#define LOCAL_PRIORITY 32000
+
+extern hicn_socket_ops_t ops;
+
+/* Configuration stored as a global variable to allow access from signal
+ * handlers for instance */
+
+static hicn_conf_t hicn_default_conf = {
+ .identifier = DEFAULT_IDENTIFIER,
+ //.format = HF_INET6_TCP
+};
+
+/* Global state */
+// FIXME move into helper state ?
+
+struct ip_rule_state_ {
+ char tun_name[IF_NAMESIZE];
+ ip_address_t ip_address;
+ uint32_t table_id;
+ uint8_t priority;
+ uint8_t address_family;
+};
+
+struct ip_route_state_ {
+ char remote_ip_address[128]; // this is to big, but it is fine for now
+ uint8_t address_family;
+ uint32_t table_id;
+};
+
+typedef struct ip_rule_state_ ip_rule_state;
+typedef struct ip_route_state_ ip_route_state;
+
+int punting_table_id;
+uint16_t rules_counter;
+uint16_t routes_counter;
+static ip_rule_state rules_to_remove[MAX_TABLES];
+static ip_route_state routes_to_remove[MAX_TABLES];
+
+// END FIXME
+
+hicn_socket_helper_t *hicn_create() {
+ int rc;
+
+ punting_table_id = -1;
+ rules_counter = 0;
+
+ hicn_socket_helper_t *hicn = malloc(sizeof(hicn_socket_helper_t));
+ if (!hicn) {
+ goto ERR_MALLOC;
+ }
+
+ hicn->conf = malloc(sizeof(hicn_conf_t));
+ if (hicn->conf < 0) goto ERR_CONF;
+ memcpy(hicn->conf, &hicn_default_conf, sizeof(hicn_conf_t));
+
+ /* Initialize socket tree to empty */
+ hicn->socket_root = NULL;
+
+ // enable forwarding globally. Per-interface forwarding will be enabled when
+ // interfaces are created (TODO)
+ rc = ops.enable_v6_forwarding(NULL);
+ if (rc < 0) {
+ goto ERR_FW;
+ }
+
+ rc = ops.enable_v4_forwarding();
+ if (rc < 0) {
+ goto ERR_FW;
+ }
+
+ // modify priority of table local
+ /* ip -6 rule del from all prio 0 table local */
+ /* ip -6 rule add from all prio 32000 table local */
+
+ rc = ops.del_lo_prio_rule(NULL, AF_INET6, 0);
+ if (rc < 0) {
+ goto ERR_FW;
+ }
+
+ rc = ops.del_lo_prio_rule(NULL, AF_INET, 0);
+ if (rc < 0) {
+ goto ERR_FW;
+ }
+
+ rc = ops.add_lo_prio_rule(NULL, AF_INET6, LOCAL_PRIORITY);
+ if (rc < 0) {
+ goto ERR_FW;
+ }
+
+ rc = ops.add_lo_prio_rule(NULL, AF_INET, LOCAL_PRIORITY);
+ if (rc < 0) {
+ goto ERR_FW;
+ }
+
+ return hicn;
+
+ERR_FW:
+ free(hicn->conf);
+ERR_CONF:
+ free(hicn);
+ERR_MALLOC:
+ return NULL;
+}
+
+void hicn_destroy() {
+ int rc;
+ uint16_t i;
+
+ /* Restore default rules */
+ printf("Restoring default configuration.\n");
+ rc = ops.del_lo_prio_rule(NULL, AF_INET6, LOCAL_PRIORITY);
+ if (rc < 0) {
+ goto ERR;
+ }
+
+ rc = ops.del_lo_prio_rule(NULL, AF_INET, LOCAL_PRIORITY);
+ if (rc < 0) {
+ goto ERR;
+ }
+
+ rc = ops.add_lo_prio_rule(NULL, AF_INET6, 0);
+ if (rc < 0) {
+ goto ERR;
+ }
+
+ rc = ops.add_lo_prio_rule(NULL, AF_INET, 0);
+ if (rc < 0) {
+ goto ERR;
+ }
+
+ for (i = 0; i < rules_counter; i++) {
+ if (strcmp(rules_to_remove[i].tun_name, "NONE") != 0) {
+ rc = ops.del_rule(rules_to_remove[i].tun_name,
+ rules_to_remove[i].address_family,
+ rules_to_remove[i].table_id);
+ if (rc < 0) {
+ goto ERR;
+ }
+ } else {
+ rc = ops.del_prio_rule(
+ &rules_to_remove[i].ip_address, rules_to_remove[i].address_family,
+ rules_to_remove[i].priority, rules_to_remove[i].table_id);
+ if (rc < 0) {
+ goto ERR;
+ }
+ }
+ }
+
+ for (i = 0; i < routes_counter; i++) {
+ rc = ops.del_out_route(routes_to_remove[i].remote_ip_address,
+ routes_to_remove[i].address_family,
+ routes_to_remove[i].table_id);
+ if (rc < 0) {
+ goto ERR;
+ }
+ }
+
+ERR:
+ if (rc < 0) printf("Unexpected exit. Some state may not be deleted.\n");
+ return;
+}
+
+void hicn_free(hicn_socket_helper_t *hicn) {
+ // close tun ?
+ free(hicn);
+}
+
+hicn_socket_t *hicn_socket_create() {
+ hicn_socket_t *socket = calloc(1, sizeof(hicn_socket_t));
+ if (!socket) {
+ goto ERR_SOCKET;
+ }
+ socket->type = HS_UNSPEC;
+
+ return socket;
+
+ERR_SOCKET:
+ return NULL;
+}
+
+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) {
+ if (socket->type != HS_CONNECTION) {
+ return NULL;
+ }
+ return &socket->connection.tun_ip_address;
+}
+
+typedef int (*cmp_t)(const void *, const void *);
+
+int hicn_socket_add(hicn_socket_helper_t *hicn, hicn_socket_t *socket) {
+ if (!(tsearch(socket, &hicn->socket_root, (cmp_t)hicn_socket_cmp))) {
+ // ERROR("Could not insert field id into index");
+ return -1;
+ }
+ return 0;
+}
+
+hicn_socket_t *hicn_socket_find(hicn_socket_helper_t *hicn, int fd) {
+ hicn_socket_t search = {
+ .fd = fd,
+ };
+ hicn_socket_t **socket =
+ tfind(&search, &hicn->socket_root, (cmp_t)hicn_socket_cmp);
+ return socket ? *socket : NULL;
+}
+
+/*******************************************************************************
+ * New API
+ *******************************************************************************/
+
+int hicn_set_local_endpoint(hicn_socket_t *socket, const char *local_ip_address,
+ bool allow_null) {
+ int rc = HICN_SOCKET_ERROR_NONE;
+
+ if (!local_ip_address) {
+ if (!allow_null) {
+ rc = HICN_SOCKET_ERROR_SOCKET_LOCAL_NULL_ADDRESS;
+ }
+ goto end;
+ }
+
+ /* local_ip_address should be a prefix with global scope in which to pick
+ * the locator address to use as the source.
+ * If we expect to pick another IP for the tun, then it needs to be of size
+ * less than 128.
+ */
+
+ /* Copy the local IP address inside the connection */
+ rc = hicn_ip_pton(local_ip_address, &socket->connection.tun_ip_address);
+ if (rc < 0) {
+ rc = HICN_SOCKET_ERROR_SOCKET_LOCAL_REPR;
+ goto end;
+ }
+
+end:
+ return rc;
+}
+
+// XXX This could be used by hicn_set_remote_endpoint
+// XXX This has been introduced for mapme
+int hicn_get_local_address(const ip_address_t *remote_address,
+ ip_address_t *local_address) {
+ int rc = 0;
+ uint32_t interface_id;
+ char remote_address_str[INET_MAX_ADDRSTRLEN];
+
+ rc = hicn_ip_ntop(remote_address, remote_address_str,
+ sizeof(remote_address_str));
+ if (rc < 0) {
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR;
+ goto ERR;
+ }
+
+ rc = ops.get_output_ifid(remote_address_str, remote_address->family,
+ &interface_id);
+ if (rc < 0 || interface_id == 0) {
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_INTERFACE;
+ goto ERR;
+ }
+
+ /* Local ip */
+ rc = ops.get_ip_addr(interface_id, remote_address->family, local_address);
+ if (rc < 0) {
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_NETMASK;
+ goto ERR;
+ }
+
+ERR:
+ return rc;
+}
+
+/**
+ *
+ * sets socket->interface_id
+ */
+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;
+
+ af = get_addr_family(remote_ip_address);
+ if ((af != AF_INET6) && (af != AF_INET)) {
+ return HICN_SOCKET_ERROR_INVALID_IP_ADDRESS;
+ }
+
+ /* Bind local endpoint if not done yet */
+ if (ip_address_empty(&socket->connection.tun_ip_address)) {
+ char local_ip_address[INET_MAX_ADDRSTRLEN];
+
+ /* Local interface id */
+ // INFO("Getting interface_id from gateway IP address %s",
+ // remote_ip_address);
+ /////
+ int addr_family = get_addr_family(remote_ip_address);
+ if (addr_family < 0) {
+ rc = addr_family;
+ goto ERR;
+ }
+
+ rc = ops.get_output_ifid(remote_ip_address, (uint8_t)addr_family,
+ &socket->connection.interface_id);
+ if (rc < 0 || socket->connection.interface_id == 0) {
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_INTERFACE;
+ goto ERR;
+ }
+
+ /* Local ip */
+ rc = ops.get_ip_addr(socket->connection.interface_id, (uint8_t)addr_family,
+ &addr);
+ if (rc < 0) {
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_NETMASK;
+ goto ERR;
+ }
+ /////
+
+ /* Convert to representation format */
+ rc = hicn_ip_ntop(&addr, local_ip_address, sizeof(local_ip_address));
+ if (rc < 0) {
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR;
+ goto ERR;
+ }
+
+ rc = hicn_set_local_endpoint(socket, local_ip_address, true);
+ if (rc < 0) {
+ switch (rc) {
+ case HICN_SOCKET_ERROR_SOCKET_LOCAL_NULL_ADDRESS:
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_LOCAL_NULL_ADDR;
+ break;
+ case HICN_SOCKET_ERROR_SOCKET_LOCAL_REPR:
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_LOCAL_REPR;
+ break;
+ case HICN_SOCKET_ERROR_SOCKET_LOCAL_HEURISTIC:
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_LOCAL_HEURISTIC;
+ break;
+ case HICN_SOCKET_ERROR_SOCKET_LOCAL_SET_TUN_IP:
+ rc = HICN_SOCKET_ERROR_BIND_REMOTE_LOCAL_SET_TUN_IP;
+ break;
+ }
+ goto ERR;
+ }
+ }
+ return HICN_SOCKET_ERROR_NONE;
+
+ERR:
+ return rc;
+}
+
+/**
+ *
+ * We need at least an identifier.
+ */
+int hicn_socket(hicn_socket_helper_t *hicn, const char *identifier,
+ const char *local_ip_address) {
+ int rc;
+
+ hicn_socket_t *socket = hicn_socket_create();
+ if (!socket) {
+ rc = -5;
+ goto ERR_SOCKET;
+ }
+
+ ops.get_tun_name(hicn->conf->identifier, identifier, socket->tun_name);
+
+ // register the hicn face on which to bind prefixes, create the in/out TUN
+ // device
+ socket->fd = ops.tun_create(socket->tun_name);
+ if (socket->fd <= 0) {
+ rc = -2;
+ goto ERR_TUN;
+ }
+
+ // INFO("Successfully created listener on TUN device %s", socket->tun_name);
+
+ /* Retrieve interface id */
+ socket->tun_id = ops.get_ifid(socket->tun_name);
+ if (socket->tun_id < 0) {
+ rc = -3;
+ goto ERR_TUNIFID;
+ }
+ // INFO("Interface id=%d", socket->tun_id);
+
+ // WARN("Need to set offload");
+
+ // INFO("Setting interface up");
+ rc = ops.up_if(socket->tun_id);
+ if (rc < 0) {
+ rc = -4;
+ goto ERR_UP;
+ }
+
+ /* Update state */
+ rc = hicn_socket_add(hicn, socket);
+ if (rc < 0) {
+ rc = -5;
+ goto ERR_ADD;
+ }
+
+ rc = hicn_set_local_endpoint(socket, local_ip_address, true);
+ if (rc < 0) {
+ rc = -6;
+ goto ERR_ADJACENCY;
+ }
+
+ return socket->fd;
+
+ERR_ADJACENCY:
+ERR_ADD:
+ERR_UP:
+ERR_TUNIFID:
+ERR_TUN:
+ free(socket);
+ERR_SOCKET:
+ // ERR_PARAMS:
+ return rc;
+}
+
+int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix) {
+ int rc;
+ hicn_socket_t *socket = hicn_socket_find(hicn, fd);
+ if (!socket) {
+ return -1;
+ }
+
+ /* Check socket is not a connection */
+ if (socket->type == HS_CONNECTION) {
+ return -1;
+ }
+
+ rc = ops.add_in_route_s(prefix, socket->tun_id);
+ if (rc < 0) {
+ return rc;
+ }
+
+ ip_address_t ip_address;
+ rc = hicn_ip_pton(prefix, &ip_address);
+ if (rc < 0) {
+ return rc;
+ }
+
+ // ip -6 rule add from b001::/16 prio 0 table 100
+ socket->connection.table_id =
+ socket->tun_id % MAX_TABLES; // this table should be unused
+
+ if (punting_table_id == -1) punting_table_id = socket->connection.table_id;
+
+ rc = ops.add_prio_rule(&ip_address, ip_address.family, 0,
+ socket->connection.table_id);
+ if (rc < 0) {
+ return rc;
+ }
+
+ 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].table_id = socket->connection.table_id;
+ rules_to_remove[rules_counter].priority = 0;
+ ++rules_counter;
+
+ /* Update socket upon success */
+ socket->type = HS_LISTENER;
+
+ return 0;
+}
+
+/**
+ *
+ * We can pass all adjacency parameters but identifier
+ */
+int hicn_bind(hicn_socket_helper_t *hicn, int fd,
+ const char *remote_ip_address) {
+ // uint32_t interface_id;
+ int rc = HICN_SOCKET_ERROR_NONE;
+
+ hicn_socket_t *socket = hicn_socket_find(hicn, fd);
+ if (!socket) {
+ rc = HICN_SOCKET_ERROR_BIND_SOCKET_NOT_FOUND;
+ goto ERR;
+ }
+
+ /* We allow reuse */
+ if (socket->type == HS_CONNECTION) return rc;
+
+ /* Check socket is not a connection */
+ if (socket->type != HS_UNSPEC) {
+ rc = HICN_SOCKET_ERROR_BIND_SOCKET_ALREADY_BOUND;
+ goto ERR;
+ }
+ socket->type = HS_CONNECTION;
+
+ // each connection is associated a table id, let's take it equal to the
+ // tun ID by default (% MAX_TABLES, assuming TUN IDs do not overlap modulo
+ // 256...).
+ // XXX we need to make sure the corresponding table is flushed.
+ socket->connection.table_id =
+ socket->tun_id % MAX_TABLES; // interface_id; // ops.get_free_table_id();
+
+ // XXX use IP address
+ rc = hicn_set_remote_endpoint(socket, remote_ip_address);
+ if (rc < 0) {
+ goto ERR;
+ }
+
+ // rule
+ // ip -6 rule from all iif eth0 lookup 200
+ // INFO("Adding output rule for %s in table %d", socket->tun_name,
+ // socket->connection.table_id);
+ int addr_family = get_addr_family(remote_ip_address);
+ if (addr_family < 0) {
+ rc = addr_family;
+ goto ERR;
+ }
+
+ rc = ops.add_rule(socket->tun_name, (uint8_t)addr_family,
+ socket->connection.table_id);
+ if (rc < 0) {
+ rc = HICN_SOCKET_ERROR_BIND_RULE;
+ goto ERR;
+ }
+
+ strcpy(rules_to_remove[rules_counter].tun_name, socket->tun_name);
+ rules_to_remove[rules_counter].address_family = addr_family;
+ rules_to_remove[rules_counter].table_id = socket->connection.table_id;
+ ++rules_counter;
+
+ // route
+ // ip -6 route add default via 2002::2 table 28
+ // INFO("Adding output route in table %d via gateway %s",
+ // socket->connection.table_id,
+ // remote_ip_address);
+
+ // if the address is an IPv6 and start with fe80 we need to specify the device
+ // in the route
+ u32 default_interface = ~0;
+ if (addr_family == AF_INET6 && strncmp(LOCAL_IPV6_PREFIX, remote_ip_address,
+ strlen(LOCAL_IPV6_PREFIX)) == 0) {
+ rc = ops.get_output_ifid(remote_ip_address, (uint8_t)addr_family,
+ &default_interface);
+ if (rc < 0) {
+ goto ERR;
+ }
+ }
+
+ rc = ops.add_out_route(remote_ip_address, (uint8_t)addr_family,
+ socket->connection.table_id, default_interface);
+ if (rc < 0) {
+ rc = HICN_SOCKET_ERROR_BIND_ROUTE;
+ goto ERR;
+ }
+
+ strcpy(routes_to_remove[routes_counter].remote_ip_address, remote_ip_address);
+ routes_to_remove[routes_counter].table_id = socket->connection.table_id;
+ routes_to_remove[routes_counter].address_family = (uint8_t)addr_family;
+ ++routes_counter;
+
+ // add route for data
+ // ip -6 route add 0:1::/64 dev hicn-if0 table 100
+ // this routes are deleted by removing the tun interfaces
+
+ if (punting_table_id == -1) {
+ // the punting_table_id was not initialized beacause no main-tun was created
+ // we use as an id (socket->tun_id - 1) % MAX_TABLES, so that we will hava a
+ // collision only after 255 new interfaces
+ punting_table_id = (socket->tun_id - 1) % MAX_TABLES;
+ }
+ rc = ops.add_in_route_table(&socket->connection.tun_ip_address,
+ socket->tun_id, punting_table_id);
+ if (rc < 0) {
+ rc = HICN_SOCKET_ERROR_BIND_ROUTE;
+ goto ERR;
+ }
+
+ERR:
+ return rc;
+}
diff --git a/hicn-light/src/socket/api.h b/hicn-light/src/socket/api.h
new file mode 100755
index 000000000..e1516ebe1
--- /dev/null
+++ b/hicn-light/src/socket/api.h
@@ -0,0 +1,216 @@
+/*
+ * 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 hicn_face.h
+ * @brief hICN socket library
+ *
+ * This module provides an interface to managing so-called hICN sockets,
+ * realizing punting of interest and data packets using a TUN device.
+ */
+
+#ifndef HICN_SOCKET_API_H
+#define HICN_SOCKET_API_H
+
+#include <stdint.h> // uint*_t
+#include <stdlib.h>
+
+#include <hicn/hicn.h>
+#include "error.h"
+
+#define BUFSIZE 4096
+#define MAX_CONNECTIONS \
+ 255 // We currently limit the number of connections we can establish
+#define IF_NAMESIZE 16
+
+/* hICN socket helper */
+
+/** hICN configuration options */
+typedef struct {
+ // uint32_t interval;
+
+ /* Identifier used to name hICN TUN interfaces (should be unique) */
+ char *identifier;
+ // hicn_format_t format;
+
+} hicn_conf_t;
+
+/**
+ * hICN adjacency
+ */
+typedef struct {
+ char *local_ip_address;
+ char *gateway_ip_address;
+} hicn_adjacency_t;
+
+#define EMPTY_HICN_ADJACENCY \
+ (hicn_adjacency_t) { 0, 0 }
+
+/* hICN socket operations */
+
+typedef struct {
+ uint8_t pkbuf[BUFSIZE];
+ uint32_t rb_pkbuf_r;
+ uint32_t rb_pkbuf_w;
+} hicn_buffer_t;
+
+typedef enum { HS_UNSPEC, HS_LISTENER, HS_CONNECTION } hicn_socket_type_t;
+
+typedef struct hicn_socket_s {
+ hicn_socket_type_t type;
+ int fd;
+
+ /* Implementation specific state follows */
+ char tun_name[IF_NAMESIZE];
+ uint32_t tun_id;
+
+ hicn_buffer_t buffer;
+ void (*cb)(struct hicn_socket_s *, void *, uint8_t *, size_t);
+ void *cb_data;
+
+ union {
+ struct {
+ ip_address_t tun_ip_address;
+ uint32_t interface_id;
+
+ /* ID of the corresponding table : avoid default values of 0, 32766 and
+ * 32767 */
+ uint8_t table_id;
+ } connection;
+ };
+} hicn_socket_t;
+
+/**
+ * hICN global state
+ */
+typedef struct {
+ /* Configuration data */
+ hicn_conf_t *conf;
+
+ // We need state associate to each FD, to know what type of socket it is and
+ // its state.
+ void *socket_root; /**< A tree of socket indexed by their fd */
+
+} hicn_socket_helper_t;
+
+/**
+ * Create an hICN instance.
+ *
+ * This is used to configure the state of an hICN router consistently between
+ * a listener and the different connections. It also regroups all the state
+ * related to hICN functionalities.
+ *
+ * @return A pointer to an hICN instance.
+ */
+hicn_socket_helper_t *hicn_create();
+
+void hicn_destroy();
+
+/**
+ * Retrieve hICN configuration.
+ *
+ * Gets the current configuration of an hICN instance for information purposes,
+ * or later update it.
+ *
+ * TODO
+ * - We might want to prevent configuration updates while the hICN instance is
+ * running. Define running...
+ *
+ * @param [in] hicn Pointer to hICN instance.
+ * @return Pointer to an hICN configuration data structure.
+ *
+ * @see hicn_set_conf
+ */
+hicn_conf_t *hicn_get_conf(hicn_socket_helper_t *hicn);
+
+/**
+ * Update hICN configuration.
+ *
+ * @param [in] hicn Pointer to an hICN instance.
+ * @param [in] hicn_conf Pointer to an hICN configuration data structure.
+ * @return 0 in case of success, -1 otherwise.
+ *
+ * @see hicn_get_conf
+ */
+int hicn_set_conf(hicn_socket_helper_t *hicn, hicn_conf_t *hicn_conf);
+
+/**
+ * Release hICN state.
+ *
+ * @param [in] hicn Pointer to an hICN instance.
+ */
+void hicn_free(hicn_socket_helper_t *hicn);
+
+// FIXME doc
+int hicn_get_local_address(const ip_address_t *remote_address,
+ ip_address_t *local_address);
+
+/* hICN socket */
+
+/**
+ * Create an hICN socket.
+ *
+ * An hICN socket abstracts the underlying implementation and allows hICN
+ * packets to be sent and received independently of the underlying
+ * implementation.
+ *
+ * It is possible to further specialize the socket in a listener socket, and a
+ * connection socket.
+ *
+ * @param [in] hicn Pointer to an hICN instance.
+ * @param [in] identifier Unique identifier for this socket, used to named the
+ * TUN device
+ * @param [in] local_ip_address IP address used locally by the socket (or NULL
+ * for letting the library decide automatically).
+ * @return File descriptor (>0) in case of success, -1 otherwise.
+ *
+ * @see hicn_listen
+ * @see hicn_bind
+ */
+int hicn_socket(hicn_socket_helper_t *hicn, const char *identifier,
+ const char *local_ip_address);
+
+/**
+ * Packet punting.
+ *
+ * Note that we cannot listen on a socket that is already bound.
+ *
+ * @param [in] hicn Pointer to an hICN instance.
+ * @param [in] fd File descriptor identifying the hICN socket.
+ * @param [in] prefix Prefix (IPv4 or IPv6) to be bound to hICN in
+ * RFC-compliant presentation format.
+ * @return 0 in case of success, -1 otherwise.
+ *
+ * @see hicn_socket
+ */
+int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix);
+
+/**
+ * Packet forwarding
+ * @param [in] hicn Pointer to an hICN instance.
+ * @param [in] fd File descriptor identifying the hICN socket.
+ * @param [in] prefix Prefix (IPv4 or IPv6) to be bound to hICN in
+ * RFC-compliant presentation format.
+ * @return 0 in case of success, -1 otherwise.
+ *
+ * XXX adjacency does not perform any copy heresofar
+ *
+ * @see hicn_socket
+ */
+int hicn_bind(hicn_socket_helper_t *hicn, int fd,
+ const char *remote_ip_address);
+
+#endif /* HICN_SOCKET_API_H */
diff --git a/hicn-light/src/socket/error.c b/hicn-light/src/socket/error.c
new file mode 100755
index 000000000..3dafec8cf
--- /dev/null
+++ b/hicn-light/src/socket/error.c
@@ -0,0 +1,7 @@
+#include "error.h"
+
+const char* HICN_SOCKET_ERROR_STRING[] = {
+#define _(a, b, c) [b] = c,
+ foreach_hicn_socket_error
+#undef _
+};
diff --git a/hicn-light/src/socket/error.h b/hicn-light/src/socket/error.h
new file mode 100755
index 000000000..8195efd84
--- /dev/null
+++ b/hicn-light/src/socket/error.h
@@ -0,0 +1,46 @@
+#ifndef HICN_SOCKET_ERROR_H
+#define HICN_SOCKET_ERROR_H
+
+// FIXME remove unused errors
+#define foreach_hicn_socket_error \
+ _(NONE, 0, "OK") \
+ _(UNSPEC, 1, "unspecified error") \
+ _(NOT_HICN, 2, "not a hICN paclet") \
+ _(UNKNOWN_ADDRESS, 10, "unknown address") \
+ _(INVALID_PARAMETER, 20, "invalid parameter") \
+ _(INVALID_IP_ADDRESS, 21, "invalid IP address") \
+ _(CORRUPTED_PACKET, 22, "corrupted packet") \
+ _(UNEXPECTED, 98, "unexpected error") \
+ _(NOT_IMPLEMENTED, 99, "not implemented") \
+ _(SOCKET_LOCAL_NULL_ADDRESS, 101, "empty local address") \
+ _(SOCKET_LOCAL_REPR, 102, "cannot represent local address") \
+ _(SOCKET_LOCAL_HEURISTIC, 103, "error finding local address") \
+ _(SOCKET_LOCAL_SET_TUN_IP, 104, "cannot set local IP to TUN") \
+ _(BIND_SOCKET_NOT_FOUND, 301, "bind: socket not found") \
+ _(BIND_SOCKET_ALREADY_BOUND, 302, "bind: socket already bound") \
+ _(BIND_REMOTE_INTERFACE, 303, "bind: no interface towards gateway") \
+ _(BIND_REMOTE_NETMASK, 304, "bind: no local IP with netmask < 128") \
+ _(BIND_REMOTE_REPR, 305, "bind: error representing local IP") \
+ _(BIND_REMOTE_LOCAL_NULL_ADDR, 306, "bind: could not set local endpoint") \
+ _(BIND_REMOTE_LOCAL_REPR, 307, "bind: error representing remote IP") \
+ _(BIND_REMOTE_LOCAL_HEURISTIC, 308, "bind: could not apply heuristic") \
+ _(BIND_REMOTE_LOCAL_SET_TUN_IP, 309, "bind: error setting local IP to TUN") \
+ _(BIND_NDP, 310, "bind: could not enable NDP proxy") \
+ _(BIND_NEIGH_PROXY, 311, "bind: could not neighbour") \
+ _(BIND_REPR, 312, "bind: error represeting IP") \
+ _(BIND_LO, 313, "bind: could not remove local route") \
+ _(BIND_RULE, 314, "bind: could not add rule") \
+ _(BIND_ROUTE, 315, "bind: could not add output route")
+
+typedef enum {
+#define _(a, b, c) HICN_SOCKET_ERROR_##a = (-b),
+ foreach_hicn_socket_error
+#undef _
+ HICN_SOCKET_N_ERROR,
+} hicn_socket_error_t;
+
+extern const char *HICN_SOCKET_ERROR_STRING[];
+
+#define hicn_socket_strerror(errno) (char *)(HICN_SOCKET_ERROR_STRING[-errno])
+
+#endif /* HICN_SOCKET_ERROR_H */
diff --git a/hicn-light/src/socket/ops.h b/hicn-light/src/socket/ops.h
new file mode 100755
index 000000000..249caf87a
--- /dev/null
+++ b/hicn-light/src/socket/ops.h
@@ -0,0 +1,54 @@
+#ifndef HICN_SOCKET_OPS_H
+#define HICN_SOCKET_OPS_H
+
+#include <hicn/hicn.h>
+#include <stdint.h>
+
+typedef struct {
+ char *arch;
+ int (*tun_create)(char *name);
+ int (*get_tun_name)(const char *prefix, const char *identifier,
+ char *tun_name);
+ int (*enable_v6_forwarding)(char *interface_name);
+ int (*enable_v4_forwarding)();
+ int (*enable_ndp_proxy)();
+
+ uint32_t (*get_ifid)(const char *ifname);
+ 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);
+ int (*up_if)(uint32_t interface_id);
+ int (*add_in_route_table)(const ip_address_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,
+ const uint8_t table_id);
+ int (*add_in_route_s)(const char *prefix, const uint32_t interface_id);
+ int (*add_out_route)(const char *gateway, const uint8_t address_family,
+ 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 (*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,
+ const uint32_t interface_id);
+ int (*add_prio_rule)(const ip_address_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,
+ const uint8_t address_family,
+ const uint32_t priority);
+ int (*del_prio_rule)(const ip_address_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,
+ const uint8_t address_family,
+ const uint32_t priority);
+} hicn_socket_ops_t;
+
+#endif /* HICN_SOCKET_OPS_H */
diff --git a/hicn-light/src/socket/ops_linux.c b/hicn-light/src/socket/ops_linux.c
new file mode 100755
index 000000000..d085f0d3d
--- /dev/null
+++ b/hicn-light/src/socket/ops_linux.c
@@ -0,0 +1,1723 @@
+#include <sys/ioctl.h> // ioctl
+#include <sys/socket.h> // needed by linux/if.h
+//#include <linux/if.h>
+#include <errno.h>
+#include <fcntl.h> // ''
+#include <linux/if_tun.h>
+#include <linux/limits.h> // PATH_MAX
+#include <stdio.h> // fprintf
+#include <string.h> // memset
+#include <sys/stat.h> // open
+#include <sys/uio.h> // writev
+#include <unistd.h> // close
+
+#include "error.h"
+#include "ops.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+/******************************************************************************
+ * netlink.h
+ ******************************************************************************/
+
+#ifndef HICN_NETLINK_H
+#define HICN_NETLINK_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+// DEPRECATED|/* Socket */
+// DEPRECATED|int _nl_get_socket();
+// DEPRECATED|int _nl_send(int s, uint8_t * buffer, size_t len);
+// DEPRECATED|size_t _nl_receive(uint8_t * buffer, size_t len);
+// DEPRECATED|
+// DEPRECATED|/* Netlink packet format */
+// DEPRECATED|int _nl_header(int request, uint8_t * buffer, size_t len, uint32_t
+// flags); DEPRECATED|int _nl_payload_rule(uint8_t table_id, uint8_t * buffer,
+// size_t len); DEPRECATED|int _nl_payload_link(uint32_t ifindex, uint8_t *
+// buffer, size_t len); DEPRECATED|int _nl_payload_route(uint8_t table_id,
+// uint8_t dst_len, uint8_t * buffer, size_t len); DEPRECATED| DEPRECATED|int
+// _nl_parse(uint8_t * buffer, size_t len); DEPRECATED|int _nl_parse_ret(uint8_t
+// * buffer, size_t len); DEPRECATED|int _nl_parse_link_ifid(uint8_t * buffer,
+// size_t len, uint32_t * interface_id); DEPRECATED|int
+// _nl_parse_link_ip_addr(uint8_t * buffer, size_t len, struct in6_addr * addr);
+
+/* Public interface */
+
+/**
+ * Get the interface ID of an interface by its name
+ *
+ * @return 32-bit interface identifier in case of success, or 0.
+ *
+ * @see if_nametoindex
+ *
+ */
+uint32_t _nl_get_ifid(const char *ifname);
+
+/**
+ * Retrieve the output interface corresponding to the specified IP address.
+ *
+ * @param [in] addr IP(v6) address in presentation form.
+ * @param [out] Identifier of the corresponding output interface.
+ * @return int 0 in case of success, -1 otherwise
+ */
+int _nl_get_output_ifid(const char *ip_address, uint8_t address_family,
+ uint32_t *interface_id);
+
+/**
+ * Retrieve the first IP address of an interface (identified by its id) which
+ * has a netmask < 128.
+ *
+ * @param [in] s File descriptor of the netlink socket (deprecated).
+ * @param [in] interface_id Identifier of the interface for which to retrieve
+ * the IP address.
+ * @param [out] addr IP(v6) address in binary form.
+ * @return int 0 in case of success, -1 otherwise
+ *
+ * @see getifaddrs
+ */
+int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family,
+ ip_address_t *ip_address);
+
+int _nl_set_ip_addr(uint32_t interface_id, ip_address_t *ip_address);
+
+int _nl_up_if(uint32_t interface_id);
+
+int _nl_add_in_route_table(const ip_address_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);
+int _nl_add_in_route_s(const char *prefix, const uint32_t interface_id);
+
+int _nl_add_out_route(const char *gateway, const uint8_t address_family,
+ const uint8_t table_idi, int default_route);
+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_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,
+ const uint32_t interface_id);
+
+int _nl_add_prio_rule(const ip_address_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,
+ const uint8_t address_family, const uint32_t priority);
+int _nl_del_prio_rule(const ip_address_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,
+ const uint8_t address_family, const uint32_t priority);
+
+#endif /* HICN_NETLINK_H */
+
+/******************************************************************************
+ * netlink.c
+ ******************************************************************************/
+
+/*
+ * This module offers an interface to the Netlink API appropriate for
+ * implementing punting as required by hICN (1).
+ *
+ * More specifically, it consists of the following functionalities:
+ * - LINK
+ . map interface name to ID
+ . set and interface up
+ * - ADDR
+ . get and set ip addresses on a given interface ID
+ * - ROUTE
+ . get output interface id towards IP (ip route get IP > interface_id)
+ . add input route (ip route add PREFIX dev INTERFACE) for punting
+ interests . add output route (ip route add default GATEWAY table TABLE) for
+ routing interests (2, 3) . delete local route towards IP (ip route del IP table
+ local) for ???
+ /!\ could this be avoided by removing the local attribute in the
+ netlink call ?
+ * - RULE
+ * . add output rule (ip rule add iif interface table TABLE) for routing
+ interests (2, 3)
+ * - ND PROXY
+ * . enable NDP proxy functionality for IP on interface ID (ip -6 neigh add
+ proxy IP dev INTERFACE)
+ * for allowing the TUN to be reachable on the reverse data path
+ *
+ * Implementation notes:
+ * (1) We have not been using the libnl library because it requires
+ * manipulating too many function and data structures for a simple purpose.
+ * Currently, many parts of the code are somehow repetitive, but this might
+ * be improved by a proper API in a future release.
+ * (2) allows load balancing over different interfaces = multihoming. Please
+ * note that it is not possible to have load balancing over two faces using
+ * the same output interface as we are using the underlying IP network !
+ * This might be mitigated with the use of SR however.
+ * (3) The implementation of punting heavily uses the policy routing
+ * functionalities, as we need to hook through a TUN into user space a
+ * whole prefix used as a destination (for interests) or source (for data
+ * packets). We thus combine the use of rules to assign routing table IDs,
+ * and routes inside those tables. As there is no easy way to allocate
+ * which routing tables we use, we made the choice to index them by the ID
+ * of the interface, assuming there is no external conflict. This might be
+ * improved in the future.
+ *
+ * This hICN implementation uses TUNs in two different ways:
+ * - a main TUN interface, which receives all punted interests,
+ * demultiplex them before assigning them an input face (eventually
+ * dynamically creating it);
+ * - a set of output TUN interfaces, aka faces, used for routing of
+ * interests, and for receiving the corresponding data packets on the way
+ * back. Punting of data packets if based of their destination IP, which
+ * is the IP of the physical output interface used for the interest, which
+ * is unique (cf (2)).
+ *
+ * The corresponding routing tables IDs are :
+ * MAIN_TUN_ID -> used for punting of data packets
+ * OUTPUT_TUN_ID_i -> used for routing of interests towards next hop
+ * (bypassing local IP routing table)
+ *
+ * Note that punting of interests is done just through a route, and routing
+ * of data packets is done just through the regular IP routing table on the
+ * note after the address translation done in the forwarder.
+ *
+ * - Forging netlink packets
+ *
+ * A previous implementation used function calls with pointers to populate
+ * the various header parts in a buffer in order to build a netlink packet.
+ * A newer implementation uses nested structs and iovecs to build the whole
+ * packet in a single write call. This should allow a simpler evolution
+ * towards a cleaner API.
+ */
+
+#include <arpa/inet.h> // inet_pton
+#include <errno.h> // errno
+#include <linux/fib_rules.h> // fib_rule_hdr, FRA_*
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h> // IFF_UP
+#include <netinet/in.h> // in6addr
+#include <stdio.h> // perror
+#include <string.h>
+#include <sys/socket.h> // ''
+#include <sys/types.h> // socket
+#include <unistd.h> // read
+
+#include <sys/socket.h> // ''
+#include <sys/types.h> // send, recv
+
+//#include "../../hicn.h"
+//#include "../../hicn_util.h" // ARRAY_SIZE, hicn_packet_dump_iov
+
+#define BUFSIZE 4096
+#define FLAGS_CREATE NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK
+// ??
+#define FLAGS_CREATE_MATCH \
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_MATCH
+
+// XXX putting ACK poses a prolem for the value received by get_if_id.
+#define FLAGS_GET NLM_F_REQUEST
+#define FLAGS_GET_ROOT (NLM_F_REQUEST | NLM_F_ROOT)
+
+#define FLAGS_LIST NLM_F_REQUEST | NLM_F_DUMP
+
+#define IF_NAMESIZE 16
+#define FR_ACT_TO_TBL 1
+#define NLMSG_BOTTOM(nlmsg) \
+ ((struct rtattr *)(((void *)(nlmsg)) + NLMSG_ALIGN((nlmsg)->nlmsg_len)))
+
+int seq = 1;
+
+static inline size_t iov_length(const struct iovec *iov,
+ unsigned long nr_segs) {
+ unsigned long seg;
+ size_t ret = 0;
+
+ for (seg = 0; seg < nr_segs; seg++) ret += iov[seg].iov_len;
+ return ret;
+}
+
+typedef struct {
+ struct nlmsghdr hdr;
+ struct nlmsgerr payload;
+} nl_err_hdr_t;
+
+/* Low level : nl header */
+
+int _nl_get_socket() { return socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); }
+
+int _nl_header(int request, uint8_t *buffer, size_t len, uint32_t flags) {
+ struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+
+ nl->nlmsg_len = 0; // NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ nl->nlmsg_type = request;
+ nl->nlmsg_flags = flags;
+ nl->nlmsg_seq = seq++; //
+ nl->nlmsg_pid = 0; // getpid();
+
+ return 0;
+}
+
+/* Low level : nl protocols */
+
+/* Low level : attributes */
+
+int addAttr(struct nlmsghdr *nl, int maxlen, int type, void *data,
+ int attr_len) {
+ struct rtattr *rta;
+ int len = RTA_LENGTH(attr_len);
+
+ if (NLMSG_ALIGN(nl->nlmsg_len) + len > maxlen) {
+ exit(EXIT_FAILURE);
+ }
+
+ rta = (struct rtattr *)((char *)nl + NLMSG_ALIGN(nl->nlmsg_len));
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy(RTA_DATA(rta), data, attr_len);
+ nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + len;
+ return 0;
+}
+
+int _nl_payload_rule(uint8_t table_id, uint8_t address_family, uint8_t *buffer,
+ size_t len) {
+ struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+ struct fib_rule_hdr *frh = (struct fib_rule_hdr *)(NLMSG_DATA(buffer));
+
+ memset(frh, 0, sizeof(struct fib_rule_hdr));
+ frh->family = address_family;
+ frh->table = table_id;
+ frh->action = FR_ACT_TO_TBL,
+ frh->flags = NLM_F_REPLACE; // 0
+ frh->tos = 0;
+
+ nl->nlmsg_len += NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
+
+ return 0;
+}
+
+int _nl_payload_link(uint32_t ifindex, uint8_t *buffer, size_t len) {
+ struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+ struct ifinfomsg *ifi = (struct ifinfomsg *)(NLMSG_DATA(buffer));
+
+ memset(ifi, 0, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
+ // ifi->ifi_type = 0;
+ ifi->ifi_index =
+ ifindex; // new interface, could be specified since linux 3.7
+ ifi->ifi_flags = 0;
+ // ifi->ifi_change = 0xffffffff;
+
+ nl->nlmsg_len += NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+ return 0;
+}
+
+int _nl_payload_addr(uint32_t ifindex, uint8_t *buffer, size_t len) {
+ struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+ struct ifaddrmsg *addr = (struct ifaddrmsg *)(NLMSG_DATA(buffer));
+
+ memset(addr, 0, sizeof(struct ifaddrmsg));
+ addr->ifa_family = AF_UNSPEC; // INET6;
+ /*
+ addr->ifa_prefixlen = 128;
+ addr->ifa_flags = 0;
+ addr->ifa_scope = RT_SCOPE_LINK; //IFA_ADDRESS;
+ addr->ifa_index = ifindex;
+ */
+
+ nl->nlmsg_len += NLMSG_LENGTH(sizeof(struct ifaddrmsg)) - 4;
+
+ return 0;
+}
+
+int _nl_payload_route(uint8_t table_id, uint8_t addr_family, uint8_t dst_len,
+ uint8_t *buffer, size_t len) {
+ struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+ struct rtmsg *raddr = (struct rtmsg *)(NLMSG_DATA(buffer));
+
+ raddr->rtm_family = addr_family;
+ raddr->rtm_dst_len = dst_len;
+ raddr->rtm_src_len = 0;
+ raddr->rtm_tos = 0;
+
+ raddr->rtm_table = table_id;
+ raddr->rtm_protocol = RTPROT_BOOT;
+ raddr->rtm_scope = RT_SCOPE_UNIVERSE;
+ raddr->rtm_type = RTN_UNICAST;
+
+ raddr->rtm_flags = 0;
+
+ nl->nlmsg_len += NLMSG_LENGTH(sizeof(struct rtmsg));
+
+ return 0;
+}
+
+uint32_t _nl_get_ifid(const char *interface_name) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+ size_t len = interface_name ? strlen(interface_name) + 1 : 0;
+ uint8_t padding[RTA_ALIGNTO] = {0, 0, 0, 0};
+
+ if (len == 0) {
+ goto ERR_IF;
+ }
+
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg payload;
+ } msg = {//.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .hdr.nlmsg_type = RTM_GETLINK,
+ .hdr.nlmsg_flags = FLAGS_GET,
+ .payload.ifi_family = AF_UNSPEC,
+ .payload.ifi_index = 0};
+ struct rtattr a_ifname = {RTA_LENGTH(strlen(interface_name) + 1),
+ IFLA_IFNAME};
+
+ struct iovec iov[] = {{&msg, sizeof(msg)},
+ {&a_ifname, sizeof(a_ifname)},
+ {(char *)interface_name, len},
+ {padding, RTA_SPACE(len) - RTA_LENGTH(len)}};
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ return 0; /* Unexpected */
+ }
+
+ for (; NLMSG_OK(hdr, n); hdr = NLMSG_NEXT(hdr, n)) {
+ struct ifinfomsg *payload = (struct ifinfomsg *)NLMSG_DATA(hdr);
+ return payload->ifi_index;
+ }
+ return 0;
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ERR_IF:
+ return 0;
+}
+
+int _nl_get_output_ifid(const char *ip_address, uint8_t family_address,
+ uint32_t *interface_id) {
+ int rc;
+
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR;
+ }
+
+ if (family_address == AF_INET6) {
+ struct in6_addr addr; // V6SPECIFIC
+
+ struct {
+ struct nlmsghdr hdr;
+ struct rtmsg payload;
+ } msg = {
+ .hdr.nlmsg_type = RTM_GETROUTE,
+ .hdr.nlmsg_flags = NLM_F_REQUEST,
+ .hdr.nlmsg_seq = seq++,
+ .payload.rtm_family = AF_INET6,
+ .payload.rtm_dst_len = IPV6_ADDR_LEN_BITS,
+ .payload.rtm_src_len = 0,
+ .payload.rtm_tos = 0,
+ .payload.rtm_table = RT_TABLE_UNSPEC,
+ .payload.rtm_protocol = RTPROT_UNSPEC,
+ .payload.rtm_scope = RT_SCOPE_UNIVERSE,
+ .payload.rtm_type = RTN_UNSPEC,
+ .payload.rtm_flags = 0 // RTM_F_NOTIFY in 'ip route get'
+ };
+
+ /* Convert the IP address to binary form */
+ rc = inet_pton(AF_INET6, ip_address, &addr);
+ if (rc <= 0) {
+ goto ERR;
+ }
+
+ /* Set attribute = length/type/value */
+ struct rtattr a_dst = {RTA_LENGTH(16), RTA_DST};
+ struct iovec iov[] = {
+ {&msg, sizeof(msg)},
+ {&a_dst, sizeof(a_dst)}, // attribute
+ {&addr, sizeof(addr)} // value
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+ } else if (family_address == AF_INET) {
+ struct in_addr addr;
+
+ struct {
+ struct nlmsghdr hdr;
+ struct rtmsg payload;
+ } msg = {
+ .hdr.nlmsg_type = RTM_GETROUTE,
+ .hdr.nlmsg_flags = NLM_F_REQUEST,
+ .hdr.nlmsg_seq = seq++,
+ .payload.rtm_family = AF_INET,
+ .payload.rtm_dst_len = IPV4_ADDR_LEN_BITS,
+ .payload.rtm_src_len = 0,
+ .payload.rtm_tos = 0,
+ .payload.rtm_table = RT_TABLE_UNSPEC,
+ .payload.rtm_protocol = RTPROT_UNSPEC,
+ .payload.rtm_scope = RT_SCOPE_UNIVERSE,
+ .payload.rtm_type = RTN_UNSPEC,
+ .payload.rtm_flags = 0 // RTM_F_NOTIFY in 'ip route get'
+ };
+
+ /* Convert the IP address to binary form */
+ rc = inet_pton(AF_INET, ip_address, &addr);
+ if (rc <= 0) {
+ goto ERR;
+ }
+
+ /* Set attribute = length/type/value */
+ struct rtattr a_dst = {RTA_LENGTH(4), RTA_DST};
+ struct iovec iov[] = {
+ {&msg, sizeof(msg)},
+ {&a_dst, sizeof(a_dst)}, // attribute
+ {&addr, sizeof(addr)} // value
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+ } else {
+ goto ERR;
+ }
+
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR;
+ }
+ return HICN_SOCKET_ERROR_UNEXPECTED; /* Unexpected */
+ }
+
+ for (; NLMSG_OK(hdr, n); hdr = NLMSG_NEXT(hdr, n)) {
+ struct rtmsg *rtm = (struct rtmsg *)NLMSG_DATA(hdr);
+ int attrlen = RTM_PAYLOAD(hdr);
+ struct rtattr *rta;
+ for (rta = RTM_RTA(rtm); RTA_OK(rta, attrlen);
+ rta = RTA_NEXT(rta, attrlen)) {
+ if (rta->rta_type == RTA_OIF) {
+ *interface_id = *(uint32_t *)RTA_DATA(rta);
+ return HICN_SOCKET_ERROR_NONE;
+ }
+ }
+ }
+
+ return HICN_SOCKET_ERROR_NONE;
+
+ERR:
+ return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family,
+ ip_address_t *ip_address) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ struct {
+ struct nlmsghdr hdr;
+ struct ifaddrmsg payload;
+ } msg = {.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+ .hdr.nlmsg_type = RTM_GETADDR,
+ .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT, // | NLM_F_MATCH,
+ .payload.ifa_family = address_family,
+ .payload.ifa_index = 0};
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+
+ n = send(fd, &msg, sizeof(msg), 0);
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ return -99; /* Unexpected */
+ }
+
+ for (; NLMSG_OK(hdr, n); hdr = NLMSG_NEXT(hdr, n)) {
+ struct ifaddrmsg *payload = (struct ifaddrmsg *)NLMSG_DATA(hdr);
+
+ 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);
+ 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);
+ return HICN_SOCKET_ERROR_NONE;
+ }
+ } else {
+ return -99;
+ }
+ }
+
+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) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ struct {
+ struct nlmsghdr hdr;
+ struct ifaddrmsg payload;
+ } msg = {
+ .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_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)),
+ IFA_ADDRESS};
+ // XXX maybe the reason why we have a local route ?
+ // struct rtattr ifa_local = { RTA_LENGTH(ip_address_len(ip_address)),
+ // IFA_LOCAL };
+ struct iovec iov[] = {
+ {&msg, sizeof(msg)},
+ {&ifa_address, sizeof(ifa_address)},
+ {(void *)&ip_address->buffer, sizeof(ip_address->buffer)},
+ // { &ifa_local, sizeof(ifa_local) },
+ // { (void*)&ip_address->buffer, sizeof(ip_address->buffer) },
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+
+ // hicn_packet_dump_iov(iov, ARRAY_SIZE(iov));
+
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ }
+
+ return 0;
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ return -1;
+}
+
+int _nl_up_if(uint32_t interface_id) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg payload;
+ } msg = {
+ .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .hdr.nlmsg_type = RTM_NEWLINK,
+ .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+ .payload.ifi_family = AF_UNSPEC,
+ .payload.ifi_index = interface_id,
+ .payload.ifi_flags = IFF_UP,
+ .payload.ifi_change = IFF_UP // 0xffffffff
+ };
+
+ n = send(fd, &msg, sizeof(msg), 0);
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ return 0;
+ }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ return -1;
+}
+
+struct route_info {
+ char *dst_addr;
+ char *src_addr;
+ char *gateway;
+ char ifName[IF_NAMESIZE];
+};
+
+/*
+ * ip -6 route add PREFIX dev INTERFACE_NAME
+ */
+#if 0
+int _nl_add_in_route(const char * prefix, const uint32_t interface_id)
+{
+ char buffer[BUFSIZE];
+ struct nlmsghdr * hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ int pton_fd;
+ unsigned char dst[sizeof(struct in6_addr)];
+ char * p;
+ char * eptr;
+ char addr[strlen(prefix)];
+ uint32_t dst_len;
+
+ strncpy(addr, prefix, strlen(prefix));
+
+ p = strchr(addr, '/');
+ if (!p) {
+ dst_len = IPV6_ADDR_LEN;
+ } else {
+ dst_len = strtoul(p + 1, &eptr, 10);
+ if (dst_len > IPV6_ADDR_LEN * 8) {
+ printf("E: Netmask > IPV6_ADDR_LEN");
+ return -1;
+ }
+ *p = 0;
+ }
+
+ pton_fd = inet_pton(AF_INET6, addr, dst);
+ if (pton_fd <= 0) {
+ if (pton_fd == 0)
+ ;//ERROR("Not in presentation format");
+ else
+ perror("inet_pton");
+ return -2;
+ }
+
+ _nl_header(RTM_NEWROUTE, (uint8_t *)buffer, BUFSIZE, FLAGS_CREATE_MATCH);
+ _nl_payload_route(RT_TABLE_MAIN, dst_len, (uint8_t *)buffer, BUFSIZE);
+
+ addAttr(hdr, BUFSIZE, RTA_DST, dst, IPV6_ADDR_LEN);
+ addAttr(hdr, BUFSIZE, RTA_OIF, (void*)&interface_id, sizeof(uint32_t));
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+
+ n = send(fd, buffer, hdr->nlmsg_len, 0);
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr * err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ return 0;
+ }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ return -1;
+
+}
+#endif
+
+/*
+ * ip -6 route add local default via GATEWAY_IP table TABLE_ID
+ */
+int _nl_add_out_route(const char *gateway, uint8_t address_family,
+ const uint8_t table_id, int default_route) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ int pton_fd;
+
+ if (address_family == AF_INET) {
+ struct in_addr gw;
+
+ pton_fd = inet_pton(AF_INET, gateway, (struct in_addr *)&gw);
+ if (pton_fd < 0) {
+ return -1;
+ }
+
+ _nl_header(RTM_NEWROUTE, (uint8_t *)buffer, BUFSIZE,
+ NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC);
+ _nl_payload_route(table_id, address_family, 0, (uint8_t *)buffer, BUFSIZE);
+
+ /* gw */
+ addAttr(hdr, BUFSIZE, RTA_GATEWAY, &gw, sizeof(gw));
+
+ } else if (address_family == AF_INET6) {
+ struct in6_addr gw;
+
+ pton_fd = inet_pton(AF_INET6, gateway, (struct in6_addr *)&gw);
+ if (pton_fd < 0) {
+ return -1;
+ }
+
+ _nl_header(RTM_NEWROUTE, (uint8_t *)buffer, BUFSIZE,
+ NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC);
+ _nl_payload_route(table_id, address_family, 0, (uint8_t *)buffer, BUFSIZE);
+
+ /* gw */
+ addAttr(hdr, BUFSIZE, RTA_GATEWAY, &gw, sizeof(gw));
+ if (default_route != -1) {
+ addAttr(hdr, BUFSIZE, RTA_OIF, &default_route, sizeof(default_route));
+ }
+
+ } else {
+ return -1;
+ }
+
+ // For more than 255 tables
+ // addAttr(msg, BUFSIZE, RTA_TABLE, &table_id, sizeof(uint32_t));
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+
+ n = send(fd, buffer, hdr->nlmsg_len, 0);
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ return 0;
+ }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ return -1;
+}
+
+/*
+ * ip -6 route del local default via GATEWAY_IP table TABLE_ID
+ */
+int _nl_del_out_route(const char *gateway, const uint8_t address_family,
+ const uint8_t table_id) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ int pton_fd;
+
+ if (address_family == AF_INET) {
+ struct in_addr gw;
+
+ pton_fd = inet_pton(AF_INET, gateway, (struct in_addr *)&gw);
+ if (pton_fd < 0) {
+ return -1;
+ }
+
+ _nl_header(RTM_DELROUTE, (uint8_t *)buffer, BUFSIZE,
+ NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC);
+ _nl_payload_route(table_id, address_family, 0, (uint8_t *)buffer, BUFSIZE);
+
+ /* gw */
+ addAttr(hdr, BUFSIZE, RTA_GATEWAY, &gw, sizeof(gw));
+
+ } else if (address_family == AF_INET6) {
+ struct in6_addr gw;
+
+ pton_fd = inet_pton(AF_INET6, gateway, (struct in6_addr *)&gw);
+ if (pton_fd < 0) {
+ return -1;
+ }
+
+ _nl_header(RTM_DELROUTE, (uint8_t *)buffer, BUFSIZE,
+ NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC);
+ _nl_payload_route(table_id, address_family, 0, (uint8_t *)buffer, BUFSIZE);
+
+ /* gw */
+ addAttr(hdr, BUFSIZE, RTA_GATEWAY, &gw, sizeof(gw));
+
+ } else {
+ return -1;
+ }
+
+ // For more than 255 tables
+ // addAttr(msg, BUFSIZE, RTA_TABLE, &table_id, sizeof(uint32_t));
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+
+ n = send(fd, buffer, hdr->nlmsg_len, 0);
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ return 0;
+ }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ return -1;
+}
+
+/*
+ * ip route del 1:2::2 dev lo table local
+ *
+ */
+int _nl_del_lo_route(const ip_address_t *ip_address) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ struct {
+ struct nlmsghdr hdr;
+ struct rtmsg payload;
+ } msg = {
+ .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_src_len = 0,
+ .payload.rtm_tos = 0,
+ .payload.rtm_table = RT_TABLE_LOCAL,
+ .payload.rtm_protocol = RTPROT_UNSPEC,
+ .payload.rtm_scope = RT_SCOPE_UNIVERSE,
+ .payload.rtm_type = RTN_UNSPEC,
+ .payload.rtm_flags = 0 // RTM_F_NOTIFY in 'ip route get'
+ };
+
+ /* 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_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)},
+ /* Interface id */
+ {&a_ifid_lo, sizeof(a_ifid_lo)},
+ {&one, sizeof(one)}};
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR;
+ }
+
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR;
+ }
+ return 0;
+ }
+
+ return HICN_SOCKET_ERROR_NONE;
+ERR:
+ return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+/*
+ * ip -6 rule add iif INTERFACE_NAME lookup TABLE_ID
+ */
+int _nl_add_rule(const char *interface_name, uint8_t address_family,
+ const uint8_t table_id) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ _nl_header(RTM_NEWRULE, (uint8_t *)buffer, BUFSIZE, FLAGS_CREATE);
+ _nl_payload_rule(table_id, address_family, (uint8_t *)buffer, BUFSIZE);
+
+ /* XXX iif */
+ addAttr(hdr, BUFSIZE, FRA_IIFNAME, (void *)interface_name,
+ strlen(interface_name));
+ // attr1 = addNestedAttr(hdr, IFLA_LINKINFO);
+ // endNestedAttr(hdr, attr1);
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+
+ n = send(fd, buffer, hdr->nlmsg_len, 0);
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ return 0;
+ }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ return -1;
+}
+
+/*
+ * ip -6 rule del iif INTERFACE_NAME //lookup TABLE_ID
+ */
+int _nl_del_rule(const char *interface_name, uint8_t address_family,
+ const uint8_t table_id) {
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ size_t n;
+ int fd;
+
+ _nl_header(RTM_DELRULE, (uint8_t *)buffer, BUFSIZE, FLAGS_CREATE);
+ _nl_payload_rule(table_id, address_family, (uint8_t *)buffer, BUFSIZE);
+
+ /* XXX iif */
+ addAttr(hdr, BUFSIZE, FRA_IIFNAME, (void *)interface_name,
+ strlen(interface_name));
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR_SOCKET;
+ }
+
+ n = send(fd, buffer, hdr->nlmsg_len, 0);
+ if (n == -1) {
+ goto ERR_SEND;
+ }
+
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR_RECV;
+ }
+
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR_NL;
+ }
+ return 0;
+ }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ return -1;
+}
+
+/*
+ * 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,
+ const uint32_t interface_id) {
+ /* Buffer for holding the response, with appropriate casting on the header */
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+
+ /* Used for send and receive operations on netlink socket */
+ int fd;
+ size_t n;
+
+ /* Packet header */
+ struct {
+ struct nlmsghdr hdr;
+ struct ndmsg payload;
+ } msg = {
+ .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_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};
+
+ /* 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)},
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ /* Open netlink socket */
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR;
+ }
+
+ /* Send packet */
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+
+ /* Receive answer */
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR;
+ }
+
+ /* Parse answer */
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR;
+ }
+ }
+
+ return HICN_SOCKET_ERROR_NONE;
+ERR:
+ return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+/* 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,
+ const uint32_t interface_id,
+ const uint8_t table_id) {
+ /* Buffer for holding the response, with appropriate casting on the header */
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+
+ /* Used for send and receive operations on netlink socket */
+ int fd;
+ size_t n;
+
+ /* Packet header */
+ struct {
+ struct nlmsghdr hdr;
+ struct rtmsg payload;
+ } msg = {
+ .hdr.nlmsg_type = RTM_NEWROUTE,
+ .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, // XXX ? XXX dst_len,
+ .payload.rtm_src_len = 0,
+ .payload.rtm_tos = 0,
+ .payload.rtm_table = table_id, /* RT_TABLE_MAIN, etc. */
+ .payload.rtm_protocol = RTPROT_BOOT,
+ .payload.rtm_scope =
+ prefix->family == AF_INET6 ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
+ .payload.rtm_type = RTN_UNICAST,
+ .payload.rtm_flags = 0,
+ };
+
+ /* Message attributes = length/type/value */
+ // XXX This could be put directly inside the iovec maybe ? XXX
+ struct rtattr a_dst = {RTA_LENGTH(ip_address_len(prefix)), RTA_DST};
+ struct rtattr a_oif = {RTA_LENGTH(sizeof(uint32_t)), RTA_OIF};
+
+ /* Iovec describing the packets */
+ struct iovec iov[] = {
+ {&msg, sizeof(msg)},
+ /* Destination prefix / ip address */
+ {&a_dst, sizeof(a_dst)},
+ {(void *)&prefix->buffer, ip_address_len(prefix)},
+ /* Output interface */
+ {&a_oif, sizeof(a_oif)},
+ {(void *)&interface_id, sizeof(uint32_t)},
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ /* Open netlink socket */
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR;
+ }
+
+ /* Send packet */
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+
+ /* Receive answer */
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR;
+ }
+
+ /* Parse answer */
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR;
+ }
+ }
+
+ return HICN_SOCKET_ERROR_NONE;
+ERR:
+ return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+/* Additional helper functions */
+
+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;
+
+ rc = hicn_ip_pton(prefix, &ip_address);
+ if (rc < 0) {
+ return rc;
+ }
+
+ return _nl_add_in_route_table(&ip_address, interface_id, table_id);
+}
+
+int _nl_add_in_route_s(const char *prefix, const uint32_t interface_id) {
+ return _nl_add_in_route_table_s(prefix, interface_id, RT_TABLE_MAIN);
+}
+
+////////* ip -6 rule add from all prio 10 table local */
+/* 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,
+ const uint32_t priority, const uint8_t table_id) {
+ /* Buffer for holding the response, with appropriate casting on the header */
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+
+ /* Used for send and receive operations on netlink socket */
+ int fd;
+ size_t n;
+
+ /* Packet header */
+ struct {
+ struct nlmsghdr hdr;
+ struct fib_rule_hdr payload;
+ } msg = {
+ .hdr.nlmsg_type = RTM_NEWRULE,
+ .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL,
+ .hdr.nlmsg_seq = seq++,
+ .payload.family = address_family,
+ //.payload.dst_len = ,
+ .payload.src_len = ip_address ? ip_address->prefix_len : 0,
+ .payload.tos = 0,
+ .payload.table = table_id,
+ .payload.action = FR_ACT_TO_TBL,
+ .payload.flags = NLM_F_REPLACE, // 0
+ };
+
+ /* Open netlink socket */
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR;
+ }
+
+ if (ip_address) {
+ /* Message attributes = length/type/value */
+ struct rtattr a_src = {RTA_LENGTH(ip_address_len(ip_address)), 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 */
+ {&a_src, sizeof(a_src)},
+ {(void *)&ip_address->buffer, ip_address_len(ip_address)},
+ /* Priority */
+ {&a_prio, sizeof(a_prio)},
+ {(void *)&priority, sizeof(uint32_t)},
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ /* Send packet */
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+ } else {
+ struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY};
+
+ /* Iovec describing the packets */
+ struct iovec iov[] = {
+ {&msg, sizeof(msg)},
+ /* Priority */
+ {&a_prio, sizeof(a_prio)},
+ {(void *)&priority, sizeof(uint32_t)},
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ /* Send packet */
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+ }
+
+ /* Receive answer */
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR;
+ }
+
+ /* Parse answer */
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0) {
+ errno = -err->error;
+ goto ERR;
+ }
+ }
+
+ return HICN_SOCKET_ERROR_NONE;
+ERR:
+ return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+int _nl_add_lo_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+ const uint32_t priority) {
+ return _nl_add_prio_rule(ip_address, 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,
+ const uint32_t priority, const uint8_t table_id) {
+ /* Buffer for holding the response, with appropriate casting on the header */
+ char buffer[BUFSIZE];
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+
+ /* Used for send and receive operations on netlink socket */
+ int fd;
+ size_t n;
+
+ /* Packet header */
+ struct {
+ struct nlmsghdr hdr;
+ struct fib_rule_hdr payload;
+ } msg = {
+ .hdr.nlmsg_type = RTM_DELRULE,
+ .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL,
+ .hdr.nlmsg_seq = seq++,
+ .payload.family = address_family,
+ //.payload.dst_len = ,
+ .payload.src_len = ip_address ? ip_address->prefix_len : 0,
+ .payload.tos = 0,
+ .payload.table = table_id,
+ .payload.action = FR_ACT_TO_TBL,
+ .payload.flags = NLM_F_REPLACE, // 0
+ };
+
+ /* Open netlink socket */
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ goto ERR;
+ }
+
+ /* Message attributes = length/type/value */
+ if (ip_address) {
+ struct rtattr a_src = {RTA_LENGTH(ip_address_len(ip_address)), 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 */
+ {&a_src, sizeof(a_src)},
+ {(void *)&ip_address->buffer, ip_address_len(ip_address)},
+ /* Priority */
+ {&a_prio, sizeof(a_prio)},
+ {(void *)&priority, sizeof(uint32_t)},
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ /* Send packet */
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+
+ } else {
+ struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY};
+
+ /* Iovec describing the packets */
+ struct iovec iov[] = {
+ {&msg, sizeof(msg)},
+ /* Priority */
+ {&a_prio, sizeof(a_prio)},
+ {(void *)&priority, sizeof(uint32_t)},
+ };
+ msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+ /* Send packet */
+ n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+ if (n == -1) {
+ goto ERR;
+ }
+ }
+
+ /* Receive answer */
+ n = recv(fd, buffer, BUFSIZE, 0);
+ if (n == -1) {
+ goto ERR;
+ }
+
+ /* Parse answer */
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+ if (err->error < 0 &&
+ err->error != -2) { //-2 is not such file or directory
+ errno = -err->error;
+ goto ERR;
+ }
+ }
+
+ return HICN_SOCKET_ERROR_NONE;
+ERR:
+ return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+int _nl_del_lo_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+ const uint32_t priority) {
+ return _nl_del_prio_rule(ip_address, address_family, priority,
+ RT_TABLE_LOCAL);
+}
+
+/******************************************************************************/
+
+// #include <net/if.h>
+// duplicate declarations, in the meantime
+#define IF_NAMESIZE 16
+
+//#define WITH_TUN_PI 1
+
+#ifdef WITH_TUN_PI
+#define TUN_FLAGS IFF_TUN
+#else
+#define TUN_FLAGS IFF_TUN | IFF_NO_PI
+#endif
+
+/*
+ * Taken from Kernel Documentation/networking/tuntap.txt
+ */
+
+int tun_alloc(char *dev, int flags) {
+ struct ifreq ifr;
+ int fd, err;
+ char *clonedev = "/dev/net/tun";
+
+ /* Arguments taken by the function:
+ *
+ * char *dev: the name of an interface (or '\0'). MUST have enough
+ * space to hold the interface name if '\0' is passed
+ * int flags: interface flags (eg, IFF_TUN etc.)
+ */
+
+ /* open the clone device */
+ if ((fd = open(clonedev, O_RDWR)) < 0) {
+ return fd;
+ }
+
+ /* preparation of the struct ifr, of type "struct ifreq" */
+ memset(&ifr, 0, sizeof(ifr));
+
+ ifr.ifr_flags = flags;
+
+ if (*dev) {
+ /* if a device name was specified, put it in the structure; otherwise,
+ * the kernel will try to allocate the "next" device of the
+ * specified type */
+ strncpy(ifr.ifr_name, dev, IF_NAMESIZE - 1);
+ }
+
+ /* try to create the device */
+ if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
+ close(fd);
+ return err;
+ }
+
+ /* if the operation was successful, write back the name of the
+ * interface to the variable "dev", so the caller can know
+ * it. Note that the caller MUST reserve space in *dev (see calling
+ * code below) */
+ strcpy(dev, ifr.ifr_name);
+
+ /* this is the special file descriptor that the caller will use to talk
+ * with the virtual interface */
+ return fd;
+}
+
+int linux_get_tun_name(const char *prefix, const char *identifier,
+ char *tun_name) {
+ snprintf(tun_name, IF_NAMESIZE, "%s-%s", prefix,
+ identifier ? identifier : "main");
+ return 0;
+}
+
+int linux_tun_enable_offload(int fd) {
+ unsigned int offload = 0, tso4 = 1, tso6 = 1, ecn = 1, ufo = 1, csum = 1;
+
+ /* Check if our kernel supports TUNSETOFFLOAD */
+ if (ioctl(fd, TUNSETOFFLOAD, 0) != 0 && errno == EINVAL) {
+ goto ERR_TUN;
+ }
+
+ if (csum) {
+ offload |= TUN_F_CSUM;
+ if (tso4) offload |= TUN_F_TSO4;
+ if (tso6) offload |= TUN_F_TSO6;
+ if ((tso4 || tso6) && ecn) offload |= TUN_F_TSO_ECN;
+ if (ufo) offload |= TUN_F_UFO;
+ }
+
+ if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
+ offload &= ~TUN_F_UFO;
+ if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
+ fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n", strerror(errno));
+ }
+ }
+
+ return 0;
+
+ERR_TUN:
+ return -1;
+}
+
+int linux_tun_create(char *name) {
+ int fd, rc;
+
+ fd = tun_alloc(name, TUN_FLAGS);
+ if (fd < 0) {
+ // ERROR("Error connecting to tun/tap interface %s!", name);
+ errno = -2;
+ goto ERR_TUN;
+ }
+
+ rc = linux_tun_enable_offload(fd);
+ if (rc < 0) {
+ // WARN("Could not enable hardware offload on TUN device");
+ } else {
+ // INFO("Enabled hardware offload on TUN device");
+ }
+
+ return fd;
+
+ERR_TUN:
+ return -1;
+}
+
+/*
+ *
+ * interface name can be NULL for all interfaces
+ */
+int linux_enable_proc(char *path) {
+ int ret = 0;
+ int fd;
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ if (write(fd, "1", 1) != 1) {
+ ret = -2;
+ }
+
+ close(fd);
+ return ret;
+}
+
+int linux_enable_v4_forwarding() {
+ return linux_enable_proc("/proc/sys/net/ipv4/ip_forward");
+}
+
+int linux_enable_v6_forwarding(char *interface_name) {
+ char path[PATH_MAX];
+ snprintf(path, PATH_MAX, "/proc/sys/net/ipv6/conf/%s/forwarding",
+ (interface_name) ? interface_name : "all");
+
+ return linux_enable_proc(path);
+}
+
+int linux_enable_ndp_proxy() {
+ return linux_enable_proc("/proc/sys/net/ipv6/conf/all/proxy_ndp");
+}
+
+const hicn_socket_ops_t ops = {
+ .arch = "linux",
+ .get_tun_name = linux_get_tun_name,
+ .tun_create = linux_tun_create,
+ .enable_v4_forwarding = linux_enable_v4_forwarding,
+ .enable_v6_forwarding = linux_enable_v6_forwarding,
+ .enable_ndp_proxy = linux_enable_ndp_proxy,
+ .get_ifid = _nl_get_ifid,
+ .get_output_ifid = _nl_get_output_ifid,
+ .get_ip_addr = _nl_get_ip_addr,
+ .set_ip_addr = _nl_set_ip_addr,
+ .up_if = _nl_up_if,
+ .add_in_route_table = _nl_add_in_route_table,
+ .add_in_route_table_s = _nl_add_in_route_table_s,
+ .add_in_route_s = _nl_add_in_route_s,
+ .add_out_route = _nl_add_out_route,
+ .del_out_route = _nl_del_out_route,
+ .del_lo_route = _nl_del_lo_route,
+ .add_rule = _nl_add_rule,
+ .del_rule = _nl_del_rule,
+ .add_neigh_proxy = _nl_add_neigh_proxy,
+ .add_prio_rule = _nl_add_prio_rule,
+ .add_lo_prio_rule = _nl_add_lo_prio_rule,
+ .del_prio_rule = _nl_del_prio_rule,
+ .del_lo_prio_rule = _nl_del_lo_prio_rule,
+};
diff --git a/hicn-light/src/strategies/CMakeLists.txt b/hicn-light/src/strategies/CMakeLists.txt
new file mode 100755
index 000000000..7f0730b2f
--- /dev/null
+++ b/hicn-light/src/strategies/CMakeLists.txt
@@ -0,0 +1,36 @@
+# 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/strategyImpl.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancerWithPD.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/nexthopState.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/nexthopStateWithPD.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rnd.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rndSegment.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancer.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancerWithPD.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/nexthopState.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/nexthopStateWithPD.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/rnd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/rndSegment.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/hicn-light/src/strategies/loadBalancer.c b/hicn-light/src/strategies/loadBalancer.c
new file mode 100755
index 000000000..14e907770
--- /dev/null
+++ b/hicn-light/src/strategies/loadBalancer.c
@@ -0,0 +1,278 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Unsigned.h>
+
+#include <src/strategies/loadBalancer.h>
+#include <src/strategies/nexthopState.h>
+
+static void _strategyLoadBalancer_ReceiveObject(StrategyImpl *strategy,
+ const NumberSet *egressId,
+ const Message *objectMessage,
+ Ticks rtt);
+static void _strategyLoadBalancer_OnTimeout(StrategyImpl *strategy,
+ const NumberSet *egressId);
+static NumberSet *_strategyLoadBalancer_LookupNexthop(
+ StrategyImpl *strategy, const Message *interestMessage);
+static NumberSet *_strategyLoadBalancer_ReturnNexthops(StrategyImpl *strategy);
+static unsigned _strategyLoadBalancer_CountNexthops(StrategyImpl *strategy);
+static void _strategyLoadBalancer_AddNexthop(StrategyImpl *strategy,
+ unsigned connectionId);
+static void _strategyLoadBalancer_RemoveNexthop(StrategyImpl *strategy,
+ unsigned connectionId);
+static void _strategyLoadBalancer_ImplDestroy(StrategyImpl **strategyPtr);
+static strategy_type _strategyLoadBalancer_GetStrategy(StrategyImpl *strategy);
+
+static StrategyImpl _template = {
+ .context = NULL,
+ .receiveObject = &_strategyLoadBalancer_ReceiveObject,
+ .onTimeout = &_strategyLoadBalancer_OnTimeout,
+ .lookupNexthop = &_strategyLoadBalancer_LookupNexthop,
+ .returnNexthops = &_strategyLoadBalancer_ReturnNexthops,
+ .countNexthops = &_strategyLoadBalancer_CountNexthops,
+ .addNexthop = &_strategyLoadBalancer_AddNexthop,
+ .removeNexthop = &_strategyLoadBalancer_RemoveNexthop,
+ .destroy = &_strategyLoadBalancer_ImplDestroy,
+ .getStrategy = &_strategyLoadBalancer_GetStrategy,
+};
+
+struct strategy_load_balancer;
+typedef struct strategy_load_balancer StrategyLoadBalancer;
+
+struct strategy_load_balancer {
+ double weights_sum;
+ // hash map from connectionId to StrategyNexthopState
+ PARCHashMap *strategy_state;
+ NumberSet *nexthops;
+};
+
+StrategyImpl *strategyLoadBalancer_Create() {
+ StrategyLoadBalancer *strategy =
+ parcMemory_AllocateAndClear(sizeof(StrategyLoadBalancer));
+ parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(StrategyLoadBalancer));
+
+ strategy->weights_sum = 0.0;
+ strategy->strategy_state = parcHashMap_Create();
+ strategy->nexthops = numberSet_Create();
+ srand(time(NULL));
+
+ StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl));
+ parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(StrategyImpl));
+ memcpy(impl, &_template, sizeof(StrategyImpl));
+ impl->context = strategy;
+
+ return impl;
+}
+
+// =======================================================
+// Dispatch API
+
+strategy_type _strategyLoadBalancer_GetStrategy(StrategyImpl *strategy) {
+ return SET_STRATEGY_LOADBALANCER;
+}
+
+static void _update_Stats(StrategyLoadBalancer *strategy,
+ StrategyNexthopState *state, bool inc) {
+ const double ALPHA = 0.9;
+ double w = strategyNexthopState_GetWeight(state);
+ strategy->weights_sum -= w;
+ w = strategyNexthopState_UpdateState(state, inc, ALPHA);
+ strategy->weights_sum += w;
+}
+
+static unsigned _select_Nexthop(StrategyLoadBalancer *strategy) {
+ double rnd = (double)rand() / (double)RAND_MAX;
+ double start_range = 0.0;
+
+ PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state);
+
+ unsigned nexthop = 100000;
+ while (parcIterator_HasNext(it)) {
+ PARCUnsigned *cid = parcIterator_Next(it);
+ const StrategyNexthopState *elem =
+ parcHashMap_Get(strategy->strategy_state, cid);
+
+ double w = strategyNexthopState_GetWeight(elem);
+
+ double prob = w / strategy->weights_sum;
+ if ((rnd >= start_range) && (rnd < (start_range + prob))) {
+ nexthop = parcUnsigned_GetUnsigned(cid);
+ break;
+ } else {
+ start_range += prob;
+ }
+ }
+
+ parcIterator_Release(&it);
+
+ // if no face is selected by the algorithm (for example because of a wrong
+ // round in the weights) we may always select the last face here. Double check
+ // this!
+ return nexthop;
+}
+
+static void _strategyLoadBalancer_ReceiveObject(StrategyImpl *strategy,
+ const NumberSet *egressId,
+ const Message *objectMessage,
+ Ticks rtt) {
+ _strategyLoadBalancer_OnTimeout(strategy, egressId);
+}
+
+static void _strategyLoadBalancer_OnTimeout(StrategyImpl *strategy,
+ const NumberSet *egressId) {
+ StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+
+ for (unsigned i = 0; i < numberSet_Length(egressId); i++) {
+ unsigned outId = numberSet_GetItem(egressId, i);
+ PARCUnsigned *cid = parcUnsigned_Create(outId);
+
+ const StrategyNexthopState *state =
+ parcHashMap_Get(lb->strategy_state, cid);
+ if (state != NULL) {
+ _update_Stats(lb, (StrategyNexthopState *)state, false);
+ } else {
+ // this may happen if we remove a face/route while downloading a file
+ // we should ignore this timeout
+ }
+ parcUnsigned_Release(&cid);
+ }
+}
+
+static NumberSet *_strategyLoadBalancer_LookupNexthop(
+ StrategyImpl *strategy, const Message *interestMessage) {
+ StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+
+ unsigned in_connection = message_GetIngressConnectionId(interestMessage);
+ PARCUnsigned *in = parcUnsigned_Create(in_connection);
+
+ unsigned mapSize = parcHashMap_Size(lb->strategy_state);
+ NumberSet *outList = numberSet_Create();
+
+ if ((mapSize == 0) ||
+ ((mapSize == 1) && parcHashMap_Contains(lb->strategy_state, in))) {
+ // there are no output faces or the input face is also the only output face.
+ // return null to avoid loops
+ parcUnsigned_Release(&in);
+ return outList;
+ }
+
+ unsigned out_connection;
+ do {
+ out_connection = _select_Nexthop(lb);
+ } while (out_connection == in_connection);
+
+ PARCUnsigned *out = parcUnsigned_Create(out_connection);
+
+ const StrategyNexthopState *state = parcHashMap_Get(lb->strategy_state, out);
+ if (state == NULL) {
+ // this is an error and should not happen!
+ parcTrapNotImplemented(
+ "Try to send an interest on a face that does not exists");
+ }
+
+ _update_Stats(lb, (StrategyNexthopState *)state, true);
+
+ parcUnsigned_Release(&in);
+ parcUnsigned_Release(&out);
+
+ numberSet_Add(outList, out_connection);
+ return outList;
+}
+
+static NumberSet *_strategyLoadBalancer_ReturnNexthops(StrategyImpl *strategy) {
+ StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+ return lb->nexthops;
+}
+
+unsigned _strategyLoadBalancer_CountNexthops(StrategyImpl *strategy) {
+ StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+ return numberSet_Length(lb->nexthops);
+}
+
+static void _strategyLoadBalancer_resetState(StrategyImpl *strategy) {
+ StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+ lb->weights_sum = 0.0;
+ PARCIterator *it = parcHashMap_CreateKeyIterator(lb->strategy_state);
+
+ while (parcIterator_HasNext(it)) {
+ PARCUnsigned *cid = parcIterator_Next(it);
+ StrategyNexthopState *elem =
+ (StrategyNexthopState *)parcHashMap_Get(lb->strategy_state, cid);
+
+ strategyNexthopState_Reset(elem);
+ lb->weights_sum += strategyNexthopState_GetWeight(elem);
+ }
+
+ parcIterator_Release(&it);
+}
+
+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)) {
+ parcHashMap_Put(lb->strategy_state, cid, state);
+ numberSet_Add(lb->nexthops, connectionId);
+ _strategyLoadBalancer_resetState(strategy);
+ }
+}
+
+static void _strategyLoadBalancer_RemoveNexthop(StrategyImpl *strategy,
+ unsigned connectionId) {
+ StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+
+ PARCUnsigned *cid = parcUnsigned_Create(connectionId);
+
+ if (parcHashMap_Contains(lb->strategy_state, cid)) {
+ parcHashMap_Remove(lb->strategy_state, cid);
+ numberSet_Remove(lb->nexthops, connectionId);
+ _strategyLoadBalancer_resetState(strategy);
+ }
+
+ parcUnsigned_Release(&cid);
+}
+
+static void _strategyLoadBalancer_ImplDestroy(StrategyImpl **strategyPtr) {
+ parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*strategyPtr,
+ "Parameter must dereference to non-null pointer");
+
+ StrategyImpl *impl = *strategyPtr;
+ StrategyLoadBalancer *strategy = (StrategyLoadBalancer *)impl->context;
+
+ parcHashMap_Release(&(strategy->strategy_state));
+ numberSet_Release(&(strategy->nexthops));
+
+ parcMemory_Deallocate((void **)&strategy);
+ parcMemory_Deallocate((void **)&impl);
+ *strategyPtr = NULL;
+}
diff --git a/hicn-light/src/strategies/loadBalancer.h b/hicn-light/src/strategies/loadBalancer.h
new file mode 100755
index 000000000..1178c30fe
--- /dev/null
+++ b/hicn-light/src/strategies/loadBalancer.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Forward on the less loaded path
+ */
+
+#ifndef loadBalancer_h
+#define loadBalancer_h
+
+#include <src/strategies/strategyImpl.h>
+
+StrategyImpl *strategyLoadBalancer_Create();
+#endif // loadBalancer_h
diff --git a/hicn-light/src/strategies/loadBalancerWithPD.c b/hicn-light/src/strategies/loadBalancerWithPD.c
new file mode 100755
index 000000000..1aad8fd89
--- /dev/null
+++ b/hicn-light/src/strategies/loadBalancerWithPD.c
@@ -0,0 +1,368 @@
+/*
+ * 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 <limits.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Unsigned.h>
+
+#include <src/strategies/loadBalancerWithPD.h>
+#include <src/strategies/nexthopStateWithPD.h>
+
+const unsigned PROBE_FREQUENCY = 1024;
+
+static void _strategyLoadBalancerWithPD_ReceiveObject(
+ StrategyImpl *strategy, const NumberSet *egressId,
+ const Message *objectMessage, Ticks rtt);
+static void _strategyLoadBalancerWithPD_OnTimeout(StrategyImpl *strategy,
+ const NumberSet *egressId);
+static NumberSet *_strategyLoadBalancerWithPD_LookupNexthop(
+ StrategyImpl *strategy, const Message *interestMessage);
+static NumberSet *_strategyLoadBalancerWithPD_ReturnNexthops(
+ StrategyImpl *strategy);
+static unsigned _strategyLoadBalancerWithPD_CountNexthops(
+ StrategyImpl *strategy);
+static void _strategyLoadBalancerWithPD_AddNexthop(StrategyImpl *strategy,
+ unsigned connectionId);
+static void _strategyLoadBalancerWithPD_RemoveNexthop(StrategyImpl *strategy,
+ unsigned connectionId);
+static void _strategyLoadBalancerWithPD_ImplDestroy(StrategyImpl **strategyPtr);
+static strategy_type _strategyLoadBalancerWithPD_GetStrategy(
+ StrategyImpl *strategy);
+
+static StrategyImpl _template = {
+ .context = NULL,
+ .receiveObject = &_strategyLoadBalancerWithPD_ReceiveObject,
+ .onTimeout = &_strategyLoadBalancerWithPD_OnTimeout,
+ .lookupNexthop = &_strategyLoadBalancerWithPD_LookupNexthop,
+ .returnNexthops = &_strategyLoadBalancerWithPD_ReturnNexthops,
+ .countNexthops = &_strategyLoadBalancerWithPD_CountNexthops,
+ .addNexthop = &_strategyLoadBalancerWithPD_AddNexthop,
+ .removeNexthop = &_strategyLoadBalancerWithPD_RemoveNexthop,
+ .destroy = &_strategyLoadBalancerWithPD_ImplDestroy,
+ .getStrategy = &_strategyLoadBalancerWithPD_GetStrategy,
+};
+
+struct strategy_load_balancer_with_pd;
+typedef struct strategy_load_balancer_with_pd StrategyLoadBalancerWithPD;
+
+struct strategy_load_balancer_with_pd {
+ double weights_sum;
+ unsigned min_delay;
+ // hash map from connectionId to StrategyNexthopState
+ PARCHashMap *strategy_state;
+ NumberSet *nexthops;
+ ConnectionTable *connTable;
+ bool toInit;
+ unsigned int fwdPackets;
+};
+
+StrategyImpl *strategyLoadBalancerWithPD_Create() {
+ StrategyLoadBalancerWithPD *strategy =
+ parcMemory_AllocateAndClear(sizeof(StrategyLoadBalancerWithPD));
+ parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(StrategyLoadBalancerWithPD));
+
+ strategy->weights_sum = 0.0;
+ strategy->min_delay = INT_MAX;
+ strategy->strategy_state = parcHashMap_Create();
+ strategy->nexthops = numberSet_Create();
+ srand(time(NULL));
+
+ StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl));
+ parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(StrategyImpl));
+ memcpy(impl, &_template, sizeof(StrategyImpl));
+ impl->context = strategy;
+ strategy->connTable = NULL;
+ strategy->fwdPackets = 0;
+ strategy->toInit = true;
+
+ return impl;
+}
+
+void strategyLoadBalancerWithPD_SetConnectionTable(StrategyImpl *strategy,
+ ConnectionTable *connTable) {
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+ lb->connTable = connTable;
+}
+
+// =======================================================
+// Dispatch API
+
+strategy_type _strategyLoadBalancerWithPD_GetStrategy(StrategyImpl *strategy) {
+ return SET_STRATEGY_LOADBALANCER_WITH_DELAY;
+}
+
+static void _update_Stats(StrategyLoadBalancerWithPD *strategy,
+ StrategyNexthopStateWithPD *state, bool inc,
+ Ticks rtt) {
+ const double ALPHA = 0.9;
+ double w = strategyNexthopStateWithPD_GetWeight(state);
+ strategy->weights_sum -= w;
+ w = strategyNexthopStateWithPD_UpdateState(state, inc, strategy->min_delay,
+ ALPHA);
+ strategy->weights_sum += w;
+}
+
+static void _sendProbes(StrategyLoadBalancerWithPD *strategy) {
+ unsigned size = numberSet_Length(strategy->nexthops);
+ for (unsigned i = 0; i < size; i++) {
+ unsigned nhop = numberSet_GetItem(strategy->nexthops, i);
+ Connection *conn =
+ (Connection *)connectionTable_FindById(strategy->connTable, nhop);
+ if (conn != NULL) {
+ connection_Probe(conn);
+ unsigned delay = connection_GetDelay(conn);
+ PARCUnsigned *cid = parcUnsigned_Create(nhop);
+ StrategyNexthopStateWithPD *elem =
+ (StrategyNexthopStateWithPD *)parcHashMap_Get(
+ strategy->strategy_state, cid);
+ strategyNexthopStateWithPD_SetDelay(elem, delay);
+ if (delay < strategy->min_delay && delay != 0) {
+ strategy->min_delay = delay;
+ }
+
+ parcUnsigned_Release(&cid);
+ }
+ }
+}
+
+static unsigned _select_Nexthop(StrategyLoadBalancerWithPD *strategy) {
+ strategy->fwdPackets++;
+ if (strategy->toInit || strategy->fwdPackets == PROBE_FREQUENCY) {
+ strategy->toInit = false;
+ strategy->fwdPackets = 0;
+ _sendProbes(strategy);
+ }
+ double rnd = (double)rand() / (double)RAND_MAX;
+ double start_range = 0.0;
+
+ PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state);
+
+ unsigned nexthop = 100000;
+ while (parcIterator_HasNext(it)) {
+ PARCUnsigned *cid = parcIterator_Next(it);
+ const StrategyNexthopStateWithPD *elem =
+ parcHashMap_Get(strategy->strategy_state, cid);
+
+ double w = strategyNexthopStateWithPD_GetWeight(elem);
+
+ // printf("next = %u .. pi %u avgpi %f w %f avgrtt
+ // %f\n",parcUnsigned_GetUnsigned(cid),
+ // strategyNexthopStateWithPD_GetPI(elem),
+ // strategyNexthopStateWithPD_GetWeight(elem),
+ // strategyNexthopStateWithPD_GetWeight(elem),
+ // strategyNexthopStateWithPD_GetAvgRTT(elem));
+
+ double prob = w / strategy->weights_sum;
+ if ((rnd >= start_range) && (rnd < (start_range + prob))) {
+ nexthop = parcUnsigned_GetUnsigned(cid);
+ break;
+ } else {
+ start_range += prob;
+ }
+ }
+
+ parcIterator_Release(&it);
+
+ // if no face is selected by the algorithm (for example because of a wrong
+ // round in the weights) we may always select the last face here. Double check
+ // this!
+ return nexthop;
+}
+
+static void _strategyLoadBalancerWithPD_ReceiveObject(
+ StrategyImpl *strategy, const NumberSet *egressId,
+ const Message *objectMessage, Ticks rtt) {
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+
+ for (unsigned i = 0; i < numberSet_Length(egressId); i++) {
+ unsigned outId = numberSet_GetItem(egressId, i);
+ PARCUnsigned *cid = parcUnsigned_Create(outId);
+
+ const StrategyNexthopStateWithPD *state =
+ parcHashMap_Get(lb->strategy_state, cid);
+ if (state != NULL) {
+ _update_Stats(lb, (StrategyNexthopStateWithPD *)state, false, 0);
+ } else {
+ // this may happen if we remove a face/route while downloading a file
+ // we should ignore this timeout
+ }
+ parcUnsigned_Release(&cid);
+ }
+}
+
+static void _strategyLoadBalancerWithPD_OnTimeout(StrategyImpl *strategy,
+ const NumberSet *egressId) {
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+
+ for (unsigned i = 0; i < numberSet_Length(egressId); i++) {
+ unsigned outId = numberSet_GetItem(egressId, i);
+ PARCUnsigned *cid = parcUnsigned_Create(outId);
+
+ const StrategyNexthopStateWithPD *state =
+ parcHashMap_Get(lb->strategy_state, cid);
+ if (state != NULL) {
+ _update_Stats(lb, (StrategyNexthopStateWithPD *)state, false, 0);
+ } else {
+ // this may happen if we remove a face/route while downloading a file
+ // we should ignore this timeout
+ }
+ parcUnsigned_Release(&cid);
+ }
+}
+
+// ATTENTION!! This interface force us to create a NumberSet which need to be
+// delited somewhere The specification in the interface requires that this
+// function never returns NULL. in case we have no output face we need to return
+// an empty NumberSet
+static NumberSet *_strategyLoadBalancerWithPD_LookupNexthop(
+ StrategyImpl *strategy, const Message *interestMessage) {
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+
+ unsigned in_connection = message_GetIngressConnectionId(interestMessage);
+ PARCUnsigned *in = parcUnsigned_Create(in_connection);
+
+ unsigned mapSize = parcHashMap_Size(lb->strategy_state);
+ NumberSet *outList = numberSet_Create();
+
+ if ((mapSize == 0) ||
+ ((mapSize == 1) && parcHashMap_Contains(lb->strategy_state, in))) {
+ // there are no output faces or the input face is also the only output face.
+ // return null to avoid loops
+ parcUnsigned_Release(&in);
+ return outList;
+ }
+
+ unsigned out_connection;
+ do {
+ out_connection = _select_Nexthop(lb);
+ } while (out_connection == in_connection);
+
+ PARCUnsigned *out = parcUnsigned_Create(out_connection);
+
+ const StrategyNexthopStateWithPD *state =
+ parcHashMap_Get(lb->strategy_state, out);
+ if (state == NULL) {
+ // this is an error and should not happen!
+ parcTrapNotImplemented(
+ "Try to send an interest on a face that does not exists");
+ }
+
+ _update_Stats(lb, (StrategyNexthopStateWithPD *)state, true, 0);
+
+ parcUnsigned_Release(&in);
+ parcUnsigned_Release(&out);
+
+ numberSet_Add(outList, out_connection);
+ return outList;
+}
+
+static NumberSet *_strategyLoadBalancerWithPD_ReturnNexthops(
+ StrategyImpl *strategy) {
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+ return lb->nexthops;
+}
+
+unsigned _strategyLoadBalancerWithPD_CountNexthops(StrategyImpl *strategy) {
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+ return numberSet_Length(lb->nexthops);
+}
+
+static void _strategyLoadBalancerWithPD_resetState(StrategyImpl *strategy) {
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+ lb->weights_sum = 0.0;
+ lb->min_delay = INT_MAX;
+ lb->toInit = true;
+ PARCIterator *it = parcHashMap_CreateKeyIterator(lb->strategy_state);
+
+ while (parcIterator_HasNext(it)) {
+ PARCUnsigned *cid = parcIterator_Next(it);
+ StrategyNexthopStateWithPD *elem =
+ (StrategyNexthopStateWithPD *)parcHashMap_Get(lb->strategy_state, cid);
+
+ strategyNexthopStateWithPD_Reset(elem);
+ lb->weights_sum += strategyNexthopStateWithPD_GetWeight(elem);
+ }
+
+ parcIterator_Release(&it);
+}
+
+static void _strategyLoadBalancerWithPD_AddNexthop(StrategyImpl *strategy,
+ unsigned connectionId) {
+ StrategyNexthopStateWithPD *state = strategyNexthopStateWithPD_Create();
+
+ PARCUnsigned *cid = parcUnsigned_Create(connectionId);
+
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+
+ if (!parcHashMap_Contains(lb->strategy_state, cid)) {
+ parcHashMap_Put(lb->strategy_state, cid, state);
+ numberSet_Add(lb->nexthops, connectionId);
+ _strategyLoadBalancerWithPD_resetState(strategy);
+ }
+}
+
+static void _strategyLoadBalancerWithPD_RemoveNexthop(StrategyImpl *strategy,
+ unsigned connectionId) {
+ StrategyLoadBalancerWithPD *lb =
+ (StrategyLoadBalancerWithPD *)strategy->context;
+
+ PARCUnsigned *cid = parcUnsigned_Create(connectionId);
+
+ if (parcHashMap_Contains(lb->strategy_state, cid)) {
+ parcHashMap_Remove(lb->strategy_state, cid);
+ numberSet_Remove(lb->nexthops, connectionId);
+ _strategyLoadBalancerWithPD_resetState(strategy);
+ }
+
+ parcUnsigned_Release(&cid);
+}
+
+static void _strategyLoadBalancerWithPD_ImplDestroy(
+ StrategyImpl **strategyPtr) {
+ parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*strategyPtr,
+ "Parameter must dereference to non-null pointer");
+
+ StrategyImpl *impl = *strategyPtr;
+ StrategyLoadBalancerWithPD *strategy =
+ (StrategyLoadBalancerWithPD *)impl->context;
+
+ parcHashMap_Release(&(strategy->strategy_state));
+ numberSet_Release(&(strategy->nexthops));
+
+ parcMemory_Deallocate((void **)&strategy);
+ parcMemory_Deallocate((void **)&impl);
+ *strategyPtr = NULL;
+}
diff --git a/hicn-light/src/strategies/loadBalancerWithPD.h b/hicn-light/src/strategies/loadBalancerWithPD.h
new file mode 100755
index 000000000..6ea7f0785
--- /dev/null
+++ b/hicn-light/src/strategies/loadBalancerWithPD.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * Forward on the less loaded path taking into account the propagation delay of
+ * the first hop
+ */
+
+#ifndef loadBalancerWithPD_h
+#define loadBalancerWithPD_h
+
+#include <src/core/connectionTable.h>
+#include <src/strategies/strategyImpl.h>
+
+StrategyImpl *strategyLoadBalancerWithPD_Create();
+void strategyLoadBalancerWithPD_SetConnectionTable(StrategyImpl *strategy,
+ ConnectionTable *connTable);
+#endif // loadBalancerWithPD_h
diff --git a/hicn-light/src/strategies/nexthopState.c b/hicn-light/src/strategies/nexthopState.c
new file mode 100755
index 000000000..ef0ffe982
--- /dev/null
+++ b/hicn-light/src/strategies/nexthopState.c
@@ -0,0 +1,206 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/strategies/nexthopState.h>
+
+struct strategy_nexthop_state {
+ unsigned int pi;
+ double avg_pi;
+ double weight;
+};
+
+static bool _strategyNexthopState_Destructor(
+ StrategyNexthopState **instancePtr) {
+ return true;
+}
+
+parcObject_ImplementAcquire(strategyNexthopState, StrategyNexthopState);
+
+parcObject_ImplementRelease(strategyNexthopState, StrategyNexthopState);
+
+parcObject_Override(
+ StrategyNexthopState, PARCObject,
+ .destructor = (PARCObjectDestructor *)_strategyNexthopState_Destructor,
+ .copy = (PARCObjectCopy *)strategyNexthopState_Copy,
+ .display = (PARCObjectDisplay *)strategyNexthopState_Display,
+ .toString = (PARCObjectToString *)strategyNexthopState_ToString,
+ .equals = (PARCObjectEquals *)strategyNexthopState_Equals,
+ .compare = (PARCObjectCompare *)strategyNexthopState_Compare,
+ .hashCode = (PARCObjectHashCode *)strategyNexthopState_HashCode,
+ .display = (PARCObjectDisplay *)strategyNexthopState_Display);
+
+void strategyNexthopState_AssertValid(const StrategyNexthopState *instance) {
+ parcAssertTrue(strategyNexthopState_IsValid(instance),
+ "StrategyNexthopState is not valid.");
+}
+
+StrategyNexthopState *strategyNexthopState_Create() {
+ StrategyNexthopState *result =
+ parcObject_CreateInstance(StrategyNexthopState);
+ if (result != NULL) {
+ result->pi = 0;
+ result->avg_pi = 0.0;
+ result->weight = 1;
+ }
+ return result;
+}
+
+void strategyNexthopState_Reset(StrategyNexthopState *x) {
+ x->pi = 0;
+ x->avg_pi = 0.0;
+ x->weight = 1;
+}
+
+int strategyNexthopState_Compare(const StrategyNexthopState *val,
+ const StrategyNexthopState *other) {
+ if (val == NULL) {
+ if (other != NULL) {
+ return -1;
+ }
+ } else if (other == NULL) {
+ return 1;
+ } else {
+ strategyNexthopState_OptionalAssertValid(val);
+ strategyNexthopState_OptionalAssertValid(other);
+
+ if (val->pi < other->pi) {
+ return -1;
+ } else if (val->pi > other->pi) {
+ return 1;
+ }
+
+ if (val->avg_pi < other->avg_pi) {
+ return -1;
+ } else if (val->avg_pi > other->avg_pi) {
+ return 1;
+ }
+
+ if (val->weight < other->weight) {
+ return -1;
+ } else if (val->weight > other->weight) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+StrategyNexthopState *strategyNexthopState_Copy(
+ const StrategyNexthopState *original) {
+ StrategyNexthopState *result = strategyNexthopState_Create();
+ result->pi = original->pi;
+ result->avg_pi = original->avg_pi;
+ result->weight = original->weight;
+
+ return result;
+}
+
+void strategyNexthopState_Display(const StrategyNexthopState *instance,
+ int indentation) {
+ parcDisplayIndented_PrintLine(indentation, "StrategyNexthopState@%p {",
+ instance);
+ parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->pi);
+ parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_pi);
+ parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->weight);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool strategyNexthopState_Equals(const StrategyNexthopState *x,
+ const StrategyNexthopState *y) {
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ strategyNexthopState_OptionalAssertValid(x);
+ strategyNexthopState_OptionalAssertValid(y);
+
+ if (strategyNexthopState_Compare(x, y) == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode strategyNexthopState_HashCode(const StrategyNexthopState *x) {
+ PARCHashCode result = 0;
+ char str[128];
+ sprintf(str, "PI:%d: AVG_PI:%f: W:%f", x->pi, x->avg_pi, x->weight);
+ result = parcHashCode_Hash((uint8_t *)&str, strlen(str));
+ return result;
+}
+
+bool strategyNexthopState_IsValid(const StrategyNexthopState *x) {
+ bool result = false;
+
+ if (x != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+char *strategyNexthopState_ToString(const StrategyNexthopState *x) {
+ // this is not implemented
+ parcTrapNotImplemented("strategyNexthopState_ToString is not implemented");
+ return NULL;
+}
+
+unsigned strategyNexthopState_GetPI(const StrategyNexthopState *x) {
+ strategyNexthopState_OptionalAssertValid(x);
+
+ return x->pi;
+}
+
+double strategyNexthopState_GetAvgPI(const StrategyNexthopState *x) {
+ strategyNexthopState_OptionalAssertValid(x);
+
+ return x->avg_pi;
+}
+
+double strategyNexthopState_GetWeight(const StrategyNexthopState *x) {
+ strategyNexthopState_OptionalAssertValid(x);
+
+ return x->weight;
+}
+
+double strategyNexthopState_UpdateState(StrategyNexthopState *x, bool inc,
+ double alpha) {
+ if (inc) {
+ x->pi++;
+ } else {
+ if (x->pi > 0) {
+ x->pi--;
+ }
+ }
+ x->avg_pi = (x->avg_pi * alpha) + (x->pi * (1 - alpha));
+ if (x->avg_pi == 0.0) {
+ x->avg_pi = 0.1;
+ }
+ x->weight = 1 / x->avg_pi;
+
+ return x->weight;
+}
diff --git a/hicn-light/src/strategies/nexthopState.h b/hicn-light/src/strategies/nexthopState.h
new file mode 100755
index 000000000..35a9f497b
--- /dev/null
+++ b/hicn-light/src/strategies/nexthopState.h
@@ -0,0 +1,94 @@
+/*
+ * 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 nexthopstate_h
+#define nexthopstate_h
+
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Object.h>
+
+struct strategy_nexthop_state;
+typedef struct strategy_nexthop_state StrategyNexthopState;
+extern parcObjectDescriptor_Declaration(StrategyNexthopState);
+
+/**
+ */
+StrategyNexthopState *strategyNexthopState_Acquire(
+ const StrategyNexthopState *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+#define strategyNexthopState_OptionalAssertValid(_instance_)
+#else
+#define strategyNexthopState_OptionalAssertValid(_instance_) \
+ strategyNexthopState_AssertValid(_instance_)
+#endif
+
+/**
+ */
+void strategyNexthopState_AssertValid(const StrategyNexthopState *instance);
+
+/**
+ */
+StrategyNexthopState *strategyNexthopState_Create();
+
+void strategyNexthopState_Reset(StrategyNexthopState *x);
+/**
+ */
+int strategyNexthopState_Compare(const StrategyNexthopState *instance,
+ const StrategyNexthopState *other);
+
+/**
+ */
+StrategyNexthopState *strategyNexthopState_Copy(
+ const StrategyNexthopState *original);
+
+/**
+ */
+void strategyNexthopState_Display(const StrategyNexthopState *instance,
+ int indentation);
+
+/**
+ */
+bool strategyNexthopState_Equals(const StrategyNexthopState *x,
+ const StrategyNexthopState *y);
+
+/**
+ */
+PARCHashCode strategyNexthopState_HashCode(
+ const StrategyNexthopState *instance);
+
+/**
+ */
+bool strategyNexthopState_IsValid(const StrategyNexthopState *instance);
+
+/**
+ */
+void strategyNexthopState_Release(StrategyNexthopState **instancePtr);
+
+/**
+ */
+char *strategyNexthopState_ToString(const StrategyNexthopState *instance);
+
+/**
+ */
+unsigned strategyNexthopState_GetPI(const StrategyNexthopState *x);
+
+double strategyNexthopState_GetAvgPI(const StrategyNexthopState *x);
+
+double strategyNexthopState_GetWeight(const StrategyNexthopState *x);
+
+double strategyNexthopState_UpdateState(StrategyNexthopState *x, bool inc,
+ double alpha);
+#endif
diff --git a/hicn-light/src/strategies/nexthopStateWithPD.c b/hicn-light/src/strategies/nexthopStateWithPD.c
new file mode 100755
index 000000000..2eecb0c64
--- /dev/null
+++ b/hicn-light/src/strategies/nexthopStateWithPD.c
@@ -0,0 +1,254 @@
+/*
+ * 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 <float.h>
+#include <limits.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/strategies/nexthopStateWithPD.h>
+
+struct strategy_nexthop_state_with_pd {
+ unsigned int pi;
+ unsigned delay;
+ double weight;
+ double avg_pi;
+};
+
+static bool _strategyNexthopStateWithPD_Destructor(
+ StrategyNexthopStateWithPD **instancePtr) {
+ return true;
+}
+
+parcObject_ImplementAcquire(strategyNexthopStateWithPD,
+ StrategyNexthopStateWithPD);
+
+parcObject_ImplementRelease(strategyNexthopStateWithPD,
+ StrategyNexthopStateWithPD);
+
+parcObject_Override(
+ StrategyNexthopStateWithPD, PARCObject,
+ .destructor = (PARCObjectDestructor *)
+ _strategyNexthopStateWithPD_Destructor,
+ .copy = (PARCObjectCopy *)strategyNexthopStateWithPD_Copy,
+ .display = (PARCObjectDisplay *)strategyNexthopStateWithPD_Display,
+ .toString = (PARCObjectToString *)strategyNexthopStateWithPD_ToString,
+ .equals = (PARCObjectEquals *)strategyNexthopStateWithPD_Equals,
+ .compare = (PARCObjectCompare *)strategyNexthopStateWithPD_Compare,
+ .hashCode = (PARCObjectHashCode *)strategyNexthopStateWithPD_HashCode,
+ .display = (PARCObjectDisplay *)strategyNexthopStateWithPD_Display);
+
+void strategyNexthopStateWithPD_AssertValid(
+ const StrategyNexthopStateWithPD *instance) {
+ parcAssertTrue(strategyNexthopStateWithPD_IsValid(instance),
+ "StrategyNexthopStateWithPD is not valid.");
+}
+
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Create() {
+ StrategyNexthopStateWithPD *result =
+ parcObject_CreateInstance(StrategyNexthopStateWithPD);
+ if (result != NULL) {
+ result->pi = 0;
+ result->avg_pi = 1.0;
+ result->weight = 1;
+ result->delay = 0;
+ }
+ return result;
+}
+
+void strategyNexthopStateWithPD_Reset(StrategyNexthopStateWithPD *x) {
+ x->pi = 0;
+ x->avg_pi = 1.0;
+ x->weight = 1;
+ x->delay = 0;
+}
+
+int strategyNexthopStateWithPD_Compare(
+ const StrategyNexthopStateWithPD *val,
+ const StrategyNexthopStateWithPD *other) {
+ if (val == NULL) {
+ if (other != NULL) {
+ return -1;
+ }
+ } else if (other == NULL) {
+ return 1;
+ } else {
+ strategyNexthopStateWithPD_OptionalAssertValid(val);
+ strategyNexthopStateWithPD_OptionalAssertValid(other);
+
+ if (val->pi < other->pi) {
+ return -1;
+ } else if (val->pi > other->pi) {
+ return 1;
+ }
+
+ if (val->avg_pi < other->avg_pi) {
+ return -1;
+ } else if (val->avg_pi > other->avg_pi) {
+ return 1;
+ }
+
+ if (val->weight < other->weight) {
+ return -1;
+ } else if (val->weight > other->weight) {
+ return 1;
+ }
+
+ if (val->delay < other->delay) {
+ return -1;
+ } else if (val->delay > other->delay) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Copy(
+ const StrategyNexthopStateWithPD *original) {
+ StrategyNexthopStateWithPD *result = strategyNexthopStateWithPD_Create();
+ result->pi = original->pi;
+ result->avg_pi = original->avg_pi;
+ result->weight = original->weight;
+ result->delay = original->delay;
+
+ return result;
+}
+
+void strategyNexthopStateWithPD_Display(
+ const StrategyNexthopStateWithPD *instance, int indentation) {
+ parcDisplayIndented_PrintLine(indentation, "StrategyNexthopStateWithPD@%p {",
+ instance);
+ parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->pi);
+ parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_pi);
+ parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->weight);
+ parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->delay);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool strategyNexthopStateWithPD_Equals(const StrategyNexthopStateWithPD *x,
+ const StrategyNexthopStateWithPD *y) {
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ strategyNexthopStateWithPD_OptionalAssertValid(x);
+ strategyNexthopStateWithPD_OptionalAssertValid(y);
+
+ if (strategyNexthopStateWithPD_Compare(x, y) == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode strategyNexthopStateWithPD_HashCode(
+ const StrategyNexthopStateWithPD *x) {
+ PARCHashCode result = 0;
+ char str[128];
+ sprintf(str, "PI:%d: AVG_PI:%f: W:%f D:%d", x->pi, x->avg_pi, x->weight,
+ x->delay);
+ result = parcHashCode_Hash((uint8_t *)&str, strlen(str));
+ return result;
+}
+
+bool strategyNexthopStateWithPD_IsValid(const StrategyNexthopStateWithPD *x) {
+ bool result = false;
+
+ if (x != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+char *strategyNexthopStateWithPD_ToString(const StrategyNexthopStateWithPD *x) {
+ // this is not implemented
+ parcTrapNotImplemented(
+ "strategyNexthopStateWithPD_ToString is not implemented");
+ return NULL;
+}
+
+unsigned strategyNexthopStateWithPD_GetPI(const StrategyNexthopStateWithPD *x) {
+ strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+ return x->pi;
+}
+
+double strategyNexthopStateWithPD_GetAvgPI(
+ const StrategyNexthopStateWithPD *x) {
+ strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+ return x->avg_pi;
+}
+
+double strategyNexthopStateWithPD_GetWeight(
+ const StrategyNexthopStateWithPD *x) {
+ strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+ return x->weight;
+}
+
+unsigned strategyNexthopStateWithPD_GetDelay(
+ const StrategyNexthopStateWithPD *x) {
+ strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+ return x->delay;
+}
+
+void strategyNexthopStateWithPD_SetDelay(StrategyNexthopStateWithPD *x,
+ unsigned delay) {
+ strategyNexthopStateWithPD_OptionalAssertValid(x);
+ if (delay != 0) {
+ x->delay = delay;
+ }
+}
+
+double strategyNexthopStateWithPD_UpdateState(StrategyNexthopStateWithPD *x,
+ bool inc, unsigned min_delay,
+ double alpha) {
+ strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+ if (inc) {
+ x->pi++;
+ } else {
+ if (x->pi > 0) {
+ x->pi--;
+ }
+ }
+
+ x->avg_pi = (x->avg_pi * alpha) + (x->pi * (1 - alpha));
+ if (x->avg_pi == 0.0) {
+ x->avg_pi = 0.1;
+ }
+
+ double factor = 1.0;
+ if (min_delay != INT_MAX && x->delay != 0) {
+ factor = ((double)min_delay / (double)x->delay);
+ }
+
+ x->weight = 1 / (x->avg_pi * factor);
+
+ return x->weight;
+}
diff --git a/hicn-light/src/strategies/nexthopStateWithPD.h b/hicn-light/src/strategies/nexthopStateWithPD.h
new file mode 100755
index 000000000..4d8bd6d15
--- /dev/null
+++ b/hicn-light/src/strategies/nexthopStateWithPD.h
@@ -0,0 +1,106 @@
+/*
+ * 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 nexthopstatewithpd_h
+#define nexthopstatewithpd_h
+
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Object.h>
+
+struct strategy_nexthop_state_with_pd;
+typedef struct strategy_nexthop_state_with_pd StrategyNexthopStateWithPD;
+extern parcObjectDescriptor_Declaration(StrategyNexthopStateWithPD);
+
+/**
+ */
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Acquire(
+ const StrategyNexthopStateWithPD *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+#define strategyNexthopStateWithPD_OptionalAssertValid(_instance_)
+#else
+#define strategyNexthopStateWithPD_OptionalAssertValid(_instance_) \
+ strategyNexthopStateWithPD_AssertValid(_instance_)
+#endif
+
+/**
+ */
+void strategyNexthopStateWithPD_AssertValid(
+ const StrategyNexthopStateWithPD *instance);
+
+/**
+ */
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Create();
+
+void strategyNexthopStateWithPD_Reset(StrategyNexthopStateWithPD *x);
+/**
+ */
+int strategyNexthopStateWithPD_Compare(
+ const StrategyNexthopStateWithPD *instance,
+ const StrategyNexthopStateWithPD *other);
+
+/**
+ */
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Copy(
+ const StrategyNexthopStateWithPD *original);
+
+/**
+ */
+void strategyNexthopStateWithPD_Display(
+ const StrategyNexthopStateWithPD *instance, int indentation);
+
+/**
+ */
+bool strategyNexthopStateWithPD_Equals(const StrategyNexthopStateWithPD *x,
+ const StrategyNexthopStateWithPD *y);
+
+/**
+ */
+PARCHashCode strategyNexthopStateWithPD_HashCode(
+ const StrategyNexthopStateWithPD *instance);
+
+/**
+ */
+bool strategyNexthopStateWithPD_IsValid(
+ const StrategyNexthopStateWithPD *instance);
+
+/**
+ */
+void strategyNexthopStateWithPD_Release(
+ StrategyNexthopStateWithPD **instancePtr);
+
+/**
+ */
+char *strategyNexthopStateWithPD_ToString(
+ const StrategyNexthopStateWithPD *instance);
+
+/**
+ */
+unsigned strategyNexthopStateWithPD_GetPI(const StrategyNexthopStateWithPD *x);
+
+double strategyNexthopStateWithPD_GetAvgPI(const StrategyNexthopStateWithPD *x);
+
+double strategyNexthopStateWithPD_GetWeight(
+ const StrategyNexthopStateWithPD *x);
+
+unsigned strategyNexthopStateWithPD_GetDelay(
+ const StrategyNexthopStateWithPD *x);
+void strategyNexthopStateWithPD_SetDelay(StrategyNexthopStateWithPD *x,
+ unsigned delay);
+
+double strategyNexthopStateWithPD_UpdateState(StrategyNexthopStateWithPD *x,
+ bool inc, unsigned min_delay,
+ double alpha);
+#endif
diff --git a/hicn-light/src/strategies/rnd.c b/hicn-light/src/strategies/rnd.c
new file mode 100755
index 000000000..37f3f6f30
--- /dev/null
+++ b/hicn-light/src/strategies/rnd.c
@@ -0,0 +1,175 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/strategies/rnd.h>
+
+static void _strategyRnd_ReceiveObject(StrategyImpl *strategy,
+ const NumberSet *egressId,
+ const Message *objectMessage, Ticks rtt);
+static void _strategyRnd_OnTimeout(StrategyImpl *strategy,
+ const NumberSet *egressId);
+static NumberSet *_strategyRnd_LookupNexthop(StrategyImpl *strategy,
+ const Message *interestMessage);
+static NumberSet *_strategyRnd_ReturnNexthops(StrategyImpl *strategy);
+static unsigned _strategyRnd_CountNexthops(StrategyImpl *strategy);
+static void _strategyRnd_AddNexthop(StrategyImpl *strategy,
+ unsigned connectionId);
+static void _strategyRnd_RemoveNexthop(StrategyImpl *strategy,
+ unsigned connectionId);
+static void _strategyRnd_ImplDestroy(StrategyImpl **strategyPtr);
+static strategy_type _strategyRnd_GetStrategy(StrategyImpl *strategy);
+
+static StrategyImpl _template = {
+ .context = NULL,
+ .receiveObject = &_strategyRnd_ReceiveObject,
+ .onTimeout = &_strategyRnd_OnTimeout,
+ .lookupNexthop = &_strategyRnd_LookupNexthop,
+ .returnNexthops = &_strategyRnd_ReturnNexthops,
+ .countNexthops = &_strategyRnd_CountNexthops,
+ .addNexthop = &_strategyRnd_AddNexthop,
+ .removeNexthop = &_strategyRnd_RemoveNexthop,
+ .destroy = &_strategyRnd_ImplDestroy,
+ .getStrategy = &_strategyRnd_GetStrategy,
+};
+
+struct strategy_rnd;
+typedef struct strategy_rnd StrategyRnd;
+
+struct strategy_rnd {
+ NumberSet *nexthops;
+};
+
+StrategyImpl *strategyRnd_Create() {
+ StrategyRnd *strategy = parcMemory_AllocateAndClear(sizeof(StrategyRnd));
+ parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(StrategyRnd));
+
+ strategy->nexthops = numberSet_Create();
+ srand(time(NULL));
+
+ StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl));
+ parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(StrategyImpl));
+ memcpy(impl, &_template, sizeof(StrategyImpl));
+ impl->context = strategy;
+ return impl;
+}
+
+// =======================================================
+// Dispatch API
+
+strategy_type _strategyRnd_GetStrategy(StrategyImpl *strategy) {
+ return SET_STRATEGY_RANDOM;
+}
+
+static int _select_Nexthop(StrategyRnd *strategy) {
+ unsigned len = numberSet_Length(strategy->nexthops);
+ if (len == 0) {
+ return -1;
+ }
+
+ int rnd = (rand() % len);
+ return numberSet_GetItem(strategy->nexthops, rnd);
+}
+
+static void _strategyRnd_ReceiveObject(StrategyImpl *strategy,
+ const NumberSet *egressId,
+ const Message *objectMessage,
+ Ticks rtt) {}
+
+static void _strategyRnd_OnTimeout(StrategyImpl *strategy,
+ const NumberSet *egressId) {}
+
+static NumberSet *_strategyRnd_LookupNexthop(StrategyImpl *strategy,
+ const Message *interestMessage) {
+ StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+
+ unsigned in_connection = message_GetIngressConnectionId(interestMessage);
+ unsigned nexthopSize = numberSet_Length(srnd->nexthops);
+
+ NumberSet *out = numberSet_Create();
+ if ((nexthopSize == 0) ||
+ ((nexthopSize == 1) &&
+ numberSet_Contains(srnd->nexthops, in_connection))) {
+ // there are no output faces or the input face is also the only output face.
+ // return null to avoid loops
+ return out;
+ }
+
+ unsigned out_connection;
+ do {
+ out_connection = _select_Nexthop(srnd);
+ } while (out_connection == in_connection);
+
+ if (out_connection == -1) {
+ return out;
+ }
+
+ numberSet_Add(out, out_connection);
+ return out;
+}
+
+static NumberSet *_strategyRnd_ReturnNexthops(StrategyImpl *strategy) {
+ StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+ return srnd->nexthops;
+}
+
+unsigned _strategyRnd_CountNexthops(StrategyImpl *strategy) {
+ StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+ return numberSet_Length(srnd->nexthops);
+}
+
+static void _strategyRnd_AddNexthop(StrategyImpl *strategy,
+ unsigned connectionId) {
+ StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+ if (!numberSet_Contains(srnd->nexthops, connectionId)) {
+ numberSet_Add(srnd->nexthops, connectionId);
+ }
+}
+
+static void _strategyRnd_RemoveNexthop(StrategyImpl *strategy,
+ unsigned connectionId) {
+ StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+
+ if (numberSet_Contains(srnd->nexthops, connectionId)) {
+ numberSet_Remove(srnd->nexthops, connectionId);
+ }
+}
+
+static void _strategyRnd_ImplDestroy(StrategyImpl **strategyPtr) {
+ parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*strategyPtr,
+ "Parameter must dereference to non-null pointer");
+
+ StrategyImpl *impl = *strategyPtr;
+ StrategyRnd *strategy = (StrategyRnd *)impl->context;
+
+ numberSet_Release(&(strategy->nexthops));
+
+ parcMemory_Deallocate((void **)&strategy);
+ parcMemory_Deallocate((void **)&impl);
+ *strategyPtr = NULL;
+}
diff --git a/hicn-light/src/strategies/rnd.h b/hicn-light/src/strategies/rnd.h
new file mode 100755
index 000000000..69bedc1a5
--- /dev/null
+++ b/hicn-light/src/strategies/rnd.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Forward randomly
+ */
+
+#ifndef rnd_h
+#define rnd_h
+
+#include <src/strategies/strategyImpl.h>
+
+StrategyImpl* strategyRnd_Create();
+#endif // rnd_h
diff --git a/hicn-light/src/strategies/rndSegment.c b/hicn-light/src/strategies/rndSegment.c
new file mode 100755
index 000000000..2000ed7b7
--- /dev/null
+++ b/hicn-light/src/strategies/rndSegment.c
@@ -0,0 +1,207 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+#include <src/core/nameBitvector.h>
+#include <src/strategies/rndSegment.h>
+
+static void _strategyRndSegment_ReceiveObject(StrategyImpl *strategy,
+ const NumberSet *egressId,
+ const Message *objectMessage,
+ Ticks rtt);
+static void _strategyRndSegment_OnTimeout(StrategyImpl *strategy,
+ const NumberSet *egressId);
+static NumberSet *_strategyRndSegment_LookupNexthop(
+ StrategyImpl *strategy, const Message *interestMessage);
+static NumberSet *_strategyRndSegment_ReturnNexthops(StrategyImpl *strategy);
+static unsigned _strategyRndSegment_CountNexthops(StrategyImpl *strategy);
+static void _strategyRndSegment_AddNexthop(StrategyImpl *strategy,
+ unsigned connectionId);
+static void _strategyRndSegment_RemoveNexthop(StrategyImpl *strategy,
+ unsigned connectionId);
+static void _strategyRndSegment_ImplDestroy(StrategyImpl **strategyPtr);
+static strategy_type _strategyRndSegment_GetStrategy(StrategyImpl *strategy);
+
+static StrategyImpl _template = {
+ .context = NULL,
+ .receiveObject = &_strategyRndSegment_ReceiveObject,
+ .onTimeout = &_strategyRndSegment_OnTimeout,
+ .lookupNexthop = &_strategyRndSegment_LookupNexthop,
+ .returnNexthops = &_strategyRndSegment_ReturnNexthops,
+ .countNexthops = &_strategyRndSegment_CountNexthops,
+ .addNexthop = &_strategyRndSegment_AddNexthop,
+ .removeNexthop = &_strategyRndSegment_RemoveNexthop,
+ .destroy = &_strategyRndSegment_ImplDestroy,
+ .getStrategy = &_strategyRndSegment_GetStrategy,
+};
+
+struct strategy_rnd_segment;
+typedef struct strategy_rnd_segment StrategyRndSegment;
+
+struct strategy_rnd_segment {
+ NumberSet *nexthops;
+ NameBitvector *segmentName;
+ int last_used_face;
+};
+
+StrategyImpl *strategyRndSegment_Create() {
+ StrategyRndSegment *strategy =
+ parcMemory_AllocateAndClear(sizeof(StrategyRndSegment));
+ parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(StrategyRndSegment));
+
+ strategy->nexthops = numberSet_Create();
+ strategy->segmentName = NULL;
+ strategy->last_used_face = 0;
+ srand(time(NULL));
+
+ StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl));
+ parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(StrategyImpl));
+ memcpy(impl, &_template, sizeof(StrategyImpl));
+ impl->context = strategy;
+
+ return impl;
+}
+
+// =======================================================
+// Dispatch API
+
+strategy_type _strategyRndSegment_GetStrategy(StrategyImpl *strategy) {
+ return SET_STRATEGY_RANDOM_PER_DASH_SEGMENT;
+}
+
+static int _select_Nexthop(StrategyRndSegment *strategy) {
+ unsigned len = numberSet_Length(strategy->nexthops);
+ if (len == 0) {
+ return -1;
+ }
+
+ int rnd = (rand() % len);
+ return numberSet_GetItem(strategy->nexthops, rnd);
+}
+
+static void _strategyRndSegment_ReceiveObject(StrategyImpl *strategy,
+ const NumberSet *egressId,
+ const Message *objectMessage,
+ Ticks rtt) {}
+
+static void _strategyRndSegment_OnTimeout(StrategyImpl *strategy,
+ const NumberSet *egressId) {}
+
+static NumberSet *_strategyRndSegment_LookupNexthop(
+ StrategyImpl *strategy, const Message *interestMessage) {
+ StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+
+ unsigned in_connection = message_GetIngressConnectionId(interestMessage);
+ unsigned nexthopSize = numberSet_Length(srnd->nexthops);
+
+ NumberSet *out = numberSet_Create();
+ if ((nexthopSize == 0) ||
+ ((nexthopSize == 1) &&
+ numberSet_Contains(srnd->nexthops, in_connection))) {
+ // there are no output faces or the input face is also the only output face.
+ // return null to avoid loops
+ return out;
+ }
+
+ NameBitvector *interestName =
+ name_GetContentName(message_GetName(interestMessage));
+
+ if (srnd->segmentName == NULL) {
+ srnd->segmentName = nameBitvector_Copy(interestName);
+ } else if (!nameBitvector_Equals(srnd->segmentName, interestName)) {
+ nameBitvector_Destroy(&srnd->segmentName);
+ srnd->segmentName = nameBitvector_Copy(interestName);
+ } else {
+ // here we need to check if the output face still exists or if someone erase
+ // it
+ if (numberSet_Contains(srnd->nexthops, srnd->last_used_face)) {
+ // face exists, so keep using it!
+ numberSet_Add(out, srnd->last_used_face);
+ return out;
+ } else {
+ // the face does not exists anymore, try to find a new face but keep the
+ // name of the dash segment
+ }
+ }
+
+ int out_connection;
+ do {
+ out_connection = _select_Nexthop(srnd);
+ } while (out_connection == in_connection);
+
+ if (out_connection == -1) {
+ return out;
+ }
+
+ srnd->last_used_face = out_connection;
+ numberSet_Add(out, out_connection);
+ return out;
+}
+
+static NumberSet *_strategyRndSegment_ReturnNexthops(StrategyImpl *strategy) {
+ StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+ return srnd->nexthops;
+}
+
+unsigned _strategyRndSegment_CountNexthops(StrategyImpl *strategy) {
+ StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+ return numberSet_Length(srnd->nexthops);
+}
+
+static void _strategyRndSegment_AddNexthop(StrategyImpl *strategy,
+ unsigned connectionId) {
+ StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+ if (!numberSet_Contains(srnd->nexthops, connectionId)) {
+ numberSet_Add(srnd->nexthops, connectionId);
+ }
+}
+
+static void _strategyRndSegment_RemoveNexthop(StrategyImpl *strategy,
+ unsigned connectionId) {
+ StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+
+ if (numberSet_Contains(srnd->nexthops, connectionId)) {
+ numberSet_Remove(srnd->nexthops, connectionId);
+ }
+}
+
+static void _strategyRndSegment_ImplDestroy(StrategyImpl **strategyPtr) {
+ parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*strategyPtr,
+ "Parameter must dereference to non-null pointer");
+
+ StrategyImpl *impl = *strategyPtr;
+ StrategyRndSegment *strategy = (StrategyRndSegment *)impl->context;
+
+ numberSet_Release(&(strategy->nexthops));
+ if (strategy->segmentName != NULL) {
+ nameBitvector_Destroy(&strategy->segmentName);
+ }
+
+ parcMemory_Deallocate((void **)&strategy);
+ parcMemory_Deallocate((void **)&impl);
+ *strategyPtr = NULL;
+}
diff --git a/hicn-light/src/strategies/rndSegment.h b/hicn-light/src/strategies/rndSegment.h
new file mode 100755
index 000000000..0749692f7
--- /dev/null
+++ b/hicn-light/src/strategies/rndSegment.h
@@ -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.
+ */
+
+/**
+ * Forward randomly, selects a path every time the client ask for a new dash
+ * segment
+ */
+
+#ifndef rnd_Segment_h
+#define rnd_Segment_h
+
+#include <src/strategies/strategyImpl.h>
+
+StrategyImpl* strategyRndSegment_Create();
+#endif // rnd_Segment_h
diff --git a/hicn-light/src/strategies/strategyImpl.h b/hicn-light/src/strategies/strategyImpl.h
new file mode 100755
index 000000000..c089e0b2b
--- /dev/null
+++ b/hicn-light/src/strategies/strategyImpl.h
@@ -0,0 +1,66 @@
+/*
+ * 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 strategyImpl.h
+ * @brief Defines the function structure for a Strategy implementation
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+/**
+ * A dispatch structure for a concrete implementation of a forwarding strategy.
+ */
+
+#ifndef strategyImpl_h
+#define strategyImpl_h
+
+#include <src/core/message.h>
+#include <src/core/numberSet.h>
+
+struct strategy_impl;
+typedef struct strategy_impl StrategyImpl;
+
+/**
+ * @typedef StrategyImpl
+ * @abstract Forwarding strategy implementation
+ * @constant receiveObject is called when we receive an object and have a
+ * measured round trip time. This allows a strategy to update its performance
+ * data.
+ * @constant lookupNexthop Find the set of nexthops to use for the Interest.
+ * May be empty, should not be NULL. Must be destroyed.
+ * @constant addNexthop Add a nexthop to the list of available nexthops with a
+ * routing protocol-specific cost.
+ * @constant destroy cleans up the strategy, freeing all memory and state. A
+ * strategy is reference counted, so the final destruction only happens after
+ * the last reference is released.
+ * @discussion <#Discussion#>
+ */
+struct strategy_impl {
+ void *context;
+ void (*receiveObject)(StrategyImpl *strategy, const NumberSet *egressId,
+ const Message *objectMessage, Ticks rtt);
+ void (*onTimeout)(StrategyImpl *strategy, const NumberSet *egressId);
+ NumberSet *(*lookupNexthop)(StrategyImpl *strategy,
+ const Message *interestMessage);
+ NumberSet *(*returnNexthops)(StrategyImpl *strategy);
+ unsigned (*countNexthops)(StrategyImpl *strategy);
+ void (*addNexthop)(StrategyImpl *strategy, unsigned connectionId);
+ void (*removeNexthop)(StrategyImpl *strategy, unsigned connectionId);
+ void (*destroy)(StrategyImpl **strategyPtr);
+ strategy_type (*getStrategy)(StrategyImpl *strategy);
+};
+#endif // strategyImpl_h
diff --git a/hicn-light/src/utils/CMakeLists.txt b/hicn-light/src/utils/CMakeLists.txt
new file mode 100755
index 000000000..7d438d157
--- /dev/null
+++ b/hicn-light/src/utils/CMakeLists.txt
@@ -0,0 +1,36 @@
+# 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/address.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/addressList.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/commands.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/interface.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/punting.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/utils.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/address.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/addressList.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/interface.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/punting.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/utils.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file
diff --git a/hicn-light/src/utils/address.c b/hicn-light/src/utils/address.c
new file mode 100755
index 000000000..3f6fe2591
--- /dev/null
+++ b/hicn-light/src/utils/address.c
@@ -0,0 +1,419 @@
+/*
+ * 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 <arpa/inet.h>
+#include <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <src/utils/address.h>
+
+#include <parc/algol/parc_Base64.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct address {
+ address_type addressType;
+ PARCBuffer *blob;
+};
+
+static struct address_type_str {
+ address_type type;
+ const char *str;
+} addressTypeString[] = {
+ {.type = ADDR_INET, .str = "INET"}, {.type = ADDR_INET6, .str = "INET6"},
+ {.type = ADDR_LINK, .str = "LINK"}, {.type = ADDR_IFACE, .str = "IFACE"},
+ {.type = ADDR_UNIX, .str = "UNIX"}, {.type = 0, .str = NULL}};
+
+void addressDestroy(Address **addressPtr) {
+ parcAssertNotNull(addressPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*addressPtr,
+ "Parameter must dereference to non-null pointer");
+
+ Address *address = *addressPtr;
+ parcBuffer_Release(&address->blob);
+ parcMemory_Deallocate((void **)&address);
+ *addressPtr = NULL;
+}
+
+void addressAssertValid(const Address *address) {
+ parcAssertNotNull(address, "Parameter must be non-null Address *");
+}
+
+const char *addressTypeToString(address_type type) {
+ for (int i = 0; addressTypeString[i].str != NULL; i++) {
+ if (addressTypeString[i].type == type) {
+ return addressTypeString[i].str;
+ }
+ }
+ parcTrapIllegalValue(type, "Unknown value: %d", type);
+ const char *result = NULL;
+ return result;
+}
+
+address_type addressStringToType(const char *str) {
+ for (int i = 0; addressTypeString[i].str != NULL; i++) {
+ if (strcasecmp(addressTypeString[i].str, str) == 0) {
+ return addressTypeString[i].type;
+ }
+ }
+ parcTrapIllegalValue(str, "Unknown type '%s'", str);
+ return 0;
+}
+
+static Address *_addressCreate(address_type addressType, PARCBuffer *buffer) {
+ Address *result = parcMemory_AllocateAndClear(sizeof(Address));
+
+ parcAssertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Address));
+ if (result != NULL) {
+ result->addressType = addressType;
+ result->blob = buffer;
+ }
+ return result;
+}
+
+Address *addressCreateFromInet(struct sockaddr_in *addr_in) {
+ parcAssertNotNull(addr_in, "Parameter must be non-null");
+
+ addr_in->sin_family = AF_INET;
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in));
+ parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in), (uint8_t *)addr_in);
+ parcBuffer_Flip(buffer);
+
+ Address *result = _addressCreate(ADDR_INET, buffer);
+
+ return result;
+}
+
+Address *addressCreateFromInet6(struct sockaddr_in6 *addr_in6) {
+ parcAssertNotNull(addr_in6, "Parameter must be non-null");
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6));
+ parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in6), (uint8_t *)addr_in6);
+ parcBuffer_Flip(buffer);
+
+ Address *result = _addressCreate(ADDR_INET6, buffer);
+
+ return result;
+}
+
+Address *addressCreateFromLink(const uint8_t *linkaddr, size_t length) {
+ parcAssertNotNull(linkaddr, "Parameter must be non-null");
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6));
+ parcBuffer_PutArray(buffer, length, linkaddr);
+ parcBuffer_Flip(buffer);
+
+ Address *result = _addressCreate(ADDR_LINK, buffer);
+ return result;
+}
+
+Address *addressCreateFromInterface(unsigned interfaceIndex) {
+ unsigned netbyteorder = htonl(interfaceIndex);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(netbyteorder));
+ parcBuffer_PutArray(buffer, sizeof(netbyteorder), (uint8_t *)&netbyteorder);
+ parcBuffer_Flip(buffer);
+
+ Address *result = _addressCreate(ADDR_IFACE, buffer);
+ return result;
+}
+
+Address *addressCreateFromUnix(struct sockaddr_un *addr_un) {
+ parcAssertNotNull(addr_un, "Parameter must be non-null");
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_un));
+ parcBuffer_PutArray(buffer, sizeof(struct sockaddr_un), (uint8_t *)addr_un);
+ parcBuffer_Flip(buffer);
+
+ Address *result = _addressCreate(ADDR_UNIX, buffer);
+ return result;
+}
+
+Address *addressCopy(const Address *original) {
+ addressAssertValid(original);
+
+ Address *result =
+ _addressCreate(original->addressType, parcBuffer_Copy(original->blob));
+ return result;
+}
+
+bool addressEquals(const Address *a, const Address *b) {
+ if (a == b) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->addressType == b->addressType) {
+ if (parcBuffer_Equals(a->blob, b->blob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+address_type addressGetType(const Address *address) {
+ addressAssertValid(address);
+
+ return address->addressType;
+}
+
+// The Get functions need better names, what they do (Get from what? Put to
+// what?) is not clear from their names. Case 1028
+bool addressGetInet(const Address *address, struct sockaddr_in *addr_in) {
+ addressAssertValid(address);
+ parcAssertNotNull(addr_in, "Parameter addr_in must be non-null");
+
+ if (address->addressType == ADDR_INET) {
+ parcAssertTrue(
+ parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in),
+ "Address corrupted. Expected length %zu, actual length %zu",
+ sizeof(struct sockaddr_in), parcBuffer_Remaining(address->blob));
+
+ memcpy(addr_in, parcBuffer_Overlay(address->blob, 0),
+ sizeof(struct sockaddr_in));
+ return true;
+ }
+ return false;
+}
+
+bool addressGetInet6(const Address *address, struct sockaddr_in6 *addr_in6) {
+ addressAssertValid(address);
+ parcAssertNotNull(addr_in6, "Parameter addr_in6 must be non-null");
+
+ if (address->addressType == ADDR_INET6) {
+ parcAssertTrue(
+ parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in6),
+ "Address corrupted. Expected length %zu, actual length %zu",
+ sizeof(struct sockaddr_in6), parcBuffer_Remaining(address->blob));
+
+ memcpy(addr_in6, parcBuffer_Overlay(address->blob, 0),
+ sizeof(struct sockaddr_in6));
+ return true;
+ }
+ return false;
+}
+
+bool addressGetUnix(const Address *address, struct sockaddr_un *addr_un) {
+ addressAssertValid(address);
+ parcAssertNotNull(addr_un, "Parameter addr_in6 must be non-null");
+
+ if (address->addressType == ADDR_UNIX) {
+ parcAssertTrue(
+ parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_un),
+ "Address corrupted. Expected length %zu, actual length %zu",
+ sizeof(struct sockaddr_un), parcBuffer_Remaining(address->blob));
+
+ memcpy(addr_un, parcBuffer_Overlay(address->blob, 0),
+ sizeof(struct sockaddr_un));
+ return true;
+ }
+ return false;
+}
+
+bool addressGetInterfaceIndex(const Address *address, uint32_t *ifidx) {
+ addressAssertValid(address);
+ parcAssertNotNull(ifidx, "Parameter ifidx must be non-null");
+
+ if (address->addressType == ADDR_IFACE) {
+ parcAssertTrue(parcBuffer_Remaining(address->blob) == sizeof(uint32_t),
+ "Address corrupted. Expected length %zu, actual length %zu",
+ sizeof(uint32_t), parcBuffer_Remaining(address->blob));
+
+ uint32_t netbyteorder;
+ memcpy(&netbyteorder, parcBuffer_Overlay(address->blob, 0),
+ sizeof(uint32_t));
+ *ifidx = ntohl(netbyteorder);
+ return true;
+ }
+ return false;
+}
+
+PARCBuffer *addressGetLinkAddress(const Address *address) {
+ addressAssertValid(address);
+ if (address->addressType == ADDR_LINK) {
+ return address->blob;
+ }
+ return NULL;
+}
+
+static PARCBufferComposer *_Inet_BuildString(const Address *address,
+ PARCBufferComposer *composer) {
+ addressAssertValid(address);
+
+ struct sockaddr_in *saddr =
+ (struct sockaddr_in *)parcBuffer_Overlay(address->blob, 0);
+ return parcNetwork_SockInet4Address_BuildString(saddr, composer);
+}
+
+static PARCBufferComposer *_Inet6_BuildString(const Address *address,
+ PARCBufferComposer *composer) {
+ addressAssertValid(address);
+
+ struct sockaddr_in6 *saddr =
+ (struct sockaddr_in6 *)parcBuffer_Overlay(address->blob, 0);
+ return parcNetwork_SockInet6Address_BuildString(saddr, composer);
+}
+
+static PARCBufferComposer *_Link_BuildString(const Address *address,
+ PARCBufferComposer *composer) {
+ addressAssertValid(address);
+
+ const unsigned char *addr = parcBuffer_Overlay(address->blob, 0);
+
+ size_t length = parcBuffer_Remaining(address->blob);
+
+ return parcNetwork_LinkAddress_BuildString(addr, length, composer);
+}
+
+static ssize_t _UnixToString(char *output, size_t remaining_size,
+ const PARCBuffer *addr) {
+ parcAssertNotNull(output, "parameter output must be non-null");
+ parcBuffer_AssertValid(addr);
+
+ parcAssertTrue(parcBuffer_Remaining(addr) == sizeof(struct sockaddr_un),
+ "Address corrupted. Expected %zu actual %zu",
+ sizeof(struct sockaddr_un), parcBuffer_Remaining(addr));
+
+ // sockaddr length for the path, 16 for the ascii stuff, 3 for the length
+ // number
+ struct sockaddr_un *saddr =
+ (struct sockaddr_un *)parcBuffer_Overlay((PARCBuffer *)addr, 0);
+ size_t min_remaining = strlen(saddr->sun_path) + 16 + 3;
+ parcAssertTrue(remaining_size >= min_remaining,
+ "Remaining size too small, need at least %zu", min_remaining);
+
+ ssize_t output_length = sprintf(output, "{ .path=%s, .len=%zu }",
+ saddr->sun_path, strlen(saddr->sun_path));
+ return output_length;
+}
+
+static ssize_t _IfaceToString(char *output, size_t remaining_size,
+ const PARCBuffer *addr) {
+ parcAssertNotNull(output, "parameter output must be non-null");
+ parcBuffer_AssertValid(addr);
+
+ parcAssertTrue(parcBuffer_Remaining(addr) == sizeof(uint32_t),
+ "Address corrupted. Expected %zu actual %zu", sizeof(uint32_t),
+ parcBuffer_Remaining(addr));
+
+ uint32_t *ifidx = (uint32_t *)parcBuffer_Overlay((PARCBuffer *)addr, 0);
+
+ ssize_t output_length = sprintf(output, "{ .ifidx=%u }", ntohl(*ifidx));
+
+ return output_length;
+}
+
+PARCBufferComposer *addressBuildString(const Address *address,
+ PARCBufferComposer *composer) {
+ if (address != NULL) {
+ char *str = addressToString(address);
+ parcBufferComposer_PutString(composer, str);
+ parcMemory_Deallocate((void **)&str);
+ }
+ return composer;
+}
+
+char *addressToString(const Address *address) {
+ addressAssertValid(address);
+
+ char addrstr[256];
+
+ switch (address->addressType) {
+ case ADDR_INET: {
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+ _Inet_BuildString(address, composer));
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ return result;
+ } break;
+
+ case ADDR_INET6: {
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+ _Inet6_BuildString(address, composer));
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+ return result;
+ } break;
+
+ case ADDR_LINK:
+ _UnixToString(addrstr, 256, address->blob);
+ break;
+
+ case ADDR_IFACE: {
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+ _Link_BuildString(address, composer));
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+ return result;
+ } break;
+
+ case ADDR_UNIX:
+ _IfaceToString(addrstr, 256, address->blob);
+ break;
+
+ default:
+ sprintf(addrstr, "UNKNOWN type = %d", address->addressType);
+ break;
+ }
+
+ ssize_t alloc_size = 1024;
+ char *output = parcMemory_Allocate(alloc_size);
+ parcAssertNotNull(output, "parcMemory_Allocate(%zu) returned NULL",
+ alloc_size);
+ ssize_t output_length =
+ snprintf(output, alloc_size, "{ .type=%s, .data=%s }",
+ addressTypeToString(address->addressType), addrstr);
+
+ parcAssertTrue(output_length < alloc_size,
+ "allocated size too small, needed %zd", output_length);
+ parcAssertFalse(output_length < 0, "snprintf error: (%d) %s", errno,
+ strerror(errno));
+
+ return output;
+}
+
+PARCHashCode addressHashCode(const Address *address) {
+ addressAssertValid(address);
+
+ PARCHashCode hash = parcBuffer_HashCode(address->blob);
+ hash = parcHashCode_HashImpl((uint8_t *)&address->addressType,
+ sizeof(address->addressType), hash);
+
+ return hash;
+}
diff --git a/hicn-light/src/utils/address.h b/hicn-light/src/utils/address.h
new file mode 100755
index 000000000..a98d15084
--- /dev/null
+++ b/hicn-light/src/utils/address.h
@@ -0,0 +1,498 @@
+/*
+ * 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.
+ */
+
+/**
+ * @brief Represents an endpoint address.
+ *
+ * Represents an endpoint address. May be INET, INET6, or a multi-byte LINK,
+ * or an Interface Index.
+ *
+ * INET and INET6 must contain the .sa_addr member, and other members as needed
+ * by the use of the address.
+ *
+ * The Interface Index address is essentially a pointer to a device.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef address_h
+#define address_h
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <sys/un.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <src/utils/commands.h>
+
+/**
+ * Return a string representation of the given `address_type`
+ *
+ * @param [in] type A valid address_type value.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a static string representation of the
+ * `address_type`.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *typeAsString = addressTypeToString(commandAddrType_INET);
+ * }
+ * @endcode
+ *
+ * @see addressStringToType
+ */
+const char *addressTypeToString(address_type type);
+
+/**
+ * Return a `address_type` from the given nul-terminated C string.
+ *
+ * @param [in] typeAsString A nul-terminated, C string representation of a
+ * `address_type`.
+ *
+ * @return A address_type
+ *
+ * Example:
+ * @code
+ * {
+ * address_type type = addressTypeToString("INET");
+ * }
+ * @endcode
+ *
+ * @see addressTypeToString
+ */
+address_type addressStringToType(const char *typeAsString);
+
+struct address;
+typedef struct address Address;
+
+/**
+ * Create a new `Address` instance from an IPv4 IP address, the port is
+ * optional.
+ *
+ * The sockaddr_in should be filled in network byte order. The newly created
+ * instance must eventually be destroyed by calling {@link addressDestroy}().
+ *
+ * @param [in] addr_in The `sockaddr_in` representing the IPv4 IP address with
+ * which to initialize the new `Address` instance.
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}().
+ *
+ * Example:
+ * @code
+ * {
+ * Address *dest = addressCreateFromInet(
+ * &(struct sockaddr_in) {
+ * .sa_addr =
+ * inet_addr("foo.bar.com"), .sa_port = htons(9695) } ); addressDestroy(&dest);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromInet(struct sockaddr_in *addr_in);
+
+/**
+ * Create a new `Address` instance from an IPv6 IP address, the port is
+ * optional.
+ *
+ *
+ * The sockaddr_in should be filled in network byte order. The newly created
+ * instance must eventually be destroyed by calling {@link addressDestroy}().
+ *
+ * @param [in] addr_in6 A `sockaddr_in6` from which to initialize a new instance
+ * of Address
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}()
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_in6 addr_in6;
+ * memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+ *
+ * inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ * addr_in6.sin6_family = AF_INET6;
+ * addr_in6.sin6_port = 0x0A0B;
+ * addr_in6.sin6_flowinfo = 0x01020304;
+ *
+ * Address *address = addressCreateFromInet6(&addr_in6);
+ *
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromInet6(struct sockaddr_in6 *addr_in6);
+
+/**
+ * Create a new `Address` instance, initialized from a Link address.
+ *
+ * User must know the link address format (i.e. token ring vs ethernet) and have
+ * the address in a byte array. The array is encoded in left-to-right order. The
+ * newly created instance must eventually be destroyed by calling {@link
+ * addressDestroy}().
+ *
+ * @param [in] linkaddr A byte array containing the link address
+ * @param [in] length The length of the link address byte array
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}()
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 };
+ * Address *address = addressCreateFromLink(mac, sizeof(mac));
+ *
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromLink(const uint8_t *linkaddr, size_t length);
+
+/**
+ * Create a new `Address` instance from a network interface index.
+ *
+ * The interfaceIndex should be in host byte order. The newly created instance
+ * must eventually be destroyed by calling {@link addressDestroy}().
+ *
+ * @param [in] interfaceIndex The index of the interface to encode
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}()
+ *
+ * Example:
+ * @code
+ * {
+ * Address *address = addressCreateFromInterface(2);
+ *
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromInterface(uint32_t interfaceIndex);
+
+/**
+ * Create a new Address instance from a PF_UNIX address domain.
+ *
+ * The newly created instance must eventually be destroyed by calling {@link
+ * addressDestroy}().
+ *
+ * @param [in] addr_un The `struct sockaddr_un` specifying the local PF_UNIX
+ * socket address
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}()
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_un addr_unix;
+ * memset(&addr_unix, 0, sizeof(struct sockaddr_un));
+ * char path[] = "/Hello/Cruel/World";
+ * strcpy(addr_un.sun_path, path);
+ * addr_un.sun_family = AF_UNIX;
+ *
+ * Address *address = addressCreateFromUnix(&addr_un);
+ *
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromUnix(struct sockaddr_un *addr_un);
+
+/**
+ * Create a deep copy of an instance of a `Address`. A completely new,
+ * indedependent instance is created.
+ *
+ * The newly created instance must eventually be destroyed by calling {@link
+ * addressDestroy}().
+ *
+ * @param [in] original A pointer to a `Address` instance to be copied.
+ * @return A new instance of a Address, deep copied from the `original`
+ * instance.
+ *
+ * Example:
+ * @code
+ * {
+ * Address *address = addressCreateFromInterface(2);
+ *
+ * Address *copy = addressCopy(address);
+ *
+ * addressDestroy(&address);
+ * addressDestroy(&copy);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCopy(const Address *original);
+
+/**
+ * Deallocate an instance of a Address.
+ *
+ * The Address instance is deallocated, and any referenced data is also
+ * deallocated. The referenced pointer is set to NULL upon return.
+ *
+ * @param [in] addressPtr A pointer to a pointer to an instance of Address.
+ *
+ * Example:
+ * @code
+ * {
+ * Address *address = addressCreateFromInterface(2);
+ *
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ */
+void addressDestroy(Address **addressPtr);
+
+/**
+ * Determine if two Address instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `Address` instances are
+ * maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `addressEquals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `addressEquals(x, y)` must return true if and only if
+ * `addressEquals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `addressEquals(x, y)` returns true and
+ * `addressEquals(y, z)` returns true,
+ * then `addressEquals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `addressEquals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `addressEquals(x, NULL)` must
+ * return false.
+ *
+ * If one address specifies more information than other,
+ * e.g. a is INET with a port and b is not, they are not equal.
+ *
+ * `a` and `b` may be NULL, and NULL == NULL.
+ *
+ * @param a A pointer to a Address instance
+ * @param b A pointer to a Address instance
+ * @return true if the two instances are equal
+ * @return false if the two instances are not equal
+ *
+ * Example:
+ * @code
+ * {
+ * Address *address = addressCreateFromInterface(2);
+ * Address *copy = addressCopy(address);
+ *
+ * if (addressEquals(address, copy)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ *
+ * addressDestroy(&address);
+ * addressDestroy(&copy);
+ * }
+ * @endcode
+ */
+bool addressEquals(const Address *a, const Address *b);
+
+/**
+ * Return the {@link address_type} from a specified Address.
+ *
+ * @param [in] A pointer to a Address instance
+ *
+ * @return the {@link address_type} of the specified Address instance
+ *
+ * Example:
+ * @code
+ * {
+ * Address *address = addressCreateFromInterface(2);
+ *
+ * address_type type = addressGetType(address);
+ *
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ *
+ * @see address_type
+ */
+address_type addressGetType(const Address *address);
+
+/**
+ * Fills in the output parameter with an INET address.
+ *
+ * @param addr_in must be non-NULL
+ * @return true if INET address and output filled in, false otherwise.
+ *
+ */
+bool addressGetInet(const Address *address, struct sockaddr_in *addr_in);
+
+/**
+ * Retrieve the INET6 address associated with a `Address` instance.
+ *
+ * If the specified Address instance is of type {@link commandAddrType_INET6},
+ * then populate the supplied `struct sockaddr_in6` from the Address and return
+ * true. If the Address is not of type `commandAddrType_INET6`, this function
+ * returns false.
+ *
+ * @param [in] address A pointer to a `Address` instance of type {@link
+ * commandAddrType_INET6}.
+ * @param [in] addr_in6 A pointer to a `struct sockaddr_in6`. Must be non-NULL.
+ * @return true If the Address instance is of type `commandAddrType_INET6` and
+ * `addr_in6` was filled in
+ * @return false If the Address instance was not of type `commandAddrType_INET6`
+ * or `addr_in6` could not be filled in.
+ *
+ * @see addressGetType
+ */
+bool addressGetInet6(const Address *address, struct sockaddr_in6 *addr_in6);
+
+/**
+ * Retrieve the interface index associated with a `Address` instance.
+ *
+ * If the specified `Address` instance is of type {@link commandAddrType_IFACE},
+ * then populate the supplied `uint32_t` from the Address and return true. If
+ * the `Address` is not of type `commandAddrType_INET6`, this function returns
+ * false.
+ *
+ * @param [in] address A pointer to a `Address` instance of type {@link
+ * commandAddrType_IFACE}.
+ * @param [in] interfaceIndex A pointer to a `uint32_t` to fill in. Must be
+ * non-NULL.
+ * @return true If the Address instance is of type `commandAddrType_IFACE` and
+ * `interfaceIndex` was filled in.
+ * @return false If the Address instance was not of type `commandAddrType_IFACE`
+ * or `interfaceIndex` could not be filled in.
+ *
+ * @see addressGetType
+ */
+bool addressGetInterfaceIndex(const Address *address, uint32_t *interfaceIndex);
+
+/**
+ * Retrieve the link address associated with a `Address` instance.
+ *
+ * If the specified `Address` instance is of type {@link commandAddrType_LINK},
+ * then return a pointer to the {@link PARCBuffer} containing the link address.
+ * If the `Address` is not of type {@link commandAddrType_LINK}, then return
+ * NULL. The returned PARCBuffer pointer points to memory managed by the Address
+ * instance, and does not need to be destroyed or released on its own.
+ *
+ * @param [in] address A pointer to a `Address` instance of type {@link
+ * commandAddrType_LINK}.
+ * @return A pointer to the {@link PARCBuffer} containing the link address.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 };
+ * Address *address = addressCreateFromLink(mac, sizeof(mac));
+ *
+ * PARCBuffer *macBuffer = addressGetLinkAddress(address);
+ *
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressGetType
+ */
+PARCBuffer *addressGetLinkAddress(const Address *address);
+
+/**
+ * Append the string representation of a `Address` to a specified
+ * `PARCBufferComposer`.
+ *
+ * @param [in] address A pointer to a `Address` instance.
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance to which to
+ * append the string.
+ *
+ * @return The `PARCBufferComposer` instance that was passed in.
+ *
+ * Example:
+ * @code
+ * {
+ * Address *address = addressCreateFromInterface(1);
+ * PARCBufferComposer *composer = addressBuildString(address,
+ * parcBufferComposer_Create()); parcBufferComposer_Release(&composer);
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ *
+ * @see PARCBufferComposer
+ */
+PARCBufferComposer *addressBuildString(const Address *address,
+ PARCBufferComposer *composer);
+
+/**
+ * Produce a nil-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] interest A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, nul-terminated C string that must
+ * be deallocated via {@link parcMemory_Deallocate}().
+ *
+ * Example:
+ * @code
+ * {
+ * Address *address = addressCreateFromInterface(1);
+ *
+ * char *string = addressToString(address);
+ *
+ * if (string != NULL) {
+ * printf("Address looks like: %s\n", string);
+ * parcMemory_Deallocate(string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * addressDestroy(&address);
+ * }
+ * @endcode
+ * @see parcMemory_Deallocate
+ * @see addressBuildString
+ */
+char *addressToString(const Address *address);
+
+/**
+ * Return a non-cryptographic hash code consistent with Equals
+ *
+ * If commandAddrA == commandAddrB, then addressHashCode(commandAddrA) ==
+ * addressHashCode(commandAddrB)
+ *
+ * @param [in] address A pointer to a Address instance.
+ * @return A 32-bit hashcode for the specified Address instance.
+ *
+ * Example:
+ * @code
+ * Address *address = addressCreateFromInterface(1);
+ *
+ * uint32_t hashCode = addressHashCode(address);
+ *
+ * addressDestroy(&address);
+ * @endcode
+ */
+PARCHashCode addressHashCode(const Address *address);
+#endif // address_h
diff --git a/hicn-light/src/utils/addressList.c b/hicn-light/src/utils/addressList.c
new file mode 100755
index 000000000..4f51a11bf
--- /dev/null
+++ b/hicn-light/src/utils/addressList.c
@@ -0,0 +1,133 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/addressList.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+
+struct address_list {
+ PARCArrayList *listOfAddress;
+};
+
+static void _addressListFreeAddress(void **addressVoidPtr) {
+ Address **addressPtr = (Address **)addressVoidPtr;
+ addressDestroy(addressPtr);
+}
+
+AddressList *addressListCreate() {
+ AddressList *list = parcMemory_AllocateAndClear(sizeof(AddressList));
+ parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(AddressList));
+ list->listOfAddress = parcArrayList_Create(_addressListFreeAddress);
+ parcAssertNotNull(list->listOfAddress, "Got null from parcArrayList_Create");
+
+ return list;
+}
+
+void addressListDestroy(AddressList **addressListPtr) {
+ parcAssertNotNull(addressListPtr,
+ "Parameter must be non-null double pointer");
+ parcAssertNotNull(*addressListPtr,
+ "Parameter must dereference to non-null pointer");
+ AddressList *list = *addressListPtr;
+
+ parcArrayList_Destroy(&list->listOfAddress);
+ parcMemory_Deallocate((void **)&list);
+ *addressListPtr = NULL;
+}
+
+AddressList *addressListAppend(AddressList *list, Address *address) {
+ parcAssertNotNull(list, "Parameter list must be non-null");
+ parcAssertNotNull(address, "Parameter address must be non-null");
+
+ parcArrayList_Add(list->listOfAddress, (PARCObject *)address);
+ return list;
+}
+
+AddressList *addressListCopy(const AddressList *original) {
+ parcAssertNotNull(original, "Parameter must be non-null");
+
+ AddressList *copy = addressListCreate();
+ for (int i = 0; i < parcArrayList_Size(original->listOfAddress); i++) {
+ Address *address = (Address *)parcArrayList_Get(original->listOfAddress, i);
+ parcArrayList_Add(copy->listOfAddress, (PARCObject *)addressCopy(address));
+ }
+
+ return copy;
+}
+
+bool addressListEquals(const AddressList *a, const AddressList *b) {
+ parcAssertNotNull(a, "Parameter a must be non-null");
+ parcAssertNotNull(b, "Parameter b must be non-null");
+
+ if (a == b) {
+ return true;
+ }
+
+ if (parcArrayList_Size(a->listOfAddress) !=
+ parcArrayList_Size(b->listOfAddress)) {
+ return false;
+ }
+
+ for (size_t i = 0; i < parcArrayList_Size(a->listOfAddress); i++) {
+ const Address *addr_a = (Address *)parcArrayList_Get(a->listOfAddress, i);
+ const Address *addr_b = (Address *)parcArrayList_Get(b->listOfAddress, i);
+ if (!addressEquals(addr_a, addr_b)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+size_t addressListLength(const AddressList *list) {
+ parcAssertNotNull(list, "Parameter must be non-null");
+ return parcArrayList_Size(list->listOfAddress);
+}
+
+const Address *addressListGetItem(const AddressList *list, size_t item) {
+ parcAssertNotNull(list, "Parameter must be non-null");
+ parcAssertTrue(item < addressListLength(list),
+ "Asked for item %zu beyond end of list %zu", item,
+ addressListLength(list));
+
+ return (Address *)parcArrayList_Get(list->listOfAddress, item);
+}
+
+char *addressListToString(const AddressList *list) {
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ for (size_t i = 0; i < addressListLength(list); i++) {
+ char *addressString = addressToString(addressListGetItem(list, i));
+ parcBufferComposer_PutString(composer, addressString);
+ if (i < (addressListLength(list) - 1)) {
+ parcBufferComposer_PutString(composer, " ");
+ }
+ parcMemory_Deallocate((void **)&addressString);
+ }
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(buffer);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/hicn-light/src/utils/addressList.h b/hicn-light/src/utils/addressList.h
new file mode 100755
index 000000000..bcb312c14
--- /dev/null
+++ b/hicn-light/src/utils/addressList.h
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+/**
+ * @brief A list of Address instances.
+ *
+ * An AddressList is a list of addresses.
+ * It wraps a PARCLinkedList for type saftey with Address.
+ *
+ */
+#ifndef address_list_h
+#define address_list_h
+
+#include <src/utils/address.h>
+
+struct address_list;
+/**
+ * @typedef AddressList
+ * @abstract A list of Address instance pointers.
+ */
+typedef struct address_list AddressList;
+
+/**
+ * Create an instance of {@link AddressList}
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a valid AddressList instance.
+ *
+ * Example:
+ * @code
+ * {
+ * AddressList *list = addressListCreate();
+ *
+ * }
+ * @endcode
+ *
+ * @see addressListDestroy
+ */
+AddressList *addressListCreate(void);
+
+/**
+ * Dellocate and destroy a AddressList instance.
+ *
+ * @param [in] addressListPtr A pointer to a pointer to a valid {@link
+ * AddressList}.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * AddressList *list = addressListCreate(void);
+ * addressListDestroy(&list);
+ * }
+ * @endcode
+ *
+ * @see addressListCreate
+ */
+void addressListDestroy(AddressList **addressListPtr);
+
+/**
+ * Appends the address, taking ownership of the memory
+ *
+ * @param list A pointer to a AddressList.
+ * @param address must be non-null
+ * @return The input list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+AddressList *addressListAppend(AddressList *list, Address *address);
+
+/**
+ * Creates a reference counted copy
+ *
+ * @param list A pointer to a valid {@link AddressList}.
+ *
+ * @return An allocated list, you must destroy it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+AddressList *addressListCopy(const AddressList *list);
+
+/**
+ * Determine if two AddressList instances are equal.
+ *
+ * Two AddressList instances are equal if, and only if, they have the same
+ * length, with the same elements in the same order.
+ *
+ *
+ * The following equivalence relations on non-null `AddressList` instances are
+ * maintained:
+ *
+ * * It is reflexive: for any non-null reference value x,
+ * `AddressList_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `AddressList_Equals(x, y)` must return true if and only if
+ * `addressListEquals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `addressListEquals(x, y)` returns true and
+ * `addressListEquals(y, z)` returns true,
+ * then `addressListEquals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `addressListEquals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `addressListEquals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `AddressList` instance.
+ * @param b A pointer to a `AddressList` instance.
+ * @return true if the two `AddressList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * AddressList *a = addressListCreate();
+ * AddressList *b = addressListCreate();
+ *
+ * if (addressListEquals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool addressListEquals(const AddressList *a, const AddressList *b);
+
+/**
+ * Get the number of items in the list
+ *
+ * @param list A pointer to a {@link AddressList}.
+ * @return The number of items in the list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t addressListLength(const AddressList *list);
+
+/**
+ * Returns a const reference to an item.
+ * Use addressCopy if needed.
+ *
+ * Do not free or modify the returned value.
+ * Use addressCopy if you need a mutable instance.
+ *
+ * @param list A pointer to a AddressList.
+ * @param item A value less than the number of items in the given {@link
+ * AddressList}.
+ * @return Asserts if item off end of list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const Address *addressListGetItem(const AddressList *list, size_t item);
+
+/**
+ * Get a nul-terminated, C-string representation of the given {@link
+ * AddressList}.
+ *
+ * @param list A pointer to a valid {@link AddressList} instance.
+ *
+ * @return An allocate string representation of the {@link AddressList} that
+ * must be freed via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *addressListToString(const AddressList *list);
+#endif // address_list_h
diff --git a/hicn-light/src/utils/commands.h b/hicn-light/src/utils/commands.h
new file mode 100755
index 000000000..2f8ebcbfe
--- /dev/null
+++ b/hicn-light/src/utils/commands.h
@@ -0,0 +1,282 @@
+/*
+ * 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 commands.h
+ * @brief All hicn-light commands: 14 in total.
+ *
+ * Header and payload in binary format.
+ */
+
+#ifndef commands_h
+#define commands_h
+
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+typedef struct in6_addr ipv6_addr_t;
+typedef uint32_t ipv4_addr_t;
+
+union commandAddr {
+ ipv4_addr_t ipv4;
+ ipv6_addr_t ipv6;
+};
+
+typedef enum {
+ REQUEST_LIGHT = 100,
+ RESPONSE_LIGHT,
+ ACK_LIGHT,
+ NACK_LIGHT,
+ LAST_MSG_TYPE_VALUE
+} message_type;
+
+typedef enum {
+ ADD_LISTENER,
+ ADD_CONNECTION,
+ LIST_CONNECTIONS,
+ ADD_ROUTE,
+ LIST_ROUTES,
+ REMOVE_CONNECTION,
+ REMOVE_ROUTE,
+ CACHE_STORE,
+ CACHE_SERVE,
+ CACHE_CLEAR,
+ SET_STRATEGY,
+ SET_WLDR,
+ ADD_PUNTING,
+ LIST_LISTENERS,
+ MAPME_ENABLE,
+ MAPME_DISCOVERY,
+ MAPME_TIMESCALE,
+ MAPME_RETX,
+ LAST_COMMAND_VALUE
+} command_id;
+
+typedef enum {
+ ADDR_INET = 1,
+ ADDR_INET6,
+ ADDR_LINK,
+ ADDR_IFACE,
+ ADDR_UNIX /* PF_UNIX */
+} address_type;
+
+typedef enum {
+ UDP_CONN,
+ TCP_CONN,
+ GRE_CONN, // not implemented
+ HICN_CONN
+} connection_type;
+
+typedef enum { ACTIVATE_ON, ACTIVATE_OFF } activate_type;
+
+//========== HEADER ==========
+
+typedef struct {
+ uint8_t messageType;
+ uint8_t commandID;
+ uint16_t length; // tells the number of structures in the payload
+ uint32_t seqNum;
+} header_control_message;
+// for the moment has to be at least 8 bytes
+
+// SIZE=8
+
+//========== [00] ADD LISTENER ==========
+
+typedef enum { ETHER_MODE, IP_MODE, HICN_MODE } listener_mode;
+
+typedef struct {
+ char symbolic[16];
+ // char interfaceName[16];
+ union commandAddr address;
+ uint16_t port;
+ // uint16_t etherType;
+ uint8_t addressType;
+ uint8_t listenerMode;
+ uint8_t connectionType;
+} add_listener_command;
+
+// SIZE=40
+
+//========== [01] ADD CONNECTION ==========
+
+typedef struct {
+ char symbolic[16];
+ union commandAddr remoteIp;
+ union commandAddr localIp;
+ uint16_t remotePort;
+ uint16_t localPort;
+ uint8_t ipType;
+ uint8_t connectionType;
+} add_connection_command;
+
+// SIZE=56
+
+//========== [02] LIST CONNECTIONS ==========
+
+typedef enum {
+ CONN_GRE,
+ CONN_TCP,
+ CONN_UDP,
+ CONN_MULTICAST,
+ CONN_L2,
+ CONN_HICN
+} list_connections_type;
+
+typedef enum {
+ IFACE_UP = 0,
+ IFACE_DOWN = 1,
+ IFACE_UNKNOWN = 2 // not used actually
+} connection_state;
+
+typedef struct {
+ add_connection_command connectionData;
+ uint32_t connid;
+ uint8_t state;
+} list_connections_command;
+
+// SIZE=64
+
+//========== [03] ADD ROUTE ==========
+
+typedef struct {
+ char symbolicOrConnid[16];
+ union commandAddr address;
+ uint16_t cost;
+ uint8_t addressType;
+ uint8_t len;
+} add_route_command;
+
+// SIZE=36
+
+//========== [04] LIST ROUTE ==========
+
+typedef struct {
+ union commandAddr address;
+ uint32_t connid;
+ uint16_t cost;
+ uint8_t addressType;
+ uint8_t len;
+} list_routes_command;
+
+// SIZE=24
+
+//========== [05] REMOVE CONNECTION ==========
+
+typedef struct {
+ char symbolicOrConnid[16];
+} remove_connection_command;
+
+// SIZE=16
+
+//========== [06] REMOVE ROUTE ==========
+
+typedef struct {
+ char symbolicOrConnid[16];
+ union commandAddr address;
+ uint8_t addressType;
+ uint8_t len;
+} remove_route_command;
+
+// SIZE=36
+
+//========== [07] CACHE STORE ==========
+
+typedef struct {
+ uint8_t activate;
+} cache_store_command;
+
+// SIZE=1
+
+//========== [08] CACHE SERVE ==========
+
+typedef struct {
+ uint8_t activate;
+} cache_serve_command;
+
+// SIZE=1
+
+//========== [09] 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;
+
+typedef struct {
+ union commandAddr address;
+ uint8_t strategyType;
+ uint8_t addressType;
+ uint8_t len;
+} set_strategy_command;
+
+// SIZE=20
+
+//========== [11] SET WLDR ==========
+
+typedef struct {
+ char symbolicOrConnid[16];
+ uint8_t activate;
+} set_wldr_command;
+
+// SIZE=17
+
+//========== [12] ADD PUNTING ==========
+
+typedef struct {
+ char symbolicOrConnid[16];
+ union commandAddr address;
+ uint8_t addressType;
+ uint8_t len;
+} add_punting_command;
+
+// SIZE=36
+
+//========== [13] LIST LISTENER ==========
+
+typedef struct {
+ union commandAddr address;
+ uint32_t connid;
+ uint16_t port;
+ uint8_t addressType;
+ uint8_t encapType;
+} list_listeners_command;
+
+// SIZE=24
+
+//========== [14] MAPME ==========
+
+// (enable/discovery/timescale/retx)
+
+typedef struct {
+ uint8_t activate;
+} mapme_activator_command;
+
+// SIZE=1
+
+typedef struct {
+ uint32_t timePeriod;
+} mapme_timing_command;
+
+// SIZE=1
+
+#endif
diff --git a/hicn-light/src/utils/interface.c b/hicn-light/src/utils/interface.c
new file mode 100755
index 000000000..ab7a88f0f
--- /dev/null
+++ b/hicn-light/src/utils/interface.c
@@ -0,0 +1,168 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <src/utils/addressList.h>
+#include <src/utils/interface.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/utils/commands.h>
+
+struct interface {
+ char *name;
+ unsigned interfaceIndex;
+ bool loopback;
+ bool supportMulticast;
+ unsigned mtu;
+
+ AddressList *addressList;
+};
+
+char *interfaceToString(const Interface *interface) {
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_Format(
+ composer, "%3u %10s %1s%1s %8u ", interface->interfaceIndex,
+ interface->name, interface->loopback ? "l" : " ",
+ interface->supportMulticast ? "m" : " ", interface->mtu);
+
+ for (size_t i = 0; i < addressListLength(interface->addressList); i++) {
+ addressBuildString(addressListGetItem(interface->addressList, i), composer);
+ if (i < (addressListLength(interface->addressList) - 1)) {
+ parcBufferComposer_PutStrings(composer, "\n", NULL);
+ }
+ }
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ return result;
+}
+
+Interface *interfaceCreate(const char *name, unsigned interfaceIndex,
+ bool loopback, bool supportMulticast, unsigned mtu) {
+ Interface *iface = parcMemory_AllocateAndClear(sizeof(Interface));
+
+ parcAssertNotNull(iface, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(Interface));
+ iface->name = parcMemory_StringDuplicate(name, 64);
+ iface->interfaceIndex = interfaceIndex;
+ iface->loopback = loopback;
+ iface->supportMulticast = supportMulticast;
+ iface->mtu = mtu;
+ iface->addressList = addressListCreate();
+
+ return iface;
+}
+
+void interfaceDestroy(Interface **interfacePtr) {
+ parcAssertNotNull(interfacePtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*interfacePtr,
+ "Parameter must dereference to non-null pointer");
+
+ Interface *iface = *interfacePtr;
+ parcMemory_Deallocate((void **)&iface->name);
+ addressListDestroy(&iface->addressList);
+ parcMemory_Deallocate((void **)&iface);
+ interfacePtr = NULL;
+}
+
+void interfaceAddAddress(Interface *iface, Address *address) {
+ parcAssertNotNull(iface, "Parameter iface must be non-null");
+
+ size_t length = addressListLength(iface->addressList);
+ for (size_t i = 0; i < length; i++) {
+ const Address *a = addressListGetItem(iface->addressList, i);
+ if (addressEquals(a, address)) {
+ return;
+ }
+ }
+
+ addressListAppend(iface->addressList, address);
+}
+
+const AddressList *interfaceGetAddresses(const Interface *iface) {
+ parcAssertNotNull(iface, "Parameter iface must be non-null");
+ return iface->addressList;
+}
+
+unsigned interfaceGetInterfaceIndex(const Interface *iface) {
+ parcAssertNotNull(iface, "Parameter iface must be non-null");
+ return iface->interfaceIndex;
+}
+
+bool interfaceNameEquals(const Interface *iface, const char *name) {
+ parcAssertNotNull(iface, "Parameter iface must be non-null");
+
+ if (strcasecmp(iface->name, name) == 0) {
+ return true;
+ }
+ return false;
+}
+
+bool interfaceEquals(const Interface *a, const Interface *b) {
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->interfaceIndex == b->interfaceIndex) {
+ if (a->loopback == b->loopback) {
+ if (a->supportMulticast == b->supportMulticast) {
+ if (a->mtu == b->mtu) {
+ if (strcasecmp(a->name, b->name) == 0) {
+ if (addressListEquals(a->addressList, b->addressList)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+// static const char light_Iface[] = "Interface";
+// static const char light_IfName[] = "Name";
+// static const char light_IFIDX[] = "Index";
+// static const char light_IsLoopback[] = "Loopback";
+// static const char light_Multicast[] = "Multicast";
+// static const char light_MTU[] = "MTU";
+
+// static const char light_True[] = "true";
+// static const char light_False[] = "false";
+// static const char light_Addrs[] = "Addrs";
+
+const char *interfaceGetName(const Interface *iface) {
+ parcAssertNotNull(iface, "Parameter iface must be non-null");
+ return iface->name;
+}
+
+unsigned interfaceGetMTU(const Interface *iface) {
+ parcAssertNotNull(iface, "Parameter iface must be non-null");
+ return iface->mtu;
+}
diff --git a/hicn-light/src/utils/interface.h b/hicn-light/src/utils/interface.h
new file mode 100755
index 000000000..0810ec053
--- /dev/null
+++ b/hicn-light/src/utils/interface.h
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+/**
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef interface_h
+#define interface_h
+
+#include <src/utils/address.h>
+#include <src/utils/addressList.h>
+
+struct interface;
+typedef struct interface Interface;
+
+/**
+ * Creates a representation of an interface
+ *
+ * The name is copied. Creates a representation of a system interface.
+ *
+ * @param <#param1#>
+ * @return An allocated object, you must call <code>interfaceDestroy()</code>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceCreate(const char *name, unsigned interfaceIndex,
+ bool loopback, bool supportMulticast, unsigned mtu);
+
+void interfaceDestroy(Interface **interfacePtr);
+
+/**
+ * Adds an address to an interface
+ *
+ * Does not allow duplicates, if already exists is not added again
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void interfaceAddAddress(Interface *iface, Address *address);
+
+/**
+ * Retrieves a list of interface addresses
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return Will not be NULL, but may be empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const AddressList *interfaceGetAddresses(const Interface *iface);
+
+/**
+ * The interface index
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+unsigned interfaceGetInterfaceIndex(const Interface *iface);
+
+/**
+ * Returns the interface name, e.g. "eth0"
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] iface An allocated Interface
+ *
+ * @return non-null The interface Name as a C-string
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *interfaceGetName(const Interface *iface);
+
+/**
+ * Returns the Maximum Transmission Unit (MTU) of the interface
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] iface An allocated Interface
+ *
+ * @return number The MTU as reported by the kernel
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+unsigned interfaceGetMTU(const Interface *iface);
+
+/**
+ * Determine if two InterfaceName instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `InterfaceName` instances are
+ * maintained:
+ *
+ * * It is reflexive: for any non-null reference value x,
+ * `InterfaceName_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `InterfaceName_Equals(x, y)` must return true if and only if
+ * `InterfaceName_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `InterfaceName_Equals(x, y)` returns true and
+ * `InterfaceName_Equals(y, z)` returns true,
+ * then `InterfaceName_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `InterfaceName_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `InterfaceName_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `InterfaceName` instance.
+ * @param b A pointer to a `InterfaceName` instance.
+ * @return true if the two `InterfaceName` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * InterfaceName *a = InterfaceName_Create();
+ * InterfaceName *b = InterfaceName_Create();
+ *
+ * if (InterfaceName_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool interfaceNameEquals(const Interface *iface, const char *name);
+
+/**
+ * Two Interfaces are idential
+ *
+ * All properties must be the same. The order of addresses matters, and
+ * they must have been added to the address list in the same order.
+ *
+ * The interface name match is case in-sensitive.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool interfaceEquals(const Interface *a, const Interface *b);
+
+/**
+ * <#OneLineDescription#>
+ *
+ * <#Discussion#>
+ *
+ * @param interface A Interface structure pointer.
+ * @return An allocate string representation of the Interface that must be freed
+ * via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *interfaceToString(const Interface *interface);
+#endif // interface_h
diff --git a/hicn-light/src/utils/interfaceSet.c b/hicn-light/src/utils/interfaceSet.c
new file mode 100755
index 000000000..3f56ec167
--- /dev/null
+++ b/hicn-light/src/utils/interfaceSet.c
@@ -0,0 +1,149 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <src/utils/interfaceSet.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct interfaceSet {
+ PARCArrayList *listOfInterfaces;
+};
+
+static void _destroyInterface(void **ifaceVoidPtr) {
+ interfaceDestroy((Interface **)ifaceVoidPtr);
+}
+
+InterfaceSet *interfaceSetCreate(void) {
+ InterfaceSet *set = parcMemory_AllocateAndClear(sizeof(InterfaceSet));
+ parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(InterfaceSet));
+ set->listOfInterfaces = parcArrayList_Create(_destroyInterface);
+ return set;
+}
+
+void interfaceSetDestroy(InterfaceSet **setPtr) {
+ parcAssertNotNull(setPtr, "Parameter must be non-null double pointer");
+ parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer");
+
+ InterfaceSet *set = *setPtr;
+ parcArrayList_Destroy(&set->listOfInterfaces);
+ parcMemory_Deallocate((void **)&set);
+ *setPtr = NULL;
+}
+
+bool interfaceSetAdd(InterfaceSet *set, Interface *iface) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ parcAssertNotNull(iface, "Parameter iface must be non-null");
+
+ unsigned ifaceIndex = interfaceGetInterfaceIndex(iface);
+ size_t length = parcArrayList_Size(set->listOfInterfaces);
+ for (size_t i = 0; i < length; i++) {
+ Interface *listEntry =
+ (Interface *)parcArrayList_Get(set->listOfInterfaces, i);
+ unsigned entryInterfaceIndex = interfaceGetInterfaceIndex(listEntry);
+ if (entryInterfaceIndex == ifaceIndex) {
+ return false;
+ }
+ }
+
+ parcArrayList_Add(set->listOfInterfaces, (PARCObject *)iface);
+ return true;
+}
+
+size_t interfaceSetLength(const InterfaceSet *set) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ return parcArrayList_Size(set->listOfInterfaces);
+}
+
+Interface *interfaceSetGetByOrdinalIndex(InterfaceSet *set,
+ size_t ordinalIndex) {
+ parcAssertNotNull(set, "Parameter set must be non-null");
+ return (Interface *)parcArrayList_Get(set->listOfInterfaces, ordinalIndex);
+}
+
+Interface *interfaceSetGetByInterfaceIndex(const InterfaceSet *set,
+ unsigned interfaceIndex) {
+ size_t length = parcArrayList_Size(set->listOfInterfaces);
+ for (size_t i = 0; i < length; i++) {
+ Interface *listEntry =
+ (Interface *)parcArrayList_Get(set->listOfInterfaces, i);
+ unsigned entryInterfaceIndex = interfaceGetInterfaceIndex(listEntry);
+ if (entryInterfaceIndex == interfaceIndex) {
+ return listEntry;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Uses the system name (e.g. "en0")
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceSetGetByName(InterfaceSet *set, const char *name) {
+ size_t length = parcArrayList_Size(set->listOfInterfaces);
+ for (size_t i = 0; i < length; i++) {
+ Interface *listEntry =
+ (Interface *)parcArrayList_Get(set->listOfInterfaces, i);
+ if (interfaceNameEquals(listEntry, name)) {
+ return listEntry;
+ }
+ }
+ return NULL;
+}
+
+bool interfaceSetEquals(const InterfaceSet *a, const InterfaceSet *b) {
+ if (a == NULL && b == NULL) {
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ size_t length_a = parcArrayList_Size(a->listOfInterfaces);
+ size_t length_b = parcArrayList_Size(b->listOfInterfaces);
+
+ if (length_a == length_b) {
+ for (size_t i = 0; i < length_a; i++) {
+ Interface *iface_a =
+ (Interface *)parcArrayList_Get(a->listOfInterfaces, i);
+
+ // the set is unique by interface id, so if it exists in set b, it
+ // exists there by interface id
+ Interface *iface_b = interfaceSetGetByInterfaceIndex(
+ b, interfaceGetInterfaceIndex(iface_a));
+ if (!interfaceEquals(iface_b, iface_b)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/hicn-light/src/utils/interfaceSet.h b/hicn-light/src/utils/interfaceSet.h
new file mode 100755
index 000000000..8eb8397fb
--- /dev/null
+++ b/hicn-light/src/utils/interfaceSet.h
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+/**
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef InterfaceSet_h
+#define InterfaceSet_h
+
+#include <src/utils/interface.h>
+
+struct interfaceSet;
+/**
+ *
+ * @see interfaceSetCreate
+ */
+typedef struct interfaceSet InterfaceSet;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+InterfaceSet *interfaceSetCreate(void);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void interfaceSetDestroy(InterfaceSet **setPtr);
+
+/**
+ * Adds interface to set, does not allow duplicates
+ *
+ * Takes ownership of the iface memory if added
+ *
+ * Duplicates are two entries with the same interface index
+ *
+ * @param <#param1#>
+ * @return true if added, false if not (likely a duplicate)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool interfaceSetAdd(InterfaceSet *set, Interface *iface);
+
+/**
+ * The number of interfaces in the set
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t interfaceSetLength(const InterfaceSet *set);
+
+/**
+ * Uses the ordinal index of the interface in the Set
+ *
+ * Ranges from 0 .. <code>interfaceSetLength()-1</code>.
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceSetGetByOrdinalIndex(InterfaceSet *set,
+ size_t ordinalIndex);
+
+/**
+ * Retreives by the assigned interface index
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceSetGetByInterfaceIndex(const InterfaceSet *set,
+ unsigned interfaceIndex);
+
+/**
+ * Uses the system name (e.g. "en0")
+ *
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceSetGetByName(InterfaceSet *set, const char *name);
+
+/**
+ * Determine if two InterfaceSet instances are equal.
+ *
+ * Two InterfaceSet instances are equal if, and only if, the sets contain the
+ * same elements
+ * - order independent.
+ * Each element is compared via <code>interfaceEquals()</code>
+ *
+ * The following equivalence relations on non-null `InterfaceSet` instances are
+ * maintained:
+ *
+ * * It is reflexive: for any non-null reference value x,
+ * `InterfaceSet_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `InterfaceSet_Equals(x, y)` must return true if and only if
+ * `interfaceSetEquals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `interfaceSetEquals(x, y)` returns true and
+ * `interfaceSetEquals(y, z)` returns true,
+ * then `interfaceSetEquals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `interfaceSetEquals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `interfaceSetEquals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `InterfaceSet` instance.
+ * @param b A pointer to a `InterfaceSet` instance.
+ * @return true if the two `InterfaceSet` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * InterfaceSet *a = interfaceSetCreate();
+ * InterfaceSet *b = interfaceSetCreate();
+ *
+ * if (interfaceSetEquals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool interfaceSetEquals(const InterfaceSet *a, const InterfaceSet *b);
+#endif // InterfaceSet_h
diff --git a/hicn-light/src/utils/punting.c b/hicn-light/src/utils/punting.c
new file mode 100755
index 000000000..9352732fe
--- /dev/null
+++ b/hicn-light/src/utils/punting.c
@@ -0,0 +1,98 @@
+/*
+ * 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <src/utils/punting.h>
+
+struct punting {
+ char *symbolic;
+ Address *prefix;
+ uint32_t len;
+};
+
+Punting *puntingCreate(const char *listenerName, Address *prefix,
+ uint32_t len) {
+ parcAssertNotNull(listenerName, "Parameter listenerName must be non-null");
+ parcAssertNotNull(prefix, "Parameter prefix must be non-null");
+
+ Punting *punting = parcMemory_AllocateAndClear(sizeof(Punting));
+ if (punting) {
+ punting->symbolic =
+ parcMemory_StringDuplicate(listenerName, strlen(listenerName));
+ punting->prefix = addressCopy(prefix);
+ punting->len = len;
+ }
+
+ return punting;
+}
+
+void puntingRelease(Punting **puntingPtr) {
+ parcAssertNotNull(puntingPtr,
+ "Parameter puntingPtr must be non-null double pointer");
+ parcAssertNotNull(*puntingPtr,
+ "Parameter puntingPtr dereference to non-null pointer");
+
+ Punting *punting = *puntingPtr;
+
+ if (punting->symbolic) {
+ parcMemory_Deallocate((void **)&punting->symbolic);
+ }
+
+ if (punting->prefix) {
+ addressDestroy(&punting->prefix);
+ }
+
+ parcMemory_Deallocate((void **)&punting);
+ *puntingPtr = NULL;
+}
+
+bool puntingEquals(const Punting *a, const Punting *b) {
+ if ((a == NULL && b == NULL) || a == b) {
+ // both null or identically equal
+ return true;
+ }
+
+ if (a == NULL || b == NULL) {
+ // only one is null
+ return false;
+ }
+
+ if ((strcmp(a->symbolic, b->symbolic) == 0) &&
+ (addressEquals(a->prefix, b->prefix)) && (a->len == b->len)) {
+ return true;
+ }
+
+ return false;
+}
+
+const char *puntingGetSymbolicName(const Punting *punting) {
+ parcAssertNotNull(punting, "Parameter listener must be non-null");
+ return punting->symbolic;
+}
+
+Address *puntingGetAddress(const Punting *punting) {
+ parcAssertNotNull(punting, "Parameter listener must be non-null");
+ return punting->prefix;
+}
+
+uint32_t puntingPrefixLen(const Punting *punting) {
+ parcAssertNotNull(punting, "Parameter listener must be non-null");
+ return punting->len;
+}
diff --git a/hicn-light/src/utils/punting.h b/hicn-light/src/utils/punting.h
new file mode 100755
index 000000000..03841c5ad
--- /dev/null
+++ b/hicn-light/src/utils/punting.h
@@ -0,0 +1,72 @@
+/*
+ * 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 punting_h
+#define punting_h
+
+struct punting;
+typedef struct punting Punting;
+
+#include <src/utils/address.h>
+
+/**
+ * Creates a Punting object
+ *
+ * The symbolic name represents this listener and may be used by other commands.
+ * It must be unique, otherwise the command will fail when sent to the
+ * forwarder.
+ *
+ * @param [in] symbolic name of the listener
+ * @param [in] prefix address to add to the punting rule
+ * @param [in] len prefix length
+ *
+ * @return non-null An Allocated object
+ * @return null An error
+ *
+ */
+Punting *puntingCreate(const char *symbolic, Address *prefix, uint32_t len);
+
+/**
+ * Releases a reference count to the object
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in,out] etherConnPtr A pointer to an etherConn object, will be
+ * null'd.
+ *
+ */
+void puntingRelease(Punting **puntingPtr);
+
+/**
+ * Determine if two light Punting are equal.
+ *
+ */
+
+bool puntingEquals(const Punting *a, const Punting *b);
+
+/**
+ * Returns the symbolic name
+ *
+ */
+const char *puntingGetSymbolicName(const Punting *punting);
+
+/**
+ * Returns the address (INET or INET6 ip address)
+ *
+ */
+Address *puntingGetAddress(const Punting *punting);
+
+uint32_t puntingPrefixLen(const Punting *punting);
+#endif // punting_h
diff --git a/hicn-light/src/utils/utils.c b/hicn-light/src/utils/utils.c
new file mode 100755
index 000000000..a41478a4b
--- /dev/null
+++ b/hicn-light/src/utils/utils.c
@@ -0,0 +1,258 @@
+// Utility function for commands
+
+#include <ctype.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/utils/utils.h>
+
+// This is the unique sequence number used by all messages and its thread locks
+static pthread_mutex_t nextSequenceNumberMutex = PTHREAD_MUTEX_INITIALIZER;
+static uint32_t nextSequenceNumber = 1;
+
+uint32_t utils_GetNextSequenceNumber(void) {
+ uint32_t seqnum;
+
+ int result = pthread_mutex_lock(&nextSequenceNumberMutex);
+ parcAssertTrue(result == 0, "Got error from pthread_mutex_lock: %d", result);
+
+ seqnum = nextSequenceNumber++;
+
+ result = pthread_mutex_unlock(&nextSequenceNumberMutex);
+ parcAssertTrue(result == 0, "Got error from pthread_mutex_unlock: %d",
+ result);
+
+ return seqnum;
+}
+
+/**
+ * Return true if string is purely an integer
+ */
+bool utils_IsNumber(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.
+ */
+bool utils_ValidateSymbolicName(const char *symbolic) {
+ bool success = false;
+ size_t len = strlen(symbolic);
+ if (len > 0) {
+ if (isalpha(symbolic[0])) {
+ success = true;
+ for (size_t i = 1; i < len; i++) {
+ if (!isalnum(symbolic[i])) {
+ success = false;
+ break;
+ }
+ }
+ }
+ }
+ return success;
+}
+
+Address *utils_AddressFromInet(in_addr_t *addr4, in_port_t *port) {
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = *port;
+ addr.sin_addr.s_addr = *addr4;
+
+ Address *result = addressCreateFromInet(&addr);
+ return result;
+}
+
+Address *utils_AddressFromInet6(struct in6_addr *addr6, in_port_t *port) {
+ struct sockaddr_in6 addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = *port;
+ addr.sin6_addr = *addr6;
+ addr.sin6_scope_id = 0;
+ // Other 2 fields: scope_id and flowinfo, do not know what to put inside.
+
+ Address *result = addressCreateFromInet6(&addr);
+ return result;
+}
+
+struct iovec *utils_CreateAck(header_control_message *header, void *payload,
+ size_t payloadLen) {
+ struct iovec *response =
+ parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+ header->messageType = ACK_LIGHT;
+
+ response[0].iov_base = header;
+ response[0].iov_len = sizeof(header_control_message);
+ response[1].iov_base = payload;
+ response[1].iov_len = payloadLen;
+
+ return response;
+}
+
+struct iovec *utils_CreateNack(header_control_message *header, void *payload,
+ size_t payloadLen) {
+ struct iovec *response =
+ 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;
+ response[1].iov_len = payloadLen;
+
+ return response;
+}
+
+char *utils_BuildStringFromInet(in_addr_t *addr4, in_port_t *port) {
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = *port;
+ addr.sin_addr.s_addr = *addr4;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+ parcNetwork_SockInet4Address_BuildString(&addr, composer));
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ return result;
+}
+
+char *utils_BuildStringFromInet6(struct in6_addr *addr6, in_port_t *port) {
+ struct sockaddr_in6 addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = *port;
+ addr.sin6_addr = *addr6;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+ parcNetwork_SockInet6Address_BuildString(&addr, composer));
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ return result;
+}
+
+char *utils_CommandAddressToString(address_type addressType,
+ union commandAddr *address,
+ in_port_t *port) {
+ char *result;
+
+ switch (addressType) {
+ case ADDR_INET: {
+ result = utils_BuildStringFromInet(&address->ipv4, port);
+ break;
+ }
+
+ case ADDR_INET6: {
+ result = utils_BuildStringFromInet6(&address->ipv6, port);
+ break;
+ }
+
+ default: {
+ char *addrStr = (char *)parcMemory_Allocate(sizeof(char) * 32);
+ sprintf(addrStr, "Error: UNKNOWN address type = %d", addressType);
+ result = addrStr;
+ break;
+ }
+ }
+ return result;
+}
+
+struct iovec *utils_SendRequest(ControlState *state, command_id command,
+ void *payload, size_t payloadLen) {
+ bool success = false;
+
+ // get sequence number for the header
+ uint32_t currentSeqNum = utils_GetNextSequenceNumber();
+
+ // Allocate and fill the header
+ header_control_message *headerControlMessage =
+ parcMemory_AllocateAndClear(sizeof(header_control_message));
+ headerControlMessage->messageType = REQUEST_LIGHT;
+ headerControlMessage->commandID = command;
+ headerControlMessage->seqNum = currentSeqNum;
+ if (payloadLen > 0) {
+ headerControlMessage->length = 1;
+ }
+
+ struct iovec msg[2];
+ msg[0].iov_base = headerControlMessage;
+ msg[0].iov_len = sizeof(header_control_message);
+ msg[1].iov_base = payload;
+ msg[1].iov_len = payloadLen;
+
+ struct iovec *response = controlState_WriteRead(state, msg);
+
+ header_control_message *receivedHeader =
+ (header_control_message *)response[0].iov_base;
+ if (receivedHeader->seqNum != currentSeqNum) {
+ printf("Seq number is NOT correct: expected %d got %d \n", currentSeqNum,
+ receivedHeader->seqNum);
+ // failure
+ } else {
+ if (receivedHeader->messageType == RESPONSE_LIGHT) {
+ return response; // command needs both payload and header
+ } else {
+ if (receivedHeader->messageType == ACK_LIGHT) {
+ success = true;
+ } else if (receivedHeader->messageType == NACK_LIGHT) {
+ success = true;
+ } else {
+ printf("Error: unrecognized message type"); // failure
+ }
+ }
+ }
+
+ // deallocate when payload & header of the response are not needed
+ if (receivedHeader->length > 0) {
+ parcMemory_Deallocate(&response[1].iov_base); // free received payload
+ }
+ parcMemory_Deallocate(&response[0].iov_base); // free receivedHeader
+
+ // return response
+ if (success) {
+ return response;
+ } else {
+ parcMemory_Deallocate(&response); // free iovec pointer
+ return NULL; // will generate a failure
+ }
+}
+
+const char *utils_PrefixLenToString(address_type addressType,
+ union commandAddr *address,
+ uint8_t *prefixLen) {
+ char len[4]; // max size + 1
+ sprintf(len, "%u", (unsigned)*prefixLen);
+ in_port_t port = htons(1234); // this is a random port number that is ignored
+
+ char *prefix = utils_CommandAddressToString(addressType, address, &port);
+ char *prefixStr = malloc(strlen(prefix) + strlen(len) + 2);
+ strcpy(prefixStr, prefix);
+ strcat(prefixStr, "/");
+ strcat(prefixStr, len);
+
+ free(prefix);
+
+ return prefixStr;
+}
diff --git a/hicn-light/src/utils/utils.h b/hicn-light/src/utils/utils.h
new file mode 100755
index 000000000..1d2616941
--- /dev/null
+++ b/hicn-light/src/utils/utils.h
@@ -0,0 +1,82 @@
+/*
+ * 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 utils_h
+#define utils_h
+
+#include <src/config/controlState.h>
+#include <src/utils/address.h>
+#include <src/utils/commands.h>
+
+/**
+ * Return true if string is purely an integer
+ */
+bool utils_IsNumber(const char *string);
+
+/**
+ * A symbolic name must be at least 1 character and must begin with an alpha.
+ * The remainder must be an alphanum.
+ */
+bool utils_ValidateSymbolicName(const char *symbolic);
+
+/**
+ * Convert an internet address family (IPv4) to the address format used by the
+ * Fwd
+ */
+Address *utils_AddressFromInet(in_addr_t *addr4, in_port_t *port);
+
+/**
+ * Convert an internet address family (IPv6) to the address format used by the
+ * Fwd
+ */
+Address *utils_AddressFromInet6(struct in6_addr *addr6, in_port_t *port);
+
+/**
+ *Create an Ack message instance as a response of a control successfully
+ *completed.
+ */
+struct iovec *utils_CreateAck(header_control_message *header, void *payload,
+ size_t payloadLen);
+
+/**
+ *Create a Nack message instance as a response of a control unsuccessfully
+ *completed.
+ */
+struct iovec *utils_CreateNack(header_control_message *header, void *payload,
+ size_t payloadLen);
+
+/**
+ *Convert IPv4/IPv6 address from binary to text string. `uint8_t *ipAddress` has
+ *to be a `in_addr_t * or `a struct in6_addr *.
+ */
+char *utils_CommandAddressToString(address_type addressType,
+ union commandAddr *address, in_port_t *port);
+
+/**
+ *Given a command payload, it generates the header and send the request to the
+ *deamon.
+ */
+struct iovec *utils_SendRequest(ControlState *state, command_id command,
+ void *payload, size_t payloadLen);
+
+/**
+ *Convert a IPv4/IPv6 address plus Netmask len from binary to text string in the
+ *form [add]:[port]/[len].
+ */
+const char *utils_PrefixLenToString(address_type addressType,
+ union commandAddr *address,
+ uint8_t *prefixLen);
+
+#endif \ No newline at end of file