summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt48
-rw-r--r--CONTRIBUTORS4
-rw-r--r--LICENSE-LGPL2
-rw-r--r--appveyor.yml10
-rw-r--r--cmake/CmakeUninstall.cmake.in22
-rw-r--r--doc/man/fccntl.327
-rw-r--r--doc/man/flow_alloc.39
-rw-r--r--doc/man/flow_read.39
-rw-r--r--doc/man/fqueue.39
-rw-r--r--doc/man/fset.36
-rw-r--r--doc/man/ouroboros-glossary.76
-rw-r--r--doc/man/ouroboros-tutorial.76
-rw-r--r--doc/man/ouroboros.863
-rw-r--r--include/ouroboros/CMakeLists.txt3
-rw-r--r--include/ouroboros/bitmap.h12
-rw-r--r--include/ouroboros/btree.h6
-rw-r--r--include/ouroboros/cdefs.h6
-rw-r--r--include/ouroboros/cep.h (renamed from include/ouroboros/cacep.h)29
-rw-r--r--include/ouroboros/crc32.h12
-rw-r--r--include/ouroboros/crypt.h56
-rw-r--r--include/ouroboros/dev.h6
-rw-r--r--include/ouroboros/endian.h13
-rw-r--r--include/ouroboros/errno.h11
-rw-r--r--include/ouroboros/fccntl.h14
-rw-r--r--include/ouroboros/flow.h54
-rw-r--r--include/ouroboros/fqueue.h9
-rw-r--r--include/ouroboros/hash.h79
-rw-r--r--include/ouroboros/ipcp-dev.h65
-rw-r--r--include/ouroboros/ipcp.h157
-rw-r--r--include/ouroboros/irm.h34
-rw-r--r--include/ouroboros/list.h8
-rw-r--r--include/ouroboros/local-dev.h12
-rw-r--r--include/ouroboros/lockfile.h12
-rw-r--r--include/ouroboros/logs.h87
-rw-r--r--include/ouroboros/md5.h6
-rw-r--r--include/ouroboros/name.h40
-rw-r--r--include/ouroboros/notifier.h6
-rw-r--r--include/ouroboros/np1_flow.h32
-rw-r--r--include/ouroboros/proc.h44
-rw-r--r--include/ouroboros/proto.h6
-rw-r--r--include/ouroboros/protobuf.h117
-rw-r--r--include/ouroboros/pthread.h51
-rw-r--r--include/ouroboros/qos.h58
-rw-r--r--include/ouroboros/qoscube.h12
-rw-r--r--include/ouroboros/random.h12
-rw-r--r--include/ouroboros/rib.h21
-rw-r--r--include/ouroboros/serdes-irm.h79
-rw-r--r--include/ouroboros/serdes-oep.h70
-rw-r--r--include/ouroboros/sha3.h6
-rw-r--r--include/ouroboros/shm_du_buff.h14
-rw-r--r--include/ouroboros/shm_flow_set.h19
-rw-r--r--include/ouroboros/shm_rbuff.h13
-rw-r--r--include/ouroboros/shm_rdrbuff.h16
-rw-r--r--include/ouroboros/sockets.h.in46
-rw-r--r--include/ouroboros/test.h82
-rw-r--r--include/ouroboros/time.h (renamed from include/ouroboros/time_utils.h)21
-rw-r--r--include/ouroboros/tpm.h6
-rw-r--r--include/ouroboros/utils.h24
-rw-r--r--include/ouroboros/version.h.in6
-rw-r--r--irmd.conf.in112
-rw-r--r--ouroboros.service.in4
-rw-r--r--src/ipcpd/CMakeLists.txt15
-rw-r--r--src/ipcpd/broadcast/CMakeLists.txt5
-rw-r--r--src/ipcpd/broadcast/comp.h45
-rw-r--r--src/ipcpd/broadcast/connmgr.c496
-rw-r--r--src/ipcpd/broadcast/connmgr.h71
-rw-r--r--src/ipcpd/broadcast/dt.c46
-rw-r--r--src/ipcpd/broadcast/dt.h6
-rw-r--r--src/ipcpd/broadcast/enroll.c363
-rw-r--r--src/ipcpd/broadcast/main.c142
-rw-r--r--src/ipcpd/common/comp.h (renamed from src/ipcpd/unicast/comp.h)18
-rw-r--r--src/ipcpd/common/connmgr.c564
-rw-r--r--src/ipcpd/common/connmgr.h (renamed from src/ipcpd/unicast/connmgr.h)14
-rw-r--r--src/ipcpd/common/enroll.c337
-rw-r--r--src/ipcpd/common/enroll.h (renamed from src/ipcpd/broadcast/enroll.h)20
-rw-r--r--src/ipcpd/config.h.in23
-rw-r--r--src/ipcpd/eth/CMakeLists.txt2
-rw-r--r--src/ipcpd/eth/dix.c6
-rw-r--r--src/ipcpd/eth/eth.c441
-rw-r--r--src/ipcpd/eth/llc.c6
-rw-r--r--src/ipcpd/ipcp.c1009
-rw-r--r--src/ipcpd/ipcp.h58
-rw-r--r--src/ipcpd/local/CMakeLists.txt2
-rw-r--r--src/ipcpd/local/main.c219
-rw-r--r--src/ipcpd/raptor/CMakeLists.txt50
-rw-r--r--src/ipcpd/raptor/main.c1114
-rw-r--r--src/ipcpd/shim-data.c51
-rw-r--r--src/ipcpd/shim-data.h6
-rw-r--r--src/ipcpd/udp/CMakeLists.txt2
-rw-r--r--src/ipcpd/udp/main.c611
-rw-r--r--src/ipcpd/unicast/CMakeLists.txt36
-rw-r--r--src/ipcpd/unicast/addr-auth.c (renamed from src/ipcpd/unicast/addr_auth.c)13
-rw-r--r--src/ipcpd/unicast/addr-auth.h (renamed from src/ipcpd/unicast/addr_auth.h)6
-rw-r--r--src/ipcpd/unicast/addr-auth/flat.c (renamed from src/ipcpd/unicast/pol/flat.c)32
-rw-r--r--src/ipcpd/unicast/addr-auth/flat.h (renamed from src/ipcpd/unicast/pol/flat.h)10
-rw-r--r--src/ipcpd/unicast/addr-auth/ops.h (renamed from src/ipcpd/unicast/pol-addr-auth-ops.h)14
-rw-r--r--src/ipcpd/unicast/addr-auth/pol.h23
-rw-r--r--src/ipcpd/unicast/ca.c109
-rw-r--r--src/ipcpd/unicast/ca.h68
-rw-r--r--src/ipcpd/unicast/ca/mb-ecn.c296
-rw-r--r--src/ipcpd/unicast/ca/mb-ecn.h56
-rw-r--r--src/ipcpd/unicast/ca/nop.c98
-rw-r--r--src/ipcpd/unicast/ca/nop.h52
-rw-r--r--src/ipcpd/unicast/ca/ops.h58
-rw-r--r--src/ipcpd/unicast/ca/pol.h24
-rw-r--r--src/ipcpd/unicast/connmgr.c504
-rw-r--r--src/ipcpd/unicast/dht.h52
-rw-r--r--src/ipcpd/unicast/dir.c58
-rw-r--r--src/ipcpd/unicast/dir.h8
-rw-r--r--src/ipcpd/unicast/dir/dht.c (renamed from src/ipcpd/unicast/dht.c)247
-rw-r--r--src/ipcpd/unicast/dir/dht.h52
-rw-r--r--src/ipcpd/unicast/dir/dht.proto (renamed from src/ipcpd/unicast/kademlia.proto)18
-rw-r--r--src/ipcpd/unicast/dir/ops.h46
-rw-r--r--src/ipcpd/unicast/dir/pol.h23
-rw-r--r--src/ipcpd/unicast/dir/tests/CMakeLists.txt40
-rw-r--r--src/ipcpd/unicast/dir/tests/dht_test.c (renamed from src/ipcpd/unicast/tests/dht_test.c)27
-rw-r--r--src/ipcpd/unicast/dt.c363
-rw-r--r--src/ipcpd/unicast/dt.h14
-rw-r--r--src/ipcpd/unicast/enroll.c379
-rw-r--r--src/ipcpd/unicast/enroll.h47
-rw-r--r--src/ipcpd/unicast/fa.c853
-rw-r--r--src/ipcpd/unicast/fa.h26
-rw-r--r--src/ipcpd/unicast/main.c180
-rw-r--r--src/ipcpd/unicast/pff.c19
-rw-r--r--src/ipcpd/unicast/pff.h6
-rw-r--r--src/ipcpd/unicast/pff/alternate.c (renamed from src/ipcpd/unicast/pol/alternate_pff.c)10
-rw-r--r--src/ipcpd/unicast/pff/alternate.h (renamed from src/ipcpd/unicast/pol/alternate_pff.h)10
-rw-r--r--src/ipcpd/unicast/pff/multipath.c (renamed from src/ipcpd/unicast/pol/multipath_pff.c)38
-rw-r--r--src/ipcpd/unicast/pff/multipath.h (renamed from src/ipcpd/unicast/pol/multipath_pff.h)10
-rw-r--r--src/ipcpd/unicast/pff/ops.h (renamed from src/ipcpd/unicast/pol-pff-ops.h)14
-rw-r--r--src/ipcpd/unicast/pff/pft.c (renamed from src/ipcpd/unicast/pol/pft.c)20
-rw-r--r--src/ipcpd/unicast/pff/pft.h (renamed from src/ipcpd/unicast/pol/pft.h)6
-rw-r--r--src/ipcpd/unicast/pff/pol.h25
-rw-r--r--src/ipcpd/unicast/pff/simple.c (renamed from src/ipcpd/unicast/pol/simple_pff.c)10
-rw-r--r--src/ipcpd/unicast/pff/simple.h (renamed from src/ipcpd/unicast/pol/simple_pff.h)10
-rw-r--r--src/ipcpd/unicast/pff/tests/CMakeLists.txt (renamed from src/ipcpd/unicast/tests/CMakeLists.txt)13
-rw-r--r--src/ipcpd/unicast/pff/tests/pft_test.c (renamed from src/ipcpd/unicast/pol/tests/pft_test.c)6
-rw-r--r--src/ipcpd/unicast/psched.c17
-rw-r--r--src/ipcpd/unicast/psched.h12
-rw-r--r--src/ipcpd/unicast/routing.c10
-rw-r--r--src/ipcpd/unicast/routing.h6
-rw-r--r--src/ipcpd/unicast/routing/graph.c (renamed from src/ipcpd/unicast/pol/graph.c)10
-rw-r--r--src/ipcpd/unicast/routing/graph.h (renamed from src/ipcpd/unicast/pol/graph.h)6
-rw-r--r--src/ipcpd/unicast/routing/link-state.c (renamed from src/ipcpd/unicast/pol/link_state.c)82
-rw-r--r--src/ipcpd/unicast/routing/link-state.h (renamed from src/ipcpd/unicast/pol/link_state.h)10
-rw-r--r--src/ipcpd/unicast/routing/ops.h (renamed from src/ipcpd/unicast/pol-routing-ops.h)14
-rw-r--r--src/ipcpd/unicast/routing/pol.h23
-rw-r--r--src/ipcpd/unicast/routing/tests/CMakeLists.txt (renamed from src/ipcpd/unicast/pol/tests/CMakeLists.txt)7
-rw-r--r--src/ipcpd/unicast/routing/tests/graph_test.c (renamed from src/ipcpd/unicast/pol/tests/graph_test.c)6
-rw-r--r--src/irmd/CMakeLists.txt73
-rw-r--r--src/irmd/config.h.in89
-rw-r--r--src/irmd/configfile.c871
-rw-r--r--src/irmd/configfile.h (renamed from src/irmd/utils.h)30
-rw-r--r--src/irmd/ipcp.c487
-rw-r--r--src/irmd/ipcp.h68
-rw-r--r--src/irmd/irm_flow.c226
-rw-r--r--src/irmd/irm_flow.h81
-rw-r--r--src/irmd/irmd.h54
-rw-r--r--src/irmd/main.c3048
-rw-r--r--src/irmd/proc_table.c303
-rw-r--r--src/irmd/proc_table.h84
-rw-r--r--src/irmd/prog_table.c187
-rw-r--r--src/irmd/prog_table.h65
-rw-r--r--src/irmd/reg/CMakeLists.txt7
-rw-r--r--src/irmd/reg/flow.c208
-rw-r--r--src/irmd/reg/flow.h63
-rw-r--r--src/irmd/reg/ipcp.c92
-rw-r--r--src/irmd/reg/ipcp.h47
-rw-r--r--src/irmd/reg/name.c375
-rw-r--r--src/irmd/reg/name.h78
-rw-r--r--src/irmd/reg/proc.c183
-rw-r--r--src/irmd/reg/proc.h56
-rw-r--r--src/irmd/reg/prog.c174
-rw-r--r--src/irmd/reg/prog.h53
-rw-r--r--src/irmd/reg/reg.c2120
-rw-r--r--src/irmd/reg/reg.h148
-rw-r--r--src/irmd/reg/tests/CMakeLists.txt33
-rw-r--r--src/irmd/reg/tests/flow_test.c294
-rw-r--r--src/irmd/reg/tests/ipcp_test.c89
-rw-r--r--src/irmd/reg/tests/name_test.c283
-rw-r--r--src/irmd/reg/tests/proc_test.c107
-rw-r--r--src/irmd/reg/tests/prog_test.c105
-rw-r--r--src/irmd/reg/tests/reg_test.c1583
-rw-r--r--src/irmd/registry.c615
-rw-r--r--src/irmd/registry.h126
-rw-r--r--src/irmd/tests/CMakeLists.txt12
-rw-r--r--src/irmd/utils.c64
-rw-r--r--src/lib/.gitignore2
-rw-r--r--src/lib/CMakeLists.txt101
-rw-r--r--src/lib/bitmap.c6
-rw-r--r--src/lib/btree.c6
-rw-r--r--src/lib/cep.c (renamed from src/lib/cacep.c)58
-rw-r--r--src/lib/config.h.in35
-rw-r--r--src/lib/crc32.c6
-rw-r--r--src/lib/crypt.c126
-rw-r--r--src/lib/dev.c1794
-rw-r--r--src/lib/frct.c869
-rw-r--r--src/lib/hash.c62
-rw-r--r--src/lib/ipcp_config.proto62
-rw-r--r--src/lib/irm.c164
-rw-r--r--src/lib/irmd_messages.proto90
-rw-r--r--src/lib/list.c10
-rw-r--r--src/lib/lockfile.c102
-rw-r--r--src/lib/logs.c6
-rw-r--r--src/lib/md5.c6
-rw-r--r--src/lib/notifier.c12
-rw-r--r--src/lib/pb/cep.proto (renamed from src/lib/cacep.proto)12
-rw-r--r--src/lib/pb/enroll.proto42
-rw-r--r--src/lib/pb/ipcp.proto (renamed from src/lib/ipcpd_messages.proto)19
-rw-r--r--src/lib/pb/ipcp_config.proto57
-rw-r--r--src/lib/pb/irm.proto97
-rw-r--r--src/lib/pb/model.proto61
-rw-r--r--src/lib/protobuf.c605
-rw-r--r--src/lib/qoscube.c6
-rw-r--r--src/lib/qosspec.proto34
-rw-r--r--src/lib/random.c6
-rw-r--r--src/lib/rib.c77
-rw-r--r--src/lib/rxmwheel.c271
-rw-r--r--src/lib/serdes-irm.c478
-rw-r--r--src/lib/serdes-oep.c161
-rw-r--r--src/lib/sha3.c9
-rw-r--r--src/lib/shm_flow_set.c109
-rw-r--r--src/lib/shm_rbuff.c55
-rw-r--r--src/lib/shm_rbuff_ll.c46
-rw-r--r--src/lib/shm_rbuff_pthr.c84
-rw-r--r--src/lib/shm_rdrbuff.c52
-rw-r--r--src/lib/sockets.c103
-rw-r--r--src/lib/tests/CMakeLists.txt9
-rw-r--r--src/lib/tests/bitmap_test.c31
-rw-r--r--src/lib/tests/btree_test.c6
-rw-r--r--src/lib/tests/crc32_test.c6
-rw-r--r--src/lib/tests/hash_test.c202
-rw-r--r--src/lib/tests/md5_test.c6
-rw-r--r--src/lib/tests/sha3_test.c6
-rw-r--r--src/lib/tests/shm_rbuff_test.c6
-rw-r--r--src/lib/tests/time_test.c (renamed from src/lib/tests/time_utils_test.c)12
-rw-r--r--src/lib/timerwheel.c414
-rw-r--r--src/lib/tpm.c17
-rw-r--r--src/lib/utils.c71
-rw-r--r--src/tools/irm/irm.c8
-rw-r--r--src/tools/irm/irm_bind.c8
-rw-r--r--src/tools/irm/irm_bind_ipcp.c16
-rw-r--r--src/tools/irm/irm_bind_process.c6
-rw-r--r--src/tools/irm/irm_bind_program.c6
-rw-r--r--src/tools/irm/irm_ipcp.c15
-rw-r--r--src/tools/irm/irm_ipcp_bootstrap.c154
-rw-r--r--src/tools/irm/irm_ipcp_connect.c30
-rw-r--r--src/tools/irm/irm_ipcp_create.c26
-rw-r--r--src/tools/irm/irm_ipcp_destroy.c14
-rw-r--r--src/tools/irm/irm_ipcp_disconnect.c24
-rw-r--r--src/tools/irm/irm_ipcp_enroll.c93
-rw-r--r--src/tools/irm/irm_ipcp_list.c40
-rw-r--r--src/tools/irm/irm_name.c13
-rw-r--r--src/tools/irm/irm_name_create.c8
-rw-r--r--src/tools/irm/irm_name_destroy.c6
-rw-r--r--src/tools/irm/irm_name_list.c6
-rw-r--r--src/tools/irm/irm_name_reg.c28
-rw-r--r--src/tools/irm/irm_name_unreg.c22
-rw-r--r--src/tools/irm/irm_ops.h6
-rw-r--r--src/tools/irm/irm_unbind.c8
-rw-r--r--src/tools/irm/irm_unbind_ipcp.c16
-rw-r--r--src/tools/irm/irm_unbind_process.c6
-rw-r--r--src/tools/irm/irm_unbind_program.c6
-rw-r--r--src/tools/irm/irm_utils.c8
-rw-r--r--src/tools/irm/irm_utils.h6
-rw-r--r--src/tools/obc/obc.c6
-rw-r--r--src/tools/ocbr/ocbr.c22
-rw-r--r--src/tools/ocbr/ocbr_client.c6
-rw-r--r--src/tools/ocbr/ocbr_server.c21
-rw-r--r--src/tools/oecho/oecho.c6
-rw-r--r--src/tools/operf/operf.c6
-rw-r--r--src/tools/operf/operf_client.c6
-rw-r--r--src/tools/operf/operf_server.c6
-rw-r--r--src/tools/oping/oping.c89
-rw-r--r--src/tools/oping/oping_client.c14
-rw-r--r--src/tools/oping/oping_server.c33
-rw-r--r--src/tools/ovpn/ovpn.c6
-rw-r--r--src/tools/time_utils.h6
279 files changed, 19886 insertions, 11993 deletions
diff --git a/.gitignore b/.gitignore
index ce18e761..43f47a46 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
*~
*#
-build/ \ No newline at end of file
+build/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8cce6a10..c08867b7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8.12.2)
+cmake_minimum_required(VERSION 2.8.12.2...3.29.1)
cmake_policy(VERSION ${CMAKE_VERSION})
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
@@ -8,8 +8,8 @@ project(ouroboros C)
include(GNUInstallDirs)
set(PACKAGE_VERSION_MAJOR 0)
-set(PACKAGE_VERSION_MINOR 17)
-set(PACKAGE_VERSION_PATCH 1)
+set(PACKAGE_VERSION_MINOR 21)
+set(PACKAGE_VERSION_PATCH 3)
set(PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
set(PACKAGE_DESCRIPTION "The Ouroboros prototype")
@@ -20,11 +20,17 @@ set(PACKAGE_VERSION
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
- "Build type (Release, Debug, DebugASan, DebugTSan, DebugLSan)" FORCE)
+ "Build type (Release, Debug, DebugASan, DebugTSan, DebugLSan, DebugUSan, DebugAnalyzer)" FORCE)
endif()
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- set(CMAKE_INSTALL_PREFIX "/usr" CACHE STRING "Installation Prefix" FORCE)
+ if (APPLE)
+ set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE STRING
+ "Installation Prefix" FORCE)
+ else()
+ set(CMAKE_INSTALL_PREFIX "/usr" CACHE STRING
+ "Installation Prefix" FORCE)
+ endif()
endif ()
if (APPLE)
@@ -60,11 +66,12 @@ include(CompilerUtils)
test_and_set_c_compiler_flag_global(-std=c89)
test_and_set_c_compiler_flag_global(-Wall)
# -Wextra may fail on clobbered warning due to pthread_cleanup
-# test_and_set_c_compiler_flag_global(-Wextra)
+test_and_set_c_compiler_flag_global(-Wno-clobbered)
+test_and_set_c_compiler_flag_global(-Wextra)
# explicitly add other flags in -Wextra
test_and_set_c_compiler_flag_global(-Wempty-body)
test_and_set_c_compiler_flag_global(-Wignored-qualifiers)
-test_and_set_c_compiler_flag_global(-Wimplicit-fallthrough)
+test_and_set_c_compiler_flag_global(-Wimplicit-fallthrough=4)
test_and_set_c_compiler_flag_global(-Wmissing-field-initializers)
test_and_set_c_compiler_flag_global(-Wmissing-parameter-type)
test_and_set_c_compiler_flag_global(-Wold-style-declaration)
@@ -75,29 +82,39 @@ test_and_set_c_compiler_flag_global(-Wuninitialized)
test_and_set_c_compiler_flag_global(-Wshift-negative-value)
test_and_set_c_compiler_flag_global(-Wunused-parameter)
test_and_set_c_compiler_flag_global(-Wunused-but-set-parameter)
-# -Wextra parameters
test_and_set_c_compiler_flag_global(-Werror)
test_and_set_c_compiler_flag_global(-Wundef)
test_and_set_c_compiler_flag_global(-Wpointer-arith)
test_and_set_c_compiler_flag_global(-Wstrict-prototypes)
test_and_set_c_compiler_flag_global(-Wvla)
-#Wswitch-default check fails on the swig-generated code
-#test_and_set_c_compiler_flag_global(-Wswitch-default)
+test_and_set_c_compiler_flag_global(-Wswitch-default)
+test_and_set_c_compiler_flag_global(-Wreturn-type)
test_and_set_c_compiler_flag_global(-Wunreachable-code)
test_and_set_c_compiler_flag_global(-Wdeclaration-after-statement)
test_and_set_c_compiler_flag_global(-Winfinite-recursion)
test_and_set_c_compiler_flag_global(-fmax-errors=5)
+
if (CMAKE_BUILD_TYPE STREQUAL "Release")
test_and_set_c_compiler_flag_global(-O3)
-else ()
+elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
+ test_and_set_c_compiler_flag_global(-g)
+elseif (CMAKE_BUILD_TYPE STREQUAL "DebugASan")
test_and_set_c_compiler_flag_global(-g)
-endif ()
-if (CMAKE_BUILD_TYPE STREQUAL "DebugASan")
test_and_set_c_compiler_flag_global(-fsanitize=address)
elseif (CMAKE_BUILD_TYPE STREQUAL "DebugTSan")
+ test_and_set_c_compiler_flag_global(-g)
test_and_set_c_compiler_flag_global(-fsanitize=thread)
elseif (CMAKE_BUILD_TYPE STREQUAL "DebugLSan")
+ test_and_set_c_compiler_flag_global(-g)
test_and_set_c_compiler_flag_global(-fsanitize=leak)
+elseif (CMAKE_BUILD_TYPE STREQUAL "DebugUSan")
+ test_and_set_c_compiler_flag_global(-g)
+ test_and_set_c_compiler_flag_global(-fsanitize=undefined)
+elseif (CMAKE_BUILD_TYPE STREQUAL "DebugAnalyzer")
+ test_and_set_c_compiler_flag_global(-g)
+ test_and_set_c_compiler_flag_global(-fanalyzer)
+else ()
+ message(FATAL_ERROR "Unkown build type ${CMAKE_BUILD_TYPE}")
endif ()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ouroboros-dev.pc.in"
@@ -125,6 +142,11 @@ if (SYSTEMD_FOUND)
endif ()
if (NOT ${SYSTEMD_UNITDIR} STREQUAL "")
message(STATUS "Installing systemd service in: ${SYSTEMD_UNITDIR}")
+ if (LIBTOML_LIBRARIES AND NOT DISABLE_CONFIGFILE)
+ set (CONFIGURE_STRING "--config ${OUROBOROS_CONFIG_DIR}${OUROBOROS_CONFIG_FILE}")
+ else ()
+ set (CONFIGURE_STRING "")
+ endif ()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ouroboros.service.in"
"${CMAKE_CURRENT_BINARY_DIR}/ouroboros.service" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ouroboros.service"
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index dbe6bde8..b64bd5d2 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,5 +1,5 @@
This file contains a list of people who have made large contributions to
Ouroboros, in alphabetical order.
-Dimitri Staessens <dimitri.staessens@ugent.be>
-Sander Vrijders <sander.vrijders@ugent.be>
+Dimitri Staessens <dimitri@ouroboros.rocks>
+Sander Vrijders <sander@ouroboros.rocks>
diff --git a/LICENSE-LGPL b/LICENSE-LGPL
index a618b2b0..d4634f46 100644
--- a/LICENSE-LGPL
+++ b/LICENSE-LGPL
@@ -341,4 +341,4 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
- END OF TERMS AND CONDITIONS \ No newline at end of file
+ END OF TERMS AND CONDITIONS
diff --git a/appveyor.yml b/appveyor.yml
index 5c663735..bf1d8076 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,6 +1,6 @@
image:
- - Ubuntu1804
- - Ubuntu
+ - Ubuntu2004
+ - Ubuntu2204
platform:
- x64
@@ -13,11 +13,11 @@ configuration:
environment:
matrix:
- CC: clang
-
- CC: gcc
install:
- sudo apt-get update
+ - sudo apt-get install clang
- sudo apt-get install protobuf-c-compiler --yes
- sudo apt-get install libprotobuf-c-dev --yes || true
- sudo apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils --yes
@@ -25,10 +25,10 @@ install:
before_build:
- mkdir -p build
- cd build
- - cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% ..
+ - cmake -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
build_script:
- make
test_script:
- - make check \ No newline at end of file
+ - env CTEST_OUTPUT_ON_FAILURE=1 make check
diff --git a/cmake/CmakeUninstall.cmake.in b/cmake/CmakeUninstall.cmake.in
index 4c07dc7b..985b31b2 100644
--- a/cmake/CmakeUninstall.cmake.in
+++ b/cmake/CmakeUninstall.cmake.in
@@ -7,14 +7,22 @@ string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
- exec_program(
- "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
- OUTPUT_VARIABLE rm_out
- RETURN_VALUE rm_retval
- )
- if(NOT "${rm_retval}" STREQUAL 0)
+ if(CMAKE_VERSION VERSION_LESS "3.28.0")
+ exec_program(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ else()
+ execute_process(
+ COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}"
+ RESULT_VARIABLE rm_out
+ ERROR_VARIABLE rm_retval
+ )
+ endif ()
+ if(NOT "${rm_retval}" STREQUAL "" AND NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
- endif(NOT "${rm_retval}" STREQUAL 0)
+ endif(NOT "${rm_retval}" STREQUAL "" AND NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
diff --git a/doc/man/fccntl.3 b/doc/man/fccntl.3
index 87e23078..767342b9 100644
--- a/doc/man/fccntl.3
+++ b/doc/man/fccntl.3
@@ -1,6 +1,6 @@
-.\" Ouroboros man pages CC-BY 2017 - 2020
-.\" Dimitri Staessens <dimitri.staessens@ugent.be>
-.\" Sander Vrijders <sander.vrijders@ugent.be>
+.\" Ouroboros man pages CC-BY 2017 - 2024
+.\" Dimitri Staessens <dimitri@ouroboros.rocks>
+.\" Sander Vrijders <sander@ouroboros.rocks>
.TH FCCNTL 3 2018-10-04 Ouroboros "Ouroboros Programmer's Manual"
@@ -40,8 +40,8 @@ disables the timeout.
\fBFLOWGQOSSPEC\fR - retrieve the current QoS specification of the
flow. Takes a \fBqosspec_t * \fIqs\fR as third argument.
-\fBFLOWSFLAGS\fR - set flow flags. Takes flow flags as third
-argument. Supported flags are:
+\fBFLOWSFLAGS\fR - set flow flags. Takes flow \fBuint32_t\fR
+\fIflags\fR as third argument. Supported flags are:
.RS 8
\fIFLOWFRDONLY\fR - set flow to read-only.
@@ -67,25 +67,30 @@ no partial writes).
.RE
-\fBFLOWGFLAGS\fR - get the current flow flags. Takes an \fBuint32_t
+\fBFLOWGFLAGS\fR - get the current flow flags. Takes an \fBuint32_t *
\fIflags\fR as third argument.
\fBFLOWGRXQLEN\fR - get the current number of packets in the receive
-buffer. Takes a \fBsize_t \fIqlen\fR as third argument.
+buffer. Takes a \fBsize_t \fIqlen\fR * as third argument.
\fBFLOWGTXQLEN\fR - get the current number of packets in the transmit
-buffer. Takes a \fBsize_t \fIqlen\fR as third argument.
+buffer. Takes a \fBsize_t \fIqlen\fR * as third argument.
-\fBFRCTGFLAGS\fR - get the current flow flags. Takes an \fBuint16_t
+\fBFRCTSFLAGS\fR - set the current flow flags. Takes an \fBuint16_t
\fIflags\fR as third argument. Supported flags are:
.RS 8
-\fIFRCTFRESCNTRL\fR - resource control enabled.
+\fIFRCTFRESCNTL\fR - resource control enabled.
+
+\fIFRCTFRTX\fR - retransmission enabled. Cannot be modified and will
+be ignored on set.
-\fIFRCTFRTX\fR - retransmission enabled.
+\fIFRCTFLINGER\fR - finish connection on flow deallocation.
.RE
+\fBFRCTGFLAGS\fR - get the current flow flags. Takes an \fBuint16_t *
+\fIflags\fR as third argument.
.SH RETURN VALUE
diff --git a/doc/man/flow_alloc.3 b/doc/man/flow_alloc.3
index 1dfc34fe..dbe5323c 100644
--- a/doc/man/flow_alloc.3
+++ b/doc/man/flow_alloc.3
@@ -1,6 +1,6 @@
-.\" Ouroboros man pages CC-BY 2017 - 2020
-.\" Dimitri Staessens <dimitri.staessens@ugent.be>
-.\" Sander Vrijders <sander.vrijders@ugent.be>
+.\" Ouroboros man pages CC-BY 2017 - 2024
+.\" Dimitri Staessens <dimitri@ouroboros.rocks>
+.\" Sander Vrijders <sander@ouroboros.rocks>
.TH FLOW_ALLOC 3 2018-10-05 Ouroboros "Ouroboros Programmer's Manual"
@@ -59,7 +59,8 @@ The \fBflow_join\fR() function allows applications to join a broadcast
flow provided by a broadcast layer. The dst is the layer name.
The \fBflow_dealloc\fR() function will release any resources
-associated with the flow.
+associated with the flow. This call may block and keep reliable flows
+active until all packets are acknowledged.
A \fBqosspec_t\fR specifies the following QoS characteristics of a
flow:
diff --git a/doc/man/flow_read.3 b/doc/man/flow_read.3
index 1a6c8eaf..acc1f61e 100644
--- a/doc/man/flow_read.3
+++ b/doc/man/flow_read.3
@@ -1,6 +1,6 @@
-.\" Ouroboros man pages CC-BY 2017 - 2020
-.\" Dimitri Staessens <dimitri.staessens@ugent.be>
-.\" Sander Vrijders <sander.vrijders@ugent.be>
+.\" Ouroboros man pages CC-BY 2017 - 2024
+.\" Dimitri Staessens <dimitri@ouroboros.rocks>
+.\" Sander Vrijders <sander@ouroboros.rocks>
.TH FLOW_READ 3 2017-04-10 Ouroboros "Ouroboros Programmer's Manual"
@@ -58,6 +58,9 @@ The flow was not allocated.
.B -EFLOWDOWN
The flow has been reported down.
+.B -EFLOWPEER
+The flow's peer is unresponsive (flow timed out).
+
.B -EMSGSIZE
The buffer was too large to be written.
diff --git a/doc/man/fqueue.3 b/doc/man/fqueue.3
index cbc8ee4e..72a0bc25 100644
--- a/doc/man/fqueue.3
+++ b/doc/man/fqueue.3
@@ -1,6 +1,6 @@
-.\" Ouroboros man pages CC-BY 2017 - 2020
-.\" Dimitri Staessens <dimitri.staessens@ugent.be>
-.\" Sander Vrijders <sander.vrijders@ugent.be>
+.\" Ouroboros man pages CC-BY 2017 - 2024
+.\" Dimitri Staessens <dimitri@ouroboros.rocks>
+.\" Sander Vrijders <sander@ouroboros.rocks>
.TH FQUEUE 3 2017-08-29 Ouroboros "Ouroboros Programmer's Manual"
@@ -68,8 +68,7 @@ On success, \fBfqueue_create\fR() returns a pointer to an
\fBfqueue_destroy\fR() has no return value.
-On success, \fBfevent\fR() returns the number of events that occured
-in \fIset\fR.
+On success, \fBfevent\fR() returns 1.
On success, \fBfqueue_next\fR() returns the next file descriptor for
which an event occurred.
diff --git a/doc/man/fset.3 b/doc/man/fset.3
index 6d1da6c7..87a7dc87 100644
--- a/doc/man/fset.3
+++ b/doc/man/fset.3
@@ -1,6 +1,6 @@
-.\" Ouroboros man pages CC-BY 2017 - 2020
-.\" Dimitri Staessens <dimitri.staessens@ugent.be>
-.\" Sander Vrijders <sander.vrijders@ugent.be>
+.\" Ouroboros man pages CC-BY 2017 - 2024
+.\" Dimitri Staessens <dimitri@ouroboros.rocks>
+.\" Sander Vrijders <sander@ouroboros.rocks>
.TH FSET 3 2017-04-10 Ouroboros "Ouroboros Programmer's Manual"
diff --git a/doc/man/ouroboros-glossary.7 b/doc/man/ouroboros-glossary.7
index 65af7a53..1f7ad882 100644
--- a/doc/man/ouroboros-glossary.7
+++ b/doc/man/ouroboros-glossary.7
@@ -1,6 +1,6 @@
-.\" Ouroboros man pages CC-BY 2017 - 2020
-.\" Dimitri Staessens <dimitri.staessens@ugent.be>
-.\" Sander Vrijders <sander.vrijders@ugent.be>
+.\" Ouroboros man pages CC-BY 2017 - 2024
+.\" Dimitri Staessens <dimitri@ouroboros.rocks>
+.\" Sander Vrijders <sander@ouroboros.rocks>
.TH OUROBOROS-GLOSSARY 7 2017-12-02 Ouroboros "Ouroboros User Manual"
diff --git a/doc/man/ouroboros-tutorial.7 b/doc/man/ouroboros-tutorial.7
index 416bf72d..1fc02a02 100644
--- a/doc/man/ouroboros-tutorial.7
+++ b/doc/man/ouroboros-tutorial.7
@@ -1,6 +1,6 @@
-.\" Ouroboros man pages CC-BY 2017 - 2020
-.\" Dimitri Staessens <dimitri.staessens@ugent.be>
-.\" Sander Vrijders <sander.vrijders@ugent.be>
+.\" Ouroboros man pages CC-BY 2017 - 2024
+.\" Dimitri Staessens <dimitri@ouroboros.rocks>
+.\" Sander Vrijders <sander@ouroboros.rocks>
.TH OUROBOROS-TUTORIAL 7 2018-10-05 Ouroboros "Ouroboros User Manual"
diff --git a/doc/man/ouroboros.8 b/doc/man/ouroboros.8
index 0958f615..df328fcc 100644
--- a/doc/man/ouroboros.8
+++ b/doc/man/ouroboros.8
@@ -1,8 +1,8 @@
-.\" Ouroboros man pages CC-BY 2017 - 2020
-.\" Dimitri Staessens <dimitri.staessens@ugent.be>
-.\" Sander Vrijders <sander.vrijders@ugent.be>
+.\" Ouroboros man pages CC-BY 2017 - 2024
+.\" Dimitri Staessens <dimitri@ouroboros.rocks>
+.\" Sander Vrijders <sander@ouroboros.rocks>
-.TH OUROBOROS 8 2018-03-10 Ouroboros "Ouroboros User Manual"
+.TH OUROBOROS 8 2020-11-29 Ouroboros "Ouroboros User Manual"
.SH NAME
@@ -99,10 +99,9 @@ In order to enroll an IPC process in a layer, some other member will
have to be reachable over a lower layer. IPCPs that wrap a legacy
transmission technology are all bootstrapped and thus need not enroll
as they work directly over a physical connection. Ouroboros currently
-supports IPCPs over shared memory (local), L1 (raptor, experimental),
-L2 (eth-llc and eth-dix) and L3 (udp). The unicast and broadcast
-layers require connections to be established between IPCP components
-for its operation.
+supports IPCPs over shared memory (local), L2 (eth-llc and eth-dix)
+and L3 (udp). The unicast and broadcast layers require connections to
+be established between IPCP components for its operation.
\fBConnecting the management components\fR using \fImanagement
flows\fR allows management information to be sent between IPCPs so
@@ -124,8 +123,6 @@ creates an IPCP process of type \fItype\fR in the system with name
.PP
\fBlocal\fR - create a loopback IPCP.
.PP
-\fBraptor\fR - create an IPCP that attaches to a raptor NetFPGA device.
-.PP
\fBeth-llc\fR - create an IPCP that attaches to Ethernet using LLC frames.
.PP
\fBeth-dix\fR - create an IPCP that attaches to Ethernet using DIX frames.
@@ -162,16 +159,6 @@ Values for [\fIparam\fR] are dependent on \fItype\fR:
default: SHA3_256.
.RE
-\fBraptor\fR
-.RS 4
-.PP
-[hash \fIpolicy\fR] specifies the hash function used for the directory,
-.br
-\fIpolicy\fR: SHA3_224, SHA3_256, SHA3_384, SHA3_512.
-.br
-default: SHA3_256.
-.RE
-
.PP
\fBeth-llc\fR
.RS 4
@@ -208,18 +195,14 @@ default: SHA3_256.
.PP
ip \fIip\fR specifies the local IP address to bind to
.PP
-[dns \fdns\fR] specifies an optional DDNS server that will be used for
+[dns \fIdns\fR] specifies an optional DDNS server that will be used for
the directory.
.PP
-[cport \fcport\fR] specifies a client UDP port that will be used for
-sending packets.
-.br
-default: A random UDP port in the ephemeral range
-.PP
-[sport \fsport\fR] specifies a server UDP port that is used for
+[port \fIport\fR] specifies a UDP port that is used for sending and
receiving ouroboros traffic. This must be the same for the entire UDP
layer. Parallel UDP layers should use different ports. This UDP port
-needs to be forwarded if the server is behind a NAT.
+needs to be forwarded if the server is behind a NAT and wants to
+receive incoming requests.
.br
default: 3435
.RE
@@ -247,11 +230,29 @@ default: flat.
.PP
[routing \fIpolicy\fR] specifies the routing policy.
.br
-\fIpolicy\fR: link_state, lfa.
+\fIpolicy\fR:
+.RS 4
+link_state: default shortest-path link-state routing.
+.br
+lfa: loop-free alternate resilient routing.
+.br
+ecmp: equal-cost multipath routing.
+.RE
.br
default: link_state.
.PP
-[hash \fIpolicy\fR] specifies the hash function used for the directory,
+[congestion \fIpolicy\fR] specifies the congestion avoidance policy.
+.br
+\fIpolicy\fR:
+.RS 4
+none: no congestion avoidance.
+.br
+mb-ecn: Multi-bit explicit congestion notification and avoidance.
+.RE
+.br
+default: mb-ecn.
+.PP
+[hash \fIpolicy\fR] specifies the hash function used for the directory.
.br
\fIpolicy\fR: SHA3_224, SHA3_256, SHA3_384, SHA3_512.
.br
@@ -265,7 +266,7 @@ name and the layer name.
\fBbroadcast\fR
.RS 4
.PP
-[hash \fIpolicy\fR] specifies the hash function used for the layer name,
+[hash \fIpolicy\fR] specifies the hash function used for the layer name.
.br
\fIpolicy\fR: SHA3_224, SHA3_256, SHA3_384, SHA3_512.
.br
diff --git a/include/ouroboros/CMakeLists.txt b/include/ouroboros/CMakeLists.txt
index 8f248710..4e90bc59 100644
--- a/include/ouroboros/CMakeLists.txt
+++ b/include/ouroboros/CMakeLists.txt
@@ -8,7 +8,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sockets.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/sockets.h" @ONLY)
set(HEADER_FILES
- cacep.h
+ cep.h
cdefs.h
dev.h
errno.h
@@ -16,6 +16,7 @@ set(HEADER_FILES
fqueue.h
ipcp.h
irm.h
+ name.h
proto.h
qos.h
${CMAKE_CURRENT_BINARY_DIR}/version.h
diff --git a/include/ouroboros/bitmap.h b/include/ouroboros/bitmap.h
index 743f0e9f..04467a8a 100644
--- a/include/ouroboros/bitmap.h
+++ b/include/ouroboros/bitmap.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Bitmap implementation
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,8 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_BITMAP_H
-#define OUROBOROS_BITMAP_H
+#ifndef OUROBOROS_LIB_BITMAP_H
+#define OUROBOROS_LIB_BITMAP_H
#include <stddef.h>
#include <unistd.h>
@@ -45,4 +45,4 @@ bool bmp_is_id_valid(struct bmp * bmp,
bool bmp_is_id_used(struct bmp * bmp,
ssize_t id);
-#endif /* OUROBOROS_BITMAP_H */
+#endif /* OUROBOROS_LIB_BITMAP_H */
diff --git a/include/ouroboros/btree.h b/include/ouroboros/btree.h
index 1e95f491..cf982856 100644
--- a/include/ouroboros/btree.h
+++ b/include/ouroboros/btree.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* B-trees
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/include/ouroboros/cdefs.h b/include/ouroboros/cdefs.h
index 8aa00662..f4a5dc65 100644
--- a/include/ouroboros/cdefs.h
+++ b/include/ouroboros/cdefs.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* C Definitions
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/include/ouroboros/cacep.h b/include/ouroboros/cep.h
index b8d387b8..4c1737f0 100644
--- a/include/ouroboros/cacep.h
+++ b/include/ouroboros/cep.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
- * The Common Application Connection Establishment Protocol
+ * The Ouroboros Connection Establishment Protocol
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,20 +20,19 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_CACEP_H
-#define OUROBOROS_CACEP_H
+#ifndef OUROBOROS_CEP_H
+#define OUROBOROS_CEP_H
#include <ouroboros/cdefs.h>
#include <ouroboros/proto.h>
#include <stdint.h>
-#include <sys/types.h>
-#define CACEP_BUF_STRLEN 64
+#define OCEP_BUF_STRLEN 128
struct conn_info {
- char comp_name[CACEP_BUF_STRLEN + 1];
- char protocol[CACEP_BUF_STRLEN + 1];
+ char comp_name[OCEP_BUF_STRLEN + 1];
+ char protocol[OCEP_BUF_STRLEN + 1];
uint32_t pref_version;
enum proto_concrete_syntax pref_syntax;
struct proto_field fixed_conc_syntax[PROTO_MAX_FIELDS];
@@ -43,12 +42,12 @@ struct conn_info {
__BEGIN_DECLS
-int cacep_snd(int fd,
- const struct conn_info * in);
+int cep_snd(int fd,
+ const struct conn_info * in);
-int cacep_rcv(int fd,
- struct conn_info * out);
+int cep_rcv(int fd,
+ struct conn_info * out);
__END_DECLS
-#endif /* OUROBOROS_CACEP_H */
+#endif /* OUROBOROS_CEP_H */
diff --git a/include/ouroboros/crc32.h b/include/ouroboros/crc32.h
index 53c810a1..eb610797 100644
--- a/include/ouroboros/crc32.h
+++ b/include/ouroboros/crc32.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* 32-bit Cyclic Redundancy Check
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,8 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_CRC32_H
-#define OUROBOROS_CRC32_H
+#ifndef OUROBOROS_LIB_CRC32_H
+#define OUROBOROS_LIB_CRC32_H
#include <stdint.h>
#include <stddef.h>
@@ -32,4 +32,4 @@ void crc32(uint32_t * crc,
const void * buf,
size_t len);
-#endif /* OUROBOROS_CRC32_H */
+#endif /* OUROBOROS_LIB_CRC32_H */
diff --git a/include/ouroboros/crypt.h b/include/ouroboros/crypt.h
new file mode 100644
index 00000000..28fe63b2
--- /dev/null
+++ b/include/ouroboros/crypt.h
@@ -0,0 +1,56 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Cryptography
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_LIB_CRYPT_H
+#define OUROBOROS_LIB_CRYPT_H
+
+#include <ouroboros/shm_du_buff.h>
+#include <ouroboros/utils.h>
+
+#define SYMMKEYSZ 32
+
+struct crypt_info {
+ uint16_t flags;
+ void * ctx;
+ uint8_t key[SYMMKEYSZ];
+};
+
+int crypt_dh_pkp_create(void ** pkp,
+ uint8_t * pk);
+
+void crypt_dh_pkp_destroy(void * pkp);
+
+int crypt_dh_derive(void * pkp,
+ buffer_t pk,
+ uint8_t * s);
+
+int crypt_encrypt(struct crypt_info * info,
+ struct shm_du_buff * sdb);
+
+int crypt_decrypt(struct crypt_info * info,
+ struct shm_du_buff * sdb);
+
+int crypt_init(struct crypt_info * info);
+
+void crypt_fini(struct crypt_info * info);
+
+#endif /* OUROBOROS_LIB_CRYPT_H */
diff --git a/include/ouroboros/dev.h b/include/ouroboros/dev.h
index 9da54096..6e643a2c 100644
--- a/include/ouroboros/dev.h
+++ b/include/ouroboros/dev.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* API for applications
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/include/ouroboros/endian.h b/include/ouroboros/endian.h
index 6a67afce..addb2ed3 100644
--- a/include/ouroboros/endian.h
+++ b/include/ouroboros/endian.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Endianness
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,9 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_ENDIAN_H
-#define OUROBOROS_ENDIAN_H
-
+#ifndef OUROBOROS_LIB_ENDIAN_H
+#define OUROBOROS_LIB_ENDIAN_H
#if defined(__linux__) || defined(__CYGWIN__) || \
(defined(__MACH__) && !defined(__APPLE__))
@@ -73,4 +72,4 @@
#define hton16(x) htobe16(x)
#define ntoh16(x) betoh16(x)
-#endif /* OUROBOROS_ENDIAN_H */
+#endif /* OUROBOROS_LIB_ENDIAN_H */
diff --git a/include/ouroboros/errno.h b/include/ouroboros/errno.h
index e393e10d..25e776df 100644
--- a/include/ouroboros/errno.h
+++ b/include/ouroboros/errno.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros specific error numbers
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -31,7 +31,8 @@
#define EIPCP 1003 /* Failed to communicate with IPCP */
#define EIPCPSTATE 1004 /* Target in wrong state */
#define EFLOWDOWN 1005 /* Flow is down */
-#define ECRYPT 1006 /* Encryption error */
-#define ENAME 1007 /* Naming error */
+#define EFLOWPEER 1006 /* Flow is down (peer timed out) */
+#define ECRYPT 1007 /* Encryption error */
+#define ENAME 1008 /* Naming error */
#endif /* OUROBOROS_ERRNO_H */
diff --git a/include/ouroboros/fccntl.h b/include/ouroboros/fccntl.h
index 965e281d..aa2b0d14 100644
--- a/include/ouroboros/fccntl.h
+++ b/include/ouroboros/fccntl.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Flow and FRCT connection control
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -46,8 +46,9 @@
#define FLOWFINVALID (FLOWFWRONLY | FLOWFRDWR)
/* FRCT flags */
-#define FRCTFRESCNTRL 00000001 /* Feedback from receiver */
-#define FRCTFRTX 00000002 /* Reliable flow */
+#define FRCTFRTX 00000001 /* Reliable flow */
+#define FRCTFRESCNTL 00000002 /* Feedback from receiver */
+#define FRCTFLINGER 00000004 /* Send unsent data */
/* Flow operations */
#define FLOWSRCVTIMEO 00000001 /* Set read timeout */
@@ -61,7 +62,8 @@
#define FLOWGTXQLEN 00000011 /* Get queue length on tx */
/* FRCT operations */
-#define FRCTGFLAGS 00001000 /* Get flags for FRCT */
+#define FRCTSFLAGS 00001000 /* Set flags for FRCT */
+#define FRCTGFLAGS 00002000 /* Get flags for FRCT */
__BEGIN_DECLS
diff --git a/include/ouroboros/flow.h b/include/ouroboros/flow.h
new file mode 100644
index 00000000..e6bf8886
--- /dev/null
+++ b/include/ouroboros/flow.h
@@ -0,0 +1,54 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Flows
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_LIB_FLOW_H
+#define OUROBOROS_LIB_FLOW_H
+
+#include <ouroboros/qos.h>
+
+#include <sys/types.h>
+
+ enum flow_state { /* DO NOT CHANGE ORDER! */
+ FLOW_INIT = 0,
+ FLOW_ALLOC_PENDING,
+ FLOW_ACCEPT_PENDING,
+ FLOW_ALLOCATED,
+ FLOW_DEALLOC_PENDING,
+ FLOW_DEALLOCATED,
+ FLOW_DESTROY, /* TODO: REMOVE! */
+ FLOW_NULL
+};
+
+struct flow_info {
+ int id;
+
+ pid_t n_pid;
+ pid_t n_1_pid;
+
+ time_t mpl;
+
+ struct qos_spec qs;
+
+ enum flow_state state;
+};
+
+#endif /* OUROBOROS_LIB_FLOW_H */
diff --git a/include/ouroboros/fqueue.h b/include/ouroboros/fqueue.h
index 60978491..8eb2ff50 100644
--- a/include/ouroboros/fqueue.h
+++ b/include/ouroboros/fqueue.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Flow queues
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -33,7 +33,8 @@ enum fqtype {
FLOW_DOWN = (1 << 1),
FLOW_UP = (1 << 2),
FLOW_ALLOC = (1 << 3),
- FLOW_DEALLOC = (1 << 4)
+ FLOW_DEALLOC = (1 << 4),
+ FLOW_PEER = (1 << 5)
};
struct flow_set;
diff --git a/include/ouroboros/hash.h b/include/ouroboros/hash.h
index 67fcfa30..6b0087ce 100644
--- a/include/ouroboros/hash.h
+++ b/include/ouroboros/hash.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Hashing functions
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -25,49 +25,60 @@
#include "config.h"
-#include <ouroboros/endian.h>
+#include <ouroboros/ipcp.h>
-#ifdef HAVE_LIBGCRYPT
-#include <gcrypt.h>
-#endif
#include <stdint.h>
#include <stddef.h>
/* Hash algorithms */
enum hash_algo {
-#ifdef HAVE_LIBGCRYPT
- HASH_CRC32 = GCRY_MD_CRC32,
- HASH_MD5 = GCRY_MD_MD5,
- HASH_SHA3_224 = GCRY_MD_SHA3_224,
- HASH_SHA3_256 = GCRY_MD_SHA3_256,
- HASH_SHA3_384 = GCRY_MD_SHA3_384,
- HASH_SHA3_512 = GCRY_MD_SHA3_512
-#else
- HASH_CRC32 = 0,
+ HASH_SHA3_224 = DIR_HASH_SHA3_224,
+ HASH_SHA3_256 = DIR_HASH_SHA3_256,
+ HASH_SHA3_384 = DIR_HASH_SHA3_384,
+ HASH_SHA3_512 = DIR_HASH_SHA3_512,
+ HASH_CRC32,
HASH_MD5,
- HASH_SHA3_224,
- HASH_SHA3_256,
- HASH_SHA3_384,
- HASH_SHA3_512
-#endif
};
-#define HASH_FMT "%02x%02x%02x%02x"
-#define HASH_VAL(hash) \
- (betoh32(*(uint32_t *) hash) & 0xFF000000) >> 24, \
- (betoh32(*(uint32_t *) hash) & 0x00FF0000) >> 16, \
- (betoh32(*(uint32_t *) hash) & 0x0000FF00) >> 8, \
- (betoh32(*(uint32_t *) hash) & 0x000000FF)
+#define HASH_FMT32 "%02x%02x%02x%02x"
+#define HASH_VAL32(hash) \
+ (hash)[0], (hash)[1], (hash)[2], (hash)[3]
+
+#define HASH_FMT64 HASH_FMT32 HASH_FMT32
+#define HASH_VAL64(hash64) \
+ HASH_VAL32(hash64), HASH_VAL32(hash64 + 4)
+
+#define HASH_FMT128 HASH_FMT64 HASH_FMT64
+#define HASH_VAL128(hash128) \
+ HASH_VAL64(hash128), HASH_VAL64(hash128 + 8)
+
+#define HASH_FMT224 HASH_FMT128 HASH_FMT64 HASH_FMT32
+#define HASH_VAL224(hash224) \
+ HASH_VAL128(hash224), HASH_VAL64(hash224 + 16), \
+ HASH_VAL32(hash224 + 24)
+
+#define HASH_FMT256 HASH_FMT128 HASH_FMT128
+#define HASH_VAL256(hash256) \
+ HASH_VAL128(hash256), HASH_VAL128(hash256 + 16)
+
+#define HASH_FMT384 HASH_FMT256 HASH_FMT128
+#define HASH_VAL384(hash384) \
+ HASH_VAL256(hash384), HASH_VAL128(hash384 + 32)
+
+#define HASH_FMT512 HASH_FMT256 HASH_FMT256
+#define HASH_VAL512(hash512) \
+ HASH_VAL256(hash512), HASH_VAL256(hash512 + 32)
+
uint16_t hash_len(enum hash_algo algo);
-void mem_hash(enum hash_algo algo,
- void * dst,
- const uint8_t * buf,
- size_t len);
+void mem_hash(enum hash_algo algo,
+ void * dst,
+ const uint8_t * buf,
+ size_t len);
-void str_hash(enum hash_algo algo,
- void * dst,
- const char * str);
+void str_hash(enum hash_algo algo,
+ void * dst,
+ const char * str);
#endif /* OUROBOROS_LIB_HASH_H */
diff --git a/include/ouroboros/ipcp-dev.h b/include/ouroboros/ipcp-dev.h
index d60e0b45..378d724a 100644
--- a/include/ouroboros/ipcp-dev.h
+++ b/include/ouroboros/ipcp-dev.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Additional API for IPCPs
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,39 +20,50 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#include <ouroboros/shm_rdrbuff.h>
+#ifndef OUROBOROS_LIB_IPCP_DEV_H
+#define OUROBOROS_LIB_IPCP_DEV_H
+
+#include <ouroboros/ipcp.h>
#include <ouroboros/qoscube.h>
+#include <ouroboros/shm_rdrbuff.h>
+#include <ouroboros/utils.h>
+
+int ipcp_create_r(const struct ipcp_info * info);
+
+int ipcp_flow_req_arr(const buffer_t * dst,
+ qosspec_t qs,
+ time_t mpl,
+ const buffer_t * data);
+
+int ipcp_flow_alloc_reply(int fd,
+ int response,
+ time_t mpl,
+ const buffer_t * data);
-#ifndef OUROBOROS_IPCP_DEV_H
-#define OUROBOROS_IPCP_DEV_H
+int ipcp_flow_read(int fd,
+ struct shm_du_buff ** sdb);
-int ipcp_create_r(int result);
+int ipcp_flow_write(int fd,
+ struct shm_du_buff * sdb);
-int ipcp_flow_req_arr(const uint8_t * dst,
- size_t len,
- qosspec_t qs,
- const void * data,
- size_t dlen);
+int np1_flow_read(int fd,
+ struct shm_du_buff ** sdb);
-int ipcp_flow_alloc_reply(int fd,
- int response,
- const void * data,
- size_t len);
+int np1_flow_write(int fd,
+ struct shm_du_buff * sdb);
-int ipcp_flow_read(int fd,
- struct shm_du_buff ** sdb);
+int ipcp_flow_dealloc(int fd);
-int ipcp_flow_write(int fd,
- struct shm_du_buff * sdb);
+int ipcp_flow_fini(int fd);
-int ipcp_flow_fini(int fd);
+int ipcp_flow_get_qoscube(int fd,
+ qoscube_t * cube);
-int ipcp_flow_get_qoscube(int fd,
- qoscube_t * cube);
+size_t ipcp_flow_queued(int fd);
-int ipcp_sdb_reserve(struct shm_du_buff ** sdb,
- size_t len);
+int ipcp_sdb_reserve(struct shm_du_buff ** sdb,
+ size_t len);
-void ipcp_sdb_release(struct shm_du_buff * sdb);
+void ipcp_sdb_release(struct shm_du_buff * sdb);
-#endif /* OUROBOROS_IPCP_DEV_H */
+#endif /* OUROBOROS_LIB_IPCP_DEV_H */
diff --git a/include/ouroboros/ipcp.h b/include/ouroboros/ipcp.h
index 6494d9b7..42c4dfa4 100644
--- a/include/ouroboros/ipcp.h
+++ b/include/ouroboros/ipcp.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPCP definitions and policies
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -26,73 +26,164 @@
#include <stdint.h>
#include <unistd.h>
#include <stdbool.h>
+#include <sys/types.h>
+#define IPCP_NAME_SIZE 255
#define LAYER_NAME_SIZE 255
+#define DEV_NAME_SIZE 255
+
+enum ipcp_state {
+ IPCP_INIT = 0,
+ IPCP_BOOT,
+ IPCP_OPERATIONAL,
+ IPCP_BOOTSTRAPPED,
+ IPCP_ENROLLED,
+ IPCP_SHUTDOWN,
+ IPCP_NULL
+};
-/*
- * NOTE: the IRMd uses this order to select an IPCP
- * for flow allocation.
- */
-enum ipcp_type {
+enum ipcp_type { /* IRMd uses order to select an IPCP for flow allocation. */
IPCP_LOCAL = 0,
IPCP_UNICAST,
IPCP_BROADCAST,
- IPCP_RAPTOR,
IPCP_ETH_LLC,
IPCP_ETH_DIX,
IPCP_UDP,
IPCP_INVALID
};
+struct ipcp_info {
+ enum ipcp_type type;
+ pid_t pid;
+ char name[IPCP_NAME_SIZE + 1];
+ enum ipcp_state state;
+};
+
+/* Unicast IPCP components. */
+#define DT_COMP "Data Transfer"
+#define MGMT_COMP "Management"
+
/* Unicast IPCP policies */
enum pol_addr_auth {
- ADDR_AUTH_FLAT_RANDOM = 0
+ ADDR_AUTH_FLAT_RANDOM = 0,
+ ADDR_AUTH_INVALID
};
enum pol_routing {
ROUTING_LINK_STATE = 0,
ROUTING_LINK_STATE_LFA,
- ROUTING_LINK_STATE_ECMP
+ ROUTING_LINK_STATE_ECMP,
+ ROUTING_INVALID
+};
+
+enum pol_cong_avoid {
+ CA_NONE = 0,
+ CA_MB_ECN,
+ CA_INVALID
+};
+
+struct dt_config {
+ uint8_t addr_size;
+ uint8_t eid_size;
+ uint8_t max_ttl;
+ enum pol_routing routing_type;
+};
+
+/* IPCP configuration */
+struct uni_config {
+ struct dt_config dt;
+ enum pol_addr_auth addr_auth_type;
+ enum pol_cong_avoid cong_avoid;
+};
+
+struct eth_config {
+ char dev[DEV_NAME_SIZE + 1];
+ uint16_t ethertype; /* DIX only*/
};
+struct udp_config {
+ uint32_t ip_addr;
+ uint32_t dns_addr;
+ uint16_t port;
+};
+
+/* Layers */
enum pol_dir_hash {
- DIR_HASH_SHA3_224 = 0,
+ DIR_HASH_SHA3_224,
DIR_HASH_SHA3_256,
DIR_HASH_SHA3_384,
- DIR_HASH_SHA3_512
+ DIR_HASH_SHA3_512,
+ DIR_HASH_INVALID
};
-/* Info reported back to the IRMd about the layer on enrollment */
struct layer_info {
- char layer_name[LAYER_NAME_SIZE + 1];
- int dir_hash_algo;
+ char name[LAYER_NAME_SIZE + 1];
+ enum pol_dir_hash dir_hash_algo;
};
/* Structure to configure the first IPCP */
struct ipcp_config {
- struct layer_info layer_info;
+ struct layer_info layer_info;
+ enum ipcp_type type;
+
+ union {
+ struct uni_config unicast;
+ struct udp_config udp;
+ struct eth_config eth;
+ };
+};
- enum ipcp_type type;
+/* default configurations */
+static const struct ipcp_config local_default_conf = {
+ .type = IPCP_LOCAL,
+ .layer_info = {
+ .dir_hash_algo = DIR_HASH_SHA3_256
+ }
+};
- /* Unicast */
- uint8_t addr_size;
- uint8_t eid_size;
- uint8_t max_ttl;
+static const struct ipcp_config eth_dix_default_conf = {
+ .type = IPCP_ETH_DIX,
+ .layer_info = {
+ .dir_hash_algo = DIR_HASH_SHA3_256
+ },
+ .eth = {
+ .ethertype=0xA000,
+ }
+};
- enum pol_addr_auth addr_auth_type;
- enum pol_routing routing_type;
+static const struct ipcp_config eth_llc_default_conf = {
+ .type = IPCP_ETH_LLC,
+ .layer_info = {
+ .dir_hash_algo = DIR_HASH_SHA3_256
+ }
+};
- /* UDP */
- uint32_t ip_addr;
- uint32_t dns_addr;
- uint16_t clt_port;
- uint16_t srv_port;
+static const struct ipcp_config udp_default_conf = {
+ .type = IPCP_UDP,
+ .udp = {
+ .port = 3435
+ }
+};
- /* Ethernet */
- char * dev;
+static const struct ipcp_config uni_default_conf = {
+ .type = IPCP_UNICAST,
+ .layer_info = {
+ .dir_hash_algo = DIR_HASH_SHA3_256
+ },
+ .unicast = {
+ .dt = {
+ .addr_size = 4,
+ .eid_size = 8,
+ .max_ttl = 60,
+ .routing_type = ROUTING_LINK_STATE
+ },
+ .addr_auth_type = ADDR_AUTH_FLAT_RANDOM,
+ .cong_avoid = CA_MB_ECN
+ }
+};
- /* Ethernet DIX */
- uint16_t ethertype;
+static const struct ipcp_config bc_default_conf = {
+ .type = IPCP_BROADCAST
};
#endif /* OUROBOROS_IPCP_H */
diff --git a/include/ouroboros/irm.h b/include/ouroboros/irm.h
index 2bb284b0..0105f88e 100644
--- a/include/ouroboros/irm.h
+++ b/include/ouroboros/irm.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* The API to instruct the IPC Resource Manager
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -25,36 +25,16 @@
#include <ouroboros/cdefs.h>
#include <ouroboros/ipcp.h>
+#include <ouroboros/name.h>
#include <ouroboros/qos.h>
#include <sys/types.h>
-/* Unicast IPCP components. */
-#define DT_COMP "Data Transfer"
-#define MGMT_COMP "Management"
-
-/* Name binding options. */
-#define BIND_AUTO 0x01
-
-#define NAME_SIZE 256
-#define LAYER_SIZE LAYER_NAME_SIZE
-
-/* Load balancing policy for incoming flows. */
-enum pol_balance {
- LB_RR = 0,
- LB_SPILL
-};
-
-struct ipcp_info {
+struct ipcp_list_info {
pid_t pid;
enum ipcp_type type;
char name[NAME_SIZE];
- char layer[LAYER_SIZE];
-};
-
-struct name_info {
- char name[NAME_SIZE];
- enum pol_balance pol_lb;
+ char layer[LAYER_NAME_SIZE];
};
__BEGIN_DECLS
@@ -64,7 +44,7 @@ pid_t irm_create_ipcp(const char * name,
int irm_destroy_ipcp(pid_t pid);
-ssize_t irm_list_ipcps(struct ipcp_info ** ipcps);
+ssize_t irm_list_ipcps(struct ipcp_list_info ** ipcps);
int irm_enroll_ipcp(pid_t pid,
const char * dst);
diff --git a/include/ouroboros/list.h b/include/ouroboros/list.h
index 5937ae78..f3ea0e46 100644
--- a/include/ouroboros/list.h
+++ b/include/ouroboros/list.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Simple doubly linked list implementation.
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -61,6 +61,6 @@ void list_del(struct list_head * e);
void list_move(struct list_head * dst,
struct list_head * src);
-bool list_is_empty(struct list_head * h);
+bool list_is_empty(const struct list_head * h);
#endif /* OUROBOROS_LIB_LIST_H */
diff --git a/include/ouroboros/local-dev.h b/include/ouroboros/local-dev.h
index 4af96770..da62e31c 100644
--- a/include/ouroboros/local-dev.h
+++ b/include/ouroboros/local-dev.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Optimized calls for the local IPCPs
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,12 +20,12 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_LOCAL_DEV_H
-#define OUROBOROS_LOCAL_DEV_H
+#ifndef OUROBOROS_LIB_LOCAL_DEV_H
+#define OUROBOROS_LIB_LOCAL_DEV_H
ssize_t local_flow_read(int fd);
int local_flow_write(int fd,
size_t idx);
-#endif /* OUROBOROS_LOCAL_DEV_H */
+#endif /* OUROBOROS_LIB_LOCAL_DEV_H */
diff --git a/include/ouroboros/lockfile.h b/include/ouroboros/lockfile.h
index 08c0c989..85a57313 100644
--- a/include/ouroboros/lockfile.h
+++ b/include/ouroboros/lockfile.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Lockfile for Ouroboros
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,8 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_LOCKFILE_H
-#define OUROBOROS_LOCKFILE_H
+#ifndef OUROBOROS_LIB_LOCKFILE_H
+#define OUROBOROS_LIB_LOCKFILE_H
#include <sys/types.h>
@@ -37,4 +37,4 @@ void lockfile_destroy(struct lockfile * lf);
pid_t lockfile_owner(struct lockfile * lf);
-#endif
+#endif /* OUROBOROS_LIB_LOCKFILE_H */
diff --git a/include/ouroboros/logs.h b/include/ouroboros/logs.h
index d6f834df..db49ae32 100644
--- a/include/ouroboros/logs.h
+++ b/include/ouroboros/logs.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Logging facilities
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,21 +20,19 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_LOGS_H
-#define OUROBOROS_LOGS_H
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <syslog.h>
+#ifndef OUROBOROS_LIB_LOGS_H
+#define OUROBOROS_LIB_LOGS_H
#ifndef OUROBOROS_PREFIX
#error You must define OUROBOROS_PREFIX before including this file
#endif
-void log_init(bool sysout);
+#include <ouroboros/hash.h>
-void log_fini(void);
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <syslog.h>
#define CLR_RED "\x1b[31m"
#define CLR_GREEN "\x1b[32m"
@@ -48,28 +46,61 @@ void log_fini(void);
extern bool log_syslog;
-#define __olog(CLR, LVL, SYSLVL, ...) \
- do { \
- if (log_syslog) { \
- syslog(SYSLVL, OUROBOROS_PREFIX ": " \
- __VA_ARGS__); \
- } else { \
- printf(CLR "==%05d== " OUROBOROS_PREFIX \
- "(" LVL "): ", getpid()); \
- printf(__VA_ARGS__); \
- printf(CLR_RESET "\n"); \
- fflush(stdout); \
- } \
+void log_init(bool sysout);
+
+void log_fini(void);
+
+
+#define __olog(CLR, LVL, SYSLVL, ...) \
+ do { \
+ if (log_syslog) { \
+ syslog(SYSLVL, __VA_ARGS__); \
+ } else { \
+ printf(CLR "==%05d== " OUROBOROS_PREFIX \
+ "(" LVL "): ", getpid()); \
+ printf(__VA_ARGS__); \
+ printf(CLR_RESET "\n"); \
+ fflush(stdout); \
+ } \
+ } while (0)
+
+#define __olog_id(CLR, LVL, SYSLVL, id, fmt, ...) \
+ do { \
+ if (log_syslog) { \
+ syslog(SYSLVL, "[" HASH_FMT64 "] " fmt, \
+ HASH_VAL64(id), ## __VA_ARGS__); \
+ } else { \
+ printf(CLR "==%05d== " OUROBOROS_PREFIX \
+ "(" LVL "): ", getpid()); \
+ printf("[" HASH_FMT64 "] " fmt, \
+ HASH_VAL64(id), ## __VA_ARGS__); \
+ printf(CLR_RESET "\n"); \
+ fflush(stdout); \
+ } \
} while (0)
-#define log_err(...) __olog(CLR_RED, ERROR_CODE, LOG_ERR, __VA_ARGS__)
-#define log_warn(...) __olog(CLR_YELLOW, WARN_CODE, LOG_WARNING, __VA_ARGS__)
-#define log_info(...) __olog(CLR_GREEN, INFO_CODE, LOG_INFO, __VA_ARGS__)
+#define log_err(...) \
+ __olog(CLR_RED, ERROR_CODE, LOG_ERR, __VA_ARGS__)
+#define log_warn(...) \
+ __olog(CLR_YELLOW, WARN_CODE, LOG_WARNING, __VA_ARGS__)
+#define log_info(...) \
+ __olog(CLR_GREEN, INFO_CODE, LOG_INFO, __VA_ARGS__)
+
+
+#define log_err_id(id, fmt, ...) \
+ __olog_id(CLR_RED, ERROR_CODE, LOG_ERR, id, fmt, ## __VA_ARGS__)
+#define log_warn_id(id, fmt, ...) \
+ __olog_id(CLR_YELLOW, WARN_CODE, LOG_WARNING, id, fmt, ## __VA_ARGS__)
+#define log_info_id(id, fmt, ...) \
+ __olog_id(CLR_GREEN, INFO_CODE, LOG_INFO, id, fmt, ## __VA_ARGS__)
#ifdef CONFIG_OUROBOROS_DEBUG
#define log_dbg(...) __olog("", DEBUG_CODE, LOG_DEBUG, __VA_ARGS__)
+#define log_dbg_id(id, fmt, ...) \
+ __olog_id("", DEBUG_CODE, LOG_DEBUG, id, fmt, ## __VA_ARGS__)
#else
#define log_dbg(...) do { } while (0)
+#define log_dbg_id(...) do { } while (0)
#endif
-#endif /* OUROBOROS_LOGS_H */
+#endif /* OUROBOROS_LIB_LOGS_H */
diff --git a/include/ouroboros/md5.h b/include/ouroboros/md5.h
index 9da88d7a..85a22544 100644
--- a/include/ouroboros/md5.h
+++ b/include/ouroboros/md5.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* MD5 algorithm
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This implementation is adapted and redistributed from the RHASH
* project implementation of the MD5 algorithm
diff --git a/include/ouroboros/name.h b/include/ouroboros/name.h
new file mode 100644
index 00000000..9d77a90b
--- /dev/null
+++ b/include/ouroboros/name.h
@@ -0,0 +1,40 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Names
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_NAME_H
+#define OUROBOROS_NAME_H
+
+#define NAME_SIZE 255
+#define BIND_AUTO 0x01
+
+enum pol_balance {
+ LB_RR = 0,
+ LB_SPILL,
+ LB_INVALID
+};
+
+struct name_info {
+ char name[NAME_SIZE + 1];
+ enum pol_balance pol_lb;
+};
+
+#endif /* OUROBOROS_NAME_H */
diff --git a/include/ouroboros/notifier.h b/include/ouroboros/notifier.h
index 3d33b663..db945f1e 100644
--- a/include/ouroboros/notifier.h
+++ b/include/ouroboros/notifier.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Notifier event system using callbacks
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/include/ouroboros/np1_flow.h b/include/ouroboros/np1_flow.h
index 82b78339..31720eea 100644
--- a/include/ouroboros/np1_flow.h
+++ b/include/ouroboros/np1_flow.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Adapter functions for N + 1 flow descriptors
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,19 +20,31 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_NP1_FLOW_H
-#define OUROBOROS_NP1_FLOW_H
+#ifndef OUROBOROS_LIB_NP1_FLOW_H
+#define OUROBOROS_LIB_NP1_FLOW_H
#include <ouroboros/qos.h>
#include <unistd.h>
-int np1_flow_alloc(pid_t n_pid,
- int flow_id,
- qosspec_t qs);
+int np1_flow_alloc(pid_t n_pid,
+ int flow_id);
int np1_flow_resp(int flow_id);
-int np1_flow_dealloc(int flow_id);
+int np1_flow_dealloc(int flow_id,
+ time_t timeo);
-#endif /* OUROBOROS_NP1_FLOW_H */
+static const qosspec_t qos_np1 = {
+ .delay = UINT32_MAX,
+ .bandwidth = 0,
+ .availability = 0,
+ .loss = UINT32_MAX,
+ .ber = UINT32_MAX,
+ .in_order = 0,
+ .max_gap = UINT32_MAX,
+ .cypher_s = 0,
+ .timeout = 0
+};
+
+#endif /* OUROBOROS_LIB_NP1_FLOW_H */
diff --git a/include/ouroboros/proc.h b/include/ouroboros/proc.h
new file mode 100644
index 00000000..80c67227
--- /dev/null
+++ b/include/ouroboros/proc.h
@@ -0,0 +1,44 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Processes and Programs
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_LIB_PROC_H
+#define OUROBOROS_LIB_PROC_H
+
+#include <sys/types.h>
+
+#define PROG_NAME_SIZE 255
+#define PROG_PATH_SIZE 255
+
+/* Processes */
+struct proc_info {
+ pid_t pid;
+ char prog[PROG_NAME_SIZE + 1]; /* program instantiated */
+
+};
+
+/* Programs */
+struct prog_info {
+ char name[PROG_NAME_SIZE + 1];
+ char path[PROG_PATH_SIZE + 1];
+};
+
+#endif /* OUROBOROS_LIB_PROC_H */
diff --git a/include/ouroboros/proto.h b/include/ouroboros/proto.h
index 8a3db8a0..5c863c8b 100644
--- a/include/ouroboros/proto.h
+++ b/include/ouroboros/proto.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Protocol syntax definitions
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/include/ouroboros/protobuf.h b/include/ouroboros/protobuf.h
new file mode 100644
index 00000000..9d38afb1
--- /dev/null
+++ b/include/ouroboros/protobuf.h
@@ -0,0 +1,117 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Protobuf syntax conversion
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_LIB_PROTOBUF_H
+#define OUROBOROS_LIB_PROTOBUF_H
+
+#include <ouroboros/flow.h>
+#include <ouroboros/qos.h>
+#include <ouroboros/ipcp.h>
+#include <ouroboros/irm.h>
+#include <ouroboros/serdes-irm.h>
+#include <ouroboros/serdes-oep.h>
+
+#include "ipcp_config.pb-c.h"
+typedef IpcpConfigMsg ipcp_config_msg_t;
+typedef DtConfigMsg dt_config_msg_t;
+typedef EthConfigMsg eth_config_msg_t;
+typedef UdpConfigMsg udp_config_msg_t;
+typedef UniConfigMsg uni_config_msg_t;
+
+#include "ipcp.pb-c.h"
+typedef IpcpMsg ipcp_msg_t;
+
+#include "irm.pb-c.h"
+typedef IrmMsg irm_msg_t;
+typedef TimespecMsg timespec_msg_t;
+typedef IpcpInfoMsg ipcp_info_msg_t;
+typedef IpcpListMsg ipcp_list_msg_t;
+
+#include "model.pb-c.h"
+typedef FlowInfoMsg flow_info_msg_t;
+typedef LayerInfoMsg layer_info_msg_t;
+typedef NameInfoMsg name_info_msg_t;
+typedef QosspecMsg qosspec_msg_t;
+
+#include "enroll.pb-c.h"
+typedef EnrollReqMsg enroll_req_msg_t;
+typedef EnrollRespMsg enroll_resp_msg_t;
+typedef EnrollAckMsg enroll_ack_msg_t;
+
+/* IPCP configuration */
+timespec_msg_t * timespec_s_to_msg(const struct timespec * s);
+
+struct timespec timespec_msg_to_s(timespec_msg_t * msg);
+
+flow_info_msg_t * flow_info_s_to_msg(const struct flow_info * s);
+
+struct flow_info flow_info_msg_to_s(const flow_info_msg_t * msg);
+
+layer_info_msg_t * layer_info_s_to_msg(const struct layer_info * s);
+
+struct layer_info layer_info_msg_to_s(const layer_info_msg_t * msg);
+
+ipcp_info_msg_t * ipcp_info_s_to_msg(const struct ipcp_info * s);
+
+struct ipcp_info ipcp_info_msg_to_s(const ipcp_info_msg_t * msg);
+
+dt_config_msg_t * dt_config_s_to_msg(const struct dt_config * s);
+
+struct dt_config dt_config_msg_to_s(const dt_config_msg_t * msg);
+
+uni_config_msg_t * uni_config_s_to_msg(const struct uni_config * s);
+
+struct uni_config uni_config_msg_to_s(const uni_config_msg_t * msg);
+
+eth_config_msg_t * eth_config_s_to_msg(const struct eth_config * s);
+
+struct eth_config eth_config_msg_to_s(const eth_config_msg_t * msg);
+
+udp_config_msg_t * udp_config_s_to_msg(const struct udp_config * s);
+
+struct udp_config udp_config_msg_to_s(const udp_config_msg_t * msg);
+
+ipcp_config_msg_t * ipcp_config_s_to_msg(const struct ipcp_config * s);
+
+struct ipcp_config ipcp_config_msg_to_s(const ipcp_config_msg_t * msg);
+
+/* QoS */
+
+qosspec_msg_t * qos_spec_s_to_msg(const struct qos_spec * s);
+
+struct qos_spec qos_spec_msg_to_s(const qosspec_msg_t * msg);
+
+/* Enrollment */
+
+enroll_req_msg_t * enroll_req_s_to_msg(const struct enroll_req * s);
+
+struct enroll_req enroll_req_msg_to_s(const enroll_req_msg_t * msg);
+
+enroll_resp_msg_t * enroll_resp_s_to_msg(const struct enroll_resp * s);
+
+struct enroll_resp enroll_resp_msg_to_s(const enroll_resp_msg_t * msg);
+
+enroll_ack_msg_t * enroll_ack_s_to_msg(const struct enroll_ack * s);
+
+struct enroll_ack enroll_ack_msg_to_s(const enroll_ack_msg_t * msg);
+
+#endif /* OUROBOROS_LIB_PROTOBUF_H */
diff --git a/include/ouroboros/pthread.h b/include/ouroboros/pthread.h
new file mode 100644
index 00000000..7044cb5e
--- /dev/null
+++ b/include/ouroboros/pthread.h
@@ -0,0 +1,51 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Useful cleanup functions for pthreads
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_LIB_PTHREAD_H
+#define OUROBOROS_LIB_PTHREAD_H
+
+#include <pthread.h>
+
+static int __attribute__((unused)) __timedwait(pthread_cond_t * cond,
+ pthread_mutex_t * mtx,
+ const struct timespec * abstime)
+{
+ if (abstime == NULL)
+ return pthread_cond_wait(cond, mtx);
+
+ return pthread_cond_timedwait(cond, mtx, abstime);
+}
+
+#if defined (_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L
+/* various cleanup functions for pthread_cleanup_push */
+static void __attribute__((unused)) __cleanup_rwlock_unlock(void * rwlock)
+{
+ pthread_rwlock_unlock((pthread_rwlock_t *) rwlock);
+}
+#endif
+
+static void __attribute__((unused)) __cleanup_mutex_unlock(void * mutex)
+{
+ pthread_mutex_unlock((pthread_mutex_t *) mutex);
+}
+
+#endif /* OUROBOROS_LIB_PTHREAD_H */
diff --git a/include/ouroboros/qos.h b/include/ouroboros/qos.h
index 785996b9..a45e8135 100644
--- a/include/ouroboros/qos.h
+++ b/include/ouroboros/qos.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Quality of Service specification
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -26,15 +26,18 @@
#include <stdint.h>
#include <stdbool.h>
+#define DEFAULT_PEER_TIMEOUT 120000
+
typedef struct qos_spec {
- uint32_t delay; /* In ms */
- uint64_t bandwidth; /* In bits/s */
- uint8_t availability; /* Class of 9s */
- uint32_t loss; /* Packet loss */
- uint32_t ber; /* Bit error rate, errors per billion bits */
- uint8_t in_order; /* In-order delivery, enables FRCT */
- uint32_t max_gap; /* In ms */
- uint16_t cypher_s; /* Cypher strength, 0 = no encryption */
+ uint32_t delay; /* In ms. */
+ uint64_t bandwidth; /* In bits/s. */
+ uint8_t availability; /* Class of 9s. */
+ uint32_t loss; /* Packet loss. */
+ uint32_t ber; /* Bit error rate, errors per billion bits. */
+ uint8_t in_order; /* In-order delivery, enables FRCT. */
+ uint32_t max_gap; /* In ms. */
+ uint16_t cypher_s; /* Cypher strength (bits), 0 = no encryption. */
+ uint32_t timeout; /* Peer timeout time, in ms, 0 = no timeout. */
} qosspec_t;
static const qosspec_t qos_raw = {
@@ -45,7 +48,8 @@ static const qosspec_t qos_raw = {
.ber = 1,
.in_order = 0,
.max_gap = UINT32_MAX,
- .cypher_s = 0
+ .cypher_s = 0,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_raw_no_errors = {
@@ -56,7 +60,8 @@ static const qosspec_t qos_raw_no_errors = {
.ber = 0,
.in_order = 0,
.max_gap = UINT32_MAX,
- .cypher_s = 0
+ .cypher_s = 0,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_raw_crypt = {
@@ -67,7 +72,8 @@ static const qosspec_t qos_raw_crypt = {
.ber = 0,
.in_order = 0,
.max_gap = UINT32_MAX,
- .cypher_s = 256
+ .cypher_s = 256,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_best_effort = {
@@ -78,7 +84,8 @@ static const qosspec_t qos_best_effort = {
.ber = 0,
.in_order = 1,
.max_gap = UINT32_MAX,
- .cypher_s = 0
+ .cypher_s = 0,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_best_effort_crypt = {
@@ -89,7 +96,8 @@ static const qosspec_t qos_best_effort_crypt = {
.ber = 0,
.in_order = 1,
.max_gap = UINT32_MAX,
- .cypher_s = 256
+ .cypher_s = 256,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_video = {
@@ -100,7 +108,8 @@ static const qosspec_t qos_video = {
.ber = 0,
.in_order = 1,
.max_gap = 100,
- .cypher_s = 0
+ .cypher_s = 0,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_video_crypt = {
@@ -111,7 +120,8 @@ static const qosspec_t qos_video_crypt = {
.ber = 0,
.in_order = 1,
.max_gap = 100,
- .cypher_s = 256
+ .cypher_s = 256,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_voice = {
@@ -122,7 +132,8 @@ static const qosspec_t qos_voice = {
.ber = 0,
.in_order = 1,
.max_gap = 50,
- .cypher_s = 0
+ .cypher_s = 0,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_voice_crypt = {
@@ -133,7 +144,8 @@ static const qosspec_t qos_voice_crypt = {
.ber = 0,
.in_order = 1,
.max_gap = 50,
- .cypher_s = 256
+ .cypher_s = 256,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_data = {
@@ -144,7 +156,8 @@ static const qosspec_t qos_data = {
.ber = 0,
.in_order = 1,
.max_gap = 2000,
- .cypher_s = 0
+ .cypher_s = 0,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
static const qosspec_t qos_data_crypt = {
@@ -155,7 +168,8 @@ static const qosspec_t qos_data_crypt = {
.ber = 0,
.in_order = 1,
.max_gap = 2000,
- .cypher_s = 256
+ .cypher_s = 256,
+ .timeout = DEFAULT_PEER_TIMEOUT
};
#endif /* OUROBOROS_QOS_H */
diff --git a/include/ouroboros/qoscube.h b/include/ouroboros/qoscube.h
index 05d10dd2..ed20484c 100644
--- a/include/ouroboros/qoscube.h
+++ b/include/ouroboros/qoscube.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Quality of Service cubes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,8 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_QOSCUBE_H
-#define OUROBOROS_QOSCUBE_H
+#ifndef OUROBOROS_LIB_QOSCUBE_H
+#define OUROBOROS_LIB_QOSCUBE_H
#include <ouroboros/qos.h>
@@ -35,4 +35,4 @@ typedef enum qos_cube {
qoscube_t qos_spec_to_cube(qosspec_t qs);
qosspec_t qos_cube_to_spec(qoscube_t qc);
-#endif
+#endif /* OUROBOROS_LIB_QOSCUBE_H */
diff --git a/include/ouroboros/random.h b/include/ouroboros/random.h
index 25332faf..e1b25e5d 100644
--- a/include/ouroboros/random.h
+++ b/include/ouroboros/random.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Pseudo random generator
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,12 +20,12 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_RANDOM_H
-#define OUROBOROS_RANDOM_H
+#ifndef OUROBOROS_LIB_RANDOM_H
+#define OUROBOROS_LIB_RANDOM_H
#include <sys/types.h>
int random_buffer(void * buf,
size_t len);
-#endif /* OUROBOROS_RANDOM_H */
+#endif /* OUROBOROS_LIB_RANDOM_H */
diff --git a/include/ouroboros/rib.h b/include/ouroboros/rib.h
index 68ed6235..6aabe8f7 100644
--- a/include/ouroboros/rib.h
+++ b/include/ouroboros/rib.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* RIB export using FUSE
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -23,20 +23,25 @@
#ifndef OUROBOROS_LIB_RIB_H
#define OUROBOROS_LIB_RIB_H
-#define RIB_PATH_LEN 128
+#define RIB_PATH_LEN 300
+#define RIB_SEPARATOR "/"
-#include <sys/stat.h>
#include <sys/types.h>
struct rib;
+struct rib_attr {
+ size_t size; /* Size of RIB document */
+ time_t mtime; /* Last modified time */
+};
+
struct rib_ops {
int (* read)(const char * path,
char * buf,
size_t len);
int (* readdir)(char *** entries);
- int (* getattr)(const char * path,
- struct stat * st);
+ int (* getattr)(const char * path,
+ struct rib_attr * attr);
};
int rib_init(const char * prefix);
@@ -48,4 +53,6 @@ int rib_reg(const char * path,
void rib_unreg(const char * path);
+void rib_cleanup(const char * mnt);
+
#endif /* OUROBOROS_LIB_RIB_H */
diff --git a/include/ouroboros/serdes-irm.h b/include/ouroboros/serdes-irm.h
new file mode 100644
index 00000000..1d041541
--- /dev/null
+++ b/include/ouroboros/serdes-irm.h
@@ -0,0 +1,79 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros IRM Protocol - serialization/deserialization
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_LIB_SERDES_IRM_H
+#define OUROBOROS_LIB_SERDES_IRM_H
+
+#include <ouroboros/flow.h>
+#include <ouroboros/ipcp.h>
+#include <ouroboros/time.h>
+#include <ouroboros/utils.h>
+
+#include <inttypes.h>
+
+int flow_alloc__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const char * dst,
+ const struct timespec * timeo);
+
+int flow_join__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const char * dst,
+ const struct timespec * timeo);
+
+int flow_accept__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const struct timespec * timeo);
+
+int ipcp_flow_req_arr__irm_req_ser(buffer_t * buf,
+ const buffer_t * dst,
+ const struct flow_info * flow,
+ const buffer_t * data);
+
+int ipcp_flow_alloc_reply__irm_msg_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ int response,
+ const buffer_t * data);
+
+/* response to alloc / join / accept / flow_req_arr */
+int flow__irm_result_des(buffer_t * buf,
+ struct flow_info * flow,
+ buffer_t * sk);
+
+int flow_dealloc__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const struct timespec * timeo);
+
+int ipcp_flow_dealloc__irm_req_ser(buffer_t * buf,
+ const struct flow_info * info);
+
+int ipcp_create_r__irm_req_ser(buffer_t * buf,
+ const struct ipcp_info * ipcp);
+
+int proc_announce__irm_req_ser(buffer_t * buf,
+ const char * prog);
+
+int proc_exit__irm_req_ser(buffer_t * buf);
+
+int irm__irm_result_des(buffer_t * buf);
+
+#endif /* OUROBOROS_LIB_SERDES_IRM_H*/
diff --git a/include/ouroboros/serdes-oep.h b/include/ouroboros/serdes-oep.h
new file mode 100644
index 00000000..69ba71a4
--- /dev/null
+++ b/include/ouroboros/serdes-oep.h
@@ -0,0 +1,70 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros Enrollment Protocol - serialization/deserialization
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_LIB_SERDES_OEP_H
+#define OUROBOROS_LIB_SERDES_OEP_H
+
+#include <ouroboros/ipcp.h>
+#include <ouroboros/utils.h>
+
+#include <sys/time.h>
+
+/* Enrollment */
+
+#define ENROLL_ID_LEN 8
+
+struct enroll_req {
+ /* TODO: Authentication */
+ uint8_t id[ENROLL_ID_LEN];
+};
+
+struct enroll_resp {
+ uint8_t id[ENROLL_ID_LEN];
+ struct timespec t;
+ int response;
+ struct ipcp_config conf;
+};
+
+struct enroll_ack {
+ uint8_t id[ENROLL_ID_LEN];
+ int result;
+};
+
+ssize_t enroll_req_ser(const struct enroll_req * req,
+ buffer_t buf);
+
+int enroll_req_des(struct enroll_req * req,
+ const buffer_t buf);
+
+ssize_t enroll_resp_ser(const struct enroll_resp * resp,
+ buffer_t buf);
+
+int enroll_resp_des(struct enroll_resp * resp,
+ buffer_t buf);
+
+ssize_t enroll_ack_ser(const struct enroll_ack * ack,
+ buffer_t buf);
+
+int enroll_ack_des(struct enroll_ack * ack,
+ const buffer_t buf);
+
+#endif /* OUROBOROS_LIB_SERDES_OEP_H*/
diff --git a/include/ouroboros/sha3.h b/include/ouroboros/sha3.h
index fe255d9c..04871f3b 100644
--- a/include/ouroboros/sha3.h
+++ b/include/ouroboros/sha3.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* SHA3 algorithm
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This implementation is adapted and redistributed from the RHASH
* project implementation of the sha3 algorithm
diff --git a/include/ouroboros/shm_du_buff.h b/include/ouroboros/shm_du_buff.h
index 9a10263f..c25d4b95 100644
--- a/include/ouroboros/shm_du_buff.h
+++ b/include/ouroboros/shm_du_buff.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Data Buffer element in Random Deletion Ring Buffer
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,8 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_SHM_DU_BUFF_H
-#define OUROBOROS_SHM_DU_BUFF_H
+#ifndef OUROBOROS_LIB_SHM_DU_BUFF_H
+#define OUROBOROS_LIB_SHM_DU_BUFF_H
#include <sys/types.h>
#include <stdint.h>
@@ -34,6 +34,8 @@ uint8_t * shm_du_buff_head(struct shm_du_buff * sdb);
uint8_t * shm_du_buff_tail(struct shm_du_buff * sdb);
+size_t shm_du_buff_len(struct shm_du_buff * sdb);
+
uint8_t * shm_du_buff_head_alloc(struct shm_du_buff * sdb,
size_t size);
@@ -53,4 +55,4 @@ int shm_du_buff_wait_ack(struct shm_du_buff * sdb);
int shm_du_buff_ack(struct shm_du_buff * sdb);
-#endif /* OUROBOROS_SHM_DU_BUFF_H */
+#endif /* OUROBOROS_LIB_SHM_DU_BUFF_H */
diff --git a/include/ouroboros/shm_flow_set.h b/include/ouroboros/shm_flow_set.h
index 19b0f013..09e37649 100644
--- a/include/ouroboros/shm_flow_set.h
+++ b/include/ouroboros/shm_flow_set.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Management of flow_sets for fqueue
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,13 +20,18 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_SHM_FLOW_SET_H
-#define OUROBOROS_SHM_FLOW_SET_H
+#ifndef OUROBOROS_LIB_SHM_FLOW_SET_H
+#define OUROBOROS_LIB_SHM_FLOW_SET_H
#include <ouroboros/fqueue.h>
#include <sys/time.h>
+struct flowevent {
+ int flow_id;
+ int event;
+};
+
struct shm_flow_set;
struct shm_flow_set * shm_flow_set_create(pid_t pid);
@@ -58,7 +63,7 @@ void shm_flow_set_notify(struct shm_flow_set * set,
ssize_t shm_flow_set_wait(const struct shm_flow_set * shm_set,
size_t idx,
- int * fqueue,
+ struct flowevent * fqueue,
const struct timespec * abstime);
-#endif /* OUROBOROS_SHM_FLOW_SET_H */
+#endif /* OUROBOROS_LIB_SHM_FLOW_SET_H */
diff --git a/include/ouroboros/shm_rbuff.h b/include/ouroboros/shm_rbuff.h
index 9bf3a596..4323d4e1 100644
--- a/include/ouroboros/shm_rbuff.h
+++ b/include/ouroboros/shm_rbuff.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ring buffer for incoming packets
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,8 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_SHM_RBUFF_H
-#define OUROBOROS_SHM_RBUFF_H
+#ifndef OUROBOROS_LIB_SHM_RBUFF_H
+#define OUROBOROS_LIB_SHM_RBUFF_H
#include <sys/types.h>
#include <sys/time.h>
@@ -31,6 +31,7 @@
#define ACL_RDWR 0000
#define ACL_RDONLY 0001
#define ACL_FLOWDOWN 0002
+#define ACL_FLOWPEER 0004
struct shm_rbuff;
@@ -65,4 +66,4 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff * rb,
size_t shm_rbuff_queued(struct shm_rbuff * rb);
-#endif /* OUROBOROS_SHM_RBUFF_H */
+#endif /* OUROBOROS_LIB_SHM_RBUFF_H */
diff --git a/include/ouroboros/shm_rdrbuff.h b/include/ouroboros/shm_rdrbuff.h
index c4e865e5..4f9a215a 100644
--- a/include/ouroboros/shm_rdrbuff.h
+++ b/include/ouroboros/shm_rdrbuff.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Random Deletion Ring Buffer for Data Units
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,14 +20,14 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_SHM_RDRBUFF_H
-#define OUROBOROS_SHM_RDRBUFF_H
+#ifndef OUROBOROS_LIB_SHM_RDRBUFF_H
+#define OUROBOROS_LIB_SHM_RDRBUFF_H
#include <ouroboros/shm_du_buff.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/time.h>
-#include <stdint.h>
#include <pthread.h>
+#include <stdint.h>
#include <sys/types.h>
struct shm_rdrbuff;
@@ -64,4 +64,4 @@ struct shm_du_buff * shm_rdrbuff_get(struct shm_rdrbuff * rdrb,
int shm_rdrbuff_remove(struct shm_rdrbuff * rdrb,
size_t idx);
-#endif /* OUROBOROS_SHM_RDRBUFF_H */
+#endif /* OUROBOROS_LIB_SHM_RDRBUFF_H */
diff --git a/include/ouroboros/sockets.h.in b/include/ouroboros/sockets.h.in
index 9ab2314f..095674a9 100644
--- a/include/ouroboros/sockets.h.in
+++ b/include/ouroboros/sockets.h.in
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* The sockets layer to communicate between daemons
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,35 +20,20 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_SOCKETS_H
-#define OUROBOROS_SOCKETS_H
+#ifndef OUROBOROS_LIB_SOCKETS_H
+#define OUROBOROS_LIB_SOCKETS_H
-#include <ouroboros/qos.h>
+#include <ouroboros/protobuf.h>
#include <sys/types.h>
-#include "ipcp_config.pb-c.h"
-typedef IpcpConfigMsg ipcp_config_msg_t;
-typedef LayerInfoMsg layer_info_msg_t;
+#define SOCK_PATH "/var/run/ouroboros/"
+#define SOCK_PATH_SUFFIX ".sock"
-#include "irmd_messages.pb-c.h"
-typedef IrmMsg irm_msg_t;
-typedef IpcpInfoMsg ipcp_info_msg_t;
-typedef NameInfoMsg name_info_msg_t;
-
-#include "ipcpd_messages.pb-c.h"
-typedef IpcpMsg ipcp_msg_t;
-
-#include "qosspec.pb-c.h"
-typedef QosspecMsg qosspec_msg_t;
-
-#define SOCK_PATH "/var/run/ouroboros/"
-#define SOCK_PATH_SUFFIX ".sock"
-
-#define IRM_SOCK_PATH SOCK_PATH "irm" SOCK_PATH_SUFFIX
+#define IRM_SOCK_PATH SOCK_PATH "irm" SOCK_PATH_SUFFIX
#define IPCP_SOCK_PATH_PREFIX SOCK_PATH "ipcp"
-#define SOCK_BUF_SIZE @SOCK_BUF_SIZE@
+#define SOCK_BUF_SIZE @SOCK_BUF_SIZE@
/* Returns the full socket path of an IPCP */
char * ipcp_sock_path(pid_t pid);
@@ -57,12 +42,11 @@ int server_socket_open(char * file_name);
int client_socket_open(char * file_name);
-irm_msg_t * send_recv_irm_msg(irm_msg_t * msg);
-
+int send_recv_msg(buffer_t * buf);
-/* qos message conversion needed in different components */
-qosspec_msg_t spec_to_msg(const qosspec_t * qs);
+irm_msg_t * send_recv_irm_msg(irm_msg_t * msg);
-qosspec_t msg_to_spec(const qosspec_msg_t * msg);
+/* cleanup socket when cancelling thread */
+void __cleanup_close_ptr(void * o);
-#endif
+#endif /* OUROBOROS_LIB_SOCKETS_H */
diff --git a/include/ouroboros/test.h b/include/ouroboros/test.h
new file mode 100644
index 00000000..096e145c
--- /dev/null
+++ b/include/ouroboros/test.h
@@ -0,0 +1,82 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Test macros
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_LIB_TEST_H
+#define OUROBOROS_LIB_TEST_H
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#define TEST_START() \
+ do { \
+ printf("%s started.\n", __func__); \
+ fflush(stdout); \
+ } while (0)
+#define TEST_SUCCESS() \
+ do { \
+ printf("%s succeeded.\n", __func__); \
+ fflush(stdout); \
+ } while (0)
+
+#define TEST_FAIL() \
+ do { \
+ printf("%s failed.\n", __func__); \
+ fflush(stdout); \
+ } while (0)
+
+#define TEST_END(result) \
+ do { if (result == 0) TEST_SUCCESS(); else TEST_FAIL(); } while (0)
+
+static int __attribute__((unused)) test_assert_fail(int(* testfunc)(void))
+{
+ pid_t pid;
+ int wstatus;
+
+ pid = fork();
+ if (pid == -1) {
+ printf("Failed to fork: %s.\n", strerror(errno));
+ return -1;
+ }
+
+ if (pid == 0)
+ return testfunc(); /* should abort */
+
+ waitpid(pid, &wstatus, 0);
+#ifdef CONFIG_OUROBOROS_DEBUG
+ if (WIFSIGNALED(wstatus) && (wstatus == 134 || wstatus == 6))
+ return 0;
+
+ printf("Process did not abort, status: %d.\n", wstatus);
+#else
+ if (WIFEXITED(wstatus) && wstatus == 0)
+ return 0;
+
+ printf("Process did not exit, status: %d.\n", wstatus);
+#endif
+
+ return -1;
+}
+
+#endif /* OUROBOROS_LIB_TEST_H */
diff --git a/include/ouroboros/time_utils.h b/include/ouroboros/time.h
index c20d3747..b274c35b 100644
--- a/include/ouroboros/time_utils.h
+++ b/include/ouroboros/time.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Time utilities
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,8 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_TIME_UTILS_H
-#define OUROBOROS_TIME_UTILS_H
+#ifndef OUROBOROS_LIB_TIME_H
+#define OUROBOROS_LIB_TIME_H
#ifdef MILLION
#undef MILLION
@@ -37,6 +37,15 @@
#include <time.h>
#include <sys/time.h>
+#define TIMESPEC_INIT_S(s) {(s), 0}
+#define TIMESPEC_INIT_MS(ms) {(ms) / 1000, ((ms) % 1000) * MILLION}
+#define TIMESPEC_INIT_US(us) {(us) / MILLION, ((us) % MILLION) * 1000}
+#define TIMESPEC_INIT_NS(ns) {(ns) / BILLION, ((ns) % BILLION)}
+
+#define TIMEVAL_INIT_S(s) {(s), 0}
+#define TIMEVAL_INIT_MS(ms) {(ms) / 1000, ((ms) % 1000) * 1000}
+#define TIMEVAL_INIT_US(us) {(us) / MILLION, ((us) % MILLION)}
+
/* functions for timespecs */
#define ts_diff_ns(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * BILLION \
+ ((tx)->tv_nsec - (t0)->tv_nsec))
@@ -118,4 +127,4 @@
(tv)->tv_usec = (ts)->tv_nsec / 1000L; \
} while (0);
-#endif /* OUROBOROS_TIME_UTILS_H */
+#endif /* OUROBOROS_LIB_TIME_H */
diff --git a/include/ouroboros/tpm.h b/include/ouroboros/tpm.h
index 69b15a2c..445f9306 100644
--- a/include/ouroboros/tpm.h
+++ b/include/ouroboros/tpm.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Threadpool management
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/include/ouroboros/utils.h b/include/ouroboros/utils.h
index de69bc94..93fbf402 100644
--- a/include/ouroboros/utils.h
+++ b/include/ouroboros/utils.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Handy utilities
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,15 +20,18 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_UTILS_H
-#define OUROBOROS_UTILS_H
+#ifndef OUROBOROS_LIB_UTILS_H
+#define OUROBOROS_LIB_UTILS_H
#include <stdint.h>
#include <unistd.h>
+#include <string.h>
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define ABS(a) ((a) > 0 ? (a) : -(a))
+#define clrbuf(buf) do { memset(&(buf), 0, sizeof(buf)); } while (0);
+#define freebuf(buf) do { free((buf).data); clrbuf(buf); } while (0);
typedef struct {
uint8_t * data;
@@ -42,7 +45,14 @@ typedef struct {
int n_digits(unsigned i);
/* gets the application name */
-char * path_strip(char * src);
+char * path_strip(const char * src);
+
+/* functions for copying and destroying arguments list */
+size_t argvlen(const char ** argv);
+
+char ** argvdup(char ** argv);
+
+void argvfree(char ** argv);
/* destroy a ** */
#define freepp(type, ptr, len) \
@@ -54,4 +64,4 @@ char * path_strip(char * src);
free(ptr); \
} while (0);
-#endif /* OUROBOROS_UTILS_H */
+#endif /* OUROBOROS_LIB_UTILS_H */
diff --git a/include/ouroboros/version.h.in b/include/ouroboros/version.h.in
index 030a711f..c006a095 100644
--- a/include/ouroboros/version.h.in
+++ b/include/ouroboros/version.h.in
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros version
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/irmd.conf.in b/irmd.conf.in
new file mode 100644
index 00000000..4fb01c93
--- /dev/null
+++ b/irmd.conf.in
@@ -0,0 +1,112 @@
+### Example Ouroboros configuration file
+#
+# This file contains a summary of current machine configuration
+# options for the O7s prototype. The IRMd will attempt to load its
+# configuration file during startup from the file
+# @OUROBOROS_CONFIG_DIR@@OUROBOROS_CONFIG_FILE@.
+#
+# At the top level, it accepts configuration of
+# services via the "name" directive, and configuration of the network
+# specifying different IPCPs in the system. So, the list of accepted
+# top level stanza is:
+#
+# [name.<name of service>] add a new name to the system.
+# [local.<name for IPCP>] add a new local IPCP to the system.
+# [eth-llc.<name for IPCP>] add a new IPCP over Ethernet (LLC) to the system.
+# [eth-dix.<name for IPCP>] add a new IPCP over Ethernet (DIX) to the system.
+# [eth-udp.<name for IPCP>] add a new IPCP over UDP/IPv4 to the system.
+# [broadcast.<name of IPCP>] add a new broadcast IPCP to the system.
+# [unicast.<name of IPCP>] add a new unicast IPCP to the system.
+#
+# Options for names:
+#
+# A name can be created without any parameters. The following options will
+# allow more useful configurations:
+# prog: bind programs to this name. Whenever an instance of one of these
+# programs is started, it will accept incoming flows for this name.
+# args: When provided the program at the same index in the prog list will be
+# automatically started if there is an incoming flow for that name.
+# lb: Load-balancing option, if there are multiple processes accepting flows
+# for that name, the flow will get assigned to the process according to
+# the specified load-balancing algorithm.
+#
+# Options for IPCPs:
+#
+# bootstrap=<layer_name>: Immediately bootstrap this IPCP in this layer.
+# enrol=<dst>: Enrol with this neigbor (broadcast and unicast only).
+# conn=[<dst>]: Create mgmt and data flows with these neighbors.
+# reg=[<names>]: Register these names with the IPCP.
+# Bootstrap options can be set as in the examples below.
+# For more details on the configuration options for each of the IPCP types,
+# please refer to the Ouroboros man page.
+
+[name.oping]
+prog=["@INSTALL_DIR@/oping"] # Defaults to [].
+args=["--listen"] # Defaults to disabled. Autostart server with these args.
+lb="round-robin" # Defaults to spill (load-balancing options: spill, round-robin).
+
+[name.oecho]
+prog=["@INSTALL_DIR@/oecho"] # Defaults to [].
+args=["--listen"] # Defaults to disabled. Autostart server with these args.
+lb="round-robin" # Defaults to spill (load-balancing options: spill, round-robin).
+
+[name.ocbr]
+prog=["@INSTALL_DIR@/ocbr"] # Defaults to [].
+
+[name.ovpn]
+prog=["@INSTALL_DIR@/ovpn"] # Defaults to [].
+
+[local.local1]
+bootstrap="local1" # Defaults to not set.
+ # BOOTSTRAP CONFIGURATION
+# hash="SHA3_224" # Defaults to SHA3_256.
+ # NAMES KNOWN
+reg=["bc1", "LAN"] # Defaults to [].
+
+[eth-llc.ethl]
+bootstrap="ethl1" # Defaults to not set.
+ # BOOTSTRAP CONFIGURATION
+dev="lo"
+# hash="SHA3_224" # Defaults to SHA3_256.
+
+[eth-dix.eth1]
+bootstrap="eth1" # Defaults to not set.
+ # BOOTSTRAP CONFIGURATION
+dev="lo"
+# ethertype=0xA007 # Defaults to 0xA000.
+# hash="SHA3_224" # Defaults to SHA3_256.
+reg=["lan1"]
+
+[udp.udp1]
+bootstrap="udp" # Defaults to not set.
+ # BOOTSTRAP CONFIGURATION
+ip="127.0.0.1"
+# port=9000 # Defaults to 3435.
+# dns="127.0.0.1" # Requires a DDNS server. Disables DDNS support if not set.
+
+[broadcast.bc1]
+bootstrap="broadcast" # Defaults to not set.
+autobind=true # Defaults to false.
+
+[broadcast.bc2]
+enrol="bc1"
+# autobind=true # Defaults to false.
+
+[unicast.lan1]
+bootstrap="LAN" # Defaults to not set.
+autobind=true # Defaults to false.
+ # BOOTSTRAP CONFIGURATION
+# hash="SHA3_224" # Defaults to SHA3_256.
+# addr_size=4 # Defaults to 4 (32-bit addresses).
+# eid_size=8 # Defaults to 8 (64-bit endpoint IDs, only accepted option).
+# max_ttl=60 # Defaults to 60 (max 255).
+# addr-auth="flat" # Defaults to flat (currently only option).
+# routing="lfa" # Defaults to link-state (options: link-state, lfa, ecmp).
+# congestion="none" # Defaults to mb-ecn (options: none, mb-ecn).
+ # NAMES KNOWN
+reg=["oping"] # Defaults to [].
+
+[unicast.lan2]
+enrol="LAN" # Defaults to not set.
+conn=["lan1"] # Defaults to [].
+autobind=true # Defaults to false.
diff --git a/ouroboros.service.in b/ouroboros.service.in
index e6dc006e..2aa05ba2 100644
--- a/ouroboros.service.in
+++ b/ouroboros.service.in
@@ -2,8 +2,8 @@
Description=Ouroboros IPC Resource Manager Daemon
[Service]
-ExecStart=@CMAKE_INSTALL_PREFIX@/sbin/irmd
+ExecStart=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_SBINDIR@/irmd @CONFIGURE_STRING@
User=root
[Install]
-WantedBy=multi-user.target \ No newline at end of file
+WantedBy=multi-user.target
diff --git a/src/ipcpd/CMakeLists.txt b/src/ipcpd/CMakeLists.txt
index d0b368a3..54294f11 100644
--- a/src/ipcpd/CMakeLists.txt
+++ b/src/ipcpd/CMakeLists.txt
@@ -1,3 +1,7 @@
+set(CONNMGR_RCV_TIMEOUT 1000 CACHE STRING
+ "Timeout for the connection manager to wait for OCEP info (ms).")
+set(IPCP_DEBUG_LOCAL FALSE CACHE BOOL
+ "Use PID as address for local debugging")
set(IPCP_QOS_CUBE_BE_PRIO 50 CACHE STRING
"Priority for best effort QoS cube (0-99)")
set(IPCP_QOS_CUBE_VIDEO_PRIO 90 CACHE STRING
@@ -10,12 +14,16 @@ set(IPCP_ADD_THREADS 4 CACHE STRING
"Number of extra threads to start when an IPCP faces thread starvation")
set(IPCP_SCHED_THR_MUL 2 CACHE STRING
"Number of scheduler threads per QoS cube")
-set(DISABLE_CORE_LOCK FALSE CACHE BOOL
+set(DISABLE_CORE_LOCK TRUE CACHE BOOL
"Disable locking performance threads to a core")
set(IPCP_CONN_WAIT_DIR TRUE CACHE BOOL
"Check the running state of the directory when adding a dt connection")
set(DHT_ENROLL_SLACK 50 CACHE STRING
"DHT enrollment waiting time (0-999, ms)")
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set(IPCP_LINUX_TIMERSLACK_NS 1000 CACHE STRING
+ "Slack value for high resolution timers on Linux systems.")
+endif ()
if ((IPCP_QOS_CUBE_BE_PRIO LESS 0) OR (IPCP_QOS_CUBE_BE_PRIO GREATER 99))
message(FATAL_ERROR "Invalid priority for best effort QoS cube")
@@ -40,10 +48,13 @@ set(IPCP_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/shim-data.c
)
+set (COMMON_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/common/enroll.c
+ )
+
add_subdirectory(local)
add_subdirectory(eth)
add_subdirectory(udp)
-add_subdirectory(raptor)
add_subdirectory(unicast)
add_subdirectory(broadcast)
diff --git a/src/ipcpd/broadcast/CMakeLists.txt b/src/ipcpd/broadcast/CMakeLists.txt
index afcc8696..d85f335e 100644
--- a/src/ipcpd/broadcast/CMakeLists.txt
+++ b/src/ipcpd/broadcast/CMakeLists.txt
@@ -13,16 +13,17 @@ include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
set(IPCP_BROADCAST_TARGET ipcpd-broadcast CACHE INTERNAL "")
+set(IPCP_BROADCAST_MPL 60 CACHE STRING
+ "Default maximum packet lifetime for the broadcast IPCP, in seconds")
set(SOURCE_FILES
# Add source files here
connmgr.c
dt.c
- enroll.c
main.c
)
-add_executable(ipcpd-broadcast ${SOURCE_FILES} ${IPCP_SOURCES}
+add_executable(ipcpd-broadcast ${SOURCE_FILES} ${IPCP_SOURCES} ${COMMON_SOURCES}
${LAYER_CONFIG_PROTO_SRCS})
target_link_libraries(ipcpd-broadcast LINK_PUBLIC ouroboros-dev)
diff --git a/src/ipcpd/broadcast/comp.h b/src/ipcpd/broadcast/comp.h
deleted file mode 100644
index 07983978..00000000
--- a/src/ipcpd/broadcast/comp.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * Components for the broadcast IPC process
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IPCPD_BROADCAST_COMP_H
-#define OUROBOROS_IPCPD_BROADCAST_COMP_H
-
-#include <ouroboros/cacep.h>
-
-#define DST_MAX_STRLEN 64
-
-enum comp_id {
- COMPID_DT = 0,
- COMPID_ENROLL,
- COMPID_MAX
-};
-
-struct conn {
- struct conn_info conn_info;
- struct {
- char dst[DST_MAX_STRLEN + 1];
- int fd;
- qosspec_t qs;
- } flow_info;
-};
-
-#endif /* OUROBOROS_IPCPD_BROADCAST_COMP_H */
diff --git a/src/ipcpd/broadcast/connmgr.c b/src/ipcpd/broadcast/connmgr.c
index b023584a..f297175d 100644
--- a/src/ipcpd/broadcast/connmgr.c
+++ b/src/ipcpd/broadcast/connmgr.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Handles connections between components
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,496 +20,16 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
+#include "config.h"
+
#if defined(__linux__) || defined(__CYGWIN__)
#define _DEFAULT_SOURCE
#else
#define _POSIX_C_SOURCE 200112L
#endif
-#define OUROBOROS_PREFIX "connection-manager"
-
-#include <ouroboros/dev.h>
-#include <ouroboros/cacep.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/list.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/notifier.h>
-
-#include "comp.h"
-#include "connmgr.h"
-#include "enroll.h"
-#include "ipcp.h"
-
-#include <pthread.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-enum connmgr_state {
- CONNMGR_NULL = 0,
- CONNMGR_INIT,
- CONNMGR_RUNNING
-};
-
-struct conn_el {
- struct list_head next;
- struct conn conn;
-};
-
-struct comp {
- struct conn_info info;
-
- struct list_head conns;
- struct list_head pending;
-
- pthread_cond_t cond;
- pthread_mutex_t lock;
-};
-
-struct {
- struct comp comps[COMPID_MAX];
- enum connmgr_state state;
-
- pthread_t acceptor;
-} connmgr;
-
-static int get_id_by_name(const char * name)
-{
- enum comp_id i;
-
- for (i = 0; i < COMPID_MAX; ++i)
- if (strcmp(name, connmgr.comps[i].info.comp_name) == 0)
- return i;
-
- return -1;
-}
-
-static int get_conn_by_fd(int fd,
- enum comp_id id,
- struct conn * conn)
-{
- struct list_head * p;
-
- pthread_mutex_lock(&connmgr.comps[id].lock);
-
- list_for_each(p, &connmgr.comps[id].conns) {
- struct conn_el * c =
- list_entry(p, struct conn_el, next);
- if (c->conn.flow_info.fd == fd) {
- *conn = c->conn;
- pthread_mutex_unlock(&connmgr.comps[id].lock);
- return 0;
- }
- }
-
- pthread_mutex_unlock(&connmgr.comps[id].lock);
-
- return -1;
-}
-
-static int add_comp_conn(enum comp_id id,
- int fd,
- qosspec_t qs,
- struct conn_info * rcv_info)
-{
- struct conn_el * el;
-
- el = malloc(sizeof(*el));
- if (el == NULL) {
- log_err("Not enough memory.");
- return -1;
- }
-
- el->conn.conn_info = *rcv_info;
- el->conn.flow_info.fd = fd;
- el->conn.flow_info.qs = qs;
-
- pthread_mutex_lock(&connmgr.comps[id].lock);
-
- list_add(&el->next, &connmgr.comps[id].pending);
- pthread_cond_signal(&connmgr.comps[id].cond);
-
- pthread_mutex_unlock(&connmgr.comps[id].lock);
-
- return 0;
-}
-
-static void * flow_acceptor(void * o)
-{
- int fd;
- qosspec_t qs;
- struct conn_info rcv_info;
- struct conn_info fail_info;
-
- (void) o;
-
- memset(&fail_info, 0, sizeof(fail_info));
-
- while (true) {
- int id;
-
- fd = flow_accept(&qs, NULL);
- if (fd < 0) {
- if (fd != -EIRMD)
- log_warn("Flow accept failed: %d", fd);
- continue;
- }
-
- if (cacep_rcv(fd, &rcv_info)) {
- log_dbg("Error establishing application connection.");
- flow_dealloc(fd);
- continue;
- }
-
- id = get_id_by_name(rcv_info.comp_name);
- if (id < 0) {
- log_dbg("Connection request for unknown component %s.",
- rcv_info.comp_name);
- cacep_snd(fd, &fail_info);
- flow_dealloc(fd);
- continue;
- }
-
- assert(id < COMPID_MAX);
-
- if (cacep_snd(fd, &connmgr.comps[id].info)) {
- log_dbg("Failed to respond to request.");
- flow_dealloc(fd);
- continue;
- }
-
- if (add_comp_conn(id, fd, qs, &rcv_info)) {
- log_dbg("Failed to add new connection.");
- flow_dealloc(fd);
- continue;
- }
- }
-
- return (void *) 0;
-}
-
-static void handle_event(void * self,
- int event,
- const void * o)
-{
- struct conn conn;
-
- (void) self;
-
- if (!(event == NOTIFY_DT_FLOW_UP ||
- event == NOTIFY_DT_FLOW_DOWN ||
- event == NOTIFY_DT_FLOW_DEALLOC))
- return;
-
- if (get_conn_by_fd(*((int *) o), COMPID_DT, &conn))
- return;
-
- switch (event) {
- case NOTIFY_DT_FLOW_UP:
- notifier_event(NOTIFY_DT_CONN_UP, &conn);
- break;
- case NOTIFY_DT_FLOW_DOWN:
- notifier_event(NOTIFY_DT_CONN_DOWN, &conn);
- break;
- case NOTIFY_DT_FLOW_DEALLOC:
- notifier_event(NOTIFY_DT_CONN_DEL, &conn);
- break;
- default:
- break;
- }
-}
-
-int connmgr_init(void)
-{
- connmgr.state = CONNMGR_INIT;
-
- if (notifier_reg(handle_event, NULL))
- return -1;
-
- return 0;
-}
-
-void connmgr_fini(void)
-{
- int i;
-
- notifier_unreg(handle_event);
-
- if (connmgr.state == CONNMGR_RUNNING)
- pthread_join(connmgr.acceptor, NULL);
-
- for (i = 0; i < COMPID_MAX; ++i)
- connmgr_comp_fini(i);
-}
-
-int connmgr_start(void)
-{
- if (pthread_create(&connmgr.acceptor, NULL, flow_acceptor, NULL))
- return -1;
-
- connmgr.state = CONNMGR_RUNNING;
-
- return 0;
-}
-
-void connmgr_stop(void)
-{
- if (connmgr.state == CONNMGR_RUNNING)
- pthread_cancel(connmgr.acceptor);
-}
-
-int connmgr_comp_init(enum comp_id id,
- const struct conn_info * info)
-{
- struct comp * comp;
-
- assert(id >= 0 && id < COMPID_MAX);
-
- comp = connmgr.comps + id;
-
- if (pthread_mutex_init(&comp->lock, NULL))
- return -1;
-
- if (pthread_cond_init(&comp->cond, NULL)) {
- pthread_mutex_destroy(&comp->lock);
- return -1;
- }
-
- list_head_init(&comp->conns);
- list_head_init(&comp->pending);
-
- memcpy(&connmgr.comps[id].info, info, sizeof(connmgr.comps[id].info));
-
- return 0;
-}
-
-void connmgr_comp_fini(enum comp_id id)
-{
- struct list_head * p;
- struct list_head * h;
- struct comp * comp;
-
- assert(id >= 0 && id < COMPID_MAX);
-
- if (strlen(connmgr.comps[id].info.comp_name) == 0)
- return;
-
- comp = connmgr.comps + id;
-
- pthread_mutex_lock(&comp->lock);
-
- list_for_each_safe(p, h, &comp->conns) {
- struct conn_el * e = list_entry(p, struct conn_el, next);
- list_del(&e->next);
- free(e);
- }
-
- list_for_each_safe(p, h, &comp->pending) {
- struct conn_el * e = list_entry(p, struct conn_el, next);
- list_del(&e->next);
- free(e);
- }
-
- pthread_mutex_unlock(&comp->lock);
-
- pthread_cond_destroy(&comp->cond);
- pthread_mutex_destroy(&comp->lock);
-
- memset(&connmgr.comps[id].info, 0, sizeof(connmgr.comps[id].info));
-}
-
-int connmgr_ipcp_connect(const char * dst,
- const char * component,
- qosspec_t qs)
-{
- struct conn_el * ce;
- int id;
-
- assert(dst);
- assert(component);
-
- ce = malloc(sizeof(*ce));
- if (ce == NULL) {
- log_dbg("Out of memory.");
- return -1;
- }
-
- id = get_id_by_name(component);
- if (id < 0) {
- log_dbg("No such component: %s", component);
- free(ce);
- return -1;
- }
-
- if (connmgr_alloc(id, dst, &qs, &ce->conn)) {
- free(ce);
- return -1;
- }
-
- if (strlen(dst) > DST_MAX_STRLEN) {
- log_warn("Truncating dst length for connection.");
- memcpy(ce->conn.flow_info.dst, dst, DST_MAX_STRLEN);
- ce->conn.flow_info.dst[DST_MAX_STRLEN] = '\0';
- } else {
- strcpy(ce->conn.flow_info.dst, dst);
- }
-
- pthread_mutex_lock(&connmgr.comps[id].lock);
-
- list_add(&ce->next, &connmgr.comps[id].conns);
-
- pthread_mutex_unlock(&connmgr.comps[id].lock);
-
- return 0;
-}
-
-int connmgr_ipcp_disconnect(const char * dst,
- const char * component)
-{
- struct list_head * p;
- struct list_head * h;
- int id;
-
- assert(dst);
- assert(component);
-
- id = get_id_by_name(component);
- if (id < 0)
- return -1;
-
- pthread_mutex_lock(&connmgr.comps[id].lock);
-
- list_for_each_safe(p,h, &connmgr.comps[id].conns) {
- struct conn_el * el = list_entry(p, struct conn_el, next);
- if (strcmp(el->conn.flow_info.dst, dst) == 0) {
- int ret;
- pthread_mutex_unlock(&connmgr.comps[id].lock);
- list_del(&el->next);
- ret = connmgr_dealloc(id, &el->conn);
- free(el);
- return ret;
- }
- }
-
- pthread_mutex_unlock(&connmgr.comps[id].lock);
-
- return 0;
-}
-
-int connmgr_alloc(enum comp_id id,
- const char * dst,
- qosspec_t * qs,
- struct conn * conn)
-{
- assert(id >= 0 && id < COMPID_MAX);
- assert(dst);
-
- conn->flow_info.fd = flow_alloc(dst, qs, NULL);
- if (conn->flow_info.fd < 0) {
- log_dbg("Failed to allocate flow to %s.", dst);
- return -1;
- }
-
- if (qs != NULL)
- conn->flow_info.qs = *qs;
- else
- memset(&conn->flow_info.qs, 0, sizeof(conn->flow_info.qs));
-
- log_dbg("Sending cacep info for protocol %s to fd %d.",
- connmgr.comps[id].info.protocol, conn->flow_info.fd);
-
- if (cacep_snd(conn->flow_info.fd, &connmgr.comps[id].info)) {
- log_dbg("Failed to create application connection.");
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- if (cacep_rcv(conn->flow_info.fd, &conn->conn_info)) {
- log_dbg("Failed to connect to application.");
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- if (strcmp(connmgr.comps[id].info.protocol, conn->conn_info.protocol)) {
- log_dbg("Unknown protocol (requested %s, got %s).",
- connmgr.comps[id].info.protocol,
- conn->conn_info.protocol);
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- if (connmgr.comps[id].info.pref_version !=
- conn->conn_info.pref_version) {
- log_dbg("Unknown protocol version.");
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- if (connmgr.comps[id].info.pref_syntax != conn->conn_info.pref_syntax) {
- log_dbg("Unknown protocol syntax.");
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- switch (id) {
- case COMPID_DT:
- notifier_event(NOTIFY_DT_CONN_ADD, conn);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-int connmgr_dealloc(enum comp_id id,
- struct conn * conn)
-{
- switch (id) {
- case COMPID_DT:
- notifier_event(NOTIFY_DT_CONN_DEL, conn);
- break;
- default:
- break;
- }
-
- return flow_dealloc(conn->flow_info.fd);
-}
-
-
-int connmgr_wait(enum comp_id id,
- struct conn * conn)
-{
- struct conn_el * el;
- struct comp * comp;
-
- assert(id >= 0 && id < COMPID_MAX);
- assert(conn);
-
- comp = connmgr.comps + id;
-
- pthread_mutex_lock(&comp->lock);
-
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) &comp->lock);
-
- while (list_is_empty(&comp->pending))
- pthread_cond_wait(&comp->cond, &comp->lock);
-
- pthread_cleanup_pop(false);
-
- el = list_first_entry((&comp->pending), struct conn_el, next);
- if (el == NULL) {
- pthread_mutex_unlock(&comp->lock);
- return -1;
- }
-
- *conn = el->conn;
-
- list_del(&el->next);
- list_add(&el->next, &connmgr.comps[id].conns);
+#include <ouroboros/ipcp.h>
- pthread_mutex_unlock(&comp->lock);
+#define BUILD_IPCP_BROADCAST
- return 0;
-}
+#include "common/connmgr.c"
diff --git a/src/ipcpd/broadcast/connmgr.h b/src/ipcpd/broadcast/connmgr.h
deleted file mode 100644
index 019056f2..00000000
--- a/src/ipcpd/broadcast/connmgr.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * Handles the different AP connections
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IPCPD_BROADCAST_CONNMGR_H
-#define OUROBOROS_IPCPD_BROADCAST_CONNMGR_H
-
-#include <ouroboros/cacep.h>
-#include <ouroboros/qos.h>
-
-#include "comp.h"
-
-#define NOTIFY_DT_CONN_ADD 0x00D0
-#define NOTIFY_DT_CONN_DEL 0x00D1
-#define NOTIFY_DT_CONN_QOS 0x00D2
-#define NOTIFY_DT_CONN_UP 0x00D3
-#define NOTIFY_DT_CONN_DOWN 0x00D4
-#define NOTIFY_DT_FLOW_UP 0x00D5
-#define NOTIFY_DT_FLOW_DOWN 0x00D6
-#define NOTIFY_DT_FLOW_DEALLOC 0x00D7
-
-int connmgr_init(void);
-
-void connmgr_fini(void);
-
-int connmgr_start(void);
-
-void connmgr_stop(void);
-
-int connmgr_comp_init(enum comp_id id,
- const struct conn_info * info);
-
-void connmgr_comp_fini(enum comp_id id);
-
-int connmgr_ipcp_connect(const char * dst,
- const char * component,
- qosspec_t qs);
-
-int connmgr_ipcp_disconnect(const char * dst,
- const char * component);
-
-int connmgr_alloc(enum comp_id id,
- const char * dst,
- qosspec_t * qs,
- struct conn * conn);
-
-int connmgr_dealloc(enum comp_id id,
- struct conn * conn);
-
-int connmgr_wait(enum comp_id id,
- struct conn * conn);
-
-#endif /* OUROBOROS_IPCPD_BROADCAST_CONNMGR_H */
diff --git a/src/ipcpd/broadcast/dt.c b/src/ipcpd/broadcast/dt.c
index 6e8bacf1..938c9085 100644
--- a/src/ipcpd/broadcast/dt.c
+++ b/src/ipcpd/broadcast/dt.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Forward loop for broadcast
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -33,7 +33,6 @@
#define DT "dt"
#define OUROBOROS_PREFIX DT
-#include <ouroboros/endian.h>
#include <ouroboros/dev.h>
#include <ouroboros/errno.h>
#include <ouroboros/fqueue.h>
@@ -41,17 +40,16 @@
#include <ouroboros/logs.h>
#include <ouroboros/notifier.h>
#include <ouroboros/utils.h>
+#include <ouroboros/pthread.h>
-#include "comp.h"
-#include "connmgr.h"
+#include "common/comp.h"
+#include "common/connmgr.h"
#include "dt.h"
-#include "ipcp.h"
#include <assert.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
-#include <pthread.h>
struct nb {
struct list_head next;
@@ -80,15 +78,16 @@ static int dt_add_nb(int fd)
list_for_each(p, &fwd.nbs) {
struct nb * el = list_entry(p, struct nb, next);
if (el->fd == fd) {
- log_dbg("Already know neighbor.");
pthread_rwlock_unlock(&fwd.nbs_lock);
- return -EPERM;
+ log_warn("Already know neighbor on fd %d.", fd);
+ return 0;
}
}
nb = malloc(sizeof(*nb));
if (nb == NULL) {
pthread_rwlock_unlock(&fwd.nbs_lock);
+ log_err("Failed to malloc neighbor struct.");
return -ENOMEM;
}
@@ -98,10 +97,10 @@ static int dt_add_nb(int fd)
++fwd.nbs_len;
- log_dbg("Neighbor %d added.", fd);
-
pthread_rwlock_unlock(&fwd.nbs_lock);
+ log_dbg("Neighbor %d added.", fd);
+
return 0;
}
@@ -126,6 +125,8 @@ static int dt_del_nb(int fd)
pthread_rwlock_unlock(&fwd.nbs_lock);
+ log_err("Neighbor not found on fd %d.", fd);
+
return -EPERM;
}
@@ -158,8 +159,7 @@ static void dt_packet(uint8_t * buf,
pthread_rwlock_rdlock(&fwd.nbs_lock);
- pthread_cleanup_push((void (*))(void *) pthread_rwlock_unlock,
- &fwd.nbs_lock);
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &fwd.nbs_lock);
list_for_each(p, &fwd.nbs) {
struct nb * nb = list_entry(p, struct nb, next);
@@ -170,6 +170,11 @@ static void dt_packet(uint8_t * buf,
pthread_cleanup_pop(true);
}
+static void __cleanup_fqueue_destroy(void * fq)
+{
+ fqueue_destroy((fqueue_t *) fq);
+}
+
static void * dt_reader(void * o)
{
fqueue_t * fq;
@@ -184,13 +189,12 @@ static void * dt_reader(void * o)
if (fq == NULL)
return (void *) -1;
- pthread_cleanup_push((void (*) (void *)) fqueue_destroy,
- (void *) fq);
+ pthread_cleanup_push(__cleanup_fqueue_destroy, (void *) fq);
while (true) {
ret = fevent(fwd.set, fq, NULL);
if (ret < 0) {
- log_warn("Event error: %d.", ret);
+ log_warn("Event warning: %d.", ret);
continue;
}
@@ -225,13 +229,13 @@ static void handle_event(void * self,
switch (event) {
case NOTIFY_DT_CONN_ADD:
- if (dt_add_nb(c->flow_info.fd))
- log_dbg("Failed to add neighbor.");
+ if (dt_add_nb(c->flow_info.fd) < 0)
+ log_err("Failed to add neighbor.");
fset_add(fwd.set, c->flow_info.fd);
break;
case NOTIFY_DT_CONN_DEL:
- if (dt_del_nb(c->flow_info.fd))
- log_dbg("Failed to delete neighbor.");
+ if (dt_del_nb(c->flow_info.fd) < 0)
+ log_err("Failed to delete neighbor.");
fset_del(fwd.set, c->flow_info.fd);
break;
default:
diff --git a/src/ipcpd/broadcast/dt.h b/src/ipcpd/broadcast/dt.h
index e573511c..8d3b83f8 100644
--- a/src/ipcpd/broadcast/dt.h
+++ b/src/ipcpd/broadcast/dt.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Forward loop for broadcast
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/broadcast/enroll.c b/src/ipcpd/broadcast/enroll.c
deleted file mode 100644
index 511892b7..00000000
--- a/src/ipcpd/broadcast/enroll.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * Enrollment Task
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 199309L
-#endif
-
-#define OUROBOROS_PREFIX "enrollment"
-
-#include <ouroboros/endian.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/time_utils.h>
-#include <ouroboros/dev.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/sockets.h>
-
-#include "connmgr.h"
-#include "enroll.h"
-#include "ipcp.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-
-#include "ipcp_config.pb-c.h"
-typedef EnrollMsg enroll_msg_t;
-
-#define ENROLL_COMP "Enrollment"
-#define ENROLL_PROTO "OEP" /* Ouroboros enrollment protocol */
-#define ENROLL_WARN_TIME_OFFSET 20
-#define ENROLL_BUF_LEN 1024
-
-enum enroll_state {
- ENROLL_NULL = 0,
- ENROLL_INIT,
- ENROLL_RUNNING
-};
-
-struct {
- struct ipcp_config conf;
- enum enroll_state state;
- pthread_t listener;
-} enroll;
-
-static int send_rcv_enroll_msg(int fd)
-{
- enroll_msg_t req = ENROLL_MSG__INIT;
- enroll_msg_t * reply;
- uint8_t buf[ENROLL_BUF_LEN];
- ssize_t len;
- ssize_t delta_t;
- struct timespec t0;
- struct timespec rtt;
-
- req.code = ENROLL_CODE__ENROLL_REQ;
-
- len = enroll_msg__get_packed_size(&req);
- if (len < 0) {
- log_dbg("Failed pack request message.");
- return -1;
- }
-
- enroll_msg__pack(&req, buf);
-
- clock_gettime(CLOCK_REALTIME, &t0);
-
- if (flow_write(fd, buf, len) < 0) {
- log_dbg("Failed to send request message.");
- return -1;
- }
-
- len = flow_read(fd, buf, ENROLL_BUF_LEN);
- if (len < 0) {
- log_dbg("No enrollment reply received.");
- return -1;
- }
-
- log_dbg("Received enrollment info (%zd bytes).", len);
-
- reply = enroll_msg__unpack(NULL, len, buf);
- if (reply == NULL) {
- log_dbg("No enrollment response.");
- return -1;
- }
-
- if (reply->code != ENROLL_CODE__ENROLL_BOOT) {
- log_dbg("Failed to unpack enrollment response.");
- enroll_msg__free_unpacked(reply, NULL);
- return -1;
- }
-
- if (!(reply->has_t_sec && reply->has_t_nsec)) {
- log_dbg("No time in response message.");
- enroll_msg__free_unpacked(reply, NULL);
- return -1;
- }
-
- clock_gettime(CLOCK_REALTIME, &rtt);
-
- delta_t = ts_diff_ms(&t0, &rtt);
-
- rtt.tv_sec = reply->t_sec;
- rtt.tv_nsec = reply->t_nsec;
-
- if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET)
- log_warn("Clock offset above threshold.");
-
- strcpy(enroll.conf.layer_info.layer_name,
- reply->conf->layer_info->layer_name);
- enroll.conf.layer_info.dir_hash_algo
- = reply->conf->layer_info->dir_hash_algo;
-
- enroll_msg__free_unpacked(reply, NULL);
-
- return 0;
-}
-
-static ssize_t enroll_pack(uint8_t ** buf)
-{
- enroll_msg_t msg = ENROLL_MSG__INIT;
- ipcp_config_msg_t config = IPCP_CONFIG_MSG__INIT;
- layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT;
- struct timespec now;
- ssize_t len;
-
- clock_gettime(CLOCK_REALTIME, &now);
-
- msg.code = ENROLL_CODE__ENROLL_BOOT;
- msg.has_t_sec = true;
- msg.t_sec = now.tv_sec;
- msg.has_t_nsec = true;
- msg.t_nsec = now.tv_nsec;
- msg.conf = &config;
-
- config.ipcp_type = enroll.conf.type;
- config.layer_info = &layer_info;
-
- layer_info.layer_name = (char *) enroll.conf.layer_info.layer_name;
- layer_info.dir_hash_algo = enroll.conf.layer_info.dir_hash_algo;
-
- len = enroll_msg__get_packed_size(&msg);
-
- *buf = malloc(len);
- if (*buf == NULL)
- return -1;
-
- enroll_msg__pack(&msg, *buf);
-
- return len;
-}
-
-static void * enroll_handle(void * o)
-{
- struct conn conn;
- uint8_t buf[ENROLL_BUF_LEN];
- uint8_t * reply;
- ssize_t len;
- enroll_msg_t * msg;
-
- (void) o;
-
- while (true) {
- if (connmgr_wait(COMPID_ENROLL, &conn)) {
- log_err("Failed to get next connection.");
- continue;
- }
-
- len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN);
- if (len < 0) {
- log_err("Failed to read from flow.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- msg = enroll_msg__unpack(NULL, len, buf);
- if (msg == NULL) {
- log_err("Failed to unpack message.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- if (msg->code != ENROLL_CODE__ENROLL_REQ) {
- log_err("Wrong message type.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- enroll_msg__free_unpacked(msg, NULL);
- continue;
- }
-
- log_dbg("Enrolling a new neighbor.");
-
- enroll_msg__free_unpacked(msg, NULL);
-
- len = enroll_pack(&reply);
- if (reply == NULL) {
- log_err("Failed to pack enrollment message.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- log_dbg("Sending enrollment info (%zd bytes).", len);
-
- if (flow_write(conn.flow_info.fd, reply, len) < 0) {
- log_err("Failed respond to enrollment request.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- free(reply);
- continue;
- }
-
- free(reply);
-
- len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN);
- if (len < 0) {
- log_err("Failed to read from flow.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- msg = enroll_msg__unpack(NULL, len, buf);
- if (msg == NULL) {
- log_err("Failed to unpack message.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- if (msg->code != ENROLL_CODE__ENROLL_DONE || !msg->has_result) {
- log_err("Wrong message type.");
- enroll_msg__free_unpacked(msg, NULL);
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- if (msg->result == 0)
- log_dbg("Neighbor enrollment successful.");
- else
- log_dbg("Neigbor reported failed enrollment.");
-
- enroll_msg__free_unpacked(msg, NULL);
-
- connmgr_dealloc(COMPID_ENROLL, &conn);
- }
-
- return 0;
-}
-
-int enroll_boot(struct conn * conn)
-{
- log_dbg("Getting boot information.");
-
- if (send_rcv_enroll_msg(conn->flow_info.fd)) {
- log_err("Failed to enroll.");
- return -1;
- }
-
- return 0;
-}
-
-int enroll_done(struct conn * conn,
- int result)
-{
- enroll_msg_t msg = ENROLL_MSG__INIT;
- uint8_t buf[ENROLL_BUF_LEN];
- ssize_t len;
-
- msg.code = ENROLL_CODE__ENROLL_DONE;
- msg.has_result = true;
- msg.result = result;
-
- len = enroll_msg__get_packed_size(&msg);
- if (len < 0) {
- log_dbg("Failed pack request message.");
- return -1;
- }
-
- enroll_msg__pack(&msg, buf);
-
- if (flow_write(conn->flow_info.fd, buf, len) < 0) {
- log_dbg("Failed to send acknowledgment.");
- return -1;
- }
-
- return 0;
-}
-
-void enroll_bootstrap(const struct ipcp_config * conf)
-{
- assert(conf);
-
- memcpy(&enroll.conf, conf, sizeof(enroll.conf));
-}
-
-struct ipcp_config * enroll_get_conf(void)
-{
- return &enroll.conf;
-}
-
-int enroll_init(void)
-{
- struct conn_info info;
-
- memset(&info, 0, sizeof(info));
-
- strcpy(info.comp_name, ENROLL_COMP);
- strcpy(info.protocol, ENROLL_PROTO);
- info.pref_version = 1;
- info.pref_syntax = PROTO_GPB;
- info.addr = 0;
-
- if (connmgr_comp_init(COMPID_ENROLL, &info)) {
- log_err("Failed to register with connmgr.");
- return -1;
- }
-
- enroll.state = ENROLL_INIT;
-
- return 0;
-}
-
-void enroll_fini(void)
-{
- if (enroll.state == ENROLL_RUNNING)
- pthread_join(enroll.listener, NULL);
-
- connmgr_comp_fini(COMPID_ENROLL);
-}
-
-int enroll_start(void)
-{
- if (pthread_create(&enroll.listener, NULL, enroll_handle, NULL))
- return -1;
-
- enroll.state = ENROLL_RUNNING;
-
- return 0;
-}
-
-void enroll_stop(void)
-{
- if (enroll.state == ENROLL_RUNNING)
- pthread_cancel(enroll.listener);
-}
diff --git a/src/ipcpd/broadcast/main.c b/src/ipcpd/broadcast/main.c
index 120b2bf1..f51fc629 100644
--- a/src/ipcpd/broadcast/main.c
+++ b/src/ipcpd/broadcast/main.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Broadcast IPC Process
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -29,19 +29,20 @@
#include "config.h"
#define OUROBOROS_PREFIX "broadcast-ipcp"
+#define THIS_TYPE IPCP_BROADCAST
-#include <ouroboros/errno.h>
-#include <ouroboros/hash.h>
#include <ouroboros/dev.h>
+#include <ouroboros/errno.h>
#include <ouroboros/ipcp-dev.h>
#include <ouroboros/logs.h>
#include <ouroboros/notifier.h>
+#include <ouroboros/random.h>
#include <ouroboros/rib.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/time.h>
-#include "connmgr.h"
+#include "common/connmgr.h"
+#include "common/enroll.h"
#include "dt.h"
-#include "enroll.h"
#include "ipcp.h"
#include <stdbool.h>
@@ -51,54 +52,38 @@
#include <assert.h>
#include <inttypes.h>
-#define THIS_TYPE IPCP_BROADCAST
+struct ipcp ipcpi;
static int initialize_components(const struct ipcp_config * conf)
{
- ipcpi.layer_name = strdup(conf->layer_info.layer_name);
- if (ipcpi.layer_name == NULL) {
- log_err("Failed to set layer name.");
- goto fail_layer_name;
- }
-
- ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo;
+ strcpy(ipcpi.layer_name, conf->layer_info.name);
+ ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo;
assert(ipcp_dir_hash_len() != 0);
- if (dt_init()) {
+ if (dt_init() < 0) {
log_err("Failed to initialize forwarding component.");
- goto fail_dt;
+ return -1;
}
ipcp_set_state(IPCP_INIT);
return 0;
-
- fail_dt:
- free(ipcpi.layer_name);
- fail_layer_name:
- return -1;
}
static void finalize_components(void)
{
dt_fini();
-
- free(ipcpi.layer_name);
}
static int start_components(void)
{
- assert(ipcp_get_state() == IPCP_INIT);
-
- ipcp_set_state(IPCP_OPERATIONAL);
-
- if (enroll_start()) {
+ if (enroll_start() < 0) {
log_err("Failed to start enrollment.");
goto fail_enroll_start;
}
- if (connmgr_start()) {
+ if (connmgr_start() < 0) {
log_err("Failed to start AP connection manager.");
goto fail_connmgr_start;
}
@@ -114,52 +99,55 @@ static int start_components(void)
static void stop_components(void)
{
- assert(ipcp_get_state() == IPCP_OPERATIONAL ||
- ipcp_get_state() == IPCP_SHUTDOWN);
-
connmgr_stop();
enroll_stop();
-
- ipcp_set_state(IPCP_INIT);
}
static int broadcast_ipcp_enroll(const char * dst,
struct layer_info * info)
{
struct conn conn;
+ uint8_t id[ENROLL_ID_LEN];
- if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn)) {
- log_err("Failed to get connection.");
- goto fail_er_flow;
+ if (random_buffer(id, ENROLL_ID_LEN) < 0) {
+ log_err("Failed to generate enrollment ID.");
+ goto fail_id;
+ }
+
+ log_info_id(id, "Requesting enrollment.");
+
+ if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn) < 0) {
+ log_err_id(id, "Failed to get connection.");
+ goto fail_id;
}
/* Get boot state from peer. */
- if (enroll_boot(&conn)) {
- log_err("Failed to get boot information.");
+ if (enroll_boot(&conn, id) < 0) {
+ log_err_id(id, "Failed to get boot information.");
goto fail_enroll_boot;
}
- if (initialize_components(enroll_get_conf())) {
- log_err("Failed to initialize IPCP components.");
+ if (initialize_components(enroll_get_conf()) < 0) {
+ log_err_id(id, "Failed to initialize components.");
goto fail_enroll_boot;
}
- if (start_components()) {
- log_err("Failed to start components.");
+ if (start_components() < 0) {
+ log_err_id(id, "Failed to start components.");
goto fail_start_comp;
}
- if (enroll_done(&conn, 0))
- log_warn("Failed to confirm enrollment with peer.");
+ if (enroll_ack(&conn, id, 0) < 0)
+ log_err_id(id, "Failed to confirm enrollment.");
- if (connmgr_dealloc(COMPID_ENROLL, &conn))
- log_warn("Failed to deallocate enrollment flow.");
+ if (connmgr_dealloc(COMPID_ENROLL, &conn) < 0)
+ log_warn_id(id, "Failed to dealloc enrollment flow.");
- log_info("Enrolled with %s.", dst);
+ log_info_id(id, "Enrolled with %s.", dst);
- info->dir_hash_algo = ipcpi.dir_hash_algo;
- strcpy(info->layer_name, ipcpi.layer_name);
+ info->dir_hash_algo = (enum pol_dir_hash) ipcpi.dir_hash_algo;
+ strcpy(info->name, ipcpi.layer_name);
return 0;
@@ -167,7 +155,7 @@ static int broadcast_ipcp_enroll(const char * dst,
finalize_components();
fail_enroll_boot:
connmgr_dealloc(COMPID_ENROLL, &conn);
- fail_er_flow:
+ fail_id:
return -1;
}
@@ -175,6 +163,8 @@ static int broadcast_ipcp_bootstrap(const struct ipcp_config * conf)
{
assert(conf);
assert(conf->type == THIS_TYPE);
+ ((struct ipcp_config *) conf)->layer_info.dir_hash_algo =
+ DIR_HASH_SHA3_256;
enroll_bootstrap(conf);
@@ -188,8 +178,6 @@ static int broadcast_ipcp_bootstrap(const struct ipcp_config * conf)
goto fail_start;
}
- log_dbg("Bootstrapped in layer %s.", conf->layer_info.layer_name);
-
return 0;
fail_start:
@@ -223,6 +211,8 @@ static int broadcast_ipcp_join(int fd,
qosspec_t qs)
{
struct conn conn;
+ time_t mpl = IPCP_BROADCAST_MPL;
+ buffer_t data = {NULL, 0};
(void) qs;
@@ -230,12 +220,14 @@ static int broadcast_ipcp_join(int fd,
conn.flow_info.fd = fd;
- if (name_check(dst) != 0)
+ if (name_check(dst) != 0) {
+ log_err("Failed to check name.");
return -1;
+ }
notifier_event(NOTIFY_DT_CONN_ADD, &conn);
- ipcp_flow_alloc_reply(fd, 0, NULL, 0);
+ ipcp_flow_alloc_reply(fd, 0, mpl, &data);
return 0;
}
@@ -250,12 +242,11 @@ int broadcast_ipcp_dealloc(int fd)
notifier_event(NOTIFY_DT_CONN_DEL, &conn);
- flow_dealloc(fd);
+ ipcp_flow_dealloc(fd);
return 0;
}
-
static struct ipcp_ops broadcast_ops = {
.ipcp_bootstrap = broadcast_ipcp_bootstrap,
.ipcp_enroll = broadcast_ipcp_enroll,
@@ -273,17 +264,11 @@ static struct ipcp_ops broadcast_ops = {
int main(int argc,
char * argv[])
{
- if (ipcp_init(argc, argv, &broadcast_ops) < 0) {
- log_err("Failed to init IPCP.");
+ if (ipcp_init(argc, argv, &broadcast_ops, THIS_TYPE) < 0) {
+ log_err("Failed to initialize IPCP.");
goto fail_init;
}
- /* These components must be init at creation. */
- if (rib_init(ipcpi.name)) {
- log_err("Failed to initialize RIB.");
- goto fail_rib_init;
- }
-
if (notifier_init()) {
log_err("Failed to initialize notifier component.");
goto fail_notifier_init;
@@ -299,49 +284,38 @@ int main(int argc,
goto fail_enroll_init;
}
- if (ipcp_boot() < 0) {
+ if (ipcp_start() < 0) {
log_err("Failed to boot IPCP.");
- goto fail_boot;
- }
-
- if (ipcp_create_r(0)) {
- log_err("Failed to notify IRMd we are initialized.");
- ipcp_set_state(IPCP_NULL);
- goto fail_create_r;
+ goto fail_start;
}
- ipcp_shutdown();
+ ipcp_sigwait();
if (ipcp_get_state() == IPCP_SHUTDOWN) {
stop_components();
finalize_components();
}
+ ipcp_stop();
+
enroll_fini();
connmgr_fini();
notifier_fini();
- rib_fini();
-
ipcp_fini();
exit(EXIT_SUCCESS);
- fail_create_r:
- ipcp_shutdown();
- fail_boot:
+ fail_start:
enroll_fini();
fail_enroll_init:
connmgr_fini();
fail_connmgr_init:
notifier_fini();
fail_notifier_init:
- rib_fini();
- fail_rib_init:
ipcp_fini();
fail_init:
- ipcp_create_r(-1);
exit(EXIT_FAILURE);
}
diff --git a/src/ipcpd/unicast/comp.h b/src/ipcpd/common/comp.h
index 42367833..f3790d9c 100644
--- a/src/ipcpd/unicast/comp.h
+++ b/src/ipcpd/common/comp.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
- * Components for the unicast IPC process
+ * Components for the unicast/broadcast IPC process
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,12 +20,10 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_IPCPD_UNICAST_COMP_H
-#define OUROBOROS_IPCPD_UNICAST_COMP_H
+#ifndef OUROBOROS_IPCPD_COMMON_COMP_H
+#define OUROBOROS_IPCPD_COMMON_COMP_H
-#include <ouroboros/cacep.h>
-
-#include "dt.h"
+#include <ouroboros/cep.h>
#define DST_MAX_STRLEN 64
@@ -45,4 +43,4 @@ struct conn {
} flow_info;
};
-#endif /* OUROBOROS_IPCPD_UNICAST_COMP_H */
+#endif /* OUROBOROS_IPCPD_COMMON_COMP_H */
diff --git a/src/ipcpd/common/connmgr.c b/src/ipcpd/common/connmgr.c
new file mode 100644
index 00000000..4b5fd420
--- /dev/null
+++ b/src/ipcpd/common/connmgr.c
@@ -0,0 +1,564 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Handles connections between components
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define OUROBOROS_PREFIX "connection-manager"
+
+#include <ouroboros/cep.h>
+#include <ouroboros/dev.h>
+#include <ouroboros/errno.h>
+#include <ouroboros/fccntl.h>
+#include <ouroboros/list.h>
+#include <ouroboros/logs.h>
+#include <ouroboros/notifier.h>
+#include <ouroboros/pthread.h>
+
+#include "connmgr.h"
+#include "ipcp.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum connmgr_state {
+ CONNMGR_NULL = 0,
+ CONNMGR_INIT,
+ CONNMGR_RUNNING
+};
+
+struct conn_el {
+ struct list_head next;
+ struct conn conn;
+};
+
+struct comp {
+ struct conn_info info;
+
+ struct list_head conns;
+ struct list_head pending;
+
+ pthread_cond_t cond;
+ pthread_mutex_t lock;
+};
+
+struct {
+ struct comp comps[COMPID_MAX];
+ enum connmgr_state state;
+
+ pthread_t acceptor;
+} connmgr;
+
+static int get_id_by_name(const char * name)
+{
+ enum comp_id i;
+
+ for (i = 0; i < COMPID_MAX; ++i)
+ if (strcmp(name, connmgr.comps[i].info.comp_name) == 0)
+ return i;
+
+ return -1;
+}
+
+static int get_conn_by_fd(int fd,
+ enum comp_id id,
+ struct conn * conn)
+{
+ struct list_head * p;
+
+ pthread_mutex_lock(&connmgr.comps[id].lock);
+
+ list_for_each(p, &connmgr.comps[id].conns) {
+ struct conn_el * c =
+ list_entry(p, struct conn_el, next);
+ if (c->conn.flow_info.fd == fd) {
+ *conn = c->conn;
+ pthread_mutex_unlock(&connmgr.comps[id].lock);
+ return 0;
+ }
+ }
+
+ pthread_mutex_unlock(&connmgr.comps[id].lock);
+
+ return -1;
+}
+
+static int add_comp_conn(enum comp_id id,
+ int fd,
+ qosspec_t qs,
+ struct conn_info * rcv_info)
+{
+ struct conn_el * el;
+
+ el = malloc(sizeof(*el));
+ if (el == NULL) {
+ log_err("Not enough memory.");
+ return -1;
+ }
+
+ el->conn.conn_info = *rcv_info;
+ el->conn.flow_info.fd = fd;
+ el->conn.flow_info.qs = qs;
+
+ pthread_mutex_lock(&connmgr.comps[id].lock);
+
+ list_add(&el->next, &connmgr.comps[id].pending);
+ pthread_cond_signal(&connmgr.comps[id].cond);
+
+ pthread_mutex_unlock(&connmgr.comps[id].lock);
+
+ return 0;
+}
+
+static void * flow_acceptor(void * o)
+{
+ int fd;
+ qosspec_t qs;
+ struct conn_info rcv_info;
+ struct conn_info fail_info;
+ struct timespec timeo = TIMESPEC_INIT_MS(CONNMGR_RCV_TIMEOUT);
+ int err;
+
+ (void) o;
+
+ memset(&fail_info, 0, sizeof(fail_info));
+
+ while (true) {
+ int id;
+
+ fd = flow_accept(&qs, NULL);
+ if (fd < 0) {
+ if (fd != -EIRMD)
+ log_err("Flow accept failed: %d", fd);
+ continue;
+ }
+
+ log_info("Handling incoming flow %d.",fd);
+
+ fccntl(fd, FLOWSRCVTIMEO, &timeo);
+
+ err = cep_rcv(fd, &rcv_info);
+ if (err < 0) {
+ log_err("Error receiving OCEP info: %d.", err);
+ flow_dealloc(fd);
+ continue;
+ }
+
+ log_info("Request to connect to %s.", rcv_info.comp_name);
+
+ id = get_id_by_name(rcv_info.comp_name);
+ if (id < 0) {
+ log_err("Connection request for unknown component %s.",
+ rcv_info.comp_name);
+ cep_snd(fd, &fail_info);
+ flow_dealloc(fd);
+ continue;
+ }
+
+ err = cep_snd(fd, &connmgr.comps[id].info);
+ if (err < 0) {
+ log_err("Failed responding to OCEP request: %d.", err);
+ flow_dealloc(fd);
+ continue;
+ }
+
+ err = add_comp_conn(id, fd, qs, &rcv_info);
+ if (err < 0) {
+ log_err("Failed to add new connection: %d.", err);
+ flow_dealloc(fd);
+ continue;
+ }
+
+ log_info("Finished handling incoming flow %d for %s.",
+ fd, rcv_info.comp_name);
+ }
+
+ return (void *) 0;
+}
+
+static void handle_event(void * self,
+ int event,
+ const void * o)
+{
+ struct conn conn;
+
+ (void) self;
+
+ if (!(event == NOTIFY_DT_FLOW_UP ||
+ event == NOTIFY_DT_FLOW_DOWN ||
+ event == NOTIFY_DT_FLOW_DEALLOC))
+ return;
+
+ if (get_conn_by_fd(*((int *) o), COMPID_DT, &conn))
+ return;
+
+ switch (event) {
+ case NOTIFY_DT_FLOW_UP:
+ notifier_event(NOTIFY_DT_CONN_UP, &conn);
+ break;
+ case NOTIFY_DT_FLOW_DOWN:
+ notifier_event(NOTIFY_DT_CONN_DOWN, &conn);
+ break;
+ case NOTIFY_DT_FLOW_DEALLOC:
+ notifier_event(NOTIFY_DT_CONN_DEL, &conn);
+ break;
+ default:
+ break;
+ }
+}
+
+int connmgr_init(void)
+{
+ connmgr.state = CONNMGR_INIT;
+
+ if (notifier_reg(handle_event, NULL)) {
+ log_err("Failed to register notifier.");
+ return -1;
+ }
+
+ return 0;
+}
+
+void connmgr_fini(void)
+{
+ int i;
+
+ notifier_unreg(handle_event);
+
+ if (connmgr.state == CONNMGR_RUNNING)
+ pthread_join(connmgr.acceptor, NULL);
+
+ for (i = 0; i < COMPID_MAX; ++i)
+ connmgr_comp_fini(i);
+}
+
+int connmgr_start(void)
+{
+ if (pthread_create(&connmgr.acceptor, NULL, flow_acceptor, NULL)) {
+ log_err("Failed to create pthread: %s.", strerror(errno));
+ return -1;
+ }
+
+ connmgr.state = CONNMGR_RUNNING;
+
+ return 0;
+}
+
+void connmgr_stop(void)
+{
+ if (connmgr.state == CONNMGR_RUNNING)
+ pthread_cancel(connmgr.acceptor);
+}
+
+int connmgr_comp_init(enum comp_id id,
+ const struct conn_info * info)
+{
+ struct comp * comp;
+
+ assert(id >= 0 && id < COMPID_MAX);
+
+ comp = connmgr.comps + id;
+
+ if (pthread_mutex_init(&comp->lock, NULL)) {
+ log_err("Failed to initialize mutex: %s.", strerror(errno));
+ goto fail_mutex;
+ }
+
+ if (pthread_cond_init(&comp->cond, NULL)) {
+ log_err("Failed to initialize condvar: %s.", strerror(errno));
+ goto fail_cond;
+ }
+
+ list_head_init(&comp->conns);
+ list_head_init(&comp->pending);
+
+ memcpy(&connmgr.comps[id].info, info, sizeof(connmgr.comps[id].info));
+
+ return 0;
+
+ fail_cond:
+ pthread_mutex_destroy(&comp->lock);
+ fail_mutex:
+ return -1;
+}
+
+void connmgr_comp_fini(enum comp_id id)
+{
+ struct list_head * p;
+ struct list_head * h;
+ struct comp * comp;
+
+ assert(id >= 0 && id < COMPID_MAX);
+
+ if (strlen(connmgr.comps[id].info.comp_name) == 0)
+ return;
+
+ comp = connmgr.comps + id;
+
+ pthread_mutex_lock(&comp->lock);
+
+ list_for_each_safe(p, h, &comp->conns) {
+ struct conn_el * e = list_entry(p, struct conn_el, next);
+ list_del(&e->next);
+ free(e);
+ }
+
+ list_for_each_safe(p, h, &comp->pending) {
+ struct conn_el * e = list_entry(p, struct conn_el, next);
+ list_del(&e->next);
+ free(e);
+ }
+
+ pthread_mutex_unlock(&comp->lock);
+
+ pthread_cond_destroy(&comp->cond);
+ pthread_mutex_destroy(&comp->lock);
+
+ memset(&connmgr.comps[id].info, 0, sizeof(connmgr.comps[id].info));
+}
+
+int connmgr_ipcp_connect(const char * dst,
+ const char * component,
+ qosspec_t qs)
+{
+ struct conn_el * ce;
+ int id;
+ int ret;
+
+ assert(dst);
+ assert(component);
+
+ ce = malloc(sizeof(*ce));
+ if (ce == NULL) {
+ log_err("Out of memory.");
+ goto fail_malloc;
+ }
+
+ id = get_id_by_name(component);
+ if (id < 0) {
+ log_err("No such component: %s", component);
+ goto fail_id;
+ }
+
+ pthread_cleanup_push(free, ce);
+
+ ret = connmgr_alloc(id, dst, &qs, &ce->conn);
+
+ pthread_cleanup_pop(false);
+
+ if (ret < 0) {
+ log_err("Failed to allocate flow.");
+ goto fail_id;
+ }
+
+ if (strlen(dst) > DST_MAX_STRLEN) {
+ log_warn("Truncating dst length for connection.");
+ memcpy(ce->conn.flow_info.dst, dst, DST_MAX_STRLEN);
+ ce->conn.flow_info.dst[DST_MAX_STRLEN] = '\0';
+ } else {
+ strcpy(ce->conn.flow_info.dst, dst);
+ }
+
+ pthread_mutex_lock(&connmgr.comps[id].lock);
+
+ list_add(&ce->next, &connmgr.comps[id].conns);
+
+ pthread_mutex_unlock(&connmgr.comps[id].lock);
+
+ return 0;
+
+ fail_id:
+ free(ce);
+ fail_malloc:
+ return -1;
+}
+
+int connmgr_ipcp_disconnect(const char * dst,
+ const char * component)
+{
+ struct list_head * p;
+ struct list_head * h;
+ int id;
+
+ assert(dst);
+ assert(component);
+
+ id = get_id_by_name(component);
+ if (id < 0) {
+ log_err("No such component: %s.", component);
+ return -1;
+ }
+
+ pthread_mutex_lock(&connmgr.comps[id].lock);
+
+ list_for_each_safe(p,h, &connmgr.comps[id].conns) {
+ struct conn_el * el = list_entry(p, struct conn_el, next);
+ if (strcmp(el->conn.flow_info.dst, dst) == 0) {
+ int ret;
+ pthread_mutex_unlock(&connmgr.comps[id].lock);
+ list_del(&el->next);
+ ret = connmgr_dealloc(id, &el->conn);
+ free(el);
+ return ret;
+ }
+ }
+
+ pthread_mutex_unlock(&connmgr.comps[id].lock);
+
+ return 0;
+}
+
+int connmgr_alloc(enum comp_id id,
+ const char * dst,
+ qosspec_t * qs,
+ struct conn * conn)
+{
+ struct comp * comp;
+ int fd;
+ struct timespec timeo = TIMESPEC_INIT_MS(CONNMGR_RCV_TIMEOUT);
+
+ assert(id >= 0 && id < COMPID_MAX);
+ assert(dst);
+
+ comp = connmgr.comps + id;
+
+ fd = flow_alloc(dst, qs, NULL);
+ if (fd < 0) {
+ log_err("Failed to allocate flow to %s.", dst);
+ goto fail_alloc;
+ }
+
+ conn->flow_info.fd = fd;
+
+ if (qs != NULL)
+ conn->flow_info.qs = *qs;
+ else
+ memset(&conn->flow_info.qs, 0, sizeof(conn->flow_info.qs));
+
+ log_dbg("Sending OCEP info for protocol %s to fd %d.",
+ comp->info.protocol, conn->flow_info.fd);
+
+ fccntl(fd, FLOWSRCVTIMEO, &timeo);
+
+ if (cep_snd(fd, &comp->info)) {
+ log_err("Failed to send OCEP info.");
+ goto fail_cep;
+ }
+
+ if (cep_rcv(fd, &conn->conn_info)) {
+ log_err("Failed to receive OCEP info.");
+ goto fail_cep;
+ }
+
+ if (strcmp(comp->info.protocol, conn->conn_info.protocol)) {
+ log_err("Unknown protocol (requested %s, got %s).",
+ comp->info.protocol, conn->conn_info.protocol);
+ goto fail_cep;
+ }
+
+ if (comp->info.pref_version != conn->conn_info.pref_version) {
+ log_err("Unknown protocol version %d.",
+ conn->conn_info.pref_version);
+ goto fail_cep;
+ }
+
+ if (comp->info.pref_syntax != conn->conn_info.pref_syntax) {
+ log_err("Unknown protocol syntax.");
+ goto fail_cep;
+ }
+
+ switch (id) {
+ case COMPID_DT:
+ notifier_event(NOTIFY_DT_CONN_ADD, conn);
+#if defined(BUILD_IPCP_UNICAST) && defined(IPCP_CONN_WAIT_DIR)
+ dir_wait_running();
+#endif
+ break;
+ case COMPID_MGMT:
+ notifier_event(NOTIFY_MGMT_CONN_ADD, conn);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+
+ fail_cep:
+ flow_dealloc(conn->flow_info.fd);
+ fail_alloc:
+ return -1;
+}
+
+int connmgr_dealloc(enum comp_id id,
+ struct conn * conn)
+{
+ switch (id) {
+ case COMPID_DT:
+ notifier_event(NOTIFY_DT_CONN_DEL, conn);
+ break;
+#if defined(BUILD_IPCP_UNICAST) && defined(IPCP_CONN_WAIT_DIR)
+ case COMPID_MGMT:
+ notifier_event(NOTIFY_MGMT_CONN_DEL, conn);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return flow_dealloc(conn->flow_info.fd);
+}
+
+
+int connmgr_wait(enum comp_id id,
+ struct conn * conn)
+{
+ struct conn_el * el;
+ struct comp * comp;
+
+ assert(id >= 0 && id < COMPID_MAX);
+ assert(conn);
+
+ comp = connmgr.comps + id;
+
+ pthread_mutex_lock(&comp->lock);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &comp->lock);
+
+ while (list_is_empty(&comp->pending))
+ pthread_cond_wait(&comp->cond, &comp->lock);
+
+ pthread_cleanup_pop(false);
+
+ el = list_first_entry((&comp->pending), struct conn_el, next);
+ if (el == NULL) {
+ pthread_mutex_unlock(&comp->lock);
+ log_err("Failed to get connection element.");
+ return -1;
+ }
+
+ *conn = el->conn;
+
+ list_del(&el->next);
+ list_add(&el->next, &connmgr.comps[id].conns);
+
+ pthread_mutex_unlock(&comp->lock);
+
+ return 0;
+}
diff --git a/src/ipcpd/unicast/connmgr.h b/src/ipcpd/common/connmgr.h
index 17f78245..0710dbbf 100644
--- a/src/ipcpd/unicast/connmgr.h
+++ b/src/ipcpd/common/connmgr.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Handles the different AP connections
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,10 +20,10 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_IPCPD_UNICAST_CONNMGR_H
-#define OUROBOROS_IPCPD_UNICAST_CONNMGR_H
+#ifndef OUROBOROS_IPCPD_COMMON_CONNMGR_H
+#define OUROBOROS_IPCPD_COMMON_CONNMGR_H
-#include <ouroboros/cacep.h>
+#include <ouroboros/cep.h>
#include <ouroboros/qos.h>
#include "comp.h"
@@ -71,4 +71,4 @@ int connmgr_dealloc(enum comp_id id,
int connmgr_wait(enum comp_id id,
struct conn * conn);
-#endif /* OUROBOROS_IPCPD_UNICAST_CONNMGR_H */
+#endif /* OUROBOROS_IPCPD_COMMON_CONNMGR_H */
diff --git a/src/ipcpd/common/enroll.c b/src/ipcpd/common/enroll.c
new file mode 100644
index 00000000..5e35ce37
--- /dev/null
+++ b/src/ipcpd/common/enroll.c
@@ -0,0 +1,337 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Enrollment Task
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#if defined(__linux__) || defined(__CYGWIN__)
+#define _DEFAULT_SOURCE
+#else
+#define _POSIX_C_SOURCE 199309L
+#endif
+
+#define OUROBOROS_PREFIX "enrollment"
+
+#include <ouroboros/dev.h>
+#include <ouroboros/errno.h>
+#include <ouroboros/logs.h>
+#include <ouroboros/serdes-oep.h>
+#include <ouroboros/time.h>
+
+#include "common/connmgr.h"
+#include "common/enroll.h"
+#include "ipcp.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#define ENROLL_COMP "Enrollment"
+#define ENROLL_PROTO "OEP" /* Ouroboros enrollment protocol */
+#define ENROLL_WARN_TIME_OFFSET 20
+#define ENROLL_BUF_LEN 1024
+
+enum enroll_state {
+ ENROLL_NULL = 0,
+ ENROLL_INIT,
+ ENROLL_RUNNING
+};
+
+struct {
+ struct ipcp_config conf;
+ enum enroll_state state;
+ pthread_t listener;
+} enroll;
+
+static void * enroll_handle(void * o)
+{
+ struct enroll_req req;
+ struct enroll_resp resp;
+ struct enroll_ack ack;
+ struct conn conn;
+ uint8_t __buf[ENROLL_BUF_LEN];
+ buffer_t buf;
+ ssize_t len;
+
+ (void) o;
+
+ buf.data = __buf;
+ buf.len = sizeof(__buf);
+
+ resp.response = 0;
+ resp.conf = enroll.conf;
+
+ while (true) {
+ buffer_t msg;
+ int fd;
+
+ if (connmgr_wait(COMPID_ENROLL, &conn)) {
+ log_err("Failed to get next connection.");
+ continue;
+ }
+
+ fd = conn.flow_info.fd;
+
+ log_info("Incoming enrollment connection on flow %d.", fd);
+
+ len = flow_read(fd, buf.data, buf.len);
+ if (len < 0) {
+ log_err("Failed to read from flow %d.", fd);
+ goto finish_flow;
+ }
+
+ msg.data = buf.data;
+ msg.len = (size_t) len;
+
+ if (enroll_req_des(&req, msg) < 0) {
+ log_err("Failed to unpack request message.");
+ goto finish_flow;
+ }
+
+ log_info_id(req.id, "Handling incoming enrollment.");
+
+ /* TODO: authentication, timezone handling (UTC). */
+
+ ack.result = -100;
+
+ clock_gettime(CLOCK_REALTIME, &resp.t);
+
+ memcpy(resp.id, req.id, ENROLL_ID_LEN);
+
+ len = enroll_resp_ser(&resp, buf);
+ if (len < 0) {
+ log_err_id(req.id, "Failed to pack reply.");
+ goto finish_enroll;
+ }
+
+ log_dbg_id(req.id, "Sending enrollment info (%zd bytes).", len);
+
+ if (flow_write(conn.flow_info.fd, buf.data, len) < 0) {
+ log_err_id(req.id, "Failed te send response.");
+ goto finish_enroll;
+ }
+
+ len = flow_read(conn.flow_info.fd, buf.data, buf.len);
+ if (len < 0) {
+ log_err_id(req.id, "Failed to read from flow.");
+ goto finish_enroll;
+ }
+
+ msg.data = buf.data;
+ msg.len = (size_t) len;
+
+ if (enroll_ack_des(&ack, msg) < 0) {
+ log_err_id(req.id, "Failed to unpack ack.");
+ goto finish_enroll;
+ }
+
+ if (memcmp(req.id, ack.id, ENROLL_ID_LEN) != 0)
+ log_warn_id(req.id, "Enrollment ID mismatch.");
+
+ finish_enroll:
+ switch(ack.result) {
+ case 0:
+ log_info_id(req.id, "Enrollment completed.");
+ break;
+ case -100:
+ log_warn_id(req.id, "Enrollment failed.");
+ break;
+ default:
+ log_warn_id(req.id, "Enrollment failed at remote.");
+ }
+ finish_flow:
+ connmgr_dealloc(COMPID_ENROLL, &conn);
+
+ log_info("Enrollment flow %d closed.", fd);
+ }
+
+ return 0;
+}
+
+int enroll_boot(struct conn * conn,
+ const uint8_t * id)
+{
+ uint8_t __buf[ENROLL_BUF_LEN];
+ buffer_t buf;
+ buffer_t msg;
+ ssize_t len;
+ ssize_t delta_t;
+ struct timespec t0;
+ struct timespec rtt;
+ int fd;
+ int ret;
+ struct enroll_req req;
+ struct enroll_resp resp;
+
+ fd = conn->flow_info.fd;
+
+ buf.data = __buf;
+ buf.len = sizeof(__buf);
+
+ memcpy(req.id, id, ENROLL_ID_LEN);
+
+ len = enroll_req_ser(&req, buf);
+ if (len < 0) {
+ log_err_id(id, "Failed to pack request message.");
+ return -1;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &t0);
+
+ if (flow_write(fd, buf.data, len) < 0) {
+ log_err_id(id, "Failed to send request message.");
+ return -1;
+ }
+
+ len = flow_read(fd, buf.data, buf.len);
+ if (len < 0) {
+ log_err_id(id, "No reply received.");
+ return -1;
+ }
+
+ log_dbg_id(id, "Received configuration info (%zd bytes).", len);
+
+ msg.data = buf.data;
+ msg.len = len;
+
+ ret = enroll_resp_des(&resp, msg);
+ if (ret < 0) {
+ log_err_id(id, "Failed to unpack response message.");
+ return -1;
+ }
+
+ if (memcmp(resp.id, id, ENROLL_ID_LEN) != 0) {
+ log_err_id(id, "Enrollment ID mismatch.");
+ return -1;
+ }
+
+ if (resp.response < 0) {
+ log_warn_id(id, "Remote denied request: %d.", resp.response);
+ return -1;
+ }
+
+ if (resp.conf.type != ipcpi.type) {
+ log_err_id(id, "Wrong type in enrollment response %d (%d).",
+ resp.conf.type, ipcpi.type);
+ return -1;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &rtt);
+
+ delta_t = ts_diff_ms(&t0, &rtt);
+
+ rtt.tv_sec = resp.t.tv_sec;
+ rtt.tv_nsec = resp.t.tv_nsec;
+
+ if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET)
+ log_warn_id(id, "Clock offset above threshold.");
+
+ enroll.conf = resp.conf;
+
+ return 0;
+}
+
+int enroll_ack(struct conn * conn,
+ const uint8_t * id,
+ const int result)
+{
+ struct enroll_ack ack;
+ uint8_t __buf[ENROLL_BUF_LEN];
+ buffer_t buf;
+ ssize_t len;
+
+ buf.data = __buf;
+ buf.len = sizeof(__buf);
+
+ ack.result = result;
+
+ memcpy(ack.id, id, ENROLL_ID_LEN);
+
+ len = enroll_ack_ser(&ack, buf);
+ if (len < 0) {
+ log_err_id(id, "Failed to pack acknowledgement.");
+ return -1;
+ }
+
+ if (flow_write(conn->flow_info.fd, buf.data, len) < 0) {
+ log_err_id(id, "Failed to send acknowledgment.");
+ return -1;
+ }
+
+ return 0;
+}
+
+void enroll_bootstrap(const struct ipcp_config * conf)
+{
+ assert(conf);
+
+ memcpy(&enroll.conf, conf, sizeof(enroll.conf));
+}
+
+struct ipcp_config * enroll_get_conf(void)
+{
+ return &enroll.conf;
+}
+
+int enroll_init(void)
+{
+ struct conn_info info;
+
+ memset(&info, 0, sizeof(info));
+
+ strcpy(info.comp_name, ENROLL_COMP);
+ strcpy(info.protocol, ENROLL_PROTO);
+ info.pref_version = 1;
+ info.pref_syntax = PROTO_GPB;
+ info.addr = 0;
+
+ if (connmgr_comp_init(COMPID_ENROLL, &info)) {
+ log_err("Failed to register with connmgr.");
+ return -1;
+ }
+
+ enroll.state = ENROLL_INIT;
+
+ return 0;
+}
+
+void enroll_fini(void)
+{
+ if (enroll.state == ENROLL_RUNNING)
+ pthread_join(enroll.listener, NULL);
+
+ connmgr_comp_fini(COMPID_ENROLL);
+}
+
+int enroll_start(void)
+{
+ if (pthread_create(&enroll.listener, NULL, enroll_handle, NULL))
+ return -1;
+
+ enroll.state = ENROLL_RUNNING;
+
+ return 0;
+}
+
+void enroll_stop(void)
+{
+ if (enroll.state == ENROLL_RUNNING)
+ pthread_cancel(enroll.listener);
+}
diff --git a/src/ipcpd/broadcast/enroll.h b/src/ipcpd/common/enroll.h
index 837e0a28..f26c31a3 100644
--- a/src/ipcpd/broadcast/enroll.h
+++ b/src/ipcpd/common/enroll.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Enrollment Task
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,8 +20,8 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_IPCPD_BROADCAST_ENROLL_H
-#define OUROBOROS_IPCPD_BROADCAST_ENROLL_H
+#ifndef OUROBOROS_IPCPD_COMMON_ENROLL_H
+#define OUROBOROS_IPCPD_COMMON_ENROLL_H
#include <ouroboros/ipcp.h>
@@ -37,11 +37,13 @@ void enroll_stop(void);
void enroll_bootstrap(const struct ipcp_config * conf);
-int enroll_boot(struct conn * conn);
+int enroll_boot(struct conn * conn,
+ const uint8_t * id);
-int enroll_done(struct conn * conn,
- int result);
+int enroll_ack(struct conn * conn,
+ const uint8_t * id,
+ const int result);
struct ipcp_config * enroll_get_conf(void);
-#endif /* OUROBOROS_IPCPD_BROADCAST_ENROLL_H */
+#endif /* OUROBOROS_IPCPD_COMMON_ENROLL_H */
diff --git a/src/ipcpd/config.h.in b/src/ipcpd/config.h.in
index 3f69d327..fe4f5fd2 100644
--- a/src/ipcpd/config.h.in
+++ b/src/ipcpd/config.h.in
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC process configuration
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -39,6 +39,10 @@
#define IPCP_ADD_THREADS @IPCP_ADD_THREADS@
#cmakedefine HAVE_LIBGCRYPT
+#define IPCP_LINUX_SLACK_NS @IPCP_LINUX_TIMERSLACK_NS@
+
+#cmakedefine IPCP_DEBUG_LOCAL
+
/* unicast IPCP */
#define QOS_PRIO_BE @IPCP_QOS_CUBE_BE_PRIO@
#define QOS_PRIO_VIDEO @IPCP_QOS_CUBE_VIDEO_PRIO@
@@ -46,6 +50,8 @@
#define IPCP_SCHED_THR_MUL @IPCP_SCHED_THR_MUL@
#define PFT_SIZE @PFT_SIZE@
#define DHT_ENROLL_SLACK @DHT_ENROLL_SLACK@
+#define IPCP_UNICAST_MPL @IPCP_UNICAST_MPL@
+#define CONNMGR_RCV_TIMEOUT @CONNMGR_RCV_TIMEOUT@
#cmakedefine IPCP_CONN_WAIT_DIR
#cmakedefine DISABLE_CORE_LOCK
@@ -57,8 +63,9 @@
#define NSLOOKUP_EXEC "@NSLOOKUP_EXECUTABLE@"
#define IPCP_UDP_RD_THR @IPCP_UDP_RD_THR@
#define IPCP_UDP_WR_THR @IPCP_UDP_WR_THR@
+#define IPCP_UDP_MPL @IPCP_UDP_MPL@
-/* eth-llc */
+/* eth */
#cmakedefine HAVE_NETMAP
#cmakedefine HAVE_BPF
#cmakedefine HAVE_RAW_SOCKETS
@@ -66,3 +73,11 @@
#define IPCP_ETH_RD_THR @IPCP_ETH_RD_THR@
#define IPCP_ETH_WR_THR @IPCP_ETH_WR_THR@
#define IPCP_ETH_LO_MTU @IPCP_ETH_LO_MTU@
+#define IPCP_ETH_MPL @IPCP_ETH_MPL@
+
+/* local */
+#define IPCP_LOCAL_MPL @IPCP_LOCAL_MPL@
+
+/* broadcast */
+/* local */
+#define IPCP_BROADCAST_MPL @IPCP_BROADCAST_MPL@
diff --git a/src/ipcpd/eth/CMakeLists.txt b/src/ipcpd/eth/CMakeLists.txt
index d7105b4f..d57e1848 100644
--- a/src/ipcpd/eth/CMakeLists.txt
+++ b/src/ipcpd/eth/CMakeLists.txt
@@ -85,6 +85,8 @@ if (HAVE_ETH)
"Bypass the Qdisc in the kernel when using raw sockets")
set(IPCP_ETH_LO_MTU 1500 CACHE STRING
"Restrict Ethernet MTU over loopback interfaces")
+ set(IPCP_ETH_MPL 5 CACHE STRING
+ "Default maximum packet lifetime for the Ethernet IPCPs, in seconds")
set(ETH_LLC_SOURCES
# Add source files here
diff --git a/src/ipcpd/eth/dix.c b/src/ipcpd/eth/dix.c
index dd007709..37b9896d 100644
--- a/src/ipcpd/eth/dix.c
+++ b/src/ipcpd/eth/dix.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC processes over Ethernet - DIX
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c
index 6b17912b..ea6e0f1c 100644
--- a/src/ipcpd/eth/eth.c
+++ b/src/ipcpd/eth/eth.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC processes over Ethernet
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -37,6 +37,7 @@
#include "config.h"
+#include <ouroboros/endian.h>
#include <ouroboros/hash.h>
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
@@ -46,15 +47,15 @@
#include <ouroboros/ipcp-dev.h>
#include <ouroboros/fqueue.h>
#include <ouroboros/logs.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/time.h>
#include <ouroboros/fccntl.h>
+#include <ouroboros/pthread.h>
#include "ipcp.h"
#include "shim-data.h"
#include <signal.h>
#include <stdlib.h>
-#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
@@ -135,7 +136,6 @@
#define ETH_FRAME_SIZE (ETH_HEADER_SIZE + ETH_MTU_MAX)
#endif
-#define ALLOC_TIMEO 10 /* ms */
#define NAME_QUERY_TIMEO 2000 /* ms */
#define MGMT_TIMEO 100 /* ms */
#define MGMT_FRAME_SIZE 2048
@@ -145,6 +145,8 @@
#define NAME_QUERY_REQ 2
#define NAME_QUERY_REPLY 3
+struct ipcp ipcpi;
+
struct mgmt_msg {
#if defined(BUILD_ETH_DIX)
uint16_t seid;
@@ -162,6 +164,7 @@ struct mgmt_msg {
uint32_t ber;
uint32_t max_gap;
uint32_t delay;
+ uint32_t timeout;
uint16_t cypher_s;
uint8_t in_order;
#if defined (BUILD_ETH_DIX)
@@ -452,16 +455,15 @@ static int eth_ipcp_send_frame(const uint8_t * dst_addr,
return 0;
}
-static int eth_ipcp_alloc(const uint8_t * dst_addr,
+static int eth_ipcp_alloc(const uint8_t * dst_addr,
#if defined(BUILD_ETH_DIX)
- uint16_t eid,
+ uint16_t eid,
#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
+ uint8_t ssap,
#endif
- const uint8_t * hash,
- qosspec_t qs,
- const void * data,
- size_t dlen)
+ const uint8_t * hash,
+ qosspec_t qs,
+ const buffer_t * data)
{
uint8_t * buf;
struct mgmt_msg * msg;
@@ -470,7 +472,7 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr,
len = sizeof(*msg) + ipcp_dir_hash_len();
- buf = malloc(len + ETH_HEADER_TOT_SIZE + dlen);
+ buf = malloc(len + ETH_HEADER_TOT_SIZE + data->len);
if (buf == NULL)
return -1;
@@ -490,9 +492,11 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr,
msg->in_order = qs.in_order;
msg->max_gap = hton32(qs.max_gap);
msg->cypher_s = hton16(qs.cypher_s);
+ msg->timeout = hton32(qs.timeout);
memcpy(msg + 1, hash, ipcp_dir_hash_len());
- memcpy(buf + len + ETH_HEADER_TOT_SIZE, data, dlen);
+ if (data->len > 0)
+ memcpy(buf + len + ETH_HEADER_TOT_SIZE, data->data, data->len);
ret = eth_ipcp_send_frame(dst_addr,
#if defined(BUILD_ETH_DIX)
@@ -501,28 +505,27 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr,
reverse_bits(MGMT_SAP),
reverse_bits(MGMT_SAP),
#endif
- buf, len + dlen);
+ buf, len + data->len);
free(buf);
return ret;
}
-static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
+static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
#if defined(BUILD_ETH_DIX)
- uint16_t seid,
- uint16_t deid,
+ uint16_t seid,
+ uint16_t deid,
#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
- uint8_t dsap,
+ uint8_t ssap,
+ uint8_t dsap,
#endif
- int response,
- const void * data,
- size_t len)
+ int response,
+ const buffer_t * data)
{
struct mgmt_msg * msg;
uint8_t * buf;
- buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + len);
+ buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len);
if (buf == NULL)
return -1;
@@ -538,7 +541,8 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
#endif
msg->response = response;
- memcpy(msg + 1, data, len);
+ if (data->len > 0)
+ memcpy(msg + 1, data->data, data->len);
if (eth_ipcp_send_frame(dst_addr,
#if defined(BUILD_ETH_DIX)
@@ -547,7 +551,7 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
reverse_bits(MGMT_SAP),
reverse_bits(MGMT_SAP),
#endif
- buf, sizeof(*msg) + len)) {
+ buf, sizeof(*msg) + data->len)) {
free(buf);
return -1;
}
@@ -557,42 +561,20 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
return 0;
}
-static int eth_ipcp_req(uint8_t * r_addr,
+static int eth_ipcp_req(uint8_t * r_addr,
#if defined(BUILD_ETH_DIX)
- uint16_t r_eid,
+ uint16_t r_eid,
#elif defined(BUILD_ETH_LLC)
- uint8_t r_sap,
+ uint8_t r_sap,
#endif
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t len)
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
- struct timespec ts = {0, ALLOC_TIMEO * MILLION};
- struct timespec abstime;
- int fd;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ int fd;
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_dbg("Won't allocate over non-operational IPCP.");
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- return -1;
- }
-
- /* reply to IRM, called under lock to prevent race */
- fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len);
+ fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_ETH_MPL, data);
if (fd < 0) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
log_err("Could not get new flow from IRMd.");
return -1;
}
@@ -607,11 +589,6 @@ static int eth_ipcp_req(uint8_t * r_addr,
pthread_rwlock_unlock(&eth_data.flows_lock);
- ipcpi.alloc_id = fd;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
#if defined(BUILD_ETH_DIX)
log_dbg("New flow request, fd %d, remote endpoint %d.", fd, r_eid);
#elif defined(BUILD_ETH_LLC)
@@ -620,20 +597,20 @@ static int eth_ipcp_req(uint8_t * r_addr,
return 0;
}
-static int eth_ipcp_alloc_reply(uint8_t * r_addr,
+static int eth_ipcp_alloc_reply(uint8_t * r_addr,
#if defined(BUILD_ETH_DIX)
- uint16_t seid,
- uint16_t deid,
+ uint16_t seid,
+ uint16_t deid,
#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
- int dsap,
+ uint8_t ssap,
+ int dsap,
#endif
- int response,
- const void * data,
- size_t len)
+ int response,
+ const buffer_t * data)
{
- int ret = 0;
- int fd = -1;
+ int ret = 0;
+ int fd = -1;
+ time_t mpl = IPCP_ETH_MPL;
pthread_rwlock_wrlock(&eth_data.flows_lock);
@@ -668,11 +645,12 @@ static int eth_ipcp_alloc_reply(uint8_t * r_addr,
#elif defined(BUILD_ETH_LLC)
log_dbg("Flow reply, fd %d, SSAP %d, DSAP %d.", fd, ssap, dsap);
#endif
- if ((ret = ipcp_flow_alloc_reply(fd, response, data, len)) < 0)
+ if ((ret = ipcp_flow_alloc_reply(fd, response, mpl, data)) < 0) {
+ log_err("Failed to reply to flow allocation.");
return -1;
+ }
return ret;
-
}
static int eth_ipcp_name_query_req(const uint8_t * hash,
@@ -734,6 +712,7 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
struct mgmt_msg * msg;
size_t msg_len;
qosspec_t qs;
+ buffer_t data;
msg = (struct mgmt_msg *) buf;
@@ -751,6 +730,10 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
qs.in_order = msg->in_order;
qs.max_gap = ntoh32(msg->max_gap);
qs.cypher_s = ntoh16(msg->cypher_s);
+ qs.timeout = ntoh32(msg->timeout);
+
+ data.data = (uint8_t *) buf + msg_len;
+ data.len = len - msg_len;
if (shim_data_reg_has(eth_data.shim_data,
buf + sizeof(*msg))) {
@@ -762,13 +745,15 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
#endif
buf + sizeof(*msg),
qs,
- buf + msg_len,
- len - msg_len);
+ &data);
}
break;
case FLOW_REPLY:
assert(len >= sizeof(*msg));
+ data.data = (uint8_t *) buf + sizeof(*msg);
+ data.len = len - sizeof(*msg);
+
eth_ipcp_alloc_reply(r_addr,
#if defined(BUILD_ETH_DIX)
ntohs(msg->seid),
@@ -778,8 +763,7 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
msg->dsap,
#endif
msg->response,
- buf + sizeof(*msg),
- len - sizeof(*msg));
+ &data);
break;
case NAME_QUERY_REQ:
eth_ipcp_name_query_req(buf + sizeof(*msg), r_addr);
@@ -797,19 +781,15 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
static void * eth_ipcp_mgmt_handler(void * o)
{
- int ret;
- struct timespec timeout = {(MGMT_TIMEO / 1000),
- (MGMT_TIMEO % 1000) * MILLION};
- struct timespec abstime;
- struct mgmt_frame * frame;
-
(void) o;
- pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock,
- (void *) &eth_data.mgmt_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &eth_data.mgmt_lock);
while (true) {
- ret = 0;
+ int ret = 0;
+ struct timespec timeout = TIMESPEC_INIT_MS(MGMT_TIMEO);
+ struct timespec abstime;
+ struct mgmt_frame * frame = NULL;
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeout, &abstime);
@@ -821,23 +801,19 @@ static void * eth_ipcp_mgmt_handler(void * o)
ret = -pthread_cond_timedwait(&eth_data.mgmt_cond,
&eth_data.mgmt_lock,
&abstime);
+ if (ret != -ETIMEDOUT)
+ frame = list_first_entry((&eth_data.mgmt_frames),
+ struct mgmt_frame, next);
+ if (frame != NULL)
+ list_del(&frame->next);
- if (ret == -ETIMEDOUT) {
- pthread_mutex_unlock(&eth_data.mgmt_lock);
- continue;
- }
+ pthread_mutex_unlock(&eth_data.mgmt_lock);
- frame = list_first_entry((&eth_data.mgmt_frames),
- struct mgmt_frame, next);
- if (frame == NULL) {
- pthread_mutex_unlock(&eth_data.mgmt_lock);
+ if (frame == NULL)
continue;
- }
-
- list_del(&frame->next);
- pthread_mutex_unlock(&eth_data.mgmt_lock);
eth_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_addr);
+
free(frame);
}
@@ -883,7 +859,7 @@ static void * eth_ipcp_packet_reader(void * o)
buf = nm_nextpkt(eth_data.nmd, &hdr);
if (buf == NULL) {
- log_err("Bad read from netmap device.");
+ log_dbg("Bad read from netmap device.");
continue;
}
#else
@@ -914,6 +890,7 @@ static void * eth_ipcp_packet_reader(void * o)
ETH_MTU + ETH_HEADER_TOT_SIZE, 0);
#endif
if (frame_len <= 0) {
+ log_dbg("Failed to receive frame.");
ipcp_sdb_release(sdb);
continue;
}
@@ -940,22 +917,14 @@ static void * eth_ipcp_packet_reader(void * o)
#endif
length = ntohs(e_frame->length);
#if defined(BUILD_ETH_DIX)
- if (e_frame->ethertype != eth_data.ethertype) {
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
- }
+ if (e_frame->ethertype != eth_data.ethertype)
+ goto fail_frame;
deid = ntohs(e_frame->eid);
if (deid == MGMT_EID) {
#elif defined (BUILD_ETH_LLC)
- if (length > 0x05FF) {/* DIX */
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
- }
+ if (length > 0x05FF) /* DIX */
+ goto fail_frame;
length -= LLC_HEADER_SIZE;
@@ -964,12 +933,12 @@ static void * eth_ipcp_packet_reader(void * o)
if (ssap == MGMT_SAP && dsap == MGMT_SAP) {
#endif
+ ipcp_sdb_release(sdb); /* No need for the N+1 buffer. */
+
frame = malloc(sizeof(*frame));
if (frame == NULL) {
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
+ log_err("Failed to allocate frame.");
+ goto fail_frame;
}
memcpy(frame->buf, &e_frame->payload, length);
@@ -980,10 +949,6 @@ static void * eth_ipcp_packet_reader(void * o)
list_add(&frame->next, &eth_data.mgmt_frames);
pthread_cond_signal(&eth_data.mgmt_cond);
pthread_mutex_unlock(&eth_data.mgmt_lock);
-
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
} else {
pthread_rwlock_rdlock(&eth_data.flows_lock);
@@ -994,10 +959,7 @@ static void * eth_ipcp_packet_reader(void * o)
#endif
if (fd < 0) {
pthread_rwlock_unlock(&eth_data.flows_lock);
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
+ goto fail_frame;
}
#ifdef BUILD_ETH_LLC
@@ -1005,10 +967,7 @@ static void * eth_ipcp_packet_reader(void * o)
|| memcmp(eth_data.fd_to_ef[fd].r_addr,
e_frame->src_hwaddr, MAC_SIZE)) {
pthread_rwlock_unlock(&eth_data.flows_lock);
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
+ goto fail_frame;
}
#endif
pthread_rwlock_unlock(&eth_data.flows_lock);
@@ -1016,9 +975,20 @@ static void * eth_ipcp_packet_reader(void * o)
#ifndef HAVE_NETMAP
shm_du_buff_head_release(sdb, ETH_HEADER_TOT_SIZE);
shm_du_buff_truncate(sdb, length);
- ipcp_flow_write(fd, sdb);
#else
- flow_write(fd, &e_frame->payload, length);
+ if (ipcp_sdb_reserve(&sdb, length))
+ continue;
+
+ buf = shm_du_buff_head(sdb);
+ memcpy(buf, &e_frame->payload, length);
+#endif
+ if (np1_flow_write(fd, sdb) < 0)
+ ipcp_sdb_release(sdb);
+
+ continue;
+ fail_frame:
+#ifndef HAVE_NETMAP
+ ipcp_sdb_release(sdb);
#endif
}
}
@@ -1052,27 +1022,28 @@ static void * eth_ipcp_packet_writer(void * o)
(void) o;
- pthread_cleanup_push(cleanup_writer, fq);
-
ipcp_lock_to_core();
+ pthread_cleanup_push(cleanup_writer, fq);
+
while (true) {
fevent(eth_data.np1_flows, fq, NULL);
while ((fd = fqueue_next(fq)) >= 0) {
if (fqueue_type(fq) != FLOW_PKT)
continue;
- if (ipcp_flow_read(fd, &sdb)) {
+ if (np1_flow_read(fd, &sdb)) {
log_dbg("Bad read from fd %d.", fd);
continue;
}
- len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
+ len = shm_du_buff_len(sdb);
if (shm_du_buff_head_alloc(sdb, ETH_HEADER_TOT_SIZE)
== NULL) {
log_dbg("Failed to allocate header.");
ipcp_sdb_release(sdb);
+ continue;
}
pthread_rwlock_rdlock(&eth_data.flows_lock);
@@ -1088,14 +1059,15 @@ static void * eth_ipcp_packet_writer(void * o)
pthread_rwlock_unlock(&eth_data.flows_lock);
- eth_ipcp_send_frame(r_addr,
+ if (eth_ipcp_send_frame(r_addr,
#if defined(BUILD_ETH_DIX)
deid,
#elif defined(BUILD_ETH_LLC)
dsap, ssap,
#endif
shm_du_buff_head(sdb),
- len);
+ len))
+ log_dbg("Failed to send frame.");
ipcp_sdb_release(sdb);
}
}
@@ -1160,12 +1132,6 @@ static void change_flows_state(bool up)
pthread_rwlock_unlock(&eth_data.flows_lock);
}
-static void close_ptr(void * o)
-{
- close(*((int *) o));
-}
-
-
static void * eth_ipcp_if_monitor(void * o)
{
int fd;
@@ -1186,7 +1152,7 @@ static void * eth_ipcp_if_monitor(void * o)
return (void *) -1;
}
- pthread_cleanup_push(close_ptr, &fd);
+ pthread_cleanup_push(__cleanup_close_ptr, &fd);
while (true) {
status = recvmsg(fd, &msg, 0);
@@ -1281,25 +1247,23 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
assert(conf);
assert(conf->type == THIS_TYPE);
- if (conf->dev == NULL) {
- log_err("Device name is NULL.");
- return -1;
- }
+ ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo;
+ strcpy(ipcpi.layer_name, conf->layer_info.name);
- if (strlen(conf->dev) >= IFNAMSIZ) {
- log_err("Invalid device name: %s.", conf->dev);
+ if (strlen(conf->eth.dev) >= IFNAMSIZ) {
+ log_err("Invalid device name: %s.", conf->eth.dev);
return -1;
}
memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, conf->dev);
+ strcpy(ifr.ifr_name, conf->eth.dev);
#ifdef BUILD_ETH_DIX
- if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF) {
- log_err("Invalid Ethertype.");
+ if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) {
+ log_err("Invalid Ethertype: %d.", conf->eth.ethertype);
return -1;
}
- eth_data.ethertype = htons(conf->ethertype);
+ eth_data.ethertype = htons(conf->eth.ethertype);
#endif
#if defined(__FreeBSD__) || defined(__APPLE__)
@@ -1309,9 +1273,9 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
}
for (ifa = ifaddr, idx = 0; ifa != NULL; ifa = ifa->ifa_next, ++idx) {
- if (strcmp(ifa->ifa_name, conf->dev))
+ if (strcmp(ifa->ifa_name, conf->eth.dev))
continue;
- log_dbg("Interface %s found.", conf->dev);
+ log_dbg("Interface %s found.", conf->eth.dev);
#if defined(HAVE_NETMAP) || defined(HAVE_BPF)
memcpy(eth_data.hw_addr,
@@ -1346,7 +1310,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
log_dbg("Device MTU is %d.", ifr.ifr_mtu);
eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr.ifr_mtu);
- if (memcmp(conf->dev, "lo", 2) == 0 && eth_data.mtu > IPCP_ETH_LO_MTU) {
+ if (memcmp(conf->eth.dev, "lo", 2) == 0 &&
+ eth_data.mtu > IPCP_ETH_LO_MTU) {
log_dbg("Using loopback interface. MTU restricted to %d.",
IPCP_ETH_LO_MTU);
eth_data.mtu = IPCP_ETH_LO_MTU;
@@ -1370,7 +1335,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
close(skfd);
- idx = if_nametoindex(conf->dev);
+ idx = if_nametoindex(conf->eth.dev);
if (idx == 0) {
log_err("Failed to retrieve interface index.");
return -1;
@@ -1380,7 +1345,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
#if defined(HAVE_NETMAP)
strcpy(ifn, "netmap:");
- strcat(ifn, conf->dev);
+ strcat(ifn, conf->eth.dev);
eth_data.nmd = nm_open(ifn, NULL, 0, NULL);
if (eth_data.nmd == NULL) {
@@ -1450,7 +1415,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
if (eth_data.s_fd < 0) {
log_err("Failed to create socket.");
- return -1;
+ goto fail_socket;
}
flags = fcntl(eth_data.s_fd, F_GETFL, 0);
@@ -1472,60 +1437,52 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
#endif
if (bind(eth_data.s_fd, (struct sockaddr *) &eth_data.device,
- sizeof(eth_data.device))) {
+ sizeof(eth_data.device)) < 0) {
log_err("Failed to bind socket to interface.");
goto fail_device;
}
-
#endif /* HAVE_NETMAP */
- ipcp_set_state(IPCP_OPERATIONAL);
-
#if defined(__linux__)
- if (pthread_create(&eth_data.if_monitor,
- NULL,
- eth_ipcp_if_monitor,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
+ if (pthread_create(&eth_data.if_monitor, NULL,
+ eth_ipcp_if_monitor, NULL)) {
+ log_err("Failed to create monitor thread: %s.",
+ strerror(errno));
goto fail_device;
}
#endif
- if (pthread_create(&eth_data.mgmt_handler,
- NULL,
- eth_ipcp_mgmt_handler,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
+ if (pthread_create(&eth_data.mgmt_handler, NULL,
+ eth_ipcp_mgmt_handler, NULL)) {
+ log_err("Failed to create mgmt handler thread: %s.",
+ strerror(errno));
goto fail_mgmt_handler;
}
for (idx = 0; idx < IPCP_ETH_RD_THR; ++idx) {
- if (pthread_create(&eth_data.packet_reader[idx],
- NULL,
- eth_ipcp_packet_reader,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
+ if (pthread_create(&eth_data.packet_reader[idx], NULL,
+ eth_ipcp_packet_reader, NULL)) {
+ log_err("Failed to create packet reader thread: %s",
+ strerror(errno));
goto fail_packet_reader;
}
}
for (idx = 0; idx < IPCP_ETH_WR_THR; ++idx) {
- if (pthread_create(&eth_data.packet_writer[idx],
- NULL,
- eth_ipcp_packet_writer,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
+ if (pthread_create(&eth_data.packet_writer[idx], NULL,
+ eth_ipcp_packet_writer, NULL)) {
+ log_err("Failed to create packet writer thread: %s",
+ strerror(errno));
goto fail_packet_writer;
}
}
#if defined(BUILD_ETH_DIX)
log_dbg("Bootstrapped IPCP over DIX Ethernet with pid %d "
- "and Ethertype 0x%X.", getpid(), conf->ethertype);
+ "and Ethertype 0x%X.", getpid(), conf->eth.ethertype);
#elif defined(BUILD_ETH_LLC)
log_dbg("Bootstrapped IPCP over Ethernet with LLC with pid %d.",
getpid());
#endif
-
return 0;
fail_packet_writer:
@@ -1556,19 +1513,18 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
#elif defined(HAVE_RAW_SOCKETS)
close(eth_data.s_fd);
#endif
+ fail_socket:
return -1;
}
static int eth_ipcp_reg(const uint8_t * hash)
{
if (shim_data_reg_add_entry(eth_data.shim_data, hash)) {
- log_err("Failed to add " HASH_FMT " to local registry.",
- HASH_VAL(hash));
+ log_err("Failed to add " HASH_FMT32 " to local registry.",
+ HASH_VAL32(hash));
return -1;
}
- log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash));
-
return 0;
}
@@ -1582,8 +1538,7 @@ static int eth_ipcp_unreg(const uint8_t * hash)
static int eth_ipcp_query(const uint8_t * hash)
{
uint8_t r_addr[MAC_SIZE];
- struct timespec timeout = {(NAME_QUERY_TIMEO / 1000),
- (NAME_QUERY_TIMEO % 1000) * MILLION};
+ struct timespec timeout = TIMESPEC_INIT_MS(NAME_QUERY_TIMEO);
struct dir_query * query;
int ret;
uint8_t * buf;
@@ -1635,11 +1590,10 @@ static int eth_ipcp_query(const uint8_t * hash)
return ret;
}
-static int eth_ipcp_flow_alloc(int fd,
- const uint8_t * hash,
- qosspec_t qs,
- const void * data,
- size_t len)
+static int eth_ipcp_flow_alloc(int fd,
+ const uint8_t * hash,
+ qosspec_t qs,
+ const buffer_t * data)
{
#ifdef BUILD_ETH_LLC
uint8_t ssap = 0;
@@ -1647,12 +1601,11 @@ static int eth_ipcp_flow_alloc(int fd,
uint8_t r_addr[MAC_SIZE];
uint64_t addr = 0;
- log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(hash));
-
assert(hash);
if (!shim_data_dir_has(eth_data.shim_data, hash)) {
- log_err("Destination unreachable.");
+ log_err("Destination "HASH_FMT32 "unreachable.",
+ HASH_VAL32(hash));
return -1;
}
addr = shim_data_dir_get_addr(eth_data.shim_data, hash);
@@ -1662,6 +1615,7 @@ static int eth_ipcp_flow_alloc(int fd,
ssap = bmp_allocate(eth_data.saps);
if (!bmp_is_id_valid(eth_data.saps, ssap)) {
pthread_rwlock_unlock(&eth_data.flows_lock);
+ log_err("Failed to allocate SSAP.");
return -1;
}
@@ -1680,34 +1634,29 @@ static int eth_ipcp_flow_alloc(int fd,
#endif
hash,
qs,
- data,
- len) < 0) {
+ data) < 0) {
#ifdef BUILD_ETH_LLC
pthread_rwlock_wrlock(&eth_data.flows_lock);
bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap);
eth_data.fd_to_ef[fd].sap = -1;
eth_data.ef_to_fd[ssap] = -1;
pthread_rwlock_unlock(&eth_data.flows_lock);
+ log_err("Failed to allocate with peer.");
#endif
return -1;
}
fset_add(eth_data.np1_flows, fd);
-#if defined(BUILD_ETH_DIX)
- log_dbg("Pending flow with fd %d.", fd);
-#elif defined(BUILD_ETH_LLC)
- log_dbg("Pending flow with fd %d on SAP %d.", fd, ssap);
+#if defined(BUILD_ETH_LLC)
+ log_dbg("Assigned SAP %d for fd %d.", ssap, fd);
#endif
return 0;
}
-static int eth_ipcp_flow_alloc_resp(int fd,
- int response,
- const void * data,
- size_t len)
+static int eth_ipcp_flow_alloc_resp(int fd,
+ int response,
+ const buffer_t * data)
{
- struct timespec ts = {0, ALLOC_TIMEO * MILLION};
- struct timespec abstime;
#if defined(BUILD_ETH_DIX)
uint16_t r_eid;
#elif defined(BUILD_ETH_LLC)
@@ -1716,27 +1665,11 @@ static int eth_ipcp_flow_alloc_resp(int fd,
#endif
uint8_t r_addr[MAC_SIZE];
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ if (ipcp_wait_flow_resp(fd) < 0) {
+ log_err("Failed to wait for flow response.");
return -1;
}
- ipcpi.alloc_id = -1;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
pthread_rwlock_wrlock(&eth_data.flows_lock);
#if defined(BUILD_ETH_DIX)
r_eid = eth_data.fd_to_ef[fd].r_eid;
@@ -1744,6 +1677,7 @@ static int eth_ipcp_flow_alloc_resp(int fd,
ssap = bmp_allocate(eth_data.saps);
if (!bmp_is_id_valid(eth_data.saps, ssap)) {
pthread_rwlock_unlock(&eth_data.flows_lock);
+ log_err("Failed to allocate SSAP.");
return -1;
}
@@ -1762,21 +1696,19 @@ static int eth_ipcp_flow_alloc_resp(int fd,
ssap, r_sap,
#endif
response,
- data,
- len) < 0) {
+ data) < 0) {
#ifdef BUILD_ETH_LLC
pthread_rwlock_wrlock(&eth_data.flows_lock);
bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap);
pthread_rwlock_unlock(&eth_data.flows_lock);
#endif
+ log_err("Failed to respond to peer.");
return -1;
}
fset_add(eth_data.np1_flows, fd);
-#if defined(BUILD_ETH_DIX)
- log_dbg("Accepted flow, fd %d.", fd);
-#elif defined(BUILD_ETH_LLC)
- log_dbg("Accepted flow, fd %d, SAP %d.", fd, (uint8_t)ssap);
+#if defined(BUILD_ETH_LLC)
+ log_dbg("Assigned SAP %d for fd %d.", ssap, fd);
#endif
return 0;
}
@@ -1788,10 +1720,10 @@ static int eth_ipcp_flow_dealloc(int fd)
#endif
ipcp_flow_fini(fd);
- pthread_rwlock_wrlock(&eth_data.flows_lock);
-
fset_del(eth_data.np1_flows, fd);
+ pthread_rwlock_wrlock(&eth_data.flows_lock);
+
#if defined(BUILD_ETH_DIX)
eth_data.fd_to_ef[fd].r_eid = -1;
#elif defined BUILD_ETH_LLC
@@ -1805,9 +1737,7 @@ static int eth_ipcp_flow_dealloc(int fd)
pthread_rwlock_unlock(&eth_data.flows_lock);
- flow_dealloc(fd);
-
- log_dbg("Flow with fd %d deallocated.", fd);
+ ipcp_flow_dealloc(fd);
return 0;
}
@@ -1831,9 +1761,6 @@ int main(int argc,
{
int i;
- if (ipcp_init(argc, argv, &eth_ops) < 0)
- goto fail_init;
-
if (eth_data_init() < 0) {
#if defined(BUILD_ETH_DIX)
log_err("Failed to init eth-llc data.");
@@ -1843,18 +1770,17 @@ int main(int argc,
goto fail_data_init;
}
- if (ipcp_boot() < 0) {
- log_err("Failed to boot IPCP.");
- goto fail_boot;
+ if (ipcp_init(argc, argv, &eth_ops, THIS_TYPE) < 0) {
+ log_err("Failed to initialize IPCP.");
+ goto fail_init;
}
- if (ipcp_create_r(0)) {
- log_err("Failed to notify IRMd we are initialized.");
- ipcp_set_state(IPCP_NULL);
- goto fail_create_r;
+ if (ipcp_start() < 0) {
+ log_err("Failed to start IPCP.");
+ goto fail_start;
}
- ipcp_shutdown();
+ ipcp_sigwait();
if (ipcp_get_state() == IPCP_SHUTDOWN) {
for (i = 0; i < IPCP_ETH_WR_THR; ++i)
@@ -1877,19 +1803,18 @@ int main(int argc,
#endif
}
- eth_data_fini();
+ ipcp_stop();
ipcp_fini();
+ eth_data_fini();
+
exit(EXIT_SUCCESS);
- fail_create_r:
- ipcp_shutdown();
- fail_boot:
- eth_data_fini();
- fail_data_init:
+ fail_start:
ipcp_fini();
fail_init:
- ipcp_create_r(-1);
+ eth_data_fini();
+ fail_data_init:
exit(EXIT_FAILURE);
}
diff --git a/src/ipcpd/eth/llc.c b/src/ipcpd/eth/llc.c
index 60abfdbb..c900dcab 100644
--- a/src/ipcpd/eth/llc.c
+++ b/src/ipcpd/eth/llc.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC processes over Ethernet - LLC
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c
index 95d2f783..966c4920 100644
--- a/src/ipcpd/ipcp.c
+++ b/src/ipcpd/ipcp.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC process main loop
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,7 +24,6 @@
#define _DEFAULT_SOURCE
#else
#define _POSIX_C_SOURCE 200112L
-#define __XSI_VISIBLE 500
#endif
#if defined(__linux__) && !defined(DISABLE_CORE_LOCK)
@@ -32,26 +31,25 @@
#define NPROC (sysconf(_SC_NPROCESSORS_ONLN))
#endif
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 200112L
-#define __XSI_VISIBLE 500
-#endif
-
#include "config.h"
-#define OUROBOROS_PREFIX "ipcpd/ipcp"
+#define OUROBOROS_PREFIX "ipcpd/ipcp"
+#define IPCP_INFO "info"
+#define ALLOC_TIMEOUT 50 /* ms */
+#include <ouroboros/bitmap.h>
+#include <ouroboros/dev.h>
+#include <ouroboros/errno.h>
#include <ouroboros/hash.h>
+#include <ouroboros/ipcp-dev.h>
#include <ouroboros/logs.h>
-#include <ouroboros/time_utils.h>
-#include <ouroboros/utils.h>
-#include <ouroboros/sockets.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/dev.h>
-#include <ouroboros/bitmap.h>
#include <ouroboros/np1_flow.h>
+#include <ouroboros/protobuf.h>
+#include <ouroboros/pthread.h>
+#include <ouroboros/rib.h>
+#include <ouroboros/sockets.h>
+#include <ouroboros/time.h>
+#include <ouroboros/utils.h>
#include "ipcp.h"
@@ -59,9 +57,19 @@
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
-#if defined(__linux__) && !defined(DISABLE_CORE_LOCK)
+#if defined(__linux__)
+#include <sys/prctl.h>
+#ifndef DISABLE_CORE_LOCK
#include <unistd.h>
#endif
+#endif
+
+char * info[LAYER_NAME_SIZE + 1] = {
+ "_state",
+ "_type",
+ "_layer",
+ NULL
+};
struct cmd {
struct list_head next;
@@ -97,16 +105,115 @@ void ipcp_hash_str(char * buf,
buf[2 * i] = '\0';
}
-static void close_ptr(void * o)
+static int ipcp_rib_read(const char * path,
+ char * buf,
+ size_t len)
{
- close(*((int *) o));
+ char * entry;
+
+ if (len < LAYER_NAME_SIZE + 2) /* trailing \n */
+ return 0;
+
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
+
+ if (strcmp(entry, info[0]) == 0) { /* _state */
+ enum ipcp_state state = ipcp_get_state();
+ if (state == IPCP_NULL)
+ strcpy(buf, "null\n");
+ else if (state == IPCP_INIT)
+ strcpy(buf, "init\n");
+ else if (state == IPCP_OPERATIONAL)
+ strcpy(buf, "operational\n");
+ else if (state == IPCP_SHUTDOWN)
+ strcpy(buf, "shutdown\n");
+ else
+ strcpy(buf, "bug\n");
+ }
+
+ if (strcmp(entry, info[1]) == 0) { /* _type */
+ if (ipcpi.type == IPCP_LOCAL)
+ strcpy(buf, "local\n");
+ else if (ipcpi.type == IPCP_UNICAST)
+ strcpy(buf, "unicast\n");
+ else if (ipcpi.type == IPCP_BROADCAST)
+ strcpy(buf, "broadcast\n");
+ else if (ipcpi.type == IPCP_ETH_LLC)
+ strcpy(buf, "eth-llc\n");
+ else if (ipcpi.type == IPCP_ETH_DIX)
+ strcpy(buf, "eth-dix\n");
+ else if (ipcpi.type == IPCP_UDP)
+ strcpy(buf, "udp\n");
+ else
+ strcpy(buf, "bug\n");
+ }
+
+ if (strcmp(entry, info[2]) == 0) { /* _layer */
+ memset(buf, 0, LAYER_NAME_SIZE + 1);
+ if (ipcp_get_state() < IPCP_OPERATIONAL)
+ strcpy(buf, "(null)");
+ else
+ strcpy(buf, ipcpi.layer_name);
+
+ buf[strlen(buf)] = '\n';
+ }
+
+ return strlen(buf);
+}
+
+static int ipcp_rib_readdir(char *** buf)
+{
+ int i = 0;
+
+ while (info[i] != NULL)
+ i++;
+
+ *buf = malloc(sizeof(**buf) * i);
+ if (*buf == NULL)
+ goto fail;
+
+ i = 0;
+
+ while (info[i] != NULL) {
+ (*buf)[i] = strdup(info[i]);
+ if ((*buf)[i] == NULL)
+ goto fail_dup;
+ i++;
+ }
+
+ return i;
+ fail_dup:
+ while (i > 0)
+ free((*buf)[--i]);
+ fail:
+ free(*buf);
+
+ return -1;
}
+static int ipcp_rib_getattr(const char * path,
+ struct rib_attr * attr)
+{
+ char buf[LAYER_NAME_SIZE + 2];
+ struct timespec now;
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ attr->size = ipcp_rib_read(path, buf, LAYER_NAME_SIZE + 2);
+ attr->mtime = now.tv_sec;
+
+ return 0;
+}
+
+static struct rib_ops r_ops = {
+ .read = ipcp_rib_read,
+ .readdir = ipcp_rib_readdir,
+ .getattr = ipcp_rib_getattr
+};
+
static void * acceptloop(void * o)
{
- int csockfd;
- struct timeval tv = {(SOCKET_TIMEOUT / 1000),
- (SOCKET_TIMEOUT % 1000) * 1000};
+ int csockfd;
(void) o;
@@ -118,10 +225,6 @@ static void * acceptloop(void * o)
if (csockfd < 0)
continue;
- if (setsockopt(csockfd, SOL_SOCKET, SO_RCVTIMEO,
- (void *) &tv, sizeof(tv)))
- log_warn("Failed to set timeout on socket.");
-
cmd = malloc(sizeof(*cmd));
if (cmd == NULL) {
log_err("Out of memory");
@@ -129,7 +232,7 @@ static void * acceptloop(void * o)
break;
}
- pthread_cleanup_push(close_ptr, &csockfd);
+ pthread_cleanup_push(__cleanup_close_ptr, &csockfd);
pthread_cleanup_push(free, cmd);
cmd->len = read(csockfd, cmd->cbuf, SOCK_BUF_SIZE);
@@ -158,35 +261,401 @@ static void * acceptloop(void * o)
return (void *) 0;
}
+int ipcp_wait_flow_req_arr(const uint8_t * dst,
+ qosspec_t qs,
+ time_t mpl,
+ const buffer_t * data)
+{
+ struct timespec ts = TIMESPEC_INIT_MS(ALLOC_TIMEOUT);
+ struct timespec abstime;
+ int fd;
+ buffer_t hash;
+
+ hash.data = (uint8_t *) dst;
+ hash.len = ipcp_dir_hash_len();
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+
+ pthread_mutex_lock(&ipcpi.alloc_lock);
+
+ while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
+ ts_add(&abstime, &ts, &abstime);
+ pthread_cond_timedwait(&ipcpi.alloc_cond,
+ &ipcpi.alloc_lock,
+ &abstime);
+ }
+
+ if (ipcp_get_state() != IPCP_OPERATIONAL) {
+ pthread_mutex_unlock(&ipcpi.alloc_lock);
+ log_err("Won't allocate over non-operational IPCP.");
+ return -EIPCPSTATE;
+ }
+
+ assert(ipcpi.alloc_id == -1);
+
+ fd = ipcp_flow_req_arr(&hash, qs, mpl, data);
+ if (fd < 0) {
+ pthread_mutex_unlock(&ipcpi.alloc_lock);
+ log_err("Failed to get fd for flow.");
+ return fd;
+ }
+
+ ipcpi.alloc_id = fd;
+ pthread_cond_broadcast(&ipcpi.alloc_cond);
+
+ pthread_mutex_unlock(&ipcpi.alloc_lock);
+
+ return fd;
+
+}
+
+int ipcp_wait_flow_resp(const int fd)
+{
+ struct timespec ts = TIMESPEC_INIT_MS(ALLOC_TIMEOUT);
+ struct timespec abstime;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+
+ pthread_mutex_lock(&ipcpi.alloc_lock);
+
+ while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
+ ts_add(&abstime, &ts, &abstime);
+ pthread_cond_timedwait(&ipcpi.alloc_cond,
+ &ipcpi.alloc_lock,
+ &abstime);
+ }
+
+ if (ipcp_get_state() != IPCP_OPERATIONAL) {
+ pthread_mutex_unlock(&ipcpi.alloc_lock);
+ return -1;
+ }
+
+ assert(ipcpi.alloc_id == fd);
+
+ ipcpi.alloc_id = -1;
+ pthread_cond_broadcast(&ipcpi.alloc_cond);
+
+ pthread_mutex_unlock(&ipcpi.alloc_lock);
+
+ return 0;
+}
+
static void free_msg(void * o)
{
ipcp_msg__free_unpacked((ipcp_msg_t *) o, NULL);
}
+
+static void do_bootstrap(ipcp_config_msg_t * conf_msg,
+ ipcp_msg_t * ret_msg)
+{
+ struct ipcp_config conf;
+
+ log_info("Bootstrapping...");
+
+ if (ipcpi.ops->ipcp_bootstrap == NULL) {
+ log_err("Bootstrap unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ if (ipcp_get_state() != IPCP_INIT) {
+ log_err("IPCP in wrong state.");
+ ret_msg->result = -EIPCPSTATE;
+ goto finish;
+ }
+
+ conf = ipcp_config_msg_to_s(conf_msg);
+ ret_msg->result = ipcpi.ops->ipcp_bootstrap(&conf);
+ if (ret_msg->result == 0) {
+ ret_msg->layer_info = layer_info_s_to_msg(&conf.layer_info);
+ ipcp_set_state(IPCP_OPERATIONAL);
+ }
+ finish:
+ log_info("Finished bootstrapping: %d.", ret_msg->result);
+}
+
+static void do_enroll(const char * dst,
+ ipcp_msg_t * ret_msg)
+{
+ struct layer_info info;
+
+ log_info("Enrolling with %s...", dst);
+
+ if (ipcpi.ops->ipcp_enroll == NULL) {
+ log_err("Enroll unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ if (ipcp_get_state() != IPCP_INIT) {
+ log_err("IPCP in wrong state.");
+ ret_msg->result = -EIPCPSTATE;
+ goto finish;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_enroll(dst, &info);
+ if (ret_msg->result == 0) {
+ ret_msg->layer_info = layer_info_s_to_msg(&info);
+ ipcp_set_state(IPCP_OPERATIONAL);
+ }
+ finish:
+ log_info("Finished enrolling with %s: %d.", dst, ret_msg->result);
+}
+
+static void do_connect(const char * dst,
+ const char * comp,
+ qosspec_t qs,
+ ipcp_msg_t * ret_msg)
+{
+ log_info("Connecting %s to %s...", comp, dst);
+
+ if (ipcpi.ops->ipcp_connect == NULL) {
+ log_err("Connect unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_connect(dst, comp, qs);
+ finish:
+ log_info("Finished connecting: %d.", ret_msg->result);
+}
+
+static void do_disconnect(const char * dst,
+ const char * comp,
+ ipcp_msg_t * ret_msg)
+{
+ log_info("Disconnecting %s from %s...", comp, dst);
+
+ if (ipcpi.ops->ipcp_disconnect == NULL) {
+ log_err("Disconnect unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_disconnect(dst, comp);
+
+ finish:
+ log_info("Finished disconnecting %s from %s: %d.",
+ comp, dst, ret_msg->result);
+}
+
+static void do_reg(const uint8_t * hash,
+ ipcp_msg_t * ret_msg)
+{
+
+ log_info("Registering " HASH_FMT32 "...", HASH_VAL32(hash));
+
+ if (ipcpi.ops->ipcp_reg == NULL) {
+ log_err("Registration unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_reg(hash);
+ finish:
+ log_info("Finished registering " HASH_FMT32 " : %d.",
+ HASH_VAL32(hash), ret_msg->result);
+}
+
+static void do_unreg(const uint8_t * hash,
+ ipcp_msg_t * ret_msg)
+{
+ log_info("Unregistering " HASH_FMT32 "...", HASH_VAL32(hash));
+
+ if (ipcpi.ops->ipcp_unreg == NULL) {
+ log_err("Unregistration unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_unreg(hash);
+ finish:
+ log_info("Finished unregistering " HASH_FMT32 ": %d.",
+ HASH_VAL32(hash), ret_msg->result);
+}
+
+static void do_query(const uint8_t * hash,
+ ipcp_msg_t * ret_msg)
+{
+ /* TODO: Log this operation when IRMd has internal caches. */
+
+ if (ipcpi.ops->ipcp_query == NULL) {
+ log_err("Directory query unsupported.");
+ ret_msg->result = -ENOTSUP;
+ return;
+ }
+
+ if (ipcp_get_state() != IPCP_OPERATIONAL) {
+ log_err("IPCP in wrong state.");
+ ret_msg->result = -EIPCPSTATE;
+ return;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_query(hash);
+}
+
+static void do_flow_alloc(pid_t pid,
+ int flow_id,
+ uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data,
+ ipcp_msg_t * ret_msg)
+{
+ int fd;
+
+ log_info("Allocating flow %d for %d to " HASH_FMT32 ".",
+ flow_id, pid, HASH_VAL32(dst));
+
+ if (ipcpi.ops->ipcp_flow_alloc == NULL) {
+ log_err("Flow allocation unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ if (ipcp_get_state() != IPCP_OPERATIONAL) {
+ log_err("IPCP in wrong state.");
+ ret_msg->result = -EIPCPSTATE;
+ goto finish;
+ }
+
+ fd = np1_flow_alloc(pid, flow_id);
+ if (fd < 0) {
+ log_err("Failed allocating n + 1 fd on flow_id %d: %d",
+ flow_id, fd);
+ ret_msg->result = -EFLOWDOWN;
+ goto finish;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_flow_alloc(fd, dst, qs, data);
+ finish:
+ log_info("Finished allocating flow %d to " HASH_FMT32 ": %d.",
+ flow_id, HASH_VAL32(dst), ret_msg->result);
+}
+
+
+static void do_flow_join(pid_t pid,
+ int flow_id,
+ const uint8_t * dst,
+ qosspec_t qs,
+ ipcp_msg_t * ret_msg)
+{
+ int fd;
+
+ log_info("Joining layer " HASH_FMT32 ".", HASH_VAL32(dst));
+
+ if (ipcpi.ops->ipcp_flow_join == NULL) {
+ log_err("Broadcast unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ if (ipcp_get_state() != IPCP_OPERATIONAL) {
+ log_err("IPCP in wrong state.");
+ ret_msg->result = -EIPCPSTATE;
+ goto finish;
+ }
+
+ fd = np1_flow_alloc(pid, flow_id);
+ if (fd < 0) {
+ log_err("Failed allocating n + 1 fd on flow_id %d.", flow_id);
+ ret_msg->result = -1;
+ goto finish;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_flow_join(fd, dst, qs);
+ finish:
+ log_info("Finished joining layer " HASH_FMT32 ".", HASH_VAL32(dst));
+}
+
+static void do_flow_alloc_resp(int resp,
+ int flow_id,
+ const buffer_t * data,
+ ipcp_msg_t * ret_msg)
+{
+ int fd = -1;
+
+ log_info("Responding %d to alloc on flow_id %d.", resp, flow_id);
+
+ if (ipcpi.ops->ipcp_flow_alloc_resp == NULL) {
+ log_err("Flow_alloc_resp unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ if (ipcp_get_state() != IPCP_OPERATIONAL) {
+ log_err("IPCP in wrong state.");
+ ret_msg->result = -EIPCPSTATE;
+ goto finish;
+ }
+
+ if (resp == 0) {
+ fd = np1_flow_resp(flow_id);
+ if (fd < 0) {
+ log_warn("Flow_id %d is not known.", flow_id);
+ ret_msg->result = -1;
+ goto finish;
+ }
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_flow_alloc_resp(fd, resp, data);
+ finish:
+ log_info("Finished responding to allocation request: %d",
+ ret_msg->result);
+}
+
+static void do_flow_dealloc(int flow_id,
+ int timeo_sec,
+ ipcp_msg_t * ret_msg)
+{
+ int fd;
+
+ log_info("Deallocating flow %d.", flow_id);
+
+ if (ipcpi.ops->ipcp_flow_dealloc == NULL) {
+ log_err("Flow deallocation unsupported.");
+ ret_msg->result = -ENOTSUP;
+ goto finish;
+ }
+
+ if (ipcp_get_state() != IPCP_OPERATIONAL) {
+ log_err("IPCP in wrong state.");
+ ret_msg->result = -EIPCPSTATE;
+ goto finish;
+ }
+
+ fd = np1_flow_dealloc(flow_id, timeo_sec);
+ if (fd < 0) {
+ log_warn("Could not deallocate flow_id %d.", flow_id);
+ ret_msg->result = -1;
+ goto finish;
+ }
+
+ ret_msg->result = ipcpi.ops->ipcp_flow_dealloc(fd);
+ finish:
+ log_info("Finished deallocating flow %d: %d.",
+ flow_id, ret_msg->result);
+}
+
static void * mainloop(void * o)
{
int sfd;
buffer_t buffer;
- struct ipcp_config conf;
- struct layer_info info;
- ipcp_config_msg_t * conf_msg;
ipcp_msg_t * msg;
(void) o;
while (true) {
- ipcp_msg_t ret_msg = IPCP_MSG__INIT;
- layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT;
- int fd = -1;
- struct cmd * cmd;
- qosspec_t qs;
+ ipcp_msg_t ret_msg = IPCP_MSG__INIT;
+ qosspec_t qs;
+ struct cmd * cmd;
+ buffer_t data;
ret_msg.code = IPCP_MSG_CODE__IPCP_REPLY;
pthread_mutex_lock(&ipcpi.cmd_lock);
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &ipcpi.cmd_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &ipcpi.cmd_lock);
while (list_is_empty(&ipcpi.cmds))
pthread_cond_wait(&ipcpi.cmd_cond, &ipcpi.cmd_lock);
@@ -208,328 +677,68 @@ static void * mainloop(void * o)
tpm_dec(ipcpi.tpm);
- pthread_cleanup_push(close_ptr, &sfd);
+ pthread_cleanup_push(__cleanup_close_ptr, &sfd);
pthread_cleanup_push(free_msg, msg);
+ ret_msg.has_result = true;
+
switch (msg->code) {
case IPCP_MSG_CODE__IPCP_BOOTSTRAP:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_bootstrap == NULL) {
- log_err("Bootstrap unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
- if (ipcp_get_state() != IPCP_INIT) {
- log_err("IPCP in wrong state.");
- ret_msg.result = -EIPCPSTATE;
- break;
- }
-
- conf_msg = msg->conf;
- conf.type = conf_msg->ipcp_type;
- strcpy(conf.layer_info.layer_name,
- conf_msg->layer_info->layer_name);
-
- switch(conf_msg->ipcp_type) {
- case IPCP_LOCAL:
- break;
- case IPCP_UNICAST:
- conf.addr_size = conf_msg->addr_size;
- conf.eid_size = conf_msg->eid_size;
- conf.max_ttl = conf_msg->max_ttl;
- conf.addr_auth_type = conf_msg->addr_auth_type;
- conf.routing_type = conf_msg->routing_type;
- break;
- case IPCP_ETH_DIX:
- conf.ethertype = conf_msg->ethertype;
- /* FALLTHRU */
- case IPCP_ETH_LLC:
- conf.dev = conf_msg->dev;
- break;
- case IPCP_UDP:
- conf.ip_addr = conf_msg->ip_addr;
- conf.dns_addr = conf_msg->dns_addr;
- conf.clt_port = conf_msg->clt_port;
- conf.srv_port = conf_msg->srv_port;
- conf.layer_info.dir_hash_algo = HASH_MD5;
- layer_info.dir_hash_algo = HASH_MD5;
- break;
- case IPCP_BROADCAST:
- conf.layer_info.dir_hash_algo = HASH_SHA3_256;
- layer_info.dir_hash_algo = HASH_SHA3_256;
- break;
- default:
- log_err("Unknown IPCP type: %d.", conf_msg->ipcp_type);
- }
-
- /* UDP and broadcast use fixed hash algorithm. */
- if (conf_msg->ipcp_type != IPCP_UDP &&
- conf_msg->ipcp_type != IPCP_BROADCAST) {
- switch(conf_msg->layer_info->dir_hash_algo) {
- case DIR_HASH_SHA3_224:
- conf.layer_info.dir_hash_algo =
- HASH_SHA3_224;
- break;
- case DIR_HASH_SHA3_256:
- conf.layer_info.dir_hash_algo =
- HASH_SHA3_256;
- break;
- case DIR_HASH_SHA3_384:
- conf.layer_info.dir_hash_algo =
- HASH_SHA3_384;
- break;
- case DIR_HASH_SHA3_512:
- conf.layer_info.dir_hash_algo =
- HASH_SHA3_512;
- break;
- default:
- assert(false);
- }
-
- layer_info.dir_hash_algo =
- conf.layer_info.dir_hash_algo;
- }
-
- ipcpi.dir_hash_algo = conf.layer_info.dir_hash_algo;
-
- ret_msg.result = ipcpi.ops->ipcp_bootstrap(&conf);
- if (ret_msg.result == 0) {
- ret_msg.layer_info = &layer_info;
- layer_info.layer_name =
- conf.layer_info.layer_name;
- }
+ do_bootstrap(msg->conf, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_ENROLL:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_enroll == NULL) {
- log_err("Enroll unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
- if (ipcp_get_state() != IPCP_INIT) {
- log_err("IPCP in wrong state.");
- ret_msg.result = -EIPCPSTATE;
- break;
- }
-
- ret_msg.result = ipcpi.ops->ipcp_enroll(msg->dst,
- &info);
- if (ret_msg.result == 0) {
- ret_msg.layer_info = &layer_info;
- layer_info.dir_hash_algo = info.dir_hash_algo;
- layer_info.layer_name = info.layer_name;
- }
+ do_enroll(msg->dst, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_CONNECT:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_connect == NULL) {
- log_err("Connect unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
- qs = msg_to_spec(msg->qosspec);
- ret_msg.result = ipcpi.ops->ipcp_connect(msg->dst,
- msg->comp,
- qs);
+ qs = qos_spec_msg_to_s(msg->qosspec);
+ do_connect(msg->dst, msg->comp, qs, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_DISCONNECT:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_disconnect == NULL) {
- log_err("Disconnect unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
- ret_msg.result = ipcpi.ops->ipcp_disconnect(msg->dst,
- msg->comp);
+ do_disconnect(msg->dst, msg->comp, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_REG:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_reg == NULL) {
- log_err("Registration unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
assert(msg->hash.len == ipcp_dir_hash_len());
-
- ret_msg.result =
- ipcpi.ops->ipcp_reg(msg->hash.data);
+ do_reg(msg->hash.data, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_UNREG:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_unreg == NULL) {
- log_err("Unregistration unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
assert(msg->hash.len == ipcp_dir_hash_len());
-
- ret_msg.result =
- ipcpi.ops->ipcp_unreg(msg->hash.data);
+ do_unreg(msg->hash.data, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_QUERY:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_query == NULL) {
- log_err("Directory query unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
assert(msg->hash.len == ipcp_dir_hash_len());
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
- ret_msg.result = -EIPCPSTATE;
- break;
- }
-
- ret_msg.result =
- ipcpi.ops->ipcp_query(msg->hash.data);
+ do_query(msg->hash.data, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_FLOW_ALLOC:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_flow_alloc == NULL) {
- log_err("Flow allocation unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
assert(msg->hash.len == ipcp_dir_hash_len());
assert(msg->pk.len > 0 ? msg->pk.data != NULL
: msg->pk.data == NULL);
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
- ret_msg.result = -EIPCPSTATE;
- break;
- }
-
- qs = msg_to_spec(msg->qosspec);
- fd = np1_flow_alloc(msg->pid,
- msg->flow_id,
- qs);
- if (fd < 0) {
- log_err("Failed allocating fd on flow_id %d.",
- msg->flow_id);
- ret_msg.result = -1;
- break;
- }
-
- ret_msg.result =
- ipcpi.ops->ipcp_flow_alloc(fd,
- msg->hash.data,
- qs,
- msg->pk.data,
- msg->pk.len);
+ data.len = msg->pk.len;
+ data.data = msg->pk.data;
+ qs = qos_spec_msg_to_s(msg->qosspec);
+ do_flow_alloc(msg->pid, msg->flow_id,
+ msg->hash.data, qs,
+ &data, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_FLOW_JOIN:
- ret_msg.has_result = true;
-
- if (ipcpi.ops->ipcp_flow_join == NULL) {
- log_err("Broadcast unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
assert(msg->hash.len == ipcp_dir_hash_len());
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
- ret_msg.result = -EIPCPSTATE;
- break;
- }
-
- qs = msg_to_spec(msg->qosspec);
- fd = np1_flow_alloc(msg->pid,
- msg->flow_id,
- qs);
- if (fd < 0) {
- log_err("Failed allocating fd on flow_id %d.",
- msg->flow_id);
- ret_msg.result = -1;
- break;
- }
-
- ret_msg.result =
- ipcpi.ops->ipcp_flow_join(fd,
- msg->hash.data,
- qs);
+ qs = qos_spec_msg_to_s(msg->qosspec);
+ do_flow_join(msg->pid, msg->flow_id,
+ msg->hash.data, qs, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP:
- ret_msg.has_result = true;
- if (ipcpi.ops->ipcp_flow_alloc_resp == NULL) {
- log_err("Flow_alloc_resp unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
- ret_msg.result = -EIPCPSTATE;
- break;
- }
-
- if (!msg->response) {
- fd = np1_flow_resp(msg->flow_id);
- if (fd < 0) {
- log_warn("Port_id %d is not known.",
- msg->flow_id);
- ret_msg.result = -1;
- break;
- }
- }
-
assert(msg->pk.len > 0 ? msg->pk.data != NULL
- : msg->pk.data == NULL);
-
- ret_msg.result =
- ipcpi.ops->ipcp_flow_alloc_resp(fd,
- msg->response,
- msg->pk.data,
- msg->pk.len);
+ : msg->pk.data == NULL);
+ data.len = msg->pk.len;
+ data.data = msg->pk.data;
+ do_flow_alloc_resp(msg->response, msg->flow_id,
+ &data, &ret_msg);
break;
case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
- ret_msg.has_result = true;
- if (ipcpi.ops->ipcp_flow_dealloc == NULL) {
- log_err("Flow deallocation unsupported.");
- ret_msg.result = -ENOTSUP;
- break;
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
- ret_msg.result = -EIPCPSTATE;
- break;
- }
-
- fd = np1_flow_dealloc(msg->flow_id);
- if (fd < 0) {
- log_warn("Could not deallocate flow_id %d.",
- msg->flow_id);
- ret_msg.result = -1;
- break;
- }
-
- ret_msg.result =
- ipcpi.ops->ipcp_flow_dealloc(fd);
+ do_flow_dealloc(msg->flow_id, msg->timeo_sec, &ret_msg);
break;
default:
- ret_msg.has_result = true;
- ret_msg.result = -1;
- log_err("Don't know that message code");
+ ret_msg.result = -1;
+ log_err("Unknown message code: %d.", msg->code);
break;
}
@@ -554,12 +763,16 @@ static void * mainloop(void * o)
ipcp_msg__pack(&ret_msg, buffer.data);
- pthread_cleanup_push(close_ptr, &sfd);
+ if (ret_msg.layer_info != NULL)
+ layer_info_msg__free_unpacked(ret_msg.layer_info, NULL);
+
+ pthread_cleanup_push(__cleanup_close_ptr, &sfd);
+ pthread_cleanup_push(free, buffer.data)
if (write(sfd, buffer.data, buffer.len) == -1)
log_warn("Failed to send reply message");
- free(buffer.data);
+ pthread_cleanup_pop(true);
pthread_cleanup_pop(true);
tpm_inc(ipcpi.tpm);
@@ -595,7 +808,8 @@ static int parse_args(int argc,
int ipcp_init(int argc,
char ** argv,
- struct ipcp_ops * ops)
+ struct ipcp_ops * ops,
+ enum ipcp_type type)
{
bool log;
pthread_condattr_t cattr;
@@ -608,7 +822,11 @@ int ipcp_init(int argc,
ipcpi.irmd_fd = -1;
ipcpi.state = IPCP_NULL;
+ ipcpi.type = type;
+#if defined (__linux__)
+ prctl(PR_SET_TIMERSLACK, IPCP_LINUX_SLACK_NS, 0, 0, 0);
+#endif
ipcpi.sock_path = ipcp_sock_path(getpid());
if (ipcpi.sock_path == NULL)
goto fail_sock_path;
@@ -659,14 +877,39 @@ int ipcp_init(int argc,
goto fail_cmd_cond;
}
+ if (rib_init(ipcpi.name)) {
+ log_err("Failed to initialize RIB.");
+ goto fail_rib_init;
+ }
+
+ if (rib_reg(IPCP_INFO, &r_ops)) {
+ log_err("Failed to register rib.");
+ goto fail_rib_reg;
+ }
+
+ ipcpi.tpm = tpm_create(IPCP_MIN_THREADS, IPCP_ADD_THREADS,
+ mainloop, NULL);
+ if (ipcpi.tpm == NULL) {
+ log_err("Failed to create threadpool manager.");
+ goto fail_tpm_create;
+ }
+
list_head_init(&ipcpi.cmds);
ipcpi.alloc_id = -1;
pthread_condattr_destroy(&cattr);
+ ipcp_set_state(IPCP_INIT);
+
return 0;
+ fail_tpm_create:
+ rib_unreg(IPCP_INFO);
+ fail_rib_reg:
+ rib_fini();
+ fail_rib_init:
+ pthread_cond_destroy(&ipcpi.cmd_cond);
fail_cmd_cond:
pthread_mutex_destroy(&ipcpi.cmd_lock);
fail_cmd_lock:
@@ -687,48 +930,62 @@ int ipcp_init(int argc,
return ret;
}
-int ipcp_boot()
+int ipcp_start(void)
{
- sigset_t sigset;
+ sigset_t sigset;
+ struct ipcp_info info;
+
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGQUIT);
sigaddset(&sigset, SIGHUP);
sigaddset(&sigset, SIGPIPE);
- ipcpi.tpm = tpm_create(IPCP_MIN_THREADS, IPCP_ADD_THREADS,
- mainloop, NULL);
- if (ipcpi.tpm == NULL)
- goto fail_tpm_create;
-
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+ info.pid = getpid();
+ info.type = ipcpi.type;
+ strcpy(info.name, ipcpi.name);
+ info.state = IPCP_OPERATIONAL;
+
if (tpm_start(ipcpi.tpm))
goto fail_tpm_start;
- ipcp_set_state(IPCP_INIT);
-
if (pthread_create(&ipcpi.acceptor, NULL, acceptloop, NULL)) {
log_err("Failed to create acceptor thread.");
- ipcp_set_state(IPCP_NULL);
goto fail_acceptor;
}
+ info.state = IPCP_OPERATIONAL;
+
+ if (ipcp_create_r(&info)) {
+ log_err("Failed to notify IRMd we are initialized.");
+ goto fail_create_r;
+ }
+
return 0;
+ fail_create_r:
+ pthread_cancel(ipcpi.acceptor);
+ pthread_join(ipcpi.acceptor, NULL);
fail_acceptor:
tpm_stop(ipcpi.tpm);
fail_tpm_start:
tpm_destroy(ipcpi.tpm);
- fail_tpm_create:
+ ipcp_set_state(IPCP_NULL);
+ info.state = IPCP_NULL;
+ ipcp_create_r(&info);
return -1;
}
-void ipcp_shutdown()
+void ipcp_sigwait(void)
{
+
siginfo_t info;
sigset_t sigset;
-
+#ifdef __APPLE__
+ int sig;
+#endif
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGQUIT);
@@ -738,15 +995,27 @@ void ipcp_shutdown()
while(ipcp_get_state() != IPCP_NULL &&
ipcp_get_state() != IPCP_SHUTDOWN) {
+#ifdef __APPLE__
+ if (sigwait(&sigset, &sig) < 0) {
+#else
if (sigwaitinfo(&sigset, &info) < 0) {
+#endif
log_warn("Bad signal.");
continue;
}
+#ifdef __APPLE__
+ memset(&info, 0, sizeof(info));
+ info.si_signo = sig;
+ info.si_pid = ipcpi.irmd_pid;
+#endif
switch(info.si_signo) {
case SIGINT:
+ /* FALLTHRU */
case SIGTERM:
+ /* FALLTHRU */
case SIGHUP:
+ /* FALLTHRU */
case SIGQUIT:
if (info.si_pid == ipcpi.irmd_pid) {
if (ipcp_get_state() == IPCP_INIT)
@@ -758,22 +1027,32 @@ void ipcp_shutdown()
break;
case SIGPIPE:
log_dbg("Ignored SIGPIPE.");
+ continue;
default:
continue;
}
}
+}
- pthread_cancel(ipcpi.acceptor);
+void ipcp_stop(void)
+{
+ log_info("IPCP %d shutting down.", getpid());
+ pthread_cancel(ipcpi.acceptor);
pthread_join(ipcpi.acceptor, NULL);
- tpm_stop(ipcpi.tpm);
- tpm_destroy(ipcpi.tpm);
- log_info("IPCP %d shutting down.", getpid());
+ tpm_stop(ipcpi.tpm);
}
-void ipcp_fini()
+void ipcp_fini(void)
{
+
+ tpm_destroy(ipcpi.tpm);
+
+ rib_unreg(IPCP_INFO);
+
+ rib_fini();
+
close(ipcpi.sockfd);
if (unlink(ipcpi.sock_path))
log_warn("Could not unlink %s.", ipcpi.sock_path);
@@ -802,7 +1081,7 @@ void ipcp_set_state(enum ipcp_state state)
pthread_mutex_unlock(&ipcpi.state_mtx);
}
-enum ipcp_state ipcp_get_state()
+enum ipcp_state ipcp_get_state(void)
{
enum ipcp_state state;
@@ -815,38 +1094,6 @@ enum ipcp_state ipcp_get_state()
return state;
}
-int ipcp_wait_state(enum ipcp_state state,
- const struct timespec * timeout)
-{
- struct timespec abstime;
- int ret = 0;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- ts_add(&abstime, timeout, &abstime);
-
- pthread_mutex_lock(&ipcpi.state_mtx);
-
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &ipcpi.state_mtx);
-
- while (ipcpi.state != state
- && ipcpi.state != IPCP_SHUTDOWN
- && ipcpi.state != IPCP_NULL
- && ret != -ETIMEDOUT) {
- if (timeout == NULL)
- ret = -pthread_cond_wait(&ipcpi.state_cond,
- &ipcpi.state_mtx);
- else
- ret = -pthread_cond_timedwait(&ipcpi.state_cond,
- &ipcpi.state_mtx,
- &abstime);
- }
-
- pthread_cleanup_pop(true);
-
- return ret;
-}
-
void ipcp_lock_to_core(void)
{
#if defined(__linux__) && !defined(DISABLE_CORE_LOCK)
diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h
index 02c74f50..aab490c7 100644
--- a/src/ipcpd/ipcp.h
+++ b/src/ipcpd/ipcp.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC process structure
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,19 +26,14 @@
#include <ouroboros/hash.h>
#include <ouroboros/ipcp.h>
#include <ouroboros/list.h>
+#include <ouroboros/protobuf.h>
+#include <ouroboros/qos.h>
#include <ouroboros/sockets.h>
#include <ouroboros/tpm.h>
#include <pthread.h>
#include <time.h>
-enum ipcp_state {
- IPCP_NULL = 0,
- IPCP_INIT,
- IPCP_OPERATIONAL,
- IPCP_SHUTDOWN
-};
-
struct ipcp_ops {
int (* ipcp_bootstrap)(const struct ipcp_config * conf);
@@ -58,20 +53,18 @@ struct ipcp_ops {
int (* ipcp_query)(const uint8_t * hash);
- int (* ipcp_flow_alloc)(int fd,
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t len);
+ int (* ipcp_flow_alloc)(int fd,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data);
int (* ipcp_flow_join)(int fd,
const uint8_t * dst,
qosspec_t qs);
- int (* ipcp_flow_alloc_resp)(int fd,
- int response,
- const void * data,
- size_t len);
+ int (* ipcp_flow_alloc_resp)(int fd,
+ int response,
+ const buffer_t * data);
int (* ipcp_flow_dealloc)(int fd);
};
@@ -79,12 +72,12 @@ struct ipcp_ops {
#define ipcp_dir_hash_strlen() (hash_len(ipcpi.dir_hash_algo) * 2)
#define ipcp_dir_hash_len() (hash_len(ipcpi.dir_hash_algo))
-struct ipcp {
+extern struct ipcp {
pid_t irmd_pid;
char * name;
enum ipcp_type type;
- char * layer_name;
+ char layer_name[LAYER_NAME_SIZE + 1];
uint64_t dt_addr;
@@ -94,9 +87,8 @@ struct ipcp {
int irmd_fd;
enum ipcp_state state;
- pthread_rwlock_t state_lock;
- pthread_mutex_t state_mtx;
pthread_cond_t state_cond;
+ pthread_mutex_t state_mtx;
int sockfd;
char * sock_path;
@@ -116,11 +108,14 @@ struct ipcp {
int ipcp_init(int argc,
char ** argv,
- struct ipcp_ops * ops);
+ struct ipcp_ops * ops,
+ enum ipcp_type type);
-int ipcp_boot(void);
+int ipcp_start(void);
-void ipcp_shutdown(void);
+void ipcp_sigwait(void);
+
+void ipcp_stop(void);
void ipcp_fini(void);
@@ -128,12 +123,17 @@ void ipcp_set_state(enum ipcp_state state);
enum ipcp_state ipcp_get_state(void);
-int ipcp_wait_state(enum ipcp_state state,
- const struct timespec * timeout);
-
int ipcp_parse_arg(int argc,
char * argv[]);
+/* Helper functions to handle races during flow allocation */
+int ipcp_wait_flow_req_arr(const uint8_t * dst,
+ qosspec_t qs,
+ time_t mpl,
+ const buffer_t * data);
+
+int ipcp_wait_flow_resp(const int fd);
+
/* Helper functions for directory entries, could be moved */
uint8_t * ipcp_hash_dup(const uint8_t * hash);
diff --git a/src/ipcpd/local/CMakeLists.txt b/src/ipcpd/local/CMakeLists.txt
index a84f4f1b..10fd0120 100644
--- a/src/ipcpd/local/CMakeLists.txt
+++ b/src/ipcpd/local/CMakeLists.txt
@@ -13,6 +13,8 @@ include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
set(IPCP_LOCAL_TARGET ipcpd-local CACHE INTERNAL "")
+set(IPCP_LOCAL_MPL 2 CACHE STRING
+ "Default maximum packet lifetime for the Ethernet IPCPs, in seconds")
set(LOCAL_SOURCES
# Add source files here
diff --git a/src/ipcpd/local/main.c b/src/ipcpd/local/main.c
index a2e20017..160e07e0 100644
--- a/src/ipcpd/local/main.c
+++ b/src/ipcpd/local/main.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Local IPC process
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -48,8 +48,9 @@
#include <sys/wait.h>
#include <assert.h>
-#define THIS_TYPE IPCP_LOCAL
-#define ALLOC_TIMEOUT 10 /* ms */
+#define THIS_TYPE IPCP_LOCAL
+
+struct ipcp ipcpi;
struct {
struct shim_data * shim_data;
@@ -70,34 +71,39 @@ static int local_data_init(void)
local_data.flows = fset_create();
if (local_data.flows == NULL)
- return -ENFILE;
+ goto fail_fset;
local_data.fq = fqueue_create();
- if (local_data.fq == NULL) {
- fset_destroy(local_data.flows);
- return -ENOMEM;
- }
+ if (local_data.fq == NULL)
+ goto fail_fqueue;
local_data.shim_data = shim_data_create();
- if (local_data.shim_data == NULL) {
- fqueue_destroy(local_data.fq);
- fset_destroy(local_data.flows);
- return -ENOMEM;
- }
+ if (local_data.shim_data == NULL)
+ goto fail_shim_data;
- pthread_rwlock_init(&local_data.lock, NULL);
+ if (pthread_rwlock_init(&local_data.lock, NULL) < 0)
+ goto fail_rwlock_init;
return 0;
+
+ fail_rwlock_init:
+ shim_data_destroy(local_data.shim_data);
+ fail_shim_data:
+ fqueue_destroy(local_data.fq);
+ fail_fqueue:
+ fset_destroy(local_data.flows);
+ fail_fset:
+ return -ENOMEM;
}
static void local_data_fini(void){
+ pthread_rwlock_destroy(&local_data.lock);
shim_data_destroy(local_data.shim_data);
- fset_destroy(local_data.flows);
fqueue_destroy(local_data.fq);
- pthread_rwlock_destroy(&local_data.lock);
+ fset_destroy(local_data.flows);
}
-static void * ipcp_local_packet_loop(void * o)
+static void * local_ipcp_packet_loop(void * o)
{
(void) o;
@@ -133,49 +139,45 @@ static void * ipcp_local_packet_loop(void * o)
return (void *) 0;
}
-static int ipcp_local_bootstrap(const struct ipcp_config * conf)
+static int local_ipcp_bootstrap(const struct ipcp_config * conf)
{
assert(conf);
assert(conf->type == THIS_TYPE);
- (void) conf;
-
- ipcp_set_state(IPCP_OPERATIONAL);
+ ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo;
+ strcpy(ipcpi.layer_name,conf->layer_info.name);
if (pthread_create(&local_data.packet_loop, NULL,
- ipcp_local_packet_loop, NULL)) {
+ local_ipcp_packet_loop, NULL)) {
+ log_err("Failed to create pthread: %s", strerror(errno));
ipcp_set_state(IPCP_INIT);
return -1;
}
- log_info("Bootstrapped local IPCP with pid %d.", getpid());
-
return 0;
}
-static int ipcp_local_reg(const uint8_t * hash)
+static int local_ipcp_reg(const uint8_t * hash)
{
if (shim_data_reg_add_entry(local_data.shim_data, hash)) {
- log_dbg("Failed to add " HASH_FMT " to local registry.",
- HASH_VAL(hash));
+ log_err("Failed to add " HASH_FMT32 " to local registry.",
+ HASH_VAL32(hash));
return -1;
}
- log_info("Registered " HASH_FMT ".", HASH_VAL(hash));
-
return 0;
}
-static int ipcp_local_unreg(const uint8_t * hash)
+static int local_ipcp_unreg(const uint8_t * hash)
{
shim_data_reg_del_entry(local_data.shim_data, hash);
- log_info("Unregistered " HASH_FMT ".", HASH_VAL(hash));
+ log_info("Unregistered " HASH_FMT32 ".", HASH_VAL32(hash));
return 0;
}
-static int ipcp_local_query(const uint8_t * hash)
+static int local_ipcp_query(const uint8_t * hash)
{
int ret;
@@ -184,41 +186,19 @@ static int ipcp_local_query(const uint8_t * hash)
return ret;
}
-static int ipcp_local_flow_alloc(int fd,
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t len)
+static int local_ipcp_flow_alloc(int fd,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
- struct timespec ts = {0, ALLOC_TIMEOUT * MILLION};
- struct timespec abstime;
- int out_fd = -1;
+ int out_fd = -1;
- log_dbg("Allocating flow to " HASH_FMT " on fd %d.", HASH_VAL(dst), fd);
+ log_dbg("Allocating flow to " HASH_FMT32 " on fd %d.",
+ HASH_VAL32(dst), fd);
assert(dst);
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_dbg("Won't allocate over non-operational IPCP.");
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- return -1;
- }
-
- assert(ipcpi.alloc_id == -1);
-
- out_fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len);
+ out_fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_LOCAL_MPL, data);
if (out_fd < 0) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
log_dbg("Flow allocation failed: %d", out_fd);
return -1;
}
@@ -230,11 +210,6 @@ static int ipcp_local_flow_alloc(int fd,
pthread_rwlock_unlock(&local_data.lock);
- ipcpi.alloc_id = out_fd;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
fset_add(local_data.flows, fd);
log_info("Pending local allocation request on fd %d.", fd);
@@ -242,40 +217,21 @@ static int ipcp_local_flow_alloc(int fd,
return 0;
}
-static int ipcp_local_flow_alloc_resp(int fd,
- int response,
- const void * data,
- size_t len)
+static int local_ipcp_flow_alloc_resp(int fd,
+ int response,
+ const buffer_t * data)
{
- struct timespec ts = {0, ALLOC_TIMEOUT * MILLION};
- struct timespec abstime;
- int out_fd = -1;
- int ret = -1;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
+ struct timespec wait = TIMESPEC_INIT_MS(1);
+ time_t mpl = IPCP_LOCAL_MPL;
+ int out_fd;
- while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ if (ipcp_wait_flow_resp(fd) < 0) {
+ log_err("Failed waiting for IRMd response.");
return -1;
}
- ipcpi.alloc_id = -1;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
- pthread_rwlock_wrlock(&local_data.lock);
-
- if (response) {
+ if (response < 0) {
+ pthread_rwlock_wrlock(&local_data.lock);
if (local_data.in_out[fd] != -1)
local_data.in_out[local_data.in_out[fd]] = fd;
local_data.in_out[fd] = -1;
@@ -283,25 +239,38 @@ static int ipcp_local_flow_alloc_resp(int fd,
return 0;
}
+ pthread_rwlock_rdlock(&local_data.lock);
+
out_fd = local_data.in_out[fd];
if (out_fd == -1) {
pthread_rwlock_unlock(&local_data.lock);
- return -1;
+ log_dbg("Potential race detected");
+ nanosleep(&wait, NULL);
+ pthread_rwlock_rdlock(&local_data.lock);
+ out_fd = local_data.in_out[fd];
}
pthread_rwlock_unlock(&local_data.lock);
+ if (out_fd == -1) {
+ log_err("Invalid out_fd.");
+ return -1;
+ }
+
fset_add(local_data.flows, fd);
- if ((ret = ipcp_flow_alloc_reply(out_fd, response, data, len)) < 0)
+ if (ipcp_flow_alloc_reply(out_fd, response, mpl, data) < 0) {
+ log_err("Failed to reply to allocation");
+ fset_del(local_data.flows, fd);
return -1;
+ }
log_info("Flow allocation completed, fds (%d, %d).", out_fd, fd);
return 0;
}
-static int ipcp_local_flow_dealloc(int fd)
+static int local_ipcp_flow_dealloc(int fd)
{
assert(!(fd < 0));
@@ -315,7 +284,7 @@ static int ipcp_local_flow_dealloc(int fd)
pthread_rwlock_unlock(&local_data.lock);
- flow_dealloc(fd);
+ ipcp_flow_dealloc(fd);
log_info("Flow with fd %d deallocated.", fd);
@@ -323,60 +292,54 @@ static int ipcp_local_flow_dealloc(int fd)
}
static struct ipcp_ops local_ops = {
- .ipcp_bootstrap = ipcp_local_bootstrap,
+ .ipcp_bootstrap = local_ipcp_bootstrap,
.ipcp_enroll = NULL,
.ipcp_connect = NULL,
.ipcp_disconnect = NULL,
- .ipcp_reg = ipcp_local_reg,
- .ipcp_unreg = ipcp_local_unreg,
- .ipcp_query = ipcp_local_query,
- .ipcp_flow_alloc = ipcp_local_flow_alloc,
+ .ipcp_reg = local_ipcp_reg,
+ .ipcp_unreg = local_ipcp_unreg,
+ .ipcp_query = local_ipcp_query,
+ .ipcp_flow_alloc = local_ipcp_flow_alloc,
.ipcp_flow_join = NULL,
- .ipcp_flow_alloc_resp = ipcp_local_flow_alloc_resp,
- .ipcp_flow_dealloc = ipcp_local_flow_dealloc
+ .ipcp_flow_alloc_resp = local_ipcp_flow_alloc_resp,
+ .ipcp_flow_dealloc = local_ipcp_flow_dealloc
};
int main(int argc,
char * argv[])
{
- if (ipcp_init(argc, argv, &local_ops) < 0)
- goto fail_init;
-
if (local_data_init() < 0) {
log_err("Failed to init local data.");
goto fail_data_init;
}
- if (ipcp_boot() < 0) {
- log_err("Failed to boot IPCP.");
- goto fail_boot;
- }
+ if (ipcp_init(argc, argv, &local_ops, THIS_TYPE) < 0)
+ goto fail_init;
- if (ipcp_create_r(0)) {
- log_err("Failed to notify IRMd we are initialized.");
- goto fail_create_r;
+ if (ipcp_start() < 0) {
+ log_err("Failed to start IPCP.");
+ goto fail_start;
}
- ipcp_shutdown();
+ ipcp_sigwait();
if (ipcp_get_state() == IPCP_SHUTDOWN) {
pthread_cancel(local_data.packet_loop);
pthread_join(local_data.packet_loop, NULL);
}
- local_data_fini();
+ ipcp_stop();
ipcp_fini();
- exit(EXIT_SUCCESS);
- fail_create_r:
- ipcp_set_state(IPCP_NULL);
- ipcp_shutdown();
- fail_boot:
local_data_fini();
- fail_data_init:
+
+ exit(EXIT_SUCCESS);
+
+ fail_start:
ipcp_fini();
fail_init:
- ipcp_create_r(-1);
+ local_data_fini();
+ fail_data_init:
exit(EXIT_FAILURE);
}
diff --git a/src/ipcpd/raptor/CMakeLists.txt b/src/ipcpd/raptor/CMakeLists.txt
deleted file mode 100644
index 1883d9bb..00000000
--- a/src/ipcpd/raptor/CMakeLists.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-get_filename_component(CURRENT_SOURCE_PARENT_DIR
- ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
-get_filename_component(CURRENT_BINARY_PARENT_DIR
- ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY)
-
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
-include_directories(${CURRENT_SOURCE_PARENT_DIR})
-include_directories(${CURRENT_BINARY_PARENT_DIR})
-
-include_directories(${CMAKE_SOURCE_DIR}/include)
-include_directories(${CMAKE_BINARY_DIR}/include)
-
-if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
- find_path(RAPTOR_KERNEL_MODULE
- NAMES
- raptor.ko.gz
- raptor.ko.xz
- HINTS
- /lib/modules/${CMAKE_SYSTEM_VERSION}/extra
- )
-
- mark_as_advanced(RAPTOR_KERNEL_MODULE)
-
- if (RAPTOR_KERNEL_MODULE)
- set(DISABLE_RAPTOR FALSE CACHE BOOL
- "Disable support for raptor devices")
- if (NOT DISABLE_RAPTOR)
- message(STATUS "Kernel module for raptor found. Building raptor.")
- set(IPCP_RAPTOR_TARGET ipcpd-raptor CACHE INTERNAL "")
-
- set(RAPTOR_SOURCES
- # Add source files here
- ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
-
- add_executable(ipcpd-raptor ${RAPTOR_SOURCES} ${IPCP_SOURCES})
- target_link_libraries(ipcpd-raptor LINK_PUBLIC ouroboros-dev)
-
- include(AddCompileFlags)
- if (CMAKE_BUILD_TYPE MATCHES "Debug*")
- add_compile_flags(ipcpd-raptor -DCONFIG_OUROBOROS_DEBUG)
- endif ()
-
- install(TARGETS ipcpd-raptor RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
- else ()
- message(STATUS "Raptor support disabled by user")
- endif ()
- endif ()
-endif ()
diff --git a/src/ipcpd/raptor/main.c b/src/ipcpd/raptor/main.c
deleted file mode 100644
index 5cd7d50e..00000000
--- a/src/ipcpd/raptor/main.c
+++ /dev/null
@@ -1,1114 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * IPC process using the Raptor FPGA.
- *
- * Alexander D'hoore <dhoore.alexander@gmail.com>
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define _DEFAULT_SOURCE
-
-#include "config.h"
-
-#define OUROBOROS_PREFIX "ipcpd/raptor"
-
-#include <ouroboros/hash.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/list.h>
-#include <ouroboros/utils.h>
-#include <ouroboros/bitmap.h>
-#include <ouroboros/dev.h>
-#include <ouroboros/local-dev.h>
-#include <ouroboros/ipcp-dev.h>
-#include <ouroboros/fqueue.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/time_utils.h>
-
-#include "ipcp.h"
-#include "shim-data.h"
-
-#include <net/if.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <malloc.h>
-
-#ifdef __linux__
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>
-#endif
-
-#include <poll.h>
-#include <sys/mman.h>
-
-#define THIS_TYPE IPCP_RAPTOR
-#define MGMT_EID 0x01
-#define MAC_SIZE 6
-#define MAX_EIDS 64
-
-#define EVENT_WAIT_TIMEOUT 100 /* us */
-#define NAME_QUERY_TIMEOUT 2000 /* ms */
-#define MGMT_TIMEOUT 100 /* ms */
-
-#define IOCTL_SEND 0xAD420000
-#define IOCTL_RECV 0xAD430000
-#define IOCTL_SEND_DONE 0xAD440000
-#define IOCTL_RECV_DONE 0xAD450000
-#define IOCTL_RECV_NEED 0xAD460000
-
-#define RAPTOR_PAGE ((1 << 12) - 200) /* 4kB - 200 */
-#define RAPTOR_PAGE_MASK (~0xFFF)
-
-#define RAPTOR_BATCH 100
-#define RAPTOR_HEADER 3
-
-#define FLOW_REQ 0
-#define FLOW_REPLY 1
-#define NAME_QUERY_REQ 2
-#define NAME_QUERY_REPLY 3
-
-struct mgmt_msg {
- uint8_t code;
- uint8_t seid;
- uint8_t deid;
- int8_t response;
- /* QoS parameters from spec, aligned */
- uint32_t loss;
- uint64_t bandwidth;
- uint32_t ber;
- uint32_t max_gap;
- uint32_t delay;
- uint8_t in_order;
- uint8_t availability;
-} __attribute__((packed));
-
-struct ef {
- int8_t eid;
- int8_t r_eid;
-};
-
-struct mgmt_frame {
- struct list_head next;
- uint8_t buf[RAPTOR_PAGE];
- size_t len;
-};
-
-struct {
- struct shim_data * shim_data;
-
- int ioctl_fd;
-
- struct bmp * eids;
- fset_t * np1_flows;
- fqueue_t * fq;
- int * ef_to_fd;
- struct ef * fd_to_ef;
- pthread_rwlock_t flows_lock;
-
- pthread_t send_thread;
- pthread_t recv_thread;
- pthread_t send_done_thread;
- pthread_t recv_done_thread;
-
- /* Handle mgmt frames in a different thread */
- pthread_t mgmt_handler;
- pthread_mutex_t mgmt_lock;
- pthread_cond_t mgmt_cond;
- struct list_head mgmt_frames;
-
-} raptor_data;
-
-static int raptor_data_init(void)
-{
- int i;
- int ret = -ENOMEM;
- pthread_condattr_t cattr;
-
- raptor_data.fd_to_ef =
- malloc(sizeof(*raptor_data.fd_to_ef) * SYS_MAX_FLOWS);
- if (raptor_data.fd_to_ef == NULL)
- goto fail_fd_to_ef;
-
- raptor_data.ef_to_fd =
- malloc(sizeof(*raptor_data.ef_to_fd) * MAX_EIDS);
- if (raptor_data.ef_to_fd == NULL)
- goto fail_ef_to_fd;
-
- raptor_data.eids = bmp_create(MAX_EIDS, 2);
- if (raptor_data.eids == NULL)
- goto fail_eids;
-
- raptor_data.np1_flows = fset_create();
- if (raptor_data.np1_flows == NULL)
- goto fail_np1_flows;
-
- raptor_data.fq = fqueue_create();
- if (raptor_data.fq == NULL)
- goto fail_fq;
-
- for (i = 0; i < MAX_EIDS; ++i)
- raptor_data.ef_to_fd[i] = -1;
-
- for (i = 0; i < SYS_MAX_FLOWS; ++i) {
- raptor_data.fd_to_ef[i].eid = -1;
- raptor_data.fd_to_ef[i].r_eid = -1;
- }
-
- raptor_data.shim_data = shim_data_create();
- if (raptor_data.shim_data == NULL)
- goto fail_shim_data;
-
- ret = -1;
-
- if (pthread_rwlock_init(&raptor_data.flows_lock, NULL))
- goto fail_flows_lock;
-
- if (pthread_mutex_init(&raptor_data.mgmt_lock, NULL))
- goto fail_mgmt_lock;
-
- if (pthread_condattr_init(&cattr))
- goto fail_condattr;
-
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
-
- if (pthread_cond_init(&raptor_data.mgmt_cond, &cattr))
- goto fail_mgmt_cond;
-
- pthread_condattr_destroy(&cattr);
-
- list_head_init(&raptor_data.mgmt_frames);
-
- return 0;
-
- fail_mgmt_cond:
- pthread_condattr_destroy(&cattr);
- fail_condattr:
- pthread_mutex_destroy(&raptor_data.mgmt_lock);
- fail_mgmt_lock:
- pthread_rwlock_destroy(&raptor_data.flows_lock);
- fail_flows_lock:
- shim_data_destroy(raptor_data.shim_data);
- fail_shim_data:
- fqueue_destroy(raptor_data.fq);
- fail_fq:
- fset_destroy(raptor_data.np1_flows);
- fail_np1_flows:
- bmp_destroy(raptor_data.eids);
- fail_eids:
- free(raptor_data.ef_to_fd);
- fail_ef_to_fd:
- free(raptor_data.fd_to_ef);
- fail_fd_to_ef:
- return ret;
-}
-
-static void raptor_data_fini(void)
-{
- close(raptor_data.ioctl_fd);
- pthread_cond_destroy(&raptor_data.mgmt_cond);
- pthread_mutex_destroy(&raptor_data.mgmt_lock);
- pthread_rwlock_destroy(&raptor_data.flows_lock);
- fqueue_destroy(raptor_data.fq);
- fset_destroy(raptor_data.np1_flows);
- bmp_destroy(raptor_data.eids);
- free(raptor_data.fd_to_ef);
- free(raptor_data.ef_to_fd);
-}
-
-static int raptor_send_frame(struct shm_du_buff * sdb,
- uint8_t deid)
-{
- uint8_t * frame;
- size_t frame_len;
- uint8_t * payload;
- size_t len;
-
- payload = shm_du_buff_head(sdb);
- len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
-
- frame_len = RAPTOR_HEADER + len;
-
- if (frame_len >= RAPTOR_PAGE) {
- log_err("Payload too large.");
- return -1;
- }
-
- frame = memalign(1 << 12, 1 << 12);
- if (frame == NULL) {
- log_err("frame == NULL");
- return -1;
- }
-
- if ((uint64_t)frame & 0xFFF) {
- log_err("page offset not zero");
- return -1;
- }
-
- frame[0] = (frame_len & 0x00FF) >> 0;
- frame[1] = (frame_len & 0xFF00) >> 8;
- frame[2] = deid;
-
- memcpy(&frame[RAPTOR_HEADER], payload, len);
-
- if (ioctl(raptor_data.ioctl_fd, IOCTL_SEND | 1, &frame) != 1) {
- log_err("Ioctl send failed.");
- free(frame);
- return -1;
- }
-
- return 0;
-}
-
-static int raptor_eid_alloc(uint8_t seid,
- const uint8_t * hash,
- qosspec_t qs)
-{
- struct mgmt_msg * msg;
- struct shm_du_buff * sdb;
-
- if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + ipcp_dir_hash_len()) < 0) {
- log_err("failed to reserve sdb for management frame.");
- return -1;
- }
-
- msg = (struct mgmt_msg *) shm_du_buff_head(sdb);
- msg->code = FLOW_REQ;
- msg->seid = seid;
- msg->delay = hton32(qs.delay);
- msg->bandwidth = hton64(qs.bandwidth);
- msg->availability = qs.availability;
- msg->loss = hton32(qs.loss);
- msg->ber = hton32(qs.ber);
- msg->in_order = qs.in_order;
- msg->max_gap = hton32(qs.max_gap);
-
- memcpy(msg + 1, hash, ipcp_dir_hash_len());
-
- if (raptor_send_frame(sdb, MGMT_EID)) {
- log_err("Failed to send management frame.");
- ipcp_sdb_release(sdb);
- return -1;
- }
-
- ipcp_sdb_release(sdb);
-
- return 0;
-}
-
-static int raptor_eid_alloc_resp(uint8_t seid,
- uint8_t deid,
- int response)
-{
- struct mgmt_msg * msg;
- struct shm_du_buff * sdb;
-
- if (ipcp_sdb_reserve(&sdb, sizeof(*msg)) < 0) {
- log_err("Failed to reserve sdb for management frame.");
- return -1;
- }
-
- msg = (struct mgmt_msg *) shm_du_buff_head(sdb);
- msg->code = FLOW_REPLY;
- msg->seid = seid;
- msg->deid = deid;
- msg->response = response;
-
- if (raptor_send_frame(sdb, MGMT_EID)) {
- log_err("Failed to send management frame.");
- ipcp_sdb_release(sdb);
- return -1;
- }
-
- ipcp_sdb_release(sdb);
-
- return 0;
-}
-
-static int raptor_eid_req(uint8_t r_eid,
- const uint8_t * dst,
- qosspec_t qs)
-{
- struct timespec ts = {0, EVENT_WAIT_TIMEOUT * 1000};
- struct timespec abstime;
- int fd;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_dbg("Won't allocate over non-operational IPCP.");
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- return -1;
- }
-
- /* reply to IRM, called under lock to prevent race */
- fd = ipcp_flow_req_arr(getpid(), dst, ipcp_dir_hash_len(), qs);
- if (fd < 0) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- log_err("Could not get new flow from IRMd.");
- return -1;
- }
-
- pthread_rwlock_wrlock(&raptor_data.flows_lock);
-
- raptor_data.fd_to_ef[fd].r_eid = r_eid;
-
- ipcpi.alloc_id = fd;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_rwlock_unlock(&raptor_data.flows_lock);
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
- log_dbg("New flow request, fd %d, remote EID %d.", fd, r_eid);
-
- return 0;
-}
-
-static int raptor_eid_alloc_reply(uint8_t seid,
- int deid,
- int response)
-{
- int ret = 0;
- int fd = -1;
-
- pthread_rwlock_wrlock(&raptor_data.flows_lock);
-
- fd = raptor_data.ef_to_fd[deid];
- if (fd < 0) {
- pthread_rwlock_unlock(& raptor_data.flows_lock);
- log_err("No flow found with that EID.");
- return -1; /* -EFLOWNOTFOUND */
- }
-
- if (response)
- bmp_release(raptor_data.eids, raptor_data.fd_to_ef[fd].eid);
- else
- raptor_data.fd_to_ef[fd].r_eid = seid;
-
- pthread_rwlock_unlock(&raptor_data.flows_lock);
-
- log_dbg("Flow reply, fd %d, SEID %d, DEID %d.", fd, seid, deid);
-
- if ((ret = ipcp_flow_alloc_reply(fd, response)) < 0)
- return -1;
-
- return ret;
-
-}
-
-static int raptor_name_query_req(const uint8_t * hash)
-{
- struct mgmt_msg * msg;
- struct shm_du_buff * sdb;
-
- if (!shim_data_reg_has(raptor_data.shim_data, hash))
- return 0;
-
- if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + ipcp_dir_hash_len()) < 0) {
- log_err("Failed to reserve sdb for management frame.");
- return -1;
- }
-
- msg = (struct mgmt_msg *) shm_du_buff_head(sdb);
- msg->code = NAME_QUERY_REPLY;
-
- memcpy(msg + 1, hash, ipcp_dir_hash_len());
-
- if (raptor_send_frame(sdb, MGMT_EID)) {
- log_err("Failed to send management frame.");
- ipcp_sdb_release(sdb);
- return -1;
- }
-
- ipcp_sdb_release(sdb);
-
- return 0;
-}
-
-static int raptor_name_query_reply(const uint8_t * hash)
-{
- shim_data_dir_add_entry(raptor_data.shim_data, hash, 0);
-
- shim_data_dir_query_respond(raptor_data.shim_data, hash);
-
- return 0;
-}
-
-static int raptor_mgmt_frame(const uint8_t * buf,
- size_t len)
-{
- struct mgmt_msg * msg = (struct mgmt_msg *) buf;
- uint8_t * hash = (uint8_t *) (msg + 1);
- qosspec_t qs;
-
- switch (msg->code) {
- case FLOW_REQ:
- if (len != sizeof(*msg) + ipcp_dir_hash_len()) {
- log_err("Corrupt message received.");
- return -1;
- }
-
- qs.delay = ntoh32(msg->delay);
- qs.bandwidth = ntoh64(msg->bandwidth);
- qs.availability = msg->availability;
- qs.loss = ntoh32(msg->loss);
- qs.ber = ntoh32(msg->ber);
- qs.in_order = msg->in_order;
- qs.max_gap = ntoh32(msg->max_gap);
-
- if (shim_data_reg_has(raptor_data.shim_data, hash))
- raptor_eid_req(msg->seid, hash, qs);
- break;
- case FLOW_REPLY:
- if (len != sizeof(*msg)) {
- log_err("Corrupt message received.");
- return -1;
- }
-
- raptor_eid_alloc_reply(msg->seid, msg->deid, msg->response);
- break;
- case NAME_QUERY_REQ:
- if (len != sizeof(*msg) + ipcp_dir_hash_len()) {
- log_err("Corrupt message received.");
- return -1;
- }
-
- raptor_name_query_req(hash);
- break;
- case NAME_QUERY_REPLY:
- if (len != sizeof(*msg) + ipcp_dir_hash_len()) {
- log_err("Corrupt message received.");
- return -1;
- }
-
- raptor_name_query_reply(hash);
- break;
- default:
- log_err("Unknown message received %d.", msg->code);
- return -1;
- }
-
- return 0;
-}
-
-static void * raptor_mgmt_handler(void * o)
-{
- int ret;
- struct timespec timeout = {(MGMT_TIMEOUT / 1000),
- (MGMT_TIMEOUT % 1000) * MILLION};
- struct timespec abstime;
- struct mgmt_frame * frame;
-
- (void) o;
-
- while (true) {
- ret = 0;
-
- if (ipcp_get_state() != IPCP_OPERATIONAL)
- break;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- ts_add(&abstime, &timeout, &abstime);
-
- pthread_mutex_lock(&raptor_data.mgmt_lock);
-
- while (list_is_empty(&raptor_data.mgmt_frames) &&
- ret != -ETIMEDOUT)
- ret = -pthread_cond_timedwait(&raptor_data.mgmt_cond,
- &raptor_data.mgmt_lock,
- &abstime);
-
- if (ret == -ETIMEDOUT) {
- pthread_mutex_unlock(&raptor_data.mgmt_lock);
- continue;
- }
-
- frame = list_first_entry((&raptor_data.mgmt_frames),
- struct mgmt_frame, next);
- if (frame == NULL) {
- pthread_mutex_unlock(&raptor_data.mgmt_lock);
- continue;
- }
-
- list_del(&frame->next);
- pthread_mutex_unlock(&raptor_data.mgmt_lock);
-
- raptor_mgmt_frame(frame->buf, frame->len);
- free(frame);
- }
-
- return NULL;
-}
-
-static void raptor_recv_frame(uint8_t * frame)
-{
- uint8_t deid;
- uint8_t * payload;
- size_t frame_len;
- size_t length;
- int fd;
- struct mgmt_frame * mgmt_frame;
- struct shm_du_buff * sdb;
- size_t idx;
-
- sdb = (struct shm_du_buff *)((uint64_t) frame & RAPTOR_PAGE_MASK);
- idx = shm_du_buff_get_idx(sdb);
-
- frame_len = frame[0] | (frame[1] << 8);
- if (frame_len < RAPTOR_HEADER) {
- log_err("Received packet smaller than header alone.");
- ipcp_sdb_release(sdb);
- return;
- }
-
- if (frame_len >= RAPTOR_PAGE) {
- log_err("Received packet too large.");
- ipcp_sdb_release(sdb);
- return;
- }
-
- deid = frame[2];
- payload = &frame[RAPTOR_HEADER];
- length = frame_len - RAPTOR_HEADER;
-
- shm_du_buff_head_release(sdb, RAPTOR_HEADER);
- shm_du_buff_tail_release(sdb, RAPTOR_PAGE - frame_len);
-
- if (deid == MGMT_EID) {
- pthread_mutex_lock(&raptor_data.mgmt_lock);
-
- mgmt_frame = malloc(sizeof(*mgmt_frame));
- if (mgmt_frame == NULL) {
- pthread_mutex_unlock(&raptor_data.mgmt_lock);
- ipcp_sdb_release(sdb);
- return;
- }
-
- memcpy(mgmt_frame->buf, payload, length);
- mgmt_frame->len = length;
- list_add(&mgmt_frame->next, &raptor_data.mgmt_frames);
- pthread_cond_signal(&raptor_data.mgmt_cond);
- pthread_mutex_unlock(&raptor_data.mgmt_lock);
-
- ipcp_sdb_release(sdb);
- } else {
- pthread_rwlock_rdlock(&raptor_data.flows_lock);
-
- fd = raptor_data.ef_to_fd[deid];
- if (fd < 0) {
- pthread_rwlock_unlock(&raptor_data.flows_lock);
- ipcp_sdb_release(sdb);
- return;
- }
-
- pthread_rwlock_unlock(&raptor_data.flows_lock);
-
- local_flow_write(fd, idx);
- }
-}
-
-static void * raptor_recv_done_thread(void * o)
-{
- uint8_t * frames[RAPTOR_BATCH];
- int count;
- int i;
-
- (void) o;
-
- while (true) {
- if (ipcp_get_state() != IPCP_OPERATIONAL)
- break;
-
- count = ioctl(raptor_data.ioctl_fd,
- IOCTL_RECV_DONE | RAPTOR_BATCH, frames);
-
- if (count <= 0)
- continue;
-
- for (i = 0; i < count; i++)
- raptor_recv_frame(frames[i]);
- }
-
- return NULL;
-}
-
-static void * raptor_send_thread(void * o)
-{
- struct timespec timeout = {0, EVENT_WAIT_TIMEOUT * 1000};
- int fd;
- struct shm_du_buff * sdb;
- uint8_t deid;
-
- (void) o;
-
- while (fevent(raptor_data.np1_flows, raptor_data.fq, &timeout)) {
- if (ipcp_get_state() != IPCP_OPERATIONAL)
- break;
-
- pthread_rwlock_rdlock(&raptor_data.flows_lock);
- while ((fd = fqueue_next(raptor_data.fq)) >= 0) {
- if (ipcp_flow_read(fd, &sdb)) {
- log_err("Bad read from fd %d.", fd);
- continue;
- }
-
- deid = raptor_data.fd_to_ef[fd].r_eid;
-
- raptor_send_frame(sdb, deid);
- }
- pthread_rwlock_unlock(&raptor_data.flows_lock);
- }
-
- return NULL;
-}
-
-static void * raptor_send_done_thread(void * o)
-{
- uint8_t * frames[RAPTOR_BATCH];
- int count;
- int i;
-
- (void) o;
-
- while (true) {
- if (ipcp_get_state() != IPCP_OPERATIONAL)
- break;
-
- count = ioctl(raptor_data.ioctl_fd,
- IOCTL_SEND_DONE | RAPTOR_BATCH, frames);
-
- if (count <= 0)
- continue;
-
- for (i = 0; i < count; i++)
- free(frames[i]);
- }
-
- return NULL;
-}
-
-static void * raptor_recv_thread(void * o)
-{
- struct shm_du_buff * sdb;
- uint8_t * frames[RAPTOR_BATCH];
- uint8_t ** head;
- int needed = 0;
- int count;
- int i;
-
- (void) o;
-
- while (true) {
- if (ipcp_get_state() != IPCP_OPERATIONAL)
- break;
-
- needed = ioctl(raptor_data.ioctl_fd,
- IOCTL_RECV_NEED | RAPTOR_BATCH, NULL);
-
- if (needed <= 0)
- continue;
-
- for (i = 0; i < needed; i++) {
- if (ipcp_sdb_reserve(&sdb, RAPTOR_PAGE) < 0) {
- log_err("Recv thread: reserve sdb failed.");
- return NULL;
- }
-
- if ((uint64_t)sdb & (~RAPTOR_PAGE_MASK)) {
- log_err("Recv thread: sdb not at offset 0.");
- return NULL;
- }
-
- frames[i] = shm_du_buff_head(sdb);
-
- if ((uint64_t)frames[i] & 0x7) {
- log_err("Recv thread: frame not aligned.");
- return NULL;
- }
- }
-
- head = frames;
-
- do {
- count = ioctl(raptor_data.ioctl_fd,
- IOCTL_RECV | needed, head);
- if (count <= 0)
- continue;
-
- assert(count <= needed);
-
- needed -= count;
- head += count;
-
- } while (needed > 0 && ipcp_get_state() == IPCP_OPERATIONAL);
- }
-
- return NULL;
-}
-
-static int raptor_bootstrap(const struct ipcp_config * conf)
-{
- assert(conf);
- assert(conf->type == THIS_TYPE);
-
- (void) conf;
-
- raptor_data.ioctl_fd = open("/dev/raptor", 0);
- if (raptor_data.ioctl_fd < 0) {
- log_err("Failed to open /dev/raptor.");
- goto fail_ioctl;
- }
-
- ipcp_set_state(IPCP_OPERATIONAL);
-
- if (pthread_create(&raptor_data.mgmt_handler,
- NULL,
- raptor_mgmt_handler,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
- goto fail_mgmt_handler;
- }
-
- if (pthread_create(&raptor_data.send_thread,
- NULL,
- raptor_send_thread,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
- goto fail_send_thread;
- }
-
- if (pthread_create(&raptor_data.recv_thread,
- NULL,
- raptor_recv_thread,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
- goto fail_recv_thread;
- }
-
- if (pthread_create(&raptor_data.send_done_thread,
- NULL,
- raptor_send_done_thread,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
- goto fail_send_done_thread;
- }
-
- if (pthread_create(&raptor_data.recv_done_thread,
- NULL,
- raptor_recv_done_thread,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
- goto fail_recv_done_thread;
- }
-
- log_dbg("Bootstrapped raptor IPCP with api %d.", getpid());
-
- return 0;
-
- fail_recv_done_thread:
- pthread_join(raptor_data.send_done_thread, NULL);
- fail_send_done_thread:
- pthread_join(raptor_data.recv_thread, NULL);
- fail_recv_thread:
- pthread_join(raptor_data.send_thread, NULL);
- fail_send_thread:
- pthread_join(raptor_data.mgmt_handler, NULL);
- fail_mgmt_handler:
- close(raptor_data.ioctl_fd);
- fail_ioctl:
- return -1;
-}
-
-static int raptor_reg(const uint8_t * hash)
-{
- uint8_t * hash_dup;
-
- hash_dup = ipcp_hash_dup(hash);
- if (hash_dup == NULL) {
- log_err("Failed to duplicate hash.");
- return -ENOMEM;
- }
-
- if (shim_data_reg_add_entry(raptor_data.shim_data, hash_dup)) {
- log_err("Failed to add " HASH_FMT " to local registry.",
- HASH_VAL(hash));
- free(hash_dup);
- return -1;
- }
-
- log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash));
-
- return 0;
-}
-
-static int raptor_unreg(const uint8_t * hash)
-{
- shim_data_reg_del_entry(raptor_data.shim_data, hash);
-
- return 0;
-}
-
-static int raptor_query(const uint8_t * hash)
-{
- struct timespec timeout = {(NAME_QUERY_TIMEOUT / 1000),
- (NAME_QUERY_TIMEOUT % 1000) * MILLION};
- struct mgmt_msg * msg;
- struct dir_query * query;
- int ret;
- struct shm_du_buff * sdb;
-
- if (shim_data_dir_has(raptor_data.shim_data, hash))
- return 0;
-
- if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + ipcp_dir_hash_len()) < 0) {
- log_err("failed to reserve sdb for management frame.");
- return -1;
- }
-
- msg = (struct mgmt_msg *) shm_du_buff_head(sdb);
- msg->code = NAME_QUERY_REQ;
-
- memcpy(msg + 1, hash, ipcp_dir_hash_len());
-
- query = shim_data_dir_query_create(raptor_data.shim_data, hash);
- if (query == NULL) {
- ipcp_sdb_release(sdb);
- return -1;
- }
-
- if (raptor_send_frame(sdb, MGMT_EID)) {
- log_err("Failed to send management frame.");
- ipcp_sdb_release(sdb);
- return -1;
- }
-
- ret = shim_data_dir_query_wait(query, &timeout);
-
- shim_data_dir_query_destroy(raptor_data.shim_data, query);
-
- return ret;
-}
-
-static int raptor_flow_alloc(int fd,
- const uint8_t * hash,
- qosspec_t qs)
-{
- uint8_t seid = 0;
-
- log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(hash));
-
- assert(hash);
-
- if (!shim_data_dir_has(raptor_data.shim_data, hash)) {
- log_err("Destination unreachable.");
- return -1;
- }
-
- pthread_rwlock_wrlock(&raptor_data.flows_lock);
-
- seid = bmp_allocate(raptor_data.eids);
- if (!bmp_is_id_valid(raptor_data.eids, seid)) {
- pthread_rwlock_unlock(&raptor_data.flows_lock);
- return -1;
- }
-
- raptor_data.fd_to_ef[fd].eid = seid;
- raptor_data.ef_to_fd[seid] = fd;
-
- pthread_rwlock_unlock(&raptor_data.flows_lock);
-
- if (raptor_eid_alloc(seid, hash, qs) < 0) {
- pthread_rwlock_wrlock(&raptor_data.flows_lock);
- bmp_release(raptor_data.eids, raptor_data.fd_to_ef[fd].eid);
- raptor_data.fd_to_ef[fd].eid = -1;
- raptor_data.ef_to_fd[seid] = -1;
- pthread_rwlock_unlock(&raptor_data.flows_lock);
- return -1;
- }
-
- fset_add(raptor_data.np1_flows, fd);
-
- log_dbg("Pending flow with fd %d on EID %d.", fd, seid);
-
- return 0;
-}
-
-static int raptor_flow_alloc_resp(int fd,
- int response)
-{
- struct timespec ts = {0, EVENT_WAIT_TIMEOUT * 1000};
- struct timespec abstime;
- uint8_t seid = 0;
- uint8_t r_eid = 0;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- return -1;
- }
-
- ipcpi.alloc_id = -1;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
- pthread_rwlock_wrlock(&raptor_data.flows_lock);
-
- seid = bmp_allocate(raptor_data.eids);
- if (!bmp_is_id_valid(raptor_data.eids, seid)) {
- pthread_rwlock_unlock(&raptor_data.flows_lock);
- return -1;
- }
-
- raptor_data.fd_to_ef[fd].eid = seid;
- r_eid = raptor_data.fd_to_ef[fd].r_eid;
- raptor_data.ef_to_fd[seid] = fd;
-
- pthread_rwlock_unlock(&raptor_data.flows_lock);
-
- if (raptor_eid_alloc_resp(seid, r_eid, response) < 0) {
- pthread_rwlock_wrlock(&raptor_data.flows_lock);
- bmp_release(raptor_data.eids, raptor_data.fd_to_ef[fd].eid);
- pthread_rwlock_unlock(&raptor_data.flows_lock);
- return -1;
- }
-
- fset_add(raptor_data.np1_flows, fd);
-
- log_dbg("Accepted flow, fd %d, EID %d.", fd, (uint8_t)seid);
-
- return 0;
-}
-
-static int raptor_flow_dealloc(int fd)
-{
- uint8_t eid;
-
- ipcp_flow_fini(fd);
-
- pthread_rwlock_wrlock(&raptor_data.flows_lock);
-
- fset_del(raptor_data.np1_flows, fd);
-
- eid = raptor_data.fd_to_ef[fd].eid;
- bmp_release(raptor_data.eids, eid);
- raptor_data.fd_to_ef[fd].eid = -1;
- raptor_data.fd_to_ef[fd].r_eid = -1;
-
- raptor_data.ef_to_fd[eid] = -1;
-
- pthread_rwlock_unlock(&raptor_data.flows_lock);
-
- flow_dealloc(fd);
-
- log_dbg("Flow with fd %d deallocated.", fd);
-
- return 0;
-}
-
-static struct ipcp_ops raptor_ops = {
- .ipcp_bootstrap = raptor_bootstrap,
- .ipcp_enroll = NULL,
- .ipcp_reg = raptor_reg,
- .ipcp_unreg = raptor_unreg,
- .ipcp_query = raptor_query,
- .ipcp_flow_alloc = raptor_flow_alloc,
- .ipcp_flow_join = NULL,
- .ipcp_flow_alloc_resp = raptor_flow_alloc_resp,
- .ipcp_flow_dealloc = raptor_flow_dealloc
-};
-
-int main(int argc,
- char * argv[])
-{
- if (ipcp_init(argc, argv, &raptor_ops) < 0) {
- log_err("Failed to init IPCP.");
- goto fail_init;
- }
-
- if (raptor_data_init() < 0) {
- log_err("Failed to init shim-eth-llc data.");
- goto fail_data_init;
- }
-
- if (ipcp_boot() < 0) {
- log_err("Failed to boot IPCP.");
- goto fail_boot;
- }
-
- if (ipcp_create_r(getpid(), 0)) {
- log_err("Failed to notify IRMd we are initialized.");
- ipcp_set_state(IPCP_NULL);
- goto fail_create_r;
- }
-
- log_info("Raptor created.");
-
- ipcp_shutdown();
-
- if (ipcp_get_state() == IPCP_SHUTDOWN) {
- pthread_join(raptor_data.send_thread, NULL);
- pthread_join(raptor_data.recv_thread, NULL);
- pthread_join(raptor_data.send_done_thread, NULL);
- pthread_join(raptor_data.recv_done_thread, NULL);
- pthread_join(raptor_data.mgmt_handler, NULL);
- }
-
- raptor_data_fini();
-
- ipcp_fini();
-
- exit(EXIT_SUCCESS);
-
- fail_create_r:
- ipcp_shutdown();
- fail_boot:
- raptor_data_fini();
- fail_data_init:
- ipcp_fini();
- fail_init:
- ipcp_create_r(getpid(), -1);
- exit(EXIT_FAILURE);
-}
diff --git a/src/ipcpd/shim-data.c b/src/ipcpd/shim-data.c
index 60f0245a..1fac63ac 100644
--- a/src/ipcpd/shim-data.c
+++ b/src/ipcpd/shim-data.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC process utilities
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -30,18 +30,18 @@
#define OUROBOROS_PREFIX "shim-data"
-#include <ouroboros/endian.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/list.h>
-#include <ouroboros/time_utils.h>
#include <ouroboros/errno.h>
+#include <ouroboros/hash.h>
+#include <ouroboros/list.h>
+#include <ouroboros/logs.h>
+#include <ouroboros/time.h>
#include "shim-data.h"
#include "ipcp.h"
-#include <string.h>
-#include <stdlib.h>
#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
struct reg_entry {
struct list_head list;
@@ -74,6 +74,9 @@ static void destroy_dir_query(struct dir_query * query)
case QUERY_DESTROY:
pthread_mutex_unlock(&query->lock);
return;
+ default:
+ assert(false);
+ return;
}
while (query->state != QUERY_DONE)
@@ -136,9 +139,11 @@ static void dir_entry_destroy(struct dir_entry * entry)
free(entry);
}
-struct shim_data * shim_data_create()
+struct shim_data * shim_data_create(void)
{
- struct shim_data * sd = malloc(sizeof(*sd));
+ struct shim_data * sd;
+
+ sd = malloc(sizeof(*sd));
if (sd == NULL)
return NULL;
@@ -148,11 +153,23 @@ struct shim_data * shim_data_create()
list_head_init(&sd->dir_queries);
/* init the locks */
- pthread_rwlock_init(&sd->reg_lock, NULL);
- pthread_rwlock_init(&sd->dir_lock, NULL);
- pthread_mutex_init(&sd->dir_queries_lock, NULL);
+ if (pthread_rwlock_init(&sd->reg_lock, NULL) < 0)
+ goto fail_reg_lock_init;
+
+ if (pthread_rwlock_init(&sd->dir_lock, NULL) < 0)
+ goto fail_dir_lock_init;
+
+ if (pthread_mutex_init(&sd->dir_queries_lock, NULL) < 0)
+ goto fail_mutex_init;
return sd;
+
+ fail_mutex_init:
+ pthread_rwlock_destroy(&sd->dir_lock);
+ fail_dir_lock_init:
+ pthread_rwlock_destroy(&sd->reg_lock);
+ fail_reg_lock_init:
+ return NULL;
}
static void clear_registry(struct shim_data * data)
@@ -280,8 +297,8 @@ int shim_data_reg_add_entry(struct shim_data * data,
if (find_reg_entry_by_hash(data, hash)) {
pthread_rwlock_unlock(&data->reg_lock);
- log_dbg(HASH_FMT " was already in the directory.",
- HASH_VAL(hash));
+ log_dbg(HASH_FMT32 " was already in the directory.",
+ HASH_VAL32(hash));
return 0;
}
@@ -429,9 +446,9 @@ uint64_t shim_data_dir_get_addr(struct shim_data * data,
pthread_rwlock_rdlock(&data->dir_lock);
entry = find_dir_entry_any(data, hash);
-
if (entry == NULL) {
pthread_rwlock_unlock(&data->dir_lock);
+ log_warn("No address for " HASH_FMT32 ".", HASH_VAL32(hash));
return 0; /* undefined behaviour, 0 may be a valid address */
}
diff --git a/src/ipcpd/shim-data.h b/src/ipcpd/shim-data.h
index af937f07..372b4ea7 100644
--- a/src/ipcpd/shim-data.h
+++ b/src/ipcpd/shim-data.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Utitilies for building IPC processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/udp/CMakeLists.txt b/src/ipcpd/udp/CMakeLists.txt
index f1a29ef6..8ae5518e 100644
--- a/src/ipcpd/udp/CMakeLists.txt
+++ b/src/ipcpd/udp/CMakeLists.txt
@@ -58,6 +58,8 @@ set(IPCP_UDP_RD_THR 3 CACHE STRING
"Number of reader threads in UDP IPCP")
set(IPCP_UDP_WR_THR 3 CACHE STRING
"Number of writer threads in UDP IPCP")
+set(IPCP_UDP_MPL 60 CACHE STRING
+ "Default maximum packet lifetime for the UDP IPCP, in seconds")
include(AddCompileFlags)
if (CMAKE_BUILD_TYPE MATCHES "Debug*")
diff --git a/src/ipcpd/udp/main.c b/src/ipcpd/udp/main.c
index 04c21a8b..2e8d84ce 100644
--- a/src/ipcpd/udp/main.c
+++ b/src/ipcpd/udp/main.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC process over UDP
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,6 +31,7 @@
#define OUROBOROS_PREFIX "ipcpd/udp"
#include <ouroboros/bitmap.h>
+#include <ouroboros/endian.h>
#include <ouroboros/hash.h>
#include <ouroboros/list.h>
#include <ouroboros/utils.h>
@@ -39,6 +40,7 @@
#include <ouroboros/fqueue.h>
#include <ouroboros/errno.h>
#include <ouroboros/logs.h>
+#include <ouroboros/pthread.h>
#include "ipcp.h"
#include "shim-data.h"
@@ -51,7 +53,6 @@
#include <netinet/in.h>
#include <signal.h>
#include <stdlib.h>
-#include <pthread.h>
#include <sys/wait.h>
#include <fcntl.h>
@@ -65,18 +66,23 @@
#define IPCP_UDP_BUF_SIZE 8980
#define IPCP_UDP_MSG_SIZE 8980
#define DNS_TTL 86400
-#define FD_UPDATE_TIMEOUT 100 /* microseconds */
-#define SERV_PORT udp_data.s_saddr.sin_port;
-#define SERV_SADDR ((struct sockaddr *) &udp_data.s_saddr)
-#define CLNT_SADDR ((struct sockaddr *) &udp_data.c_saddr)
-#define SERV_SADDR_SIZE (sizeof(udp_data.s_saddr))
+#define SADDR ((struct sockaddr *) &udp_data.s_saddr)
+#define SADDR_SIZE (sizeof(udp_data.s_saddr))
#define LOCAL_IP (udp_data.s_saddr.sin_addr.s_addr)
#define MGMT_EID 0
#define MGMT_FRAME_SIZE (sizeof(struct mgmt_msg))
#define MGMT_FRAME_BUF_SIZE 2048
+#ifdef __linux__
+#define SENDTO_FLAGS MSG_CONFIRM
+#else
+#define SENDTO_FLAGS 0
+#endif
+
+struct ipcp ipcpi;
+
/* Keep order for alignment. */
struct mgmt_msg {
uint32_t eid;
@@ -92,7 +98,9 @@ struct mgmt_msg {
uint32_t loss;
uint32_t ber;
uint32_t max_gap;
+ uint32_t timeout;
uint16_t cypher_s;
+
} __attribute__((packed));
struct mgmt_frame {
@@ -104,20 +112,17 @@ struct mgmt_frame {
/* UDP flow */
struct uf {
- int d_eid;
- /* IP details are stored through connect(). */
- int skfd;
+ int d_eid;
+ struct sockaddr_in r_saddr;
};
struct {
struct shim_data * shim_data;
uint32_t dns_addr;
- /* server socket */
+
struct sockaddr_in s_saddr;
int s_fd;
- /* client port */
- int clt_port;
fset_t * np1_flows;
struct uf fd_to_uf[SYS_MAX_FLOWS];
@@ -135,21 +140,25 @@ struct {
static int udp_data_init(void)
{
- int i;
+ int i;
+ pthread_condattr_t cattr;
if (pthread_rwlock_init(&udp_data.flows_lock, NULL))
goto fail_rwlock_init;
- if (pthread_cond_init(&udp_data.mgmt_cond, NULL))
+ if (pthread_condattr_init(&cattr))
+ goto fail_condattr;
+#ifndef __APPLE__
+ pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
+#endif
+ if (pthread_cond_init(&udp_data.mgmt_cond, &cattr))
goto fail_mgmt_cond;
if (pthread_mutex_init(&udp_data.mgmt_lock, NULL))
goto fail_mgmt_lock;
- for (i = 0; i < SYS_MAX_FLOWS; ++i) {
- udp_data.fd_to_uf[i].skfd = -1;
+ for (i = 0; i < SYS_MAX_FLOWS; ++i)
udp_data.fd_to_uf[i].d_eid = -1;
- }
udp_data.np1_flows = fset_create();
if (udp_data.np1_flows == NULL)
@@ -159,9 +168,12 @@ static int udp_data_init(void)
if (udp_data.shim_data == NULL)
goto fail_data;
+ pthread_condattr_destroy(&cattr);
+
list_head_init(&udp_data.mgmt_frames);
return 0;
+
fail_data:
fset_destroy(udp_data.np1_flows);
fail_fset:
@@ -169,6 +181,8 @@ static int udp_data_init(void)
fail_mgmt_lock:
pthread_cond_destroy(&udp_data.mgmt_cond);
fail_mgmt_cond:
+ pthread_condattr_destroy(&cattr);
+ fail_condattr:
pthread_rwlock_destroy(&udp_data.flows_lock);
fail_rwlock_init:
return -1;
@@ -185,22 +199,21 @@ static void udp_data_fini(void)
pthread_mutex_destroy(&udp_data.mgmt_lock);
}
-static int ipcp_udp_port_alloc(int skfd,
- uint32_t s_eid,
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t dlen)
+static int udp_ipcp_port_alloc(const struct sockaddr_in * r_saddr,
+ uint32_t s_eid,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
uint8_t * buf;
struct mgmt_msg * msg;
size_t len;
- assert(dlen > 0 ? data != NULL : data == NULL);
+ assert(data->len > 0 ? data->data != NULL : data->data == NULL);
len = sizeof(*msg) + ipcp_dir_hash_len();
- buf = malloc(len + dlen);
+ buf = malloc(len + data->len);
if (buf == NULL)
return -1;
@@ -216,11 +229,15 @@ static int ipcp_udp_port_alloc(int skfd,
msg->in_order = qs.in_order;
msg->max_gap = hton32(qs.max_gap);
msg->cypher_s = hton16(qs.cypher_s);
+ msg->timeout = hton32(qs.timeout);
memcpy(msg + 1, dst, ipcp_dir_hash_len());
- memcpy(buf + len, data, dlen);
+ if (data->len > 0)
+ memcpy(buf + len, data->data, data->len);
- if (write(skfd, msg, len + dlen) < 0) {
+ if (sendto(udp_data.s_fd, msg, len + data->len,
+ SENDTO_FLAGS,
+ (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0) {
free(buf);
return -1;
}
@@ -230,16 +247,15 @@ static int ipcp_udp_port_alloc(int skfd,
return 0;
}
-static int ipcp_udp_port_alloc_resp(int skfd,
- uint32_t s_eid,
- uint32_t d_eid,
- int8_t response,
- const void * data,
- size_t len)
+static int udp_ipcp_port_alloc_resp(const struct sockaddr_in * r_saddr,
+ uint32_t s_eid,
+ uint32_t d_eid,
+ int8_t response,
+ const buffer_t * data)
{
- struct mgmt_msg * msg;
+ struct mgmt_msg * msg;
- msg = malloc(sizeof(*msg) + len);
+ msg = malloc(sizeof(*msg) + data->len);
if (msg == NULL)
return -1;
@@ -249,9 +265,12 @@ static int ipcp_udp_port_alloc_resp(int skfd,
msg->d_eid = hton32(d_eid);
msg->response = response;
- memcpy(msg + 1, data, len);
+ if (data->len > 0)
+ memcpy(msg + 1, data->data, data->len);
- if (write(skfd, msg, sizeof(*msg) + len) < 0) {
+ if (sendto(udp_data.s_fd, msg, sizeof(*msg) + data->len,
+ SENDTO_FLAGS,
+ (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0 ) {
free(msg);
return -1;
}
@@ -261,134 +280,74 @@ static int ipcp_udp_port_alloc_resp(int skfd,
return 0;
}
-static int ipcp_udp_port_req(struct sockaddr_in * c_saddr,
+static int udp_ipcp_port_req(struct sockaddr_in * c_saddr,
int d_eid,
const uint8_t * dst,
qosspec_t qs,
- const void * data,
- size_t len)
+ const buffer_t * data)
{
- struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000};
- struct timespec abstime;
- int skfd;
- int fd;
-
- skfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (skfd < 0) {
- log_err("Could not create UDP socket.");
- return -1;
- }
-
- /* Remote listens on server port. Mod of c_saddr allowed. */
- c_saddr->sin_port = udp_data.s_saddr.sin_port;
+ int fd;
- /* Connect stores the remote address in the file descriptor. */
- if (connect(skfd, (struct sockaddr *) c_saddr, sizeof(*c_saddr)) < 0) {
- log_err("Could not connect to remote UDP client.");
- close(skfd);
- return -1;
- }
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond, &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_dbg("Won't allocate over non-operational IPCP.");
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- close(skfd);
- return -1;
- }
-
- /* reply to IRM */
- fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len);
+ fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UDP_MPL, data);
if (fd < 0) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
log_err("Could not get new flow from IRMd.");
- close(skfd);
return -1;
}
pthread_rwlock_wrlock(&udp_data.flows_lock);
- udp_data.fd_to_uf[fd].skfd = skfd;
- udp_data.fd_to_uf[fd].d_eid = d_eid;
+ udp_data.fd_to_uf[fd].r_saddr = *c_saddr;
+ udp_data.fd_to_uf[fd].d_eid = d_eid;
pthread_rwlock_unlock(&udp_data.flows_lock);
- ipcpi.alloc_id = fd;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
log_dbg("Pending allocation request, fd %d, remote eid %d.",
fd, d_eid);
return 0;
}
-static int ipcp_udp_port_alloc_reply(uint32_t s_eid,
- uint32_t d_eid,
- int8_t response,
- const void * data,
- size_t len)
+static int udp_ipcp_port_alloc_reply(const struct sockaddr_in * saddr,
+ uint32_t s_eid,
+ uint32_t d_eid,
+ int8_t response,
+ const buffer_t * data)
{
- struct sockaddr_in t_saddr;
- socklen_t t_saddr_len;
- int ret = 0;
- int skfd = -1;
-
- t_saddr_len = sizeof(t_saddr);
+ time_t mpl = IPCP_UDP_MPL;
pthread_rwlock_wrlock(&udp_data.flows_lock);
- skfd = udp_data.fd_to_uf[s_eid].skfd;
- if (skfd < 0) {
+ if (memcmp(&udp_data.fd_to_uf[s_eid].r_saddr, saddr, sizeof(*saddr))) {
pthread_rwlock_unlock(&udp_data.flows_lock);
- log_err("Got reply for unknown UDP eid: %u.", s_eid);
+ log_err("Flow allocation reply for %u from wrong source.",
+ s_eid);
return -1;
}
- udp_data.fd_to_uf[s_eid].d_eid = d_eid;
+ if (response == 0)
+ udp_data.fd_to_uf[s_eid].d_eid = d_eid;
pthread_rwlock_unlock(&udp_data.flows_lock);
- if (getpeername(skfd, (struct sockaddr *) &t_saddr, &t_saddr_len) < 0) {
- log_dbg("Flow with fd %d has no peer.", s_eid);
- close(skfd);
- return -1;
- }
-
- if (connect(skfd, (struct sockaddr *) &t_saddr, sizeof(t_saddr)) < 0) {
- log_dbg("Could not connect flow to remote.");
- close(skfd);
- return -1;
- }
-
- if (ipcp_flow_alloc_reply(s_eid, response, data, len) < 0) {
- log_dbg("Failed to reply to flow allocation.");
+ if (ipcp_flow_alloc_reply(s_eid, response, mpl, data) < 0) {
+ log_err("Failed to reply to flow allocation.");
return -1;
}
log_dbg("Flow allocation completed on eids (%d, %d).",
s_eid, d_eid);
- return ret;
+ return 0;
}
-static int ipcp_udp_mgmt_frame(const uint8_t * buf,
+static int udp_ipcp_mgmt_frame(const uint8_t * buf,
size_t len,
struct sockaddr_in c_saddr)
{
struct mgmt_msg * msg;
size_t msg_len;
qosspec_t qs;
+ buffer_t data;
msg = (struct mgmt_msg *) buf;
@@ -398,6 +357,10 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf,
assert(len >= msg_len);
+ data.len = len - msg_len;
+ data.data = (uint8_t *) buf + msg_len;
+
+
qs.delay = ntoh32(msg->delay);
qs.bandwidth = ntoh64(msg->bandwidth);
qs.availability = msg->availability;
@@ -406,31 +369,33 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf,
qs.in_order = msg->in_order;
qs.max_gap = ntoh32(msg->max_gap);
qs.cypher_s = ntoh16(msg->cypher_s);
+ qs.timeout = ntoh32(msg->timeout);
- return ipcp_udp_port_req(&c_saddr, ntoh32(msg->s_eid),
+ return udp_ipcp_port_req(&c_saddr, ntoh32(msg->s_eid),
(uint8_t *) (msg + 1), qs,
- buf + msg_len,
- len - msg_len);
+ &data);
case FLOW_REPLY:
assert(len >= sizeof(*msg));
- return ipcp_udp_port_alloc_reply(ntoh32(msg->s_eid),
+ data.len = len - sizeof(*msg);
+ data.data = (uint8_t *) buf + sizeof(*msg);
+
+ return udp_ipcp_port_alloc_reply(&c_saddr,
+ ntoh32(msg->s_eid),
ntoh32(msg->d_eid),
msg->response,
- buf + sizeof(*msg),
- len - sizeof(*msg));
+ &data);
default:
log_err("Unknown message received %d.", msg->code);
return -1;
}
}
-static void * ipcp_udp_mgmt_handler(void * o)
+static void * udp_ipcp_mgmt_handler(void * o)
{
(void) o;
- pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock,
- (void *) &udp_data.mgmt_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &udp_data.mgmt_lock);
while (true) {
struct mgmt_frame * frame;
@@ -448,7 +413,7 @@ static void * ipcp_udp_mgmt_handler(void * o)
pthread_mutex_unlock(&udp_data.mgmt_lock);
- ipcp_udp_mgmt_frame(frame->buf, frame->len, frame->r_saddr);
+ udp_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_saddr);
free(frame);
}
@@ -458,7 +423,7 @@ static void * ipcp_udp_mgmt_handler(void * o)
return (void *) 0;
}
-static void * ipcp_udp_packet_reader(void * o)
+static void * udp_ipcp_packet_reader(void * o)
{
uint8_t buf[IPCP_UDP_MAX_PACKET_SIZE];
uint8_t * data;
@@ -468,13 +433,17 @@ static void * ipcp_udp_packet_reader(void * o)
(void) o;
+ ipcp_lock_to_core();
+
data = buf + sizeof(uint32_t);
eid_p = (uint32_t *) buf;
while (true) {
- struct mgmt_frame * frame;
- struct sockaddr_in r_saddr;
- socklen_t len;
+ struct mgmt_frame * frame;
+ struct sockaddr_in r_saddr;
+ socklen_t len;
+ struct shm_du_buff * sdb;
+ uint8_t * head;
len = sizeof(r_saddr);
@@ -515,18 +484,31 @@ static void * ipcp_udp_packet_reader(void * o)
continue;
}
- flow_write(eid, data, n - sizeof(eid));
+ n-= sizeof(eid);
+
+ if (ipcp_sdb_reserve(&sdb, n))
+ continue;
+
+ head = shm_du_buff_head(sdb);
+ memcpy(head, data, n);
+ if (np1_flow_write(eid, sdb) < 0)
+ ipcp_sdb_release(sdb);
}
- return 0;
+ return (void *) 0;
}
-static void cleanup_writer(void * o)
+static void cleanup_fqueue(void * fq)
{
- fqueue_destroy((fqueue_t *) o);
+ fqueue_destroy((fqueue_t *) fq);
}
-static void * ipcp_udp_packet_writer(void * o)
+static void cleanup_sdb(void * sdb)
+{
+ ipcp_sdb_release((struct shm_du_buff *) sdb);
+}
+
+static void * udp_ipcp_packet_writer(void * o)
{
fqueue_t * fq;
@@ -538,11 +520,12 @@ static void * ipcp_udp_packet_writer(void * o)
ipcp_lock_to_core();
- pthread_cleanup_push(cleanup_writer, fq);
+ pthread_cleanup_push(cleanup_fqueue, fq);
while (true) {
- int fd;
- int eid;
+ struct sockaddr_in saddr;
+ int eid;
+ int fd;
fevent(udp_data.np1_flows, fq, NULL);
while ((fd = fqueue_next(fq)) >= 0) {
struct shm_du_buff * sdb;
@@ -552,12 +535,12 @@ static void * ipcp_udp_packet_writer(void * o)
if (fqueue_type(fq) != FLOW_PKT)
continue;
- if (ipcp_flow_read(fd, &sdb)) {
+ if (np1_flow_read(fd, &sdb)) {
log_dbg("Bad read from fd %d.", fd);
continue;
}
- len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
+ len = shm_du_buff_len(sdb);
if (len > IPCP_UDP_MAX_PACKET_SIZE) {
log_dbg("Packet length exceeds MTU.");
ipcp_sdb_release(sdb);
@@ -574,16 +557,18 @@ static void * ipcp_udp_packet_writer(void * o)
pthread_rwlock_rdlock(&udp_data.flows_lock);
eid = hton32(udp_data.fd_to_uf[fd].d_eid);
- fd = udp_data.fd_to_uf[fd].skfd;
+ saddr = udp_data.fd_to_uf[fd].r_saddr;
pthread_rwlock_unlock(&udp_data.flows_lock);
memcpy(buf, &eid, sizeof(eid));
- pthread_cleanup_push((void (*)(void *))
- ipcp_sdb_release, (void *) sdb);
+ pthread_cleanup_push(cleanup_sdb, sdb);
- if (write(fd, buf, len + OUR_HEADER_LEN) < 0)
+ if (sendto(udp_data.s_fd, buf, len + OUR_HEADER_LEN,
+ SENDTO_FLAGS,
+ (const struct sockaddr *) &saddr,
+ sizeof(saddr)) < 0)
log_err("Failed to send packet.");
pthread_cleanup_pop(true);
@@ -595,30 +580,36 @@ static void * ipcp_udp_packet_writer(void * o)
return (void *) 1;
}
-static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
+static const char * inet4_ntop(const void * addr,
+ char * buf)
+{
+ return inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
+}
+
+static int udp_ipcp_bootstrap(const struct ipcp_config * conf)
{
char ipstr[INET_ADDRSTRLEN];
char dnsstr[INET_ADDRSTRLEN];
- char portstr[128]; /* port is max 64535 = 5 chars */
int i = 1;
assert(conf);
assert(conf->type == THIS_TYPE);
- if (inet_ntop(AF_INET, &conf->ip_addr, ipstr, INET_ADDRSTRLEN)
- == NULL) {
- log_err("Failed to convert IP address");
+ ipcpi.dir_hash_algo = HASH_MD5;
+ strcpy(ipcpi.layer_name, conf->layer_info.name);
+
+ if (inet4_ntop(&conf->udp.ip_addr, ipstr) == NULL) {
+ log_err("Failed to convert IP address.");
return -1;
}
- if (conf->dns_addr != 0) {
- if (inet_ntop(AF_INET, &conf->dns_addr, dnsstr, INET_ADDRSTRLEN)
- == NULL) {
- log_err("Failed to convert DNS address");
+ if (conf->udp.dns_addr != 0) {
+ if (inet4_ntop(&conf->udp.dns_addr, dnsstr) == NULL) {
+ log_err("Failed to convert DNS address.");
return -1;
}
#ifndef HAVE_DDNS
- log_warn("DNS disabled at compile time, address ignored");
+ log_warn("DNS disabled at compile time, address ignored.");
#endif
} else {
strcpy(dnsstr, "not set");
@@ -631,54 +622,48 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
goto fail_socket;
}
- if (setsockopt(udp_data.s_fd, SOL_SOCKET, SO_REUSEADDR,
- &i, sizeof(i)) < 0)
- log_warn("Failed to set SO_REUSEADDR.");
-
memset((char *) &udp_data.s_saddr, 0, sizeof(udp_data.s_saddr));
udp_data.s_saddr.sin_family = AF_INET;
- udp_data.s_saddr.sin_addr.s_addr = conf->ip_addr;
- udp_data.s_saddr.sin_port = htons(conf->srv_port);
+ udp_data.s_saddr.sin_addr.s_addr = conf->udp.ip_addr;
+ udp_data.s_saddr.sin_port = htons(conf->udp.port);
- if (bind(udp_data.s_fd, SERV_SADDR, SERV_SADDR_SIZE) < 0) {
- log_err("Couldn't bind to %s.", ipstr);
+ if (bind(udp_data.s_fd, SADDR, SADDR_SIZE) < 0) {
+ log_err("Couldn't bind to %s:%d. %s.",
+ ipstr, conf->udp.port, strerror(errno));
goto fail_bind;
}
- udp_data.dns_addr = conf->dns_addr;
- udp_data.clt_port = htons(conf->clt_port);
-
- ipcp_set_state(IPCP_OPERATIONAL);
+ udp_data.dns_addr = conf->udp.dns_addr;
if (pthread_create(&udp_data.mgmt_handler, NULL,
- ipcp_udp_mgmt_handler, NULL)) {
- ipcp_set_state(IPCP_INIT);
+ udp_ipcp_mgmt_handler, NULL)) {
+ log_err("Failed to create management thread.");
goto fail_bind;
}
for (i = 0; i < IPCP_UDP_RD_THR; ++i) {
if (pthread_create(&udp_data.packet_reader[i], NULL,
- ipcp_udp_packet_reader, NULL)) {
- ipcp_set_state(IPCP_INIT);
+ udp_ipcp_packet_reader, NULL)) {
+ log_err("Failed to create reader thread.");
goto fail_packet_reader;
}
}
for (i = 0; i < IPCP_UDP_WR_THR; ++i) {
if (pthread_create(&udp_data.packet_writer[i], NULL,
- ipcp_udp_packet_writer, NULL)) {
- ipcp_set_state(IPCP_INIT);
+ udp_ipcp_packet_writer, NULL)) {
+ log_err("Failed to create writer thread.");
goto fail_packet_writer;
}
}
- sprintf(portstr, "%d", conf->clt_port);
-
log_dbg("Bootstrapped IPCP over UDP with pid %d.", getpid());
log_dbg("Bound to IP address %s.", ipstr);
- log_dbg("Client port is %s.", conf->clt_port == 0 ? "random" : portstr);
- log_dbg("Server port is %u.", conf->srv_port);
- log_dbg("DNS server address is %s.", dnsstr);
+ log_dbg("Using port %u.", conf->udp.port);
+ if (conf->udp.dns_addr != 0)
+ log_dbg("DNS server address is %s.", dnsstr);
+ else
+ log_dbg("DNS server not in use.");
return 0;
@@ -706,20 +691,22 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
/* NOTE: Disgusted with this crap */
static int ddns_send(char * cmd)
{
- pid_t pid = -1;
+ pid_t pid;
int wstatus;
int pipe_fd[2];
char * argv[] = {NSUPDATE_EXEC, 0};
char * envp[] = {0};
if (pipe(pipe_fd)) {
- log_err("Failed to create pipe.");
+ log_err("Failed to create pipe: %s.", strerror(errno));
return -1;
}
pid = fork();
if (pid == -1) {
- log_err("Failed to fork.");
+ log_err("Failed to fork: %s.", strerror(errno));
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
return -1;
}
@@ -727,12 +714,15 @@ static int ddns_send(char * cmd)
close(pipe_fd[1]);
dup2(pipe_fd[0], 0);
execve(argv[0], &argv[0], envp);
+ log_err("Failed to execute: %s", strerror(errno));
+ exit(1);
}
close(pipe_fd[0]);
if (write(pipe_fd[1], cmd, strlen(cmd)) == -1) {
- log_err("Failed to communicate with nsupdate.");
+ log_err("Failed to communicate with nsupdate: %s.",
+ strerror(errno));
close(pipe_fd[1]);
return -1;
}
@@ -762,18 +752,20 @@ static uint32_t ddns_resolve(char * name,
char * addr_str = "Address:";
uint32_t ip_addr = 0;
- if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN) == NULL)
+ if (inet4_ntop(&dns_addr, dnsstr) == NULL)
return 0;
if (pipe(pipe_fd)) {
- log_err("Failed to create pipe.");
+ log_err("Failed to create pipe: %s.", strerror(errno));
return 0;
}
pid = fork();
if (pid == -1) {
- log_err("Failed to fork.");
- return 0;
+ log_err("Failed to fork: %s.", strerror(errno));
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ return -1;
}
if (pid == 0) {
@@ -783,11 +775,13 @@ static uint32_t ddns_resolve(char * name,
close(pipe_fd[0]);
dup2(pipe_fd[1], 1);
execve(argv[0], &argv[0], envp);
+ log_err("Failed to execute: %s", strerror(errno));
+ exit(1);
}
close(pipe_fd[1]);
- count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE);
+ count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE - 1);
if (count <= 0) {
log_err("Failed to communicate with nslookup.");
close(pipe_fd[0]);
@@ -798,7 +792,7 @@ static uint32_t ddns_resolve(char * name,
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0 &&
- count != IPCP_UDP_BUF_SIZE)
+ count != IPCP_UDP_BUF_SIZE - 1)
log_dbg("Succesfully communicated with nslookup.");
else
log_err("Failed to resolve DNS address.");
@@ -824,7 +818,7 @@ static uint32_t ddns_resolve(char * name,
}
#endif
-static int ipcp_udp_reg(const uint8_t * hash)
+static int udp_ipcp_reg(const uint8_t * hash)
{
#ifdef HAVE_DDNS
char ipstr[INET_ADDRSTRLEN];
@@ -836,16 +830,18 @@ static int ipcp_udp_reg(const uint8_t * hash)
char * hashstr;
hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL)
+ if (hashstr == NULL) {
+ log_err("Failed to malloc hashstr.");
return -1;
+ }
assert(hash);
ipcp_hash_str(hashstr, hash);
if (shim_data_reg_add_entry(udp_data.shim_data, hash)) {
- log_err("Failed to add " HASH_FMT " to local registry.",
- HASH_VAL(hash));
+ log_err("Failed to add " HASH_FMT32 " to local registry.",
+ HASH_VAL32(hash));
free(hashstr);
return -1;
}
@@ -858,14 +854,14 @@ static int ipcp_udp_reg(const uint8_t * hash)
if (dns_addr != 0) {
ip_addr = udp_data.s_saddr.sin_addr.s_addr;
- if (inet_ntop(AF_INET, &ip_addr,
- ipstr, INET_ADDRSTRLEN) == NULL) {
+ if (inet4_ntop(&ip_addr, ipstr) == NULL) {
+ log_err("Failed to convert IP address to string.");
free(hashstr);
return -1;
}
- if (inet_ntop(AF_INET, &dns_addr,
- dnsstr, INET_ADDRSTRLEN) == NULL) {
+ if (inet4_ntop(&dns_addr, dnsstr) == NULL) {
+ log_err("Failed to convert DNS address to string.");
free(hashstr);
return -1;
}
@@ -874,20 +870,19 @@ static int ipcp_udp_reg(const uint8_t * hash)
dnsstr, hashstr, DNS_TTL, ipstr);
if (ddns_send(cmd)) {
+ log_err("Failed to send DDNS message.");
shim_data_reg_del_entry(udp_data.shim_data, hash);
free(hashstr);
return -1;
}
}
#endif
- log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash));
-
free(hashstr);
return 0;
}
-static int ipcp_udp_unreg(const uint8_t * hash)
+static int udp_ipcp_unreg(const uint8_t * hash)
{
#ifdef HAVE_DDNS
char dnsstr[INET_ADDRSTRLEN];
@@ -900,8 +895,10 @@ static int ipcp_udp_unreg(const uint8_t * hash)
assert(hash);
hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL)
+ if (hashstr == NULL) {
+ log_err("Failed to malloc hashstr.");
return -1;
+ }
ipcp_hash_str(hashstr, hash);
@@ -911,8 +908,8 @@ static int ipcp_udp_unreg(const uint8_t * hash)
dns_addr = udp_data.dns_addr;
if (dns_addr != 0) {
- if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN)
- == NULL) {
+ if (inet4_ntop(&dns_addr, dnsstr) == NULL) {
+ log_err("Failed to convert DNS address to string.");
free(hashstr);
return -1;
}
@@ -925,14 +922,12 @@ static int ipcp_udp_unreg(const uint8_t * hash)
shim_data_reg_del_entry(udp_data.shim_data, hash);
- log_dbg("Unregistered " HASH_FMT ".", HASH_VAL(hash));
-
free(hashstr);
return 0;
}
-static int ipcp_udp_query(const uint8_t * hash)
+static int udp_ipcp_query(const uint8_t * hash)
{
uint32_t ip_addr = 0;
char * hashstr;
@@ -943,8 +938,10 @@ static int ipcp_udp_query(const uint8_t * hash)
assert(hash);
hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL)
+ if (hashstr == NULL) {
+ log_err("Failed to malloc hashstr.");
return -ENOMEM;
+ }
ipcp_hash_str(hashstr, hash);
@@ -959,7 +956,7 @@ static int ipcp_udp_query(const uint8_t * hash)
if (dns_addr != 0) {
ip_addr = ddns_resolve(hashstr, dns_addr);
if (ip_addr == 0) {
- log_dbg("Could not resolve %s.", hashstr);
+ log_err("Could not resolve %s.", hashstr);
free(hashstr);
return -1;
}
@@ -967,7 +964,7 @@ static int ipcp_udp_query(const uint8_t * hash)
#endif
h = gethostbyname(hashstr);
if (h == NULL) {
- log_dbg("Could not resolve %s.", hashstr);
+ log_err("Could not resolve %s.", hashstr);
free(hashstr);
return -1;
}
@@ -988,190 +985,116 @@ static int ipcp_udp_query(const uint8_t * hash)
return 0;
}
-static int ipcp_udp_flow_alloc(int fd,
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t len)
+static int udp_ipcp_flow_alloc(int fd,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
struct sockaddr_in r_saddr; /* Server address */
- struct sockaddr_in c_saddr; /* Client address */
- socklen_t c_saddr_len;
- int skfd;
uint32_t ip_addr = 0;
- char ip_str[INET_ADDRSTRLEN];
-
- c_saddr_len = sizeof(c_saddr);
-
- log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(dst));
+ char ipstr[INET_ADDRSTRLEN];
(void) qs;
assert(dst);
- skfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (skfd < 0) {
- log_err("Could not create socket.");
- return -1;
- }
-
- /* This socket is for the flow. */
- memset((char *) &c_saddr, 0, sizeof(c_saddr));
- c_saddr.sin_family = AF_INET;
- c_saddr.sin_addr.s_addr = LOCAL_IP;
- c_saddr.sin_port = udp_data.clt_port;
-
- if (bind(skfd, (struct sockaddr *) &c_saddr, sizeof(c_saddr)) < 0) {
- log_dbg("Could not bind socket to client address.");
- close(skfd);
+ if (!shim_data_dir_has(udp_data.shim_data, dst)) {
+ log_err("Could not resolve destination.");
return -1;
}
- if (getsockname(skfd, (struct sockaddr *) &c_saddr, &c_saddr_len) < 0) {
- log_err("Could not get address from fd.");
- close(skfd);
- return -1;
- }
+ ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst);
- if (!shim_data_dir_has(udp_data.shim_data, dst)) {
- log_dbg("Could not resolve destination.");
- close(skfd);
+ if (inet4_ntop(&ip_addr, ipstr) == NULL) {
+ log_err("Could not convert IP address.");
return -1;
}
- ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst);
-
- inet_ntop(AF_INET, &ip_addr, ip_str, INET_ADDRSTRLEN);
- log_dbg("Destination UDP ipcp resolved at %s.", ip_str);
+ log_dbg("Destination " HASH_FMT32 " resolved at IP %s.",
+ HASH_VAL32(dst), ipstr);
- /* Connect to server and store the remote IP address in the skfd. */
memset((char *) &r_saddr, 0, sizeof(r_saddr));
r_saddr.sin_family = AF_INET;
r_saddr.sin_addr.s_addr = ip_addr;
r_saddr.sin_port = udp_data.s_saddr.sin_port;
- if (connect(skfd, (struct sockaddr *) &r_saddr, sizeof(r_saddr)) < 0) {
- log_dbg("Could not connect socket to remote.");
- close(skfd);
- return -1;
- }
-
- if (ipcp_udp_port_alloc(skfd, fd, dst, qs, data, len) < 0) {
+ if (udp_ipcp_port_alloc(&r_saddr, fd, dst, qs, data) < 0) {
log_err("Could not allocate port.");
- close(skfd);
return -1;
}
pthread_rwlock_wrlock(&udp_data.flows_lock);
- udp_data.fd_to_uf[fd].d_eid = -1;
- udp_data.fd_to_uf[fd].skfd = skfd;
-
- fset_add(udp_data.np1_flows, fd);
+ udp_data.fd_to_uf[fd].d_eid = -1;
+ udp_data.fd_to_uf[fd].r_saddr = r_saddr;
pthread_rwlock_unlock(&udp_data.flows_lock);
- log_dbg("Flow pending on fd %d, UDP src port %d, dst port %d.",
- fd, ntohs(c_saddr.sin_port), ntohs(r_saddr.sin_port));
+ fset_add(udp_data.np1_flows, fd);
return 0;
}
-static int ipcp_udp_flow_alloc_resp(int fd,
- int resp,
- const void * data,
- size_t len)
+static int udp_ipcp_flow_alloc_resp(int fd,
+ int resp,
+ const buffer_t * data)
{
- struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000};
- struct timespec abstime;
- int skfd;
- int d_eid;
-
- if (resp)
- return 0;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
+ struct sockaddr_in saddr;
+ int d_eid;
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ if (ipcp_wait_flow_resp(fd) < 0) {
+ log_err("Failed to wait for flow response.");
return -1;
}
- ipcpi.alloc_id = -1;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
pthread_rwlock_rdlock(&udp_data.flows_lock);
- skfd = udp_data.fd_to_uf[fd].skfd;
+ saddr = udp_data.fd_to_uf[fd].r_saddr;
d_eid = udp_data.fd_to_uf[fd].d_eid;
- fset_add(udp_data.np1_flows, fd);
-
pthread_rwlock_unlock(&udp_data.flows_lock);
- if (ipcp_udp_port_alloc_resp(skfd, d_eid, fd, resp, data, len) < 0) {
- pthread_rwlock_rdlock(&udp_data.flows_lock);
+ if (udp_ipcp_port_alloc_resp(&saddr, d_eid, fd, resp, data) < 0) {
fset_del(udp_data.np1_flows, fd);
- pthread_rwlock_unlock(&udp_data.flows_lock);
log_err("Failed to respond to flow request.");
return -1;
}
- log_dbg("Accepted flow, fd %d on eid %d.",
- fd, d_eid);
+ fset_add(udp_data.np1_flows, fd);
return 0;
}
-static int ipcp_udp_flow_dealloc(int fd)
+static int udp_ipcp_flow_dealloc(int fd)
{
- int skfd = -1;
-
ipcp_flow_fini(fd);
- pthread_rwlock_wrlock(&udp_data.flows_lock);
-
fset_del(udp_data.np1_flows, fd);
- skfd = udp_data.fd_to_uf[fd].skfd;
+ pthread_rwlock_wrlock(&udp_data.flows_lock);
udp_data.fd_to_uf[fd].d_eid = -1;
- udp_data.fd_to_uf[fd].skfd = -1;
-
- close(skfd);
+ memset(&udp_data.fd_to_uf[fd].r_saddr, 0, SADDR_SIZE);
pthread_rwlock_unlock(&udp_data.flows_lock);
- flow_dealloc(fd);
-
- log_dbg("Flow with fd %d deallocated.", fd);
+ ipcp_flow_dealloc(fd);
return 0;
}
static struct ipcp_ops udp_ops = {
- .ipcp_bootstrap = ipcp_udp_bootstrap,
+ .ipcp_bootstrap = udp_ipcp_bootstrap,
.ipcp_enroll = NULL,
.ipcp_connect = NULL,
.ipcp_disconnect = NULL,
- .ipcp_reg = ipcp_udp_reg,
- .ipcp_unreg = ipcp_udp_unreg,
- .ipcp_query = ipcp_udp_query,
- .ipcp_flow_alloc = ipcp_udp_flow_alloc,
+ .ipcp_reg = udp_ipcp_reg,
+ .ipcp_unreg = udp_ipcp_unreg,
+ .ipcp_query = udp_ipcp_query,
+ .ipcp_flow_alloc = udp_ipcp_flow_alloc,
.ipcp_flow_join = NULL,
- .ipcp_flow_alloc_resp = ipcp_udp_flow_alloc_resp,
- .ipcp_flow_dealloc = ipcp_udp_flow_dealloc
+ .ipcp_flow_alloc_resp = udp_ipcp_flow_alloc_resp,
+ .ipcp_flow_dealloc = udp_ipcp_flow_dealloc
};
int main(int argc,
@@ -1179,53 +1102,51 @@ int main(int argc,
{
int i;
- if (ipcp_init(argc, argv, &udp_ops) < 0)
- goto fail_init;
if (udp_data_init() < 0) {
log_err("Failed to init udp data.");
goto fail_data_init;
}
- if (ipcp_boot() < 0) {
- log_err("Failed to boot IPCP.");
- goto fail_boot;
+ if (ipcp_init(argc, argv, &udp_ops, THIS_TYPE) < 0) {
+ log_err("Failed to initialize IPCP.");
+ goto fail_init;
}
- if (ipcp_create_r(0)) {
- log_err("Failed to notify IRMd we are initialized.");
- goto fail_create_r;
+ if (ipcp_start() < 0) {
+ log_err("Failed to start IPCP.");
+ goto fail_start;
}
- ipcp_shutdown();
+ ipcp_sigwait();
if (ipcp_get_state() == IPCP_SHUTDOWN) {
- for (i = 0; i < IPCP_UDP_RD_THR; ++i)
- pthread_cancel(udp_data.packet_reader[i]);
for (i = 0; i < IPCP_UDP_WR_THR; ++i)
pthread_cancel(udp_data.packet_writer[i]);
+ for (i = 0; i < IPCP_UDP_RD_THR; ++i)
+ pthread_cancel(udp_data.packet_reader[i]);
pthread_cancel(udp_data.mgmt_handler);
- for (i = 0; i < IPCP_UDP_RD_THR; ++i)
- pthread_join(udp_data.packet_reader[i], NULL);
for (i = 0; i < IPCP_UDP_WR_THR; ++i)
pthread_join(udp_data.packet_writer[i], NULL);
+ for (i = 0; i < IPCP_UDP_RD_THR; ++i)
+ pthread_join(udp_data.packet_reader[i], NULL);
pthread_join(udp_data.mgmt_handler, NULL);
+ close(udp_data.s_fd);
}
- udp_data_fini();
+ ipcp_stop();
ipcp_fini();
- exit(EXIT_SUCCESS);
- fail_create_r:
- ipcp_set_state(IPCP_NULL);
- ipcp_shutdown();
- fail_boot:
udp_data_fini();
- fail_data_init:
+
+ exit(EXIT_SUCCESS);
+
+ fail_start:
ipcp_fini();
fail_init:
- ipcp_create_r(-1);
+ udp_data_fini();
+ fail_data_init:
exit(EXIT_FAILURE);
}
diff --git a/src/ipcpd/unicast/CMakeLists.txt b/src/ipcpd/unicast/CMakeLists.txt
index c0c55519..ca742871 100644
--- a/src/ipcpd/unicast/CMakeLists.txt
+++ b/src/ipcpd/unicast/CMakeLists.txt
@@ -13,8 +13,10 @@ include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
set(IPCP_UNICAST_TARGET ipcpd-unicast CACHE INTERNAL "")
+set(IPCP_UNICAST_MPL 60 CACHE STRING
+ "Default maximum packet lifetime for the unicast IPCP, in seconds")
-protobuf_generate_c(KAD_PROTO_SRCS KAD_PROTO_HDRS kademlia.proto)
+protobuf_generate_c(DHT_PROTO_SRCS DHT_PROTO_HDRS dir/dht.proto)
math(EXPR PFT_EXPR "1 << 12")
set(PFT_SIZE ${PFT_EXPR} CACHE STRING
@@ -29,32 +31,33 @@ if (HAVE_FUSE)
endif ()
endif ()
-
set(SOURCE_FILES
# Add source files here
- addr_auth.c
+ addr-auth.c
+ ca.c
connmgr.c
- dht.c
dir.c
dt.c
- enroll.c
fa.c
main.c
pff.c
routing.c
psched.c
# Add policies last
- pol/pft.c
- pol/flat.c
- pol/link_state.c
- pol/graph.c
- pol/simple_pff.c
- pol/alternate_pff.c
- pol/multipath_pff.c
+ addr-auth/flat.c
+ ca/mb-ecn.c
+ ca/nop.c
+ dir/dht.c
+ pff/simple.c
+ pff/alternate.c
+ pff/multipath.c
+ pff/pft.c
+ routing/link-state.c
+ routing/graph.c
)
-add_executable(ipcpd-unicast ${SOURCE_FILES} ${IPCP_SOURCES}
- ${KAD_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS})
+add_executable(ipcpd-unicast ${SOURCE_FILES} ${IPCP_SOURCES} ${COMMON_SOURCES}
+ ${DHT_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS})
target_link_libraries(ipcpd-unicast LINK_PUBLIC ouroboros-dev)
include(AddCompileFlags)
@@ -64,8 +67,9 @@ endif ()
install(TARGETS ipcpd-unicast RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
-add_subdirectory(pol/tests)
+add_subdirectory(pff/tests)
+add_subdirectory(routing/tests)
if (NOT GNU)
- add_subdirectory(tests)
+ add_subdirectory(dir/tests)
endif ()
diff --git a/src/ipcpd/unicast/addr_auth.c b/src/ipcpd/unicast/addr-auth.c
index e82ea254..908a4aa1 100644
--- a/src/ipcpd/unicast/addr_auth.c
+++ b/src/ipcpd/unicast/addr-auth.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Address authority
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,13 +24,12 @@
#include <ouroboros/logs.h>
-#include "addr_auth.h"
-#include "pol-addr-auth-ops.h"
-#include "pol/flat.h"
+#include "addr-auth.h"
+#include "addr-auth/pol.h"
#include <stdlib.h>
-struct pol_addr_auth_ops * ops;
+struct addr_auth_ops * ops;
int addr_auth_init(enum pol_addr_auth type,
const void * info)
diff --git a/src/ipcpd/unicast/addr_auth.h b/src/ipcpd/unicast/addr-auth.h
index 6bedf420..e119dff3 100644
--- a/src/ipcpd/unicast/addr_auth.h
+++ b/src/ipcpd/unicast/addr-auth.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Address authority
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/unicast/pol/flat.c b/src/ipcpd/unicast/addr-auth/flat.c
index 6e5c96ab..c4562935 100644
--- a/src/ipcpd/unicast/pol/flat.c
+++ b/src/ipcpd/unicast/addr-auth/flat.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Policy for flat addresses in a distributed way
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -29,19 +29,11 @@
#define OUROBOROS_PREFIX "flat-addr-auth"
#include <ouroboros/logs.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/time_utils.h>
-#include <ouroboros/utils.h>
+#include <ouroboros/random.h>
#include "ipcp.h"
#include "flat.h"
-#include <time.h>
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
-#include <assert.h>
-
#define NAME_LEN 8
struct {
@@ -50,7 +42,7 @@ struct {
#define INVALID_ADDRESS 0
-struct pol_addr_auth_ops flat_ops = {
+struct addr_auth_ops flat_ops = {
.init = flat_init,
.fini = flat_fini,
.address = flat_address
@@ -75,13 +67,13 @@ int flat_fini(void)
uint64_t flat_address(void)
{
- struct timespec t;
- uint32_t addr;
-
- clock_gettime(CLOCK_REALTIME, &t);
- srand(t.tv_nsec);
-
- addr = (rand() % (RAND_MAX - 1) + 1) & 0xFFFFFFFF;
+ uint32_t addr = INVALID_ADDRESS;
+#if defined (CONFIG_OUROBOROS_DEBUG) && defined (IPCP_DEBUG_LOCAL)
+ addr = getpid();
+#else
+ while (addr == INVALID_ADDRESS)
+ random_buffer(&addr,sizeof(addr));
+#endif
return addr;
}
diff --git a/src/ipcpd/unicast/pol/flat.h b/src/ipcpd/unicast/addr-auth/flat.h
index 54460bb3..d4b672c7 100644
--- a/src/ipcpd/unicast/pol/flat.h
+++ b/src/ipcpd/unicast/addr-auth/flat.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Policy for flat addresses in a distributed way
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,7 +23,7 @@
#ifndef OUROBOROS_IPCPD_UNICAST_FLAT_H
#define OUROBOROS_IPCPD_UNICAST_FLAT_H
-#include "pol-addr-auth-ops.h"
+#include "ops.h"
int flat_init(const void * info);
@@ -31,6 +31,6 @@ int flat_fini(void);
uint64_t flat_address(void);
-struct pol_addr_auth_ops flat_ops;
+extern struct addr_auth_ops flat_ops;
#endif /* OUROBOROS_IPCPD_UNICAST_FLAT_H */
diff --git a/src/ipcpd/unicast/pol-addr-auth-ops.h b/src/ipcpd/unicast/addr-auth/ops.h
index 1096eecb..06b24cec 100644
--- a/src/ipcpd/unicast/pol-addr-auth-ops.h
+++ b/src/ipcpd/unicast/addr-auth/ops.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Address authority policy ops
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,10 +20,10 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_IPCPD_UNICAST_POL_ADDR_AUTH_OPS_H
-#define OUROBOROS_IPCPD_UNICAST_POL_ADDR_AUTH_OPS_H
+#ifndef OUROBOROS_IPCPD_UNICAST_ADDR_AUTH_OPS_H
+#define OUROBOROS_IPCPD_UNICAST_ADDR_AUTH_OPS_H
-struct pol_addr_auth_ops {
+struct addr_auth_ops {
int (* init)(const void * info);
int (* fini)(void);
@@ -31,4 +31,4 @@ struct pol_addr_auth_ops {
uint64_t (* address)(void);
};
-#endif /* OUROBOROS_IPCPD_UNICAST_POL_ADDR_AUTH_OPS_H */
+#endif /* OUROBOROS_IPCPD_UNICAST_ADDR_AUTH_OPS_H */
diff --git a/src/ipcpd/unicast/addr-auth/pol.h b/src/ipcpd/unicast/addr-auth/pol.h
new file mode 100644
index 00000000..844308c6
--- /dev/null
+++ b/src/ipcpd/unicast/addr-auth/pol.h
@@ -0,0 +1,23 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Address Authority policies
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "flat.h"
diff --git a/src/ipcpd/unicast/ca.c b/src/ipcpd/unicast/ca.c
new file mode 100644
index 00000000..287eaf41
--- /dev/null
+++ b/src/ipcpd/unicast/ca.c
@@ -0,0 +1,109 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Congestion Avoidance
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define OUROBOROS_PREFIX "ca"
+
+#include <ouroboros/logs.h>
+
+#include "ca.h"
+#include "ca/pol.h"
+
+struct {
+ struct ca_ops * ops;
+} ca;
+
+int ca_init(enum pol_cong_avoid pol)
+{
+ switch(pol) {
+ case CA_NONE:
+ log_dbg("Disabling congestion control.");
+ ca.ops = &nop_ca_ops;
+ break;
+ case CA_MB_ECN:
+ log_dbg("Using multi-bit ECN.");
+ ca.ops = &mb_ecn_ca_ops;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void ca_fini(void)
+{
+ ca.ops = NULL;
+}
+
+void * ca_ctx_create(void)
+{
+ return ca.ops->ctx_create();
+}
+
+void ca_ctx_destroy(void * ctx)
+{
+ return ca.ops->ctx_destroy(ctx);
+}
+
+ca_wnd_t ca_ctx_update_snd(void * ctx,
+ size_t len)
+{
+ return ca.ops->ctx_update_snd(ctx, len);
+}
+
+bool ca_ctx_update_rcv(void * ctx,
+ size_t len,
+ uint8_t ecn,
+ uint16_t * ece)
+{
+ return ca.ops->ctx_update_rcv(ctx, len, ecn, ece);
+}
+
+void ca_ctx_update_ece(void * ctx,
+ uint16_t ece)
+{
+ return ca.ops->ctx_update_ece(ctx, ece);
+}
+
+void ca_wnd_wait(ca_wnd_t wnd)
+{
+ return ca.ops->wnd_wait(wnd);
+}
+
+int ca_calc_ecn(int fd,
+ uint8_t * ecn,
+ qoscube_t qc,
+ size_t len)
+{
+ return ca.ops->calc_ecn(fd, ecn, qc, len);
+}
+
+ssize_t ca_print_stats(void * ctx,
+ char * buf,
+ size_t len)
+{
+ if (ca.ops->print_stats == NULL)
+ return 0;
+
+ return ca.ops->print_stats(ctx, buf, len);
+}
diff --git a/src/ipcpd/unicast/ca.h b/src/ipcpd/unicast/ca.h
new file mode 100644
index 00000000..ea803e17
--- /dev/null
+++ b/src/ipcpd/unicast/ca.h
@@ -0,0 +1,68 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Congestion avoidance
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IPCPD_UNICAST_CA_H
+#define OUROBOROS_IPCPD_UNICAST_CA_H
+
+#include <ouroboros/ipcp.h>
+#include <ouroboros/qoscube.h>
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+typedef union {
+ time_t wait;
+} ca_wnd_t;
+
+int ca_init(enum pol_cong_avoid ca);
+
+void ca_fini(void);
+
+
+/* OPS */
+void * ca_ctx_create(void);
+
+void ca_ctx_destroy(void * ctx);
+
+ca_wnd_t ca_ctx_update_snd(void * ctx,
+ size_t len);
+
+bool ca_ctx_update_rcv(void * ctx,
+ size_t len,
+ uint8_t ecn,
+ uint16_t * ece);
+
+void ca_ctx_update_ece(void * ctx,
+ uint16_t ece);
+
+void ca_wnd_wait(ca_wnd_t wnd);
+
+int ca_calc_ecn(int fd,
+ uint8_t * ecn,
+ qoscube_t qc,
+ size_t len);
+
+ssize_t ca_print_stats(void * ctx,
+ char * buf,
+ size_t len);
+
+#endif /* OUROBOROS_IPCPD_UNICAST_CA_H */
diff --git a/src/ipcpd/unicast/ca/mb-ecn.c b/src/ipcpd/unicast/ca/mb-ecn.c
new file mode 100644
index 00000000..d9a204b0
--- /dev/null
+++ b/src/ipcpd/unicast/ca/mb-ecn.c
@@ -0,0 +1,296 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Multi-bit ECN Congestion Avoidance
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#if defined(__linux__) || defined(__CYGWIN__)
+#define _DEFAULT_SOURCE
+#else
+#define _POSIX_C_SOURCE 200809L
+#endif
+
+#include "config.h"
+
+#include <ouroboros/ipcp-dev.h>
+#include <ouroboros/time.h>
+
+#include "mb-ecn.h"
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+/* congestion avoidance constants */
+#define CA_SHFT 5 /* Average over 32 pkts */
+#define CA_WND (1 << CA_SHFT) /* 32 pkts receiver wnd */
+#define CA_UPD (1 << (CA_SHFT - 2)) /* Update snd every 8 pkt */
+#define CA_SLOT 24 /* Initial slot = 16 ms */
+#define CA_INC 1UL << 16 /* ~4MiB/s^2 additive inc */
+#define CA_IWL 1UL << 16 /* Initial limit ~4MiB/s */
+#define CA_MINPS 8 /* Mimimum pkts / slot */
+#define CA_MAXPS 64 /* Maximum pkts / slot */
+#define ECN_Q_SHFT 4
+#define ts_to_ns(ts) ((size_t) ts.tv_sec * BILLION + ts.tv_nsec)
+
+struct mb_ecn_ctx {
+ uint16_t rx_ece; /* Level of congestion (upstream) */
+ size_t rx_ctr; /* Receiver side packet counter */
+
+ uint16_t tx_ece; /* Level of congestion (downstream) */
+ size_t tx_ctr; /* Sender side packet counter */
+ size_t tx_wbc; /* Window byte count */
+ size_t tx_wpc; /* Window packet count */
+ size_t tx_wbl; /* Window byte limit */
+ bool tx_cav; /* Congestion avoidance */
+ size_t tx_mul; /* Slot size multiplier */
+ size_t tx_inc; /* Additive increase */
+ size_t tx_slot;
+};
+
+struct ca_ops mb_ecn_ca_ops = {
+ .ctx_create = mb_ecn_ctx_create,
+ .ctx_destroy = mb_ecn_ctx_destroy,
+ .ctx_update_snd = mb_ecn_ctx_update_snd,
+ .ctx_update_rcv = mb_ecn_ctx_update_rcv,
+ .ctx_update_ece = mb_ecn_ctx_update_ece,
+ .wnd_wait = mb_ecn_wnd_wait,
+ .calc_ecn = mb_ecn_calc_ecn,
+ .print_stats = mb_ecn_print_stats
+};
+
+void * mb_ecn_ctx_create(void)
+{
+ struct timespec now;
+ struct mb_ecn_ctx * ctx;
+
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->tx_mul = CA_SLOT;
+ ctx->tx_wbl = CA_IWL;
+ ctx->tx_inc = CA_INC;
+ ctx->tx_slot = ts_to_ns(now) >> ctx->tx_mul;
+
+ return (void *) ctx;
+}
+
+void mb_ecn_ctx_destroy(void * ctx)
+{
+ free(ctx);
+}
+
+#define _slot_after(new, old) ((int64_t) (old - new) < 0)
+
+ca_wnd_t mb_ecn_ctx_update_snd(void * _ctx,
+ size_t len)
+{
+ struct timespec now;
+ size_t slot;
+ ca_wnd_t wnd;
+ struct mb_ecn_ctx * ctx = _ctx;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ slot = ts_to_ns(now) >> ctx->tx_mul;
+
+ ctx->tx_ctr++;
+ ctx->tx_wpc++;
+ ctx->tx_wbc += len;
+
+ if (ctx->tx_ctr > CA_WND)
+ ctx->tx_ece = 0;
+
+ if (_slot_after(slot, ctx->tx_slot)) {
+ bool carry = false; /* may carry over if window increases */
+
+ ctx->tx_slot = slot;
+
+ if (!ctx->tx_cav) { /* Slow start */
+ if (ctx->tx_wbc > ctx->tx_wbl)
+ ctx->tx_wbl <<= 1;
+ } else {
+ if (ctx->tx_ece) /* Mult. Decrease */
+ ctx->tx_wbl -= (ctx->tx_wbl * ctx->tx_ece)
+ >> (CA_SHFT + 8);
+ else /* Add. Increase */
+ ctx->tx_wbl = ctx->tx_wbc + ctx->tx_inc;
+ }
+
+ /* Window scaling */
+ if (ctx->tx_wpc < CA_MINPS) {
+ size_t fact = 0; /* factor to scale the window up */
+ size_t pkts = ctx->tx_wpc;
+ while (pkts < CA_MINPS) {
+ pkts <<= 1;
+ fact++;
+ }
+ ctx->tx_mul += fact;
+ ctx->tx_slot >>= fact;
+ if ((ctx->tx_slot & ((1 << fact) - 1)) == 0) {
+ carry = true;
+ ctx->tx_slot += 1;
+ }
+ ctx->tx_wbl <<= fact;
+ ctx->tx_inc <<= fact;
+ } else if (ctx->tx_wpc > CA_MAXPS) {
+ size_t fact = 0; /* factor to scale the window down */
+ size_t pkts = ctx->tx_wpc;
+ while (pkts > CA_MAXPS) {
+ pkts >>= 1;
+ fact++;
+ }
+ ctx->tx_mul -= fact;
+ ctx->tx_slot <<= fact;
+ ctx->tx_wbl >>= fact;
+ ctx->tx_inc >>= fact;
+ } else {
+ ctx->tx_slot = slot;
+ }
+
+ if (!carry) {
+ ctx->tx_wbc = 0;
+ ctx->tx_wpc = 0;
+ }
+ }
+
+ if (ctx->tx_wbc > ctx->tx_wbl)
+ wnd.wait = ((ctx->tx_slot + 1) << ctx->tx_mul) - ts_to_ns(now);
+ else
+ wnd.wait = 0;
+
+ return wnd;
+}
+
+void mb_ecn_wnd_wait(ca_wnd_t wnd)
+{
+ if (wnd.wait > 0) {
+ struct timespec s = TIMESPEC_INIT_S(0);
+ if (wnd.wait > BILLION) /* Don't care throttling < 1s */
+ s.tv_sec = 1;
+ else
+ s.tv_nsec = wnd.wait;
+
+ nanosleep(&s, NULL);
+ }
+}
+
+bool mb_ecn_ctx_update_rcv(void * _ctx,
+ size_t len,
+ uint8_t ecn,
+ uint16_t * ece)
+{
+ struct mb_ecn_ctx* ctx = _ctx;
+ bool update;
+
+ (void) len;
+
+ if ((ctx->rx_ece | ecn) == 0)
+ return false;
+
+ if (ecn == 0) { /* End of congestion */
+ ctx->rx_ece >>= 2;
+ update = ctx->rx_ece == 0;
+ } else {
+ if (ctx->rx_ece == 0) { /* Start of congestion */
+ ctx->rx_ece = ecn;
+ ctx->rx_ctr = 0;
+ update = true;
+ } else { /* Congestion update */
+ ctx->rx_ece -= ctx->rx_ece >> CA_SHFT;
+ ctx->rx_ece += ecn;
+ update = (ctx->rx_ctr++ & (CA_UPD - 1)) == true;
+ }
+ }
+
+ *ece = ctx->rx_ece;
+
+ return update;
+}
+
+
+void mb_ecn_ctx_update_ece(void * _ctx,
+ uint16_t ece)
+{
+ struct mb_ecn_ctx* ctx = _ctx;
+
+ ctx->tx_ece = ece;
+ ctx->tx_ctr = 0;
+ ctx->tx_cav = true;
+}
+
+int mb_ecn_calc_ecn(int fd,
+ uint8_t * ecn,
+ qoscube_t qc,
+ size_t len)
+{
+ size_t q;
+
+ (void) len;
+ (void) qc;
+
+ q = ipcp_flow_queued(fd);
+
+ *ecn |= (uint8_t) (q >> ECN_Q_SHFT);
+
+ return 0;
+}
+
+ssize_t mb_ecn_print_stats(void * _ctx,
+ char * buf,
+ size_t len)
+{
+ struct mb_ecn_ctx* ctx = _ctx;
+ char * regime;
+
+ if (len < 1024)
+ return 0;
+
+ if (!ctx->tx_cav)
+ regime = "Slow start";
+ else if (ctx->tx_ece)
+ regime = "Multiplicative dec";
+ else
+ regime = "Additive inc";
+
+ sprintf(buf,
+ "Congestion avoidance algorithm: %20s\n"
+ "Upstream congestion level: %20u\n"
+ "Upstream packet counter: %20zu\n"
+ "Downstream congestion level: %20u\n"
+ "Downstream packet counter: %20zu\n"
+ "Congestion window size (ns): %20" PRIu64 "\n"
+ "Packets in this window: %20zu\n"
+ "Bytes in this window: %20zu\n"
+ "Max bytes in this window: %20zu\n"
+ "Current congestion regime: %20s\n",
+ "Multi-bit ECN",
+ ctx->tx_ece, ctx->tx_ctr,
+ ctx->rx_ece, ctx->rx_ctr, (uint64_t) (1ULL << ctx->tx_mul),
+ ctx->tx_wpc, ctx->tx_wbc, ctx->tx_wbl,
+ regime);
+
+ return strlen(buf);
+}
diff --git a/src/ipcpd/unicast/ca/mb-ecn.h b/src/ipcpd/unicast/ca/mb-ecn.h
new file mode 100644
index 00000000..9a2c8b49
--- /dev/null
+++ b/src/ipcpd/unicast/ca/mb-ecn.h
@@ -0,0 +1,56 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Multi-bit ECN Congestion Avoidance
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IPCPD_UNICAST_CA_MB_ECN_H
+#define OUROBOROS_IPCPD_UNICAST_CA_MB_ECN_H
+
+#include "ops.h"
+
+void * mb_ecn_ctx_create(void);
+
+void mb_ecn_ctx_destroy(void * ctx);
+
+ca_wnd_t mb_ecn_ctx_update_snd(void * ctx,
+ size_t len);
+
+bool mb_ecn_ctx_update_rcv(void * ctx,
+ size_t len,
+ uint8_t ecn,
+ uint16_t * ece);
+
+void mb_ecn_ctx_update_ece(void * ctx,
+ uint16_t ece);
+
+void mb_ecn_wnd_wait(ca_wnd_t wnd);
+
+int mb_ecn_calc_ecn(int fd,
+ uint8_t * ecn,
+ qoscube_t qc,
+ size_t len);
+
+ssize_t mb_ecn_print_stats(void * ctx,
+ char * buf,
+ size_t len);
+
+extern struct ca_ops mb_ecn_ca_ops;
+
+#endif /* OUROBOROS_IPCPD_UNICAST_CA_MB_ECN_H */
diff --git a/src/ipcpd/unicast/ca/nop.c b/src/ipcpd/unicast/ca/nop.c
new file mode 100644
index 00000000..617fc15b
--- /dev/null
+++ b/src/ipcpd/unicast/ca/nop.c
@@ -0,0 +1,98 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Dummy Congestion Avoidance
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "nop.h"
+
+#include <string.h>
+
+struct ca_ops nop_ca_ops = {
+ .ctx_create = nop_ctx_create,
+ .ctx_destroy = nop_ctx_destroy,
+ .ctx_update_snd = nop_ctx_update_snd,
+ .ctx_update_rcv = nop_ctx_update_rcv,
+ .ctx_update_ece = nop_ctx_update_ece,
+ .wnd_wait = nop_wnd_wait,
+ .calc_ecn = nop_calc_ecn,
+ .print_stats = NULL
+};
+
+void * nop_ctx_create(void)
+{
+ return (void *) 1;
+}
+
+void nop_ctx_destroy(void * ctx)
+{
+ (void) ctx;
+}
+
+ca_wnd_t nop_ctx_update_snd(void * ctx,
+ size_t len)
+{
+ ca_wnd_t wnd;
+
+ (void) ctx;
+ (void) len;
+
+ memset(&wnd, 0, sizeof(wnd));
+
+ return wnd;
+}
+
+void nop_wnd_wait(ca_wnd_t wnd)
+{
+ (void) wnd;
+}
+
+bool nop_ctx_update_rcv(void * ctx,
+ size_t len,
+ uint8_t ecn,
+ uint16_t * ece)
+{
+ (void) ctx;
+ (void) len;
+ (void) ecn;
+ (void) ece;
+
+ return false;
+}
+
+void nop_ctx_update_ece(void * ctx,
+ uint16_t ece)
+{
+ (void) ctx;
+ (void) ece;
+}
+
+
+int nop_calc_ecn(int fd,
+ uint8_t * ecn,
+ qoscube_t qc,
+ size_t len)
+{
+ (void) fd;
+ (void) len;
+ (void) ecn;
+ (void) qc;
+
+ return 0;
+}
diff --git a/src/ipcpd/unicast/ca/nop.h b/src/ipcpd/unicast/ca/nop.h
new file mode 100644
index 00000000..248b198d
--- /dev/null
+++ b/src/ipcpd/unicast/ca/nop.h
@@ -0,0 +1,52 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Dummy Congestion Avoidance
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IPCPD_UNICAST_CA_NOP_H
+#define OUROBOROS_IPCPD_UNICAST_CA_NOP_H
+
+#include "ops.h"
+
+void * nop_ctx_create(void);
+
+void nop_ctx_destroy(void * ctx);
+
+ca_wnd_t nop_ctx_update_snd(void * ctx,
+ size_t len);
+
+bool nop_ctx_update_rcv(void * ctx,
+ size_t len,
+ uint8_t ecn,
+ uint16_t * ece);
+
+void nop_ctx_update_ece(void * ctx,
+ uint16_t ece);
+
+void nop_wnd_wait(ca_wnd_t wnd);
+
+int nop_calc_ecn(int fd,
+ uint8_t * ecn,
+ qoscube_t qc,
+ size_t len);
+
+extern struct ca_ops nop_ca_ops;
+
+#endif /* OUROBOROS_IPCPD_UNICAST_CA_NOP_H */
diff --git a/src/ipcpd/unicast/ca/ops.h b/src/ipcpd/unicast/ca/ops.h
new file mode 100644
index 00000000..3a7b7248
--- /dev/null
+++ b/src/ipcpd/unicast/ca/ops.h
@@ -0,0 +1,58 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Congestion avoidance policy ops
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IPCPD_UNICAST_CA_OPS_H
+#define OUROBOROS_IPCPD_UNICAST_CA_OPS_H
+
+#include "ca.h"
+
+struct ca_ops {
+ void * (* ctx_create)(void);
+
+ void (* ctx_destroy)(void * ctx);
+
+ ca_wnd_t (* ctx_update_snd)(void * ctx,
+ size_t len);
+
+ bool (* ctx_update_rcv)(void * ctx,
+ size_t len,
+ uint8_t ecn,
+ uint16_t * ece);
+
+ void (* ctx_update_ece)(void * ctx,
+ uint16_t ece);
+
+ void (* wnd_wait)(ca_wnd_t wnd);
+
+ int (* calc_ecn)(int fd,
+ uint8_t * ecn,
+ qoscube_t qc,
+ size_t len);
+
+ /* Optional, can be NULL */
+ ssize_t (* print_stats)(void * ctx,
+ char * buf,
+ size_t len);
+
+};
+
+#endif /* OUROBOROS_IPCPD_UNICAST_CA_OPS_H */
diff --git a/src/ipcpd/unicast/ca/pol.h b/src/ipcpd/unicast/ca/pol.h
new file mode 100644
index 00000000..db0a1a11
--- /dev/null
+++ b/src/ipcpd/unicast/ca/pol.h
@@ -0,0 +1,24 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Congestion avoidance policies
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "mb-ecn.h"
+#include "nop.h"
diff --git a/src/ipcpd/unicast/connmgr.c b/src/ipcpd/unicast/connmgr.c
index 3ebef7f9..11c5d5b6 100644
--- a/src/ipcpd/unicast/connmgr.c
+++ b/src/ipcpd/unicast/connmgr.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Handles connections between components
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,506 +20,20 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
+#include "config.h"
+
#if defined(__linux__) || defined(__CYGWIN__)
#define _DEFAULT_SOURCE
#else
#define _POSIX_C_SOURCE 200112L
#endif
-#define OUROBOROS_PREFIX "connection-manager"
-
-#include <ouroboros/dev.h>
-#include <ouroboros/cacep.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/list.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/notifier.h>
-
-#include "comp.h"
-#include "connmgr.h"
-#include "dir.h"
-#include "enroll.h"
-#include "ipcp.h"
-
-#include <pthread.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-enum connmgr_state {
- CONNMGR_NULL = 0,
- CONNMGR_INIT,
- CONNMGR_RUNNING
-};
-
-struct conn_el {
- struct list_head next;
- struct conn conn;
-};
-
-struct comp {
- struct conn_info info;
-
- struct list_head conns;
- struct list_head pending;
-
- pthread_cond_t cond;
- pthread_mutex_t lock;
-};
-
-struct {
- struct comp comps[COMPID_MAX];
- enum connmgr_state state;
-
- pthread_t acceptor;
-} connmgr;
-
-static int get_id_by_name(const char * name)
-{
- enum comp_id i;
-
- for (i = 0; i < COMPID_MAX; ++i)
- if (strcmp(name, connmgr.comps[i].info.comp_name) == 0)
- return i;
-
- return -1;
-}
-
-static int get_conn_by_fd(int fd,
- enum comp_id id,
- struct conn * conn)
-{
- struct list_head * p;
-
- pthread_mutex_lock(&connmgr.comps[id].lock);
-
- list_for_each(p, &connmgr.comps[id].conns) {
- struct conn_el * c =
- list_entry(p, struct conn_el, next);
- if (c->conn.flow_info.fd == fd) {
- *conn = c->conn;
- pthread_mutex_unlock(&connmgr.comps[id].lock);
- return 0;
- }
- }
-
- pthread_mutex_unlock(&connmgr.comps[id].lock);
-
- return -1;
-}
-
-static int add_comp_conn(enum comp_id id,
- int fd,
- qosspec_t qs,
- struct conn_info * rcv_info)
-{
- struct conn_el * el;
-
- el = malloc(sizeof(*el));
- if (el == NULL) {
- log_err("Not enough memory.");
- return -1;
- }
-
- el->conn.conn_info = *rcv_info;
- el->conn.flow_info.fd = fd;
- el->conn.flow_info.qs = qs;
-
- pthread_mutex_lock(&connmgr.comps[id].lock);
-
- list_add(&el->next, &connmgr.comps[id].pending);
- pthread_cond_signal(&connmgr.comps[id].cond);
-
- pthread_mutex_unlock(&connmgr.comps[id].lock);
-
- return 0;
-}
-
-static void * flow_acceptor(void * o)
-{
- int fd;
- qosspec_t qs;
- struct conn_info rcv_info;
- struct conn_info fail_info;
-
- (void) o;
-
- memset(&fail_info, 0, sizeof(fail_info));
-
- while (true) {
- int id;
-
- fd = flow_accept(&qs, NULL);
- if (fd < 0) {
- if (fd != -EIRMD)
- log_warn("Flow accept failed: %d", fd);
- continue;
- }
-
- if (cacep_rcv(fd, &rcv_info)) {
- log_dbg("Error establishing application connection.");
- flow_dealloc(fd);
- continue;
- }
-
- id = get_id_by_name(rcv_info.comp_name);
- if (id < 0) {
- log_dbg("Connection request for unknown component %s.",
- rcv_info.comp_name);
- cacep_snd(fd, &fail_info);
- flow_dealloc(fd);
- continue;
- }
-
- assert(id < COMPID_MAX);
-
- if (cacep_snd(fd, &connmgr.comps[id].info)) {
- log_dbg("Failed to respond to request.");
- flow_dealloc(fd);
- continue;
- }
-
- if (add_comp_conn(id, fd, qs, &rcv_info)) {
- log_dbg("Failed to add new connection.");
- flow_dealloc(fd);
- continue;
- }
- }
-
- return (void *) 0;
-}
-
-static void handle_event(void * self,
- int event,
- const void * o)
-{
- struct conn conn;
-
- (void) self;
-
- if (!(event == NOTIFY_DT_FLOW_UP ||
- event == NOTIFY_DT_FLOW_DOWN ||
- event == NOTIFY_DT_FLOW_DEALLOC))
- return;
-
- if (get_conn_by_fd(*((int *) o), COMPID_DT, &conn))
- return;
-
- switch (event) {
- case NOTIFY_DT_FLOW_UP:
- notifier_event(NOTIFY_DT_CONN_UP, &conn);
- break;
- case NOTIFY_DT_FLOW_DOWN:
- notifier_event(NOTIFY_DT_CONN_DOWN, &conn);
- break;
- case NOTIFY_DT_FLOW_DEALLOC:
- notifier_event(NOTIFY_DT_CONN_DEL, &conn);
- break;
- default:
- break;
- }
-}
-
-int connmgr_init(void)
-{
- connmgr.state = CONNMGR_INIT;
-
- if (notifier_reg(handle_event, NULL))
- return -1;
-
- return 0;
-}
-
-void connmgr_fini(void)
-{
- int i;
-
- notifier_unreg(handle_event);
-
- if (connmgr.state == CONNMGR_RUNNING)
- pthread_join(connmgr.acceptor, NULL);
-
- for (i = 0; i < COMPID_MAX; ++i)
- connmgr_comp_fini(i);
-}
-
-int connmgr_start(void)
-{
- if (pthread_create(&connmgr.acceptor, NULL, flow_acceptor, NULL))
- return -1;
-
- connmgr.state = CONNMGR_RUNNING;
-
- return 0;
-}
-
-void connmgr_stop(void)
-{
- if (connmgr.state == CONNMGR_RUNNING)
- pthread_cancel(connmgr.acceptor);
-}
-
-int connmgr_comp_init(enum comp_id id,
- const struct conn_info * info)
-{
- struct comp * comp;
-
- assert(id >= 0 && id < COMPID_MAX);
-
- comp = connmgr.comps + id;
+#include <ouroboros/ipcp.h>
- if (pthread_mutex_init(&comp->lock, NULL))
- return -1;
+#define BUILD_IPCP_UNICAST
- if (pthread_cond_init(&comp->cond, NULL)) {
- pthread_mutex_destroy(&comp->lock);
- return -1;
- }
-
- list_head_init(&comp->conns);
- list_head_init(&comp->pending);
-
- memcpy(&connmgr.comps[id].info, info, sizeof(connmgr.comps[id].info));
-
- return 0;
-}
-
-void connmgr_comp_fini(enum comp_id id)
-{
- struct list_head * p;
- struct list_head * h;
- struct comp * comp;
-
- assert(id >= 0 && id < COMPID_MAX);
-
- if (strlen(connmgr.comps[id].info.comp_name) == 0)
- return;
-
- comp = connmgr.comps + id;
-
- pthread_mutex_lock(&comp->lock);
-
- list_for_each_safe(p, h, &comp->conns) {
- struct conn_el * e = list_entry(p, struct conn_el, next);
- list_del(&e->next);
- free(e);
- }
-
- list_for_each_safe(p, h, &comp->pending) {
- struct conn_el * e = list_entry(p, struct conn_el, next);
- list_del(&e->next);
- free(e);
- }
-
- pthread_mutex_unlock(&comp->lock);
-
- pthread_cond_destroy(&comp->cond);
- pthread_mutex_destroy(&comp->lock);
-
- memset(&connmgr.comps[id].info, 0, sizeof(connmgr.comps[id].info));
-}
-
-int connmgr_ipcp_connect(const char * dst,
- const char * component,
- qosspec_t qs)
-{
- struct conn_el * ce;
- int id;
-
- assert(dst);
- assert(component);
-
- ce = malloc(sizeof(*ce));
- if (ce == NULL) {
- log_dbg("Out of memory.");
- return -1;
- }
-
- id = get_id_by_name(component);
- if (id < 0) {
- log_dbg("No such component: %s", component);
- free(ce);
- return -1;
- }
-
- if (connmgr_alloc(id, dst, &qs, &ce->conn)) {
- free(ce);
- return -1;
- }
-
- if (strlen(dst) > DST_MAX_STRLEN) {
- log_warn("Truncating dst length for connection.");
- memcpy(ce->conn.flow_info.dst, dst, DST_MAX_STRLEN);
- ce->conn.flow_info.dst[DST_MAX_STRLEN] = '\0';
- } else {
- strcpy(ce->conn.flow_info.dst, dst);
- }
-
- pthread_mutex_lock(&connmgr.comps[id].lock);
-
- list_add(&ce->next, &connmgr.comps[id].conns);
-
- pthread_mutex_unlock(&connmgr.comps[id].lock);
-
- return 0;
-}
-
-int connmgr_ipcp_disconnect(const char * dst,
- const char * component)
-{
- struct list_head * p;
- struct list_head * h;
- int id;
-
- assert(dst);
- assert(component);
-
- id = get_id_by_name(component);
- if (id < 0)
- return -1;
-
- pthread_mutex_lock(&connmgr.comps[id].lock);
-
- list_for_each_safe(p,h, &connmgr.comps[id].conns) {
- struct conn_el * el = list_entry(p, struct conn_el, next);
- if (strcmp(el->conn.flow_info.dst, dst) == 0) {
- int ret;
- pthread_mutex_unlock(&connmgr.comps[id].lock);
- list_del(&el->next);
- ret = connmgr_dealloc(id, &el->conn);
- free(el);
- return ret;
- }
- }
-
- pthread_mutex_unlock(&connmgr.comps[id].lock);
-
- return 0;
-}
-
-int connmgr_alloc(enum comp_id id,
- const char * dst,
- qosspec_t * qs,
- struct conn * conn)
-{
- assert(id >= 0 && id < COMPID_MAX);
- assert(dst);
-
- conn->flow_info.fd = flow_alloc(dst, qs, NULL);
- if (conn->flow_info.fd < 0) {
- log_dbg("Failed to allocate flow to %s.", dst);
- return -1;
- }
-
- if (qs != NULL)
- conn->flow_info.qs = *qs;
- else
- memset(&conn->flow_info.qs, 0, sizeof(conn->flow_info.qs));
-
- log_dbg("Sending cacep info for protocol %s to fd %d.",
- connmgr.comps[id].info.protocol, conn->flow_info.fd);
-
- if (cacep_snd(conn->flow_info.fd, &connmgr.comps[id].info)) {
- log_dbg("Failed to create application connection.");
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- if (cacep_rcv(conn->flow_info.fd, &conn->conn_info)) {
- log_dbg("Failed to connect to application.");
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- if (strcmp(connmgr.comps[id].info.protocol, conn->conn_info.protocol)) {
- log_dbg("Unknown protocol (requested %s, got %s).",
- connmgr.comps[id].info.protocol,
- conn->conn_info.protocol);
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- if (connmgr.comps[id].info.pref_version !=
- conn->conn_info.pref_version) {
- log_dbg("Unknown protocol version.");
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- if (connmgr.comps[id].info.pref_syntax != conn->conn_info.pref_syntax) {
- log_dbg("Unknown protocol syntax.");
- flow_dealloc(conn->flow_info.fd);
- return -1;
- }
-
- switch (id) {
- case COMPID_DT:
- notifier_event(NOTIFY_DT_CONN_ADD, conn);
#ifdef IPCP_CONN_WAIT_DIR
- dir_wait_running();
+ #include "dir.h"
#endif
- break;
- case COMPID_MGMT:
- notifier_event(NOTIFY_MGMT_CONN_ADD, conn);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-int connmgr_dealloc(enum comp_id id,
- struct conn * conn)
-{
- switch (id) {
- case COMPID_DT:
- notifier_event(NOTIFY_DT_CONN_DEL, conn);
- break;
- case COMPID_MGMT:
- notifier_event(NOTIFY_MGMT_CONN_DEL, conn);
- break;
- default:
- break;
- }
-
- return flow_dealloc(conn->flow_info.fd);
-}
-
-
-int connmgr_wait(enum comp_id id,
- struct conn * conn)
-{
- struct conn_el * el;
- struct comp * comp;
-
- assert(id >= 0 && id < COMPID_MAX);
- assert(conn);
-
- comp = connmgr.comps + id;
-
- pthread_mutex_lock(&comp->lock);
-
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) &comp->lock);
-
- while (list_is_empty(&comp->pending))
- pthread_cond_wait(&comp->cond, &comp->lock);
-
- pthread_cleanup_pop(false);
-
- el = list_first_entry((&comp->pending), struct conn_el, next);
- if (el == NULL) {
- pthread_mutex_unlock(&comp->lock);
- return -1;
- }
-
- *conn = el->conn;
-
- list_del(&el->next);
- list_add(&el->next, &connmgr.comps[id].conns);
-
- pthread_mutex_unlock(&comp->lock);
- return 0;
-}
+#include "common/connmgr.c"
diff --git a/src/ipcpd/unicast/dht.h b/src/ipcpd/unicast/dht.h
deleted file mode 100644
index 39dfc07e..00000000
--- a/src/ipcpd/unicast/dht.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * Distributed Hash Table based on Kademlia
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IPCPD_UNICAST_DHT_H
-#define OUROBOROS_IPCPD_UNICAST_DHT_H
-
-#include <ouroboros/ipcp-dev.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-struct dht;
-
-struct dht * dht_create(uint64_t addr);
-
-int dht_bootstrap(struct dht * dht,
- size_t b,
- time_t t_expire);
-
-void dht_destroy(struct dht * dht);
-
-int dht_reg(struct dht * dht,
- const uint8_t * key);
-
-int dht_unreg(struct dht * dht,
- const uint8_t * key);
-
-uint64_t dht_query(struct dht * dht,
- const uint8_t * key);
-
-int dht_wait_running(struct dht * dht);
-
-#endif /* OUROBOROS_IPCPD_UNICAST_DHT_H */
diff --git a/src/ipcpd/unicast/dir.c b/src/ipcpd/unicast/dir.c
index 43ee94f0..e0cb09fc 100644
--- a/src/ipcpd/unicast/dir.c
+++ b/src/ipcpd/unicast/dir.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
- * Directory
+ * Directory Management
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -34,8 +34,7 @@
#include <ouroboros/utils.h>
#include "dir.h"
-#include "dht.h"
-#include "ipcp.h"
+#include "dir/pol.h"
#include <stdlib.h>
#include <string.h>
@@ -43,59 +42,52 @@
#include <inttypes.h>
#include <limits.h>
-#define KAD_B (hash_len(ipcpi.dir_hash_algo) * CHAR_BIT)
-
-struct dht * dht;
+struct {
+ struct dir_ops * ops;
+ void * dir;
+} dirmgr;
int dir_init(void)
{
- dht = dht_create(ipcpi.dt_addr);
- if (dht == NULL)
+ dirmgr.ops = &dht_dir_ops;
+
+ dirmgr.dir = dirmgr.ops->create();
+ if (dirmgr.dir == NULL) {
+ dirmgr.ops = NULL;
return -ENOMEM;
+ }
return 0;
}
void dir_fini(void)
{
- dht_destroy(dht);
+ dirmgr.ops->destroy(dirmgr.dir);
+ dirmgr.ops = NULL;
+ dirmgr.dir = NULL;
}
-int dir_bootstrap(void) {
- log_dbg("Bootstrapping directory.");
-
- /* TODO: get parameters for bootstrap from IRM tool. */
- if (dht_bootstrap(dht, KAD_B, 86400)) {
- dht_destroy(dht);
- return -ENOMEM;
- }
-
- log_info("Directory bootstrapped.");
-
- return 0;
+int dir_bootstrap(void)
+{
+ return dirmgr.ops->bootstrap(dirmgr.dir);
}
int dir_reg(const uint8_t * hash)
{
- return dht_reg(dht, hash);
+ return dirmgr.ops->reg(dirmgr.dir, hash);
}
int dir_unreg(const uint8_t * hash)
{
- return dht_unreg(dht, hash);
+ return dirmgr.ops->unreg(dirmgr.dir, hash);
}
uint64_t dir_query(const uint8_t * hash)
{
- return dht_query(dht, hash);
+ return dirmgr.ops->query(dirmgr.dir, hash);
}
int dir_wait_running(void)
{
- if (dht_wait_running(dht)) {
- log_warn("Directory did not bootstrap.");
- return -1;
- }
-
- return 0;
+ return dirmgr.ops->wait_running(dirmgr.dir);
}
diff --git a/src/ipcpd/unicast/dir.h b/src/ipcpd/unicast/dir.h
index 1b67a08c..b261ea2c 100644
--- a/src/ipcpd/unicast/dir.h
+++ b/src/ipcpd/unicast/dir.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Directory
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,6 +23,8 @@
#ifndef OUROBOROS_IPCPD_UNICAST_DIR_H
#define OUROBOROS_IPCPD_UNICAST_DIR_H
+#include <inttypes.h>
+
int dir_init(void);
void dir_fini(void);
diff --git a/src/ipcpd/unicast/dht.c b/src/ipcpd/unicast/dir/dht.c
index 8555312e..08a5a5a9 100644
--- a/src/ipcpd/unicast/dht.c
+++ b/src/ipcpd/unicast/dir/dht.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Distributed Hash Table based on Kademlia
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -31,6 +31,7 @@
#define DHT "dht"
#define OUROBOROS_PREFIX DHT
+#include <ouroboros/endian.h>
#include <ouroboros/hash.h>
#include <ouroboros/ipcp-dev.h>
#include <ouroboros/bitmap.h>
@@ -39,24 +40,26 @@
#include <ouroboros/list.h>
#include <ouroboros/notifier.h>
#include <ouroboros/random.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/time.h>
#include <ouroboros/tpm.h>
#include <ouroboros/utils.h>
+#include <ouroboros/pthread.h>
-#include "connmgr.h"
+#include "common/connmgr.h"
#include "dht.h"
#include "dt.h"
+#include "ipcp.h"
+#include "ops.h"
-#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
-#include "kademlia.pb-c.h"
-typedef KadMsg kad_msg_t;
-typedef KadContactMsg kad_contact_msg_t;
+#include "dht.pb-c.h"
+typedef DhtMsg dht_msg_t;
+typedef DhtContactMsg dht_contact_msg_t;
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
@@ -208,6 +211,16 @@ struct cmd {
struct shm_du_buff * sdb;
};
+struct dir_ops dht_dir_ops = {
+ .create = dht_create,
+ .destroy = dht_destroy,
+ .bootstrap = dht_bootstrap,
+ .reg = dht_reg,
+ .unreg = dht_unreg,
+ .query = dht_query,
+ .wait_running = dht_wait_running
+};
+
struct dht {
size_t alpha;
size_t b;
@@ -239,7 +252,7 @@ struct dht {
pthread_rwlock_t lock;
- int fd;
+ uint64_t eid;
struct tpm * tpm;
@@ -302,14 +315,16 @@ static int dht_set_state(struct dht * dht,
return 0;
}
-int dht_wait_running(struct dht * dht)
+int dht_wait_running(void * dir)
{
- int ret = 0;
+ struct dht * dht;
+ int ret = 0;
+
+ dht = (struct dht *) dir;
pthread_mutex_lock(&dht->mtx);
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &dht->mtx);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &dht->mtx);
while (dht->state == DHT_JOINING)
pthread_cond_wait(&dht->cond, &dht->mtx);
@@ -339,7 +354,7 @@ static uint8_t * create_id(size_t len)
}
static void kad_req_create(struct dht * dht,
- kad_msg_t * msg,
+ dht_msg_t * msg,
uint64_t addr)
{
struct kad_req * req;
@@ -347,14 +362,14 @@ static void kad_req_create(struct dht * dht,
struct timespec t;
size_t b;
+ clock_gettime(CLOCK_REALTIME_COARSE, &t);
+
req = malloc(sizeof(*req));
if (req == NULL)
- return;
+ goto fail_malloc;
list_head_init(&req->next);
- clock_gettime(CLOCK_REALTIME_COARSE, &t);
-
req->t_exp = t.tv_sec + KAD_T_RESP;
req->addr = addr;
req->state = REQ_INIT;
@@ -368,30 +383,22 @@ static void kad_req_create(struct dht * dht,
if (msg->has_key) {
req->key = dht_dup_key(msg->key.data, b);
- if (req->key == NULL) {
- free(req);
- return;
- }
+ if (req->key == NULL)
+ goto fail_dup_key;
}
- if (pthread_mutex_init(&req->lock, NULL)) {
- free(req->key);
- free(req);
- return;
- }
+ if (pthread_mutex_init(&req->lock, NULL))
+ goto fail_mutex;
- pthread_condattr_init(&cattr);
+
+ if (pthread_condattr_init(&cattr))
+ goto fail_condattr;
#ifndef __APPLE__
pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
#endif
- if (pthread_cond_init(&req->cond, &cattr)) {
- pthread_condattr_destroy(&cattr);
- pthread_mutex_destroy(&req->lock);
- free(req->key);
- free(req);
- return;
- }
+ if (pthread_cond_init(&req->cond, &cattr))
+ goto fail_cond_init;
pthread_condattr_destroy(&cattr);
@@ -400,6 +407,19 @@ static void kad_req_create(struct dht * dht,
list_add(&req->next, &dht->requests);
pthread_rwlock_unlock(&dht->lock);
+
+ return;
+
+ fail_cond_init:
+ pthread_condattr_destroy(&cattr);
+ fail_condattr:
+ pthread_mutex_destroy(&req->lock);
+ fail_mutex:
+ free(req->key);
+ fail_dup_key:
+ free(req);
+ fail_malloc:
+ return;
}
static void cancel_req_destroy(void * o)
@@ -429,7 +449,7 @@ static void kad_req_destroy(struct kad_req * req)
return;
case REQ_PENDING:
req->state = REQ_DESTROY;
- pthread_cond_signal(&req->cond);
+ pthread_cond_broadcast(&req->cond);
break;
case REQ_INIT:
case REQ_DONE:
@@ -452,12 +472,14 @@ static void kad_req_destroy(struct kad_req * req)
static int kad_req_wait(struct kad_req * req,
time_t t)
{
- struct timespec timeo = {t, 0};
+ struct timespec timeo = TIMESPEC_INIT_S(0);
struct timespec abs;
int ret = 0;
assert(req);
+ timeo.tv_sec = t;
+
clock_gettime(PTHREAD_COND_CLOCK, &abs);
ts_add(&abs, &timeo, &abs);
@@ -466,8 +488,7 @@ static int kad_req_wait(struct kad_req * req,
req->state = REQ_PENDING;
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &req->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &req->lock);
while (req->state == REQ_PENDING && ret != -ETIMEDOUT)
ret = -pthread_cond_timedwait(&req->cond, &req->lock, &abs);
@@ -774,7 +795,7 @@ static void lookup_destroy(struct lookup * lu)
static void lookup_update(struct dht * dht,
struct lookup * lu,
- kad_msg_t * msg)
+ dht_msg_t * msg)
{
struct list_head * p = NULL;
struct list_head * h;
@@ -819,8 +840,7 @@ static void lookup_update(struct dht * dht,
return;
}
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &lu->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &lu->lock);
while (lu->state == LU_INIT) {
pthread_rwlock_unlock(&dht->lock);
@@ -967,7 +987,7 @@ static void lookup_set_state(struct lookup * lu,
pthread_mutex_unlock(&lu->lock);
}
-static void cleanup_wait(void * o)
+static void cancel_lookup_wait(void * o)
{
struct lookup * lu = (struct lookup *) o;
lu->state = LU_NULL;
@@ -977,7 +997,7 @@ static void cleanup_wait(void * o)
static enum lookup_state lookup_wait(struct lookup * lu)
{
- struct timespec timeo = {KAD_T_RESP, 0};
+ struct timespec timeo = TIMESPEC_INIT_S(KAD_T_RESP);
struct timespec abs;
enum lookup_state state;
int ret = 0;
@@ -991,7 +1011,7 @@ static enum lookup_state lookup_wait(struct lookup * lu)
if (lu->state == LU_INIT || lu->state == LU_UPDATE)
lu->state = LU_PENDING;
- pthread_cleanup_push(cleanup_wait, lu);
+ pthread_cleanup_push(cancel_lookup_wait, lu);
while (lu->state == LU_PENDING && ret != -ETIMEDOUT)
ret = -pthread_cond_timedwait(&lu->cond, &lu->lock, &abs);
@@ -1009,7 +1029,7 @@ static enum lookup_state lookup_wait(struct lookup * lu)
}
static struct kad_req * dht_find_request(struct dht * dht,
- kad_msg_t * msg)
+ dht_msg_t * msg)
{
struct list_head * p;
@@ -1257,7 +1277,7 @@ static void bucket_refresh(struct dht * dht,
struct contact * d;
c = list_first_entry(&b->contacts, struct contact, next);
d = contact_create(c->id, dht->b, c->addr);
- if (c != NULL)
+ if (d != NULL)
list_add(&d->next, r);
return;
}
@@ -1446,7 +1466,7 @@ static int dht_update_bucket(struct dht * dht,
}
static int send_msg(struct dht * dht,
- kad_msg_t * msg,
+ dht_msg_t * msg,
uint64_t addr)
{
#ifndef __DHT_TEST__
@@ -1479,7 +1499,7 @@ static int send_msg(struct dht * dht,
pthread_rwlock_unlock(&dht->lock);
#ifndef __DHT_TEST__
- len = kad_msg__get_packed_size(msg);
+ len = dht_msg__get_packed_size(msg);
if (len == 0)
goto fail_msg;
@@ -1487,9 +1507,9 @@ static int send_msg(struct dht * dht,
if (ipcp_sdb_reserve(&sdb, len))
goto fail_msg;
- kad_msg__pack(msg, shm_du_buff_head(sdb));
+ dht_msg__pack(msg, shm_du_buff_head(sdb));
- if (dt_write_packet(addr, QOS_CUBE_BE, dht->fd, sdb) == 0)
+ if (dt_write_packet(addr, QOS_CUBE_BE, dht->eid, sdb) == 0)
break;
ipcp_sdb_release(sdb);
@@ -1534,7 +1554,7 @@ static struct dht_entry * dht_find_entry(struct dht * dht,
}
static int kad_add(struct dht * dht,
- const kad_contact_msg_t * contacts,
+ const dht_contact_msg_t * contacts,
ssize_t n,
time_t exp)
{
@@ -1573,7 +1593,7 @@ static int kad_add(struct dht * dht,
}
static int wait_resp(struct dht * dht,
- kad_msg_t * msg,
+ dht_msg_t * msg,
time_t timeo)
{
struct kad_req * req;
@@ -1600,9 +1620,9 @@ static int kad_store(struct dht * dht,
uint64_t r_addr,
time_t ttl)
{
- kad_msg_t msg = KAD_MSG__INIT;
- kad_contact_msg_t cmsg = KAD_CONTACT_MSG__INIT;
- kad_contact_msg_t * cmsgp[1];
+ dht_msg_t msg = DHT_MSG__INIT;
+ dht_contact_msg_t cmsg = DHT_CONTACT_MSG__INIT;
+ dht_contact_msg_t * cmsgp[1];
cmsg.id.data = (uint8_t *) key;
cmsg.addr = addr;
@@ -1632,7 +1652,7 @@ static ssize_t kad_find(struct dht * dht,
const uint64_t * addrs,
enum kad_code code)
{
- kad_msg_t msg = KAD_MSG__INIT;
+ dht_msg_t msg = DHT_MSG__INIT;
ssize_t sent = 0;
assert(dht);
@@ -1729,7 +1749,7 @@ static struct lookup * kad_lookup(struct dht * dht,
}
}
- assert(state = LU_COMPLETE);
+ assert(state == LU_COMPLETE);
lookup_detach(dht, lu);
@@ -1772,7 +1792,7 @@ static void kad_publish(struct dht * dht,
while (n-- > 0) {
if (addrs[n] == dht->addr) {
- kad_contact_msg_t msg = KAD_CONTACT_MSG__INIT;
+ dht_contact_msg_t msg = DHT_CONTACT_MSG__INIT;
msg.id.data = (uint8_t *) key;
msg.id.len = dht->b;
msg.addr = addr;
@@ -1791,7 +1811,7 @@ static void kad_publish(struct dht * dht,
static int kad_join(struct dht * dht,
uint64_t addr)
{
- kad_msg_t msg = KAD_MSG__INIT;
+ dht_msg_t msg = DHT_MSG__INIT;
msg.code = KAD_JOIN;
@@ -1871,18 +1891,13 @@ static int dht_del(struct dht * dht,
{
struct dht_entry * e;
- pthread_rwlock_wrlock(&dht->lock);
-
e = dht_find_entry(dht, key);
if (e == NULL) {
- pthread_rwlock_unlock(&dht->lock);
return -EPERM;
}
dht_entry_del_addr(e, addr);
- pthread_rwlock_unlock(&dht->lock);
-
return 0;
}
@@ -1924,14 +1939,14 @@ static buffer_t dht_retrieve(struct dht * dht,
fail:
pthread_rwlock_unlock(&dht->lock);
- buf.len = 0;
-
+ buf.len = 0;
+ buf.data = NULL;
return buf;
}
static ssize_t dht_get_contacts(struct dht * dht,
const uint8_t * key,
- kad_contact_msg_t *** msgs)
+ dht_contact_msg_t *** msgs)
{
struct list_head l;
struct list_head * p;
@@ -1946,6 +1961,7 @@ static ssize_t dht_get_contacts(struct dht * dht,
len = dht_contact_list(dht, &l, key);
if (len == 0) {
pthread_rwlock_unlock(&dht->lock);
+ *msgs = NULL;
return 0;
}
@@ -1963,10 +1979,11 @@ static ssize_t dht_get_contacts(struct dht * dht,
while (i > 0)
free(*msgs[--i]);
free(*msgs);
+ *msgs = NULL;
return 0;
}
- kad_contact_msg__init((*msgs)[i]);
+ dht_contact_msg__init((*msgs)[i]);
(*msgs)[i]->id.data = c->id;
(*msgs)[i]->id.len = dht->b;
@@ -2103,7 +2120,7 @@ static void * work(void * o)
static int kad_handle_join_resp(struct dht * dht,
struct kad_req * req,
- kad_msg_t * msg)
+ dht_msg_t * msg)
{
assert(dht);
assert(req);
@@ -2163,7 +2180,7 @@ static int kad_handle_join_resp(struct dht * dht,
static int kad_handle_find_resp(struct dht * dht,
struct kad_req * req,
- kad_msg_t * msg)
+ dht_msg_t * msg)
{
struct lookup * lu;
@@ -2187,7 +2204,7 @@ static int kad_handle_find_resp(struct dht * dht,
}
static void kad_handle_response(struct dht * dht,
- kad_msg_t * msg)
+ dht_msg_t * msg)
{
struct kad_req * req;
@@ -2225,15 +2242,23 @@ static void kad_handle_response(struct dht * dht,
kad_req_destroy(req);
}
-int dht_bootstrap(struct dht * dht,
- size_t b,
- time_t t_expire)
+int dht_bootstrap(void * dir)
{
+ struct dht * dht;
+
+ dht = (struct dht *) dir;
+
assert(dht);
pthread_rwlock_wrlock(&dht->lock);
- dht->id = create_id(b);
+#ifndef __DHT_TEST__
+ dht->b = hash_len(ipcpi.dir_hash_algo);
+#else
+ dht->b = DHT_TEST_KEY_LEN;
+#endif
+
+ dht->id = create_id(dht->b);
if (dht->id == NULL)
goto fail_id;
@@ -2244,9 +2269,8 @@ int dht_bootstrap(struct dht * dht,
dht->buckets->depth = 0;
dht->buckets->mask = 0;
- dht->b = b / CHAR_BIT;
- dht->t_expire = MAX(2, t_expire);
- dht->t_repub = MAX(1, t_expire - 10);
+ dht->t_expire = 86400; /* 1 day */
+ dht->t_repub = dht->t_expire - 10;
dht->k = KAD_K;
if (pthread_create(&dht->worker, NULL, work, dht))
@@ -2285,13 +2309,16 @@ static struct ref_entry * ref_entry_get(struct dht * dht,
return NULL;
}
-int dht_reg(struct dht * dht,
+int dht_reg(void * dir,
const uint8_t * key)
{
+ struct dht * dht;
struct ref_entry * e;
uint64_t addr;
time_t t_expire;
+ dht = (struct dht *) dir;
+
assert(dht);
assert(key);
assert(dht->addr != 0);
@@ -2325,12 +2352,15 @@ int dht_reg(struct dht * dht,
return 0;
}
-int dht_unreg(struct dht * dht,
+int dht_unreg(void * dir,
const uint8_t * key)
{
+ struct dht * dht;
struct list_head * p;
struct list_head * h;
+ dht = (struct dht *) dir;
+
assert(dht);
assert(key);
@@ -2354,14 +2384,19 @@ int dht_unreg(struct dht * dht,
return 0;
}
-uint64_t dht_query(struct dht * dht,
+uint64_t dht_query(void * dir,
const uint8_t * key)
{
+ struct dht * dht;
struct dht_entry * e;
struct lookup * lu;
uint64_t addrs[KAD_K];
size_t n;
+ dht = (struct dht *) dir;
+
+ assert(dht);
+
addrs[0] = 0;
if (dht_wait_running(dht))
@@ -2407,9 +2442,9 @@ static void * dht_handle_packet(void * o)
assert(dht);
while (true) {
- kad_msg_t * msg;
- kad_contact_msg_t ** cmsgs;
- kad_msg_t resp_msg = KAD_MSG__INIT;
+ dht_msg_t * msg;
+ dht_contact_msg_t ** cmsgs;
+ dht_msg_t resp_msg = DHT_MSG__INIT;
uint64_t addr;
buffer_t buf;
size_t i;
@@ -2419,8 +2454,7 @@ static void * dht_handle_packet(void * o)
pthread_mutex_lock(&dht->mtx);
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &dht->mtx);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &dht->mtx);
while (list_is_empty(&dht->cmds))
pthread_cond_wait(&dht->cond, &dht->mtx);
@@ -2430,9 +2464,9 @@ static void * dht_handle_packet(void * o)
pthread_cleanup_pop(true);
- i = shm_du_buff_tail(cmd->sdb) - shm_du_buff_head(cmd->sdb);
+ i = shm_du_buff_len(cmd->sdb);
- msg = kad_msg__unpack(NULL, i, shm_du_buff_head(cmd->sdb));
+ msg = dht_msg__unpack(NULL, i, shm_du_buff_head(cmd->sdb));
#ifndef __DHT_TEST__
ipcp_sdb_release(cmd->sdb);
#endif
@@ -2444,7 +2478,7 @@ static void * dht_handle_packet(void * o)
}
if (msg->code != KAD_RESPONSE && dht_wait_running(dht)) {
- kad_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(msg, NULL);
log_dbg("Got a request message when not running.");
continue;
}
@@ -2457,13 +2491,13 @@ static void * dht_handle_packet(void * o)
pthread_rwlock_unlock(&dht->lock);
if (msg->has_key && msg->key.len != b) {
- kad_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(msg, NULL);
log_warn("Bad key in message.");
continue;
}
if (msg->has_s_id && !msg->has_b && msg->s_id.len != b) {
- kad_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(msg, NULL);
log_warn("Bad source ID in message of type %d.",
msg->code);
continue;
@@ -2552,7 +2586,7 @@ static void * dht_handle_packet(void * o)
if (dht_get_state(dht) == DHT_JOINING &&
dht->buckets == NULL) {
pthread_rwlock_unlock(&dht->lock);
- break;
+ goto finish;
}
if (dht_update_bucket(dht, msg->s_id.data, addr))
@@ -2563,7 +2597,8 @@ static void * dht_handle_packet(void * o)
if (msg->code < KAD_STORE && send_msg(dht, &resp_msg, addr) < 0)
log_warn("Failed to send response.");
- kad_msg__free_unpacked(msg, NULL);
+ finish:
+ dht_msg__free_unpacked(msg, NULL);
if (resp_msg.n_addrs > 0)
free(resp_msg.addrs);
@@ -2574,7 +2609,7 @@ static void * dht_handle_packet(void * o)
}
for (i = 0; i < resp_msg.n_contacts; ++i)
- kad_contact_msg__free_unpacked(resp_msg.contacts[i],
+ dht_contact_msg__free_unpacked(resp_msg.contacts[i],
NULL);
free(resp_msg.contacts);
@@ -2614,11 +2649,13 @@ static void dht_post_packet(void * comp,
pthread_mutex_unlock(&dht->mtx);
}
-void dht_destroy(struct dht * dht)
+void dht_destroy(void * dir)
{
+ struct dht * dht;
struct list_head * p;
struct list_head * h;
+ dht = (struct dht *) dir;
if (dht == NULL)
return;
@@ -2729,7 +2766,7 @@ static void handle_event(void * self,
pthread_t thr;
struct join_info * inf;
struct conn * c = (struct conn *) o;
- struct timespec slack = {0, DHT_ENROLL_SLACK * MILLION};
+ struct timespec slack = TIMESPEC_INIT_MS(DHT_ENROLL_SLACK);
/* Give the pff some time to update for the new link. */
nanosleep(&slack, NULL);
@@ -2771,7 +2808,7 @@ static void handle_event(void * self,
}
}
-struct dht * dht_create(uint64_t addr)
+void * dht_create(void)
{
struct dht * dht;
@@ -2801,9 +2838,9 @@ struct dht * dht_create(uint64_t addr)
goto fail_bmp;
dht->b = 0;
- dht->addr = addr;
dht->id = NULL;
#ifndef __DHT_TEST__
+ dht->addr = ipcpi.dt_addr;
dht->tpm = tpm_create(2, 1, dht_handle_packet, dht);
if (dht->tpm == NULL)
goto fail_tpm_create;
@@ -2811,8 +2848,12 @@ struct dht * dht_create(uint64_t addr)
if (tpm_start(dht->tpm))
goto fail_tpm_start;
- dht->fd = dt_reg_comp(dht, &dht_post_packet, DHT);
- notifier_reg(handle_event, dht);
+ dht->eid = dt_reg_comp(dht, &dht_post_packet, DHT);
+ if ((int) dht->eid < 0)
+ goto fail_tpm_start;
+
+ if (notifier_reg(handle_event, dht))
+ goto fail_notifier_reg;
#else
(void) handle_event;
(void) dht_handle_packet;
@@ -2820,8 +2861,10 @@ struct dht * dht_create(uint64_t addr)
#endif
dht->state = DHT_INIT;
- return dht;
+ return (void *) dht;
#ifndef __DHT_TEST__
+ fail_notifier_reg:
+ tpm_stop(dht->tpm);
fail_tpm_start:
tpm_destroy(dht->tpm);
fail_tpm_create:
diff --git a/src/ipcpd/unicast/dir/dht.h b/src/ipcpd/unicast/dir/dht.h
new file mode 100644
index 00000000..311c6b23
--- /dev/null
+++ b/src/ipcpd/unicast/dir/dht.h
@@ -0,0 +1,52 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Distributed Hash Table based on Kademlia
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IPCPD_UNICAST_DIR_DHT_H
+#define OUROBOROS_IPCPD_UNICAST_DIR_DHT_H
+
+#include <ouroboros/ipcp-dev.h>
+
+#include "ops.h"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+void * dht_create(void);
+
+void dht_destroy(void * dir);
+
+int dht_bootstrap(void * dir);
+
+int dht_reg(void * dir,
+ const uint8_t * key);
+
+int dht_unreg(void * dir,
+ const uint8_t * key);
+
+uint64_t dht_query(void * dir,
+ const uint8_t * key);
+
+int dht_wait_running(void * dir);
+
+extern struct dir_ops dht_dir_ops;
+
+#endif /* OUROBOROS_IPCPD_UNICAST_DIR_DHT_H */
diff --git a/src/ipcpd/unicast/kademlia.proto b/src/ipcpd/unicast/dir/dht.proto
index 4f807fd3..4c5b06db 100644
--- a/src/ipcpd/unicast/kademlia.proto
+++ b/src/ipcpd/unicast/dir/dht.proto
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
- * KAD protocol
+ * DHT protocol, based on Kademlia
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -22,19 +22,19 @@
syntax = "proto2";
-message kad_contact_msg {
+message dht_contact_msg {
required bytes id = 1;
required uint64 addr = 2;
-};
+}
-message kad_msg {
+message dht_msg {
required uint32 code = 1;
required uint32 cookie = 2;
required uint64 s_addr = 3;
optional bytes s_id = 4;
optional bytes key = 5;
repeated uint64 addrs = 6;
- repeated kad_contact_msg contacts = 7;
+ repeated dht_contact_msg contacts = 7;
// enrolment parameters
optional uint32 alpha = 8;
optional uint32 b = 9;
@@ -42,4 +42,4 @@ message kad_msg {
optional uint32 t_expire = 11;
optional uint32 t_refresh = 12;
optional uint32 t_replicate = 13;
-}; \ No newline at end of file
+}
diff --git a/src/ipcpd/unicast/dir/ops.h b/src/ipcpd/unicast/dir/ops.h
new file mode 100644
index 00000000..6ff61ce6
--- /dev/null
+++ b/src/ipcpd/unicast/dir/ops.h
@@ -0,0 +1,46 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Directory policy ops
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IPCPD_UNICAST_DIR_OPS_H
+#define OUROBOROS_IPCPD_UNICAST_DIR_OPS_H
+
+
+struct dir_ops {
+ void * (* create)(void);
+
+ void (* destroy)(void * dir);
+
+ int (* bootstrap)(void * dir);
+
+ int (* reg)(void * dir,
+ const uint8_t * hash);
+
+ int (* unreg)(void * dir,
+ const uint8_t * hash);
+
+ uint64_t (* query)(void * dir,
+ const uint8_t * hash);
+
+ int (* wait_running)(void * dir);
+};
+
+#endif /* OUROBOROS_IPCPD_UNICAST_DIR_OPS_H */
diff --git a/src/ipcpd/unicast/dir/pol.h b/src/ipcpd/unicast/dir/pol.h
new file mode 100644
index 00000000..eae4b2e7
--- /dev/null
+++ b/src/ipcpd/unicast/dir/pol.h
@@ -0,0 +1,23 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Directory policies
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "dht.h"
diff --git a/src/ipcpd/unicast/dir/tests/CMakeLists.txt b/src/ipcpd/unicast/dir/tests/CMakeLists.txt
new file mode 100644
index 00000000..f62ed993
--- /dev/null
+++ b/src/ipcpd/unicast/dir/tests/CMakeLists.txt
@@ -0,0 +1,40 @@
+get_filename_component(CURRENT_SOURCE_PARENT_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
+get_filename_component(CURRENT_BINARY_PARENT_DIR
+ ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${CURRENT_SOURCE_PARENT_DIR})
+include_directories(${CURRENT_BINARY_PARENT_DIR})
+
+include_directories(${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+get_filename_component(PARENT_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
+get_filename_component(PARENT_DIR ${PARENT_PATH} NAME)
+
+create_test_sourcelist(${PARENT_DIR}_tests test_suite.c
+ # Add new tests here
+ dht_test.c
+ )
+
+protobuf_generate_c(DHT_PROTO_SRCS KAD_PROTO_HDRS ../dht.proto)
+add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}
+ ${DHT_PROTO_SRCS})
+target_link_libraries(${PARENT_DIR}_test ouroboros-common)
+
+add_dependencies(check ${PARENT_DIR}_test)
+
+set(tests_to_run ${${PARENT_DIR}_tests})
+if(CMAKE_VERSION VERSION_LESS "3.29.0")
+ remove(tests_to_run test_suite.c)
+else ()
+ list(POP_FRONT tests_to_run)
+endif()
+
+foreach (test ${tests_to_run})
+ get_filename_component(test_name ${test} NAME_WE)
+ add_test(${test_name} ${C_TEST_PATH}/${PARENT_DIR}_test ${test_name})
+endforeach (test)
diff --git a/src/ipcpd/unicast/tests/dht_test.c b/src/ipcpd/unicast/dir/tests/dht_test.c
index 21ecd564..bea2c3e7 100644
--- a/src/ipcpd/unicast/tests/dht_test.c
+++ b/src/ipcpd/unicast/dir/tests/dht_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Unit tests of the DHT
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +21,7 @@
*/
#define __DHT_TEST__
+#define DHT_TEST_KEY_LEN 32
#include "dht.c"
@@ -29,23 +30,19 @@
#include <stdlib.h>
#include <stdio.h>
-#define KEY_LEN 32
-
-#define EXP 86400
-#define CONTACTS 1000
+#define CONTACTS 1000
int dht_test(int argc,
char ** argv)
{
struct dht * dht;
- uint64_t addr = 0x0D1F;
- uint8_t key[KEY_LEN];
+ uint8_t key[DHT_TEST_KEY_LEN];
size_t i;
(void) argc;
(void) argv;
- dht = dht_create(addr);
+ dht = dht_create();
if (dht == NULL) {
printf("Failed to create dht.\n");
return -1;
@@ -53,13 +50,13 @@ int dht_test(int argc,
dht_destroy(dht);
- dht = dht_create(addr);
+ dht = dht_create();
if (dht == NULL) {
printf("Failed to re-create dht.\n");
return -1;
}
- if (dht_bootstrap(dht, KEY_LEN, EXP)) {
+ if (dht_bootstrap(dht)) {
printf("Failed to bootstrap dht.\n");
dht_destroy(dht);
return -1;
@@ -67,13 +64,13 @@ int dht_test(int argc,
dht_destroy(dht);
- dht = dht_create(addr);
+ dht = dht_create();
if (dht == NULL) {
printf("Failed to re-create dht.\n");
return -1;
}
- if (dht_bootstrap(dht, KEY_LEN, EXP)) {
+ if (dht_bootstrap(dht)) {
printf("Failed to bootstrap dht.\n");
dht_destroy(dht);
return -1;
@@ -82,7 +79,7 @@ int dht_test(int argc,
for (i = 0; i < CONTACTS; ++i) {
uint64_t addr;
random_buffer(&addr, sizeof(addr));
- random_buffer(key, KEY_LEN);
+ random_buffer(key, DHT_TEST_KEY_LEN);
pthread_rwlock_wrlock(&dht->lock);
if (dht_update_bucket(dht, key, addr)) {
pthread_rwlock_unlock(&dht->lock);
diff --git a/src/ipcpd/unicast/dt.c b/src/ipcpd/unicast/dt.c
index d6a3ddc9..2bb5ed2f 100644
--- a/src/ipcpd/unicast/dt.c
+++ b/src/ipcpd/unicast/dt.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Data Transfer Component
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -41,13 +41,14 @@
#include <ouroboros/fccntl.h>
#endif
-#include "connmgr.h"
+#include "common/comp.h"
+#include "common/connmgr.h"
+#include "ca.h"
#include "ipcp.h"
#include "dt.h"
#include "pff.h"
#include "routing.h"
#include "psched.h"
-#include "comp.h"
#include "fa.h"
#include <stdlib.h>
@@ -57,8 +58,9 @@
#include <inttypes.h>
#include <assert.h>
-#define QOS_BLOCK_LEN 672
-#define STAT_FILE_LEN (189 + QOS_BLOCK_LEN * QOS_CUBE_MAX)
+#define QOS_BLOCK_LEN 672
+#define RIB_FILE_STRLEN (189 + QOS_BLOCK_LEN * QOS_CUBE_MAX)
+#define RIB_NAME_STRLEN 256
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
@@ -80,7 +82,7 @@ struct dt_pci {
qoscube_t qc;
uint8_t ttl;
uint8_t ecn;
- uint32_t eid;
+ uint64_t eid;
};
struct {
@@ -98,39 +100,29 @@ struct {
uint8_t max_ttl;
} dt_pci_info;
-static int dt_pci_ser(struct shm_du_buff * sdb,
- struct dt_pci * dt_pci)
+static void dt_pci_ser(uint8_t * head,
+ struct dt_pci * dt_pci)
{
- uint8_t * head;
- uint8_t ttl = dt_pci_info.max_ttl;
+ uint8_t ttl = dt_pci_info.max_ttl;
- assert(sdb);
+ assert(head);
assert(dt_pci);
- head = shm_du_buff_head_alloc(sdb, dt_pci_info.head_size);
- if (head == NULL)
- return -EPERM;
-
/* FIXME: Add check and operations for Big Endian machines. */
memcpy(head, &dt_pci->dst_addr, dt_pci_info.addr_size);
memcpy(head + dt_pci_info.qc_o, &dt_pci->qc, QOS_LEN);
memcpy(head + dt_pci_info.ttl_o, &ttl, TTL_LEN);
- memcpy(head + dt_pci_info.ecn_o, &dt_pci->ecn, ECN_LEN);
+ memcpy(head + dt_pci_info.ecn_o, &dt_pci->ecn, ECN_LEN);
memcpy(head + dt_pci_info.eid_o, &dt_pci->eid, dt_pci_info.eid_size);
- return 0;
}
-static void dt_pci_des(struct shm_du_buff * sdb,
- struct dt_pci * dt_pci)
+static void dt_pci_des(uint8_t * head,
+ struct dt_pci * dt_pci)
{
- uint8_t * head;
-
- assert(sdb);
+ assert(head);
assert(dt_pci);
- head = shm_du_buff_head(sdb);
-
/* Decrease TTL */
--*(head + dt_pci_info.ttl_o);
@@ -184,24 +176,28 @@ struct {
pthread_t listener;
} dt;
-static int dt_stat_read(const char * path,
- char * buf,
- size_t len)
+static int dt_rib_read(const char * path,
+ char * buf,
+ size_t len)
{
#ifdef IPCP_FLOW_STATS
int fd;
int i;
char str[QOS_BLOCK_LEN + 1];
char addrstr[20];
+ char * entry;
char tmstr[20];
size_t rxqlen = 0;
size_t txqlen = 0;
struct tm * tm;
/* NOTE: we may need stronger checks. */
- fd = atoi(path);
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
+
+ fd = atoi(entry);
- if (len < STAT_FILE_LEN)
+ if (len < RIB_FILE_STRLEN)
return 0;
buf[0] = '\0';
@@ -232,7 +228,6 @@ static int dt_stat_read(const char * path,
"Queued packets (rx): %20zu\n"
"Queued packets (tx): %20zu\n\n",
tmstr, addrstr, rxqlen, txqlen);
-
for (i = 0; i < QOS_CUBE_MAX; ++i) {
sprintf(str,
"Qos cube %3d:\n"
@@ -271,7 +266,7 @@ static int dt_stat_read(const char * path,
pthread_mutex_unlock(&dt.stat[fd].lock);
- return STAT_FILE_LEN;
+ return RIB_FILE_STRLEN;
#else
(void) path;
(void) buf;
@@ -280,7 +275,7 @@ static int dt_stat_read(const char * path,
#endif
}
-static int dt_stat_readdir(char *** buf)
+static int dt_rib_readdir(char *** buf)
{
#ifdef IPCP_FLOW_STATS
char entry[RIB_PATH_LEN + 1];
@@ -317,7 +312,7 @@ static int dt_stat_readdir(char *** buf)
if ((*buf)[idx] == NULL) {
while (idx-- > 0)
free((*buf)[idx]);
- free(buf);
+ free(*buf);
pthread_mutex_unlock(&dt.stat[i].lock);
pthread_rwlock_unlock(&dt.lock);
return -ENOMEM;
@@ -327,11 +322,10 @@ static int dt_stat_readdir(char *** buf)
pthread_mutex_unlock(&dt.stat[i].lock);
}
+ assert((size_t) idx == dt.n_flows);
pthread_rwlock_unlock(&dt.lock);
- assert((size_t) idx == dt.n_flows);
-
return idx;
#else
(void) buf;
@@ -339,45 +333,43 @@ static int dt_stat_readdir(char *** buf)
#endif
}
-static int dt_stat_getattr(const char * path,
- struct stat * st)
+static int dt_rib_getattr(const char * path,
+ struct rib_attr * attr)
{
#ifdef IPCP_FLOW_STATS
- int fd;
+ int fd;
+ char * entry;
- fd = atoi(path);
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
- st->st_mode = S_IFREG | 0755;
- st->st_nlink = 1;
- st->st_uid = getuid();
- st->st_gid = getgid();
+ fd = atoi(entry);
pthread_mutex_lock(&dt.stat[fd].lock);
if (dt.stat[fd].stamp != -1) {
- st->st_size = STAT_FILE_LEN;
- st->st_mtime = dt.stat[fd].stamp;
+ attr->size = RIB_FILE_STRLEN;
+ attr->mtime = dt.stat[fd].stamp;
} else {
- st->st_size = 0;
- st->st_mtime = 0;
+ attr->size = 0;
+ attr->mtime = 0;
}
pthread_mutex_unlock(&dt.stat[fd].lock);
#else
(void) path;
- (void) st;
+ (void) attr;
#endif
return 0;
}
static struct rib_ops r_ops = {
- .read = dt_stat_read,
- .readdir = dt_stat_readdir,
- .getattr = dt_stat_getattr
+ .read = dt_rib_read,
+ .readdir = dt_rib_readdir,
+ .getattr = dt_rib_getattr
};
#ifdef IPCP_FLOW_STATS
-
static void stat_used(int fd,
uint64_t addr)
{
@@ -407,6 +399,7 @@ static void handle_event(void * self,
const void * o)
{
struct conn * c;
+ int fd;
(void) self;
@@ -414,19 +407,20 @@ static void handle_event(void * self,
switch (event) {
case NOTIFY_DT_CONN_ADD:
+ fd = c->flow_info.fd;
#ifdef IPCP_FLOW_STATS
- stat_used(c->flow_info.fd, c->conn_info.addr);
+ stat_used(fd, c->conn_info.addr);
#endif
- psched_add(dt.psched, c->flow_info.fd);
- log_dbg("Added fd %d to packet scheduler.", c->flow_info.fd);
+ psched_add(dt.psched, fd);
+ log_dbg("Added fd %d to packet scheduler.", fd);
break;
case NOTIFY_DT_CONN_DEL:
+ fd = c->flow_info.fd;
#ifdef IPCP_FLOW_STATS
- stat_used(c->flow_info.fd, INVALID_ADDR);
+ stat_used(fd, INVALID_ADDR);
#endif
- psched_del(dt.psched, c->flow_info.fd);
- log_dbg("Removed fd %d from "
- "packet scheduler.", c->flow_info.fd);
+ psched_del(dt.psched, fd);
+ log_dbg("Removed fd %d from packet scheduler.", fd);
break;
default:
break;
@@ -440,17 +434,26 @@ static void packet_handler(int fd,
struct dt_pci dt_pci;
int ret;
int ofd;
-#ifdef IPCP_FLOW_STATS
+ uint8_t * head;
size_t len;
-#else
+
+ len = shm_du_buff_len(sdb);
+
+#ifndef IPCP_FLOW_STATS
(void) fd;
-#endif
+#else
+ pthread_mutex_lock(&dt.stat[fd].lock);
-#ifdef IPCP_FLOW_STATS
- len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
+ ++dt.stat[fd].rcv_pkt[qc];
+ dt.stat[fd].rcv_bytes[qc] += len;
+
+ pthread_mutex_unlock(&dt.stat[fd].lock);
#endif
memset(&dt_pci, 0, sizeof(dt_pci));
- dt_pci_des(sdb, &dt_pci);
+
+ head = shm_du_buff_head(sdb);
+
+ dt_pci_des(head, &dt_pci);
if (dt_pci.dst_addr != ipcpi.dt_addr) {
if (dt_pci.ttl == 0) {
log_dbg("TTL was zero.");
@@ -458,8 +461,6 @@ static void packet_handler(int fd,
#ifdef IPCP_FLOW_STATS
pthread_mutex_lock(&dt.stat[fd].lock);
- ++dt.stat[fd].rcv_pkt[qc];
- dt.stat[fd].rcv_bytes[qc] += len;
++dt.stat[fd].r_drp_pkt[qc];
dt.stat[fd].r_drp_bytes[qc] += len;
@@ -471,13 +472,12 @@ static void packet_handler(int fd,
/* FIXME: Use qoscube from PCI instead of incoming flow. */
ofd = pff_nhop(dt.pff[qc], dt_pci.dst_addr);
if (ofd < 0) {
- log_dbg("No next hop for %" PRIu64, dt_pci.dst_addr);
+ log_dbg("No next hop for %" PRIu64 ".",
+ dt_pci.dst_addr);
ipcp_sdb_release(sdb);
#ifdef IPCP_FLOW_STATS
pthread_mutex_lock(&dt.stat[fd].lock);
- ++dt.stat[fd].rcv_pkt[qc];
- dt.stat[fd].rcv_bytes[qc] += len;
++dt.stat[fd].f_nhp_pkt[qc];
dt.stat[fd].f_nhp_bytes[qc] += len;
@@ -486,6 +486,8 @@ static void packet_handler(int fd,
return;
}
+ (void) ca_calc_ecn(ofd, head + dt_pci_info.ecn_o, qc, len);
+
ret = ipcp_flow_write(ofd, sdb);
if (ret < 0) {
log_dbg("Failed to write packet to fd %d.", ofd);
@@ -493,12 +495,6 @@ static void packet_handler(int fd,
notifier_event(NOTIFY_DT_FLOW_DOWN, &ofd);
ipcp_sdb_release(sdb);
#ifdef IPCP_FLOW_STATS
- pthread_mutex_lock(&dt.stat[fd].lock);
-
- ++dt.stat[fd].rcv_pkt[qc];
- dt.stat[fd].rcv_bytes[qc] += len;
-
- pthread_mutex_unlock(&dt.stat[fd].lock);
pthread_mutex_lock(&dt.stat[ofd].lock);
++dt.stat[ofd].w_drp_pkt[qc];
@@ -509,12 +505,6 @@ static void packet_handler(int fd,
return;
}
#ifdef IPCP_FLOW_STATS
- pthread_mutex_lock(&dt.stat[fd].lock);
-
- ++dt.stat[fd].rcv_pkt[qc];
- dt.stat[fd].rcv_bytes[qc] += len;
-
- pthread_mutex_unlock(&dt.stat[fd].lock);
pthread_mutex_lock(&dt.stat[ofd].lock);
++dt.stat[ofd].snd_pkt[qc];
@@ -525,65 +515,20 @@ static void packet_handler(int fd,
} else {
dt_pci_shrink(sdb);
if (dt_pci.eid >= PROG_RES_FDS) {
- if (ipcp_flow_write(dt_pci.eid, sdb)) {
- ipcp_sdb_release(sdb);
-#ifdef IPCP_FLOW_STATS
- pthread_mutex_lock(&dt.stat[fd].lock);
- ++dt.stat[fd].rcv_pkt[qc];
- dt.stat[fd].rcv_bytes[qc] += len;
- pthread_mutex_unlock(&dt.stat[fd].lock);
-
- pthread_mutex_lock(&dt.stat[dt_pci.eid].lock);
- ++dt.stat[dt_pci.eid].w_drp_pkt[qc];
- dt.stat[dt_pci.eid].w_drp_bytes[qc] += len;
- pthread_mutex_unlock(&dt.stat[dt_pci.eid].lock);
-#endif
-
- }
-#ifdef IPCP_FLOW_STATS
- pthread_mutex_lock(&dt.stat[fd].lock);
-
- ++dt.stat[fd].rcv_pkt[qc];
- dt.stat[fd].rcv_bytes[qc] += len;
-
- pthread_mutex_unlock(&dt.stat[fd].lock);
- pthread_mutex_lock(&dt.stat[dt_pci.eid].lock);
-
- ++dt.stat[dt_pci.eid].rcv_pkt[qc];
- dt.stat[dt_pci.eid].rcv_bytes[qc] += len;
- ++dt.stat[dt_pci.eid].lcl_r_pkt[qc];
- dt.stat[dt_pci.eid].lcl_r_bytes[qc] += len;
-
- pthread_mutex_unlock(&dt.stat[dt_pci.eid].lock);
-#endif
+ uint8_t ecn = *(head + dt_pci_info.ecn_o);
+ fa_np1_rcv(dt_pci.eid, ecn, sdb);
return;
}
if (dt.comps[dt_pci.eid].post_packet == NULL) {
- log_err("No registered component on eid %d.",
+ log_err("No registered component on eid %" PRIu64 ".",
dt_pci.eid);
ipcp_sdb_release(sdb);
-#ifdef IPCP_FLOW_STATS
- pthread_mutex_lock(&dt.stat[fd].lock);
-
- ++dt.stat[fd].rcv_pkt[qc];
- dt.stat[fd].rcv_bytes[qc] += len;
-
- pthread_mutex_unlock(&dt.stat[fd].lock);
- pthread_mutex_lock(&dt.stat[dt_pci.eid].lock);
-
- ++dt.stat[dt_pci.eid].w_drp_pkt[qc];
- dt.stat[dt_pci.eid].w_drp_bytes[qc] += len;
-
- pthread_mutex_unlock(&dt.stat[dt_pci.eid].lock);
-#endif
return;
}
#ifdef IPCP_FLOW_STATS
pthread_mutex_lock(&dt.stat[fd].lock);
- ++dt.stat[fd].rcv_pkt[qc];
- dt.stat[fd].rcv_bytes[qc] += len;
++dt.stat[fd].lcl_r_pkt[qc];
dt.stat[fd].lcl_r_bytes[qc] += len;
@@ -620,14 +565,11 @@ static void * dt_conn_handle(void * o)
return 0;
}
-int dt_init(enum pol_routing pr,
- uint8_t addr_size,
- uint8_t eid_size,
- uint8_t max_ttl)
+int dt_init(struct dt_config cfg)
{
int i;
int j;
- char dtstr[256];
+ char dtstr[RIB_NAME_STRLEN + 1];
int pp;
struct conn_info info;
@@ -639,9 +581,14 @@ int dt_init(enum pol_routing pr,
info.pref_syntax = PROTO_FIXED;
info.addr = ipcpi.dt_addr;
- dt_pci_info.addr_size = addr_size;
- dt_pci_info.eid_size = eid_size;
- dt_pci_info.max_ttl = max_ttl;
+ if (cfg.eid_size != 8) { /* only support 64 bits from now */
+ log_warn("Invalid EID size. Only 64 bit is supported.");
+ cfg.eid_size = 8;
+ }
+
+ dt_pci_info.addr_size = cfg.addr_size;
+ dt_pci_info.eid_size = cfg.eid_size;
+ dt_pci_info.max_ttl = cfg.max_ttl;
dt_pci_info.qc_o = dt_pci_info.addr_size;
dt_pci_info.ttl_o = dt_pci_info.qc_o + QOS_LEN;
@@ -649,17 +596,12 @@ int dt_init(enum pol_routing pr,
dt_pci_info.eid_o = dt_pci_info.ecn_o + ECN_LEN;
dt_pci_info.head_size = dt_pci_info.eid_o + dt_pci_info.eid_size;
- if (notifier_reg(handle_event, NULL)) {
- log_err("Failed to register with notifier.");
- goto fail_notifier_reg;
- }
-
if (connmgr_comp_init(COMPID_DT, &info)) {
log_err("Failed to register with connmgr.");
goto fail_connmgr_comp_init;
}
- pp = routing_init(pr);
+ pp = routing_init(cfg.routing_type);
if (pp < 0) {
log_err("Failed to init routing.");
goto fail_routing;
@@ -697,6 +639,7 @@ int dt_init(enum pol_routing pr,
for (i = 0; i < PROG_MAX_FLOWS; ++i)
if (pthread_mutex_init(&dt.stat[i].lock, NULL)) {
+ log_err("Failed to init mutex for flow %d.", i);
for (j = 0; j < i; ++j)
pthread_mutex_destroy(&dt.stat[j].lock);
goto fail_stat_lock;
@@ -705,8 +648,10 @@ int dt_init(enum pol_routing pr,
dt.n_flows = 0;
#endif
sprintf(dtstr, "%s.%" PRIu64, DT, ipcpi.dt_addr);
- if (rib_reg(dtstr, &r_ops))
+ if (rib_reg(dtstr, &r_ops)) {
+ log_err("Failed to register RIB.");
goto fail_rib_reg;
+ }
return 0;
@@ -730,16 +675,16 @@ int dt_init(enum pol_routing pr,
fail_routing:
connmgr_comp_fini(COMPID_DT);
fail_connmgr_comp_init:
- notifier_unreg(&handle_event);
- fail_notifier_reg:
return -1;
}
void dt_fini(void)
{
+ char dtstr[RIB_NAME_STRLEN + 1];
int i;
- rib_unreg(DT);
+ sprintf(dtstr, "%s.%" PRIu64, DT, ipcpi.dt_addr);
+ rib_unreg(dtstr);
#ifdef IPCP_FLOW_STATS
for (i = 0; i < PROG_MAX_FLOWS; ++i)
pthread_mutex_destroy(&dt.stat[i].lock);
@@ -757,16 +702,19 @@ void dt_fini(void)
routing_fini();
connmgr_comp_fini(COMPID_DT);
-
- notifier_unreg(&handle_event);
}
int dt_start(void)
{
- dt.psched = psched_create(packet_handler);
+ dt.psched = psched_create(packet_handler, ipcp_flow_read);
if (dt.psched == NULL) {
log_err("Failed to create N-1 packet scheduler.");
- return -1;
+ goto fail_psched;
+ }
+
+ if (notifier_reg(handle_event, NULL)) {
+ log_err("Failed to register with notifier.");
+ goto fail_notifier_reg;
}
if (pthread_create(&dt.listener, NULL, dt_conn_handle, NULL)) {
@@ -776,12 +724,21 @@ int dt_start(void)
}
return 0;
+
+ fail_notifier_reg:
+ psched_destroy(dt.psched);
+ fail_psched:
+ return -1;
+
}
void dt_stop(void)
{
pthread_cancel(dt.listener);
pthread_join(dt.listener, NULL);
+
+ notifier_unreg(&handle_event);
+
psched_destroy(dt.psched);
}
@@ -789,81 +746,93 @@ int dt_reg_comp(void * comp,
void (* func)(void * func, struct shm_du_buff *),
char * name)
{
- int res_fd;
+ int eid;
assert(func);
pthread_rwlock_wrlock(&dt.lock);
- res_fd = bmp_allocate(dt.res_fds);
- if (!bmp_is_id_valid(dt.res_fds, res_fd)) {
- log_warn("Reserved fds depleted.");
+ eid = bmp_allocate(dt.res_fds);
+ if (!bmp_is_id_valid(dt.res_fds, eid)) {
+ log_err("Cannot allocate EID.");
pthread_rwlock_unlock(&dt.lock);
return -EBADF;
}
- assert(dt.comps[res_fd].post_packet == NULL);
- assert(dt.comps[res_fd].comp == NULL);
- assert(dt.comps[res_fd].name == NULL);
+ assert(dt.comps[eid].post_packet == NULL);
+ assert(dt.comps[eid].comp == NULL);
+ assert(dt.comps[eid].name == NULL);
- dt.comps[res_fd].post_packet = func;
- dt.comps[res_fd].comp = comp;
- dt.comps[res_fd].name = name;
+ dt.comps[eid].post_packet = func;
+ dt.comps[eid].comp = comp;
+ dt.comps[eid].name = name;
pthread_rwlock_unlock(&dt.lock);
#ifdef IPCP_FLOW_STATS
- stat_used(res_fd, ipcpi.dt_addr);
+ stat_used(eid, ipcpi.dt_addr);
#endif
- return res_fd;
+ return eid;
}
int dt_write_packet(uint64_t dst_addr,
qoscube_t qc,
- int np1_fd,
+ uint64_t eid,
struct shm_du_buff * sdb)
{
- int fd;
struct dt_pci dt_pci;
+ int fd;
int ret;
-#ifdef IPCP_FLOW_STATS
+ uint8_t * head;
size_t len;
-#endif
+
assert(sdb);
assert(dst_addr != ipcpi.dt_addr);
+ len = shm_du_buff_len(sdb);
+
+#ifdef IPCP_FLOW_STATS
+ if (eid < PROG_RES_FDS) {
+ pthread_mutex_lock(&dt.stat[eid].lock);
+
+ ++dt.stat[eid].lcl_r_pkt[qc];
+ dt.stat[eid].lcl_r_bytes[qc] += len;
+
+ pthread_mutex_unlock(&dt.stat[eid].lock);
+ }
+#endif
fd = pff_nhop(dt.pff[qc], dst_addr);
if (fd < 0) {
log_dbg("Could not get nhop for addr %" PRIu64 ".", dst_addr);
#ifdef IPCP_FLOW_STATS
- len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
-
- pthread_mutex_lock(&dt.stat[np1_fd].lock);
+ if (eid < PROG_RES_FDS) {
+ pthread_mutex_lock(&dt.stat[eid].lock);
- ++dt.stat[np1_fd].lcl_r_pkt[qc];
- dt.stat[np1_fd].lcl_r_bytes[qc] += len;
- ++dt.stat[np1_fd].f_nhp_pkt[qc];
- dt.stat[np1_fd].f_nhp_bytes[qc] += len;
+ ++dt.stat[eid].lcl_r_pkt[qc];
+ dt.stat[eid].lcl_r_bytes[qc] += len;
- pthread_mutex_unlock(&dt.stat[np1_fd].lock);
+ pthread_mutex_unlock(&dt.stat[eid].lock);
+ }
#endif
- return -1;
+ return -EPERM;
+ }
+
+ head = shm_du_buff_head_alloc(sdb, dt_pci_info.head_size);
+ if (head == NULL) {
+ log_dbg("Failed to allocate DT header.");
+ goto fail_write;
}
+ len = shm_du_buff_len(sdb);
+
dt_pci.dst_addr = dst_addr;
dt_pci.qc = qc;
- dt_pci.eid = np1_fd;
+ dt_pci.eid = eid;
dt_pci.ecn = 0;
- if (dt_pci_ser(sdb, &dt_pci)) {
- log_dbg("Failed to serialize PDU.");
-#ifdef IPCP_FLOW_STATS
- len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
-#endif
- goto fail_write;
- }
-#ifdef IPCP_FLOW_STATS
- len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
-#endif
+ (void) ca_calc_ecn(fd, &dt_pci.ecn, qc, len);
+
+ dt_pci_ser(head, &dt_pci);
+
ret = ipcp_flow_write(fd, sdb);
if (ret < 0) {
log_dbg("Failed to write packet to fd %d.", fd);
@@ -872,12 +841,6 @@ int dt_write_packet(uint64_t dst_addr,
goto fail_write;
}
#ifdef IPCP_FLOW_STATS
- pthread_mutex_lock(&dt.stat[np1_fd].lock);
-
- ++dt.stat[np1_fd].lcl_r_pkt[qc];
- dt.stat[np1_fd].lcl_r_bytes[qc] += len;
-
- pthread_mutex_unlock(&dt.stat[np1_fd].lock);
pthread_mutex_lock(&dt.stat[fd].lock);
if (dt_pci.eid < PROG_RES_FDS) {
@@ -893,15 +856,9 @@ int dt_write_packet(uint64_t dst_addr,
fail_write:
#ifdef IPCP_FLOW_STATS
- pthread_mutex_lock(&dt.stat[np1_fd].lock);
-
- ++dt.stat[np1_fd].lcl_w_pkt[qc];
- dt.stat[np1_fd].lcl_w_bytes[qc] += len;
-
- pthread_mutex_unlock(&dt.stat[np1_fd].lock);
pthread_mutex_lock(&dt.stat[fd].lock);
- if (dt_pci.eid < PROG_RES_FDS) {
+ if (eid < PROG_RES_FDS) {
++dt.stat[fd].lcl_w_pkt[qc];
dt.stat[fd].lcl_w_bytes[qc] += len;
}
diff --git a/src/ipcpd/unicast/dt.h b/src/ipcpd/unicast/dt.h
index 73b71a92..7198a013 100644
--- a/src/ipcpd/unicast/dt.h
+++ b/src/ipcpd/unicast/dt.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Data Transfer component
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,11 +31,7 @@
#define DT_PROTO "dtp"
#define INVALID_ADDR 0
-int dt_init(enum pol_routing pr,
- uint8_t addr_size,
- uint8_t eid_size,
- uint8_t max_ttl
-);
+int dt_init(struct dt_config cfg);
void dt_fini(void);
@@ -49,7 +45,7 @@ int dt_reg_comp(void * comp,
int dt_write_packet(uint64_t dst_addr,
qoscube_t qc,
- int res_fd,
+ uint64_t eid,
struct shm_du_buff * sdb);
#endif /* OUROBOROS_IPCPD_UNICAST_DT_H */
diff --git a/src/ipcpd/unicast/enroll.c b/src/ipcpd/unicast/enroll.c
deleted file mode 100644
index 3b4a5a89..00000000
--- a/src/ipcpd/unicast/enroll.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * Enrollment Task
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 199309L
-#endif
-
-#define OUROBOROS_PREFIX "enrollment"
-
-#include <ouroboros/endian.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/time_utils.h>
-#include <ouroboros/dev.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/sockets.h>
-
-#include "connmgr.h"
-#include "enroll.h"
-#include "ipcp.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-
-#include "ipcp_config.pb-c.h"
-typedef EnrollMsg enroll_msg_t;
-
-#define ENROLL_COMP "Enrollment"
-#define ENROLL_PROTO "OEP" /* Ouroboros enrollment protocol */
-#define ENROLL_WARN_TIME_OFFSET 20
-#define ENROLL_BUF_LEN 1024
-
-enum enroll_state {
- ENROLL_NULL = 0,
- ENROLL_INIT,
- ENROLL_RUNNING
-};
-
-struct {
- struct ipcp_config conf;
- enum enroll_state state;
- pthread_t listener;
-} enroll;
-
-static int send_rcv_enroll_msg(int fd)
-{
- enroll_msg_t req = ENROLL_MSG__INIT;
- enroll_msg_t * reply;
- uint8_t buf[ENROLL_BUF_LEN];
- ssize_t len;
- ssize_t delta_t;
- struct timespec t0;
- struct timespec rtt;
-
- req.code = ENROLL_CODE__ENROLL_REQ;
-
- len = enroll_msg__get_packed_size(&req);
- if (len < 0) {
- log_dbg("Failed pack request message.");
- return -1;
- }
-
- enroll_msg__pack(&req, buf);
-
- clock_gettime(CLOCK_REALTIME, &t0);
-
- if (flow_write(fd, buf, len) < 0) {
- log_dbg("Failed to send request message.");
- return -1;
- }
-
- len = flow_read(fd, buf, ENROLL_BUF_LEN);
- if (len < 0) {
- log_dbg("No enrollment reply received.");
- return -1;
- }
-
- log_dbg("Received enrollment info (%zd bytes).", len);
-
- reply = enroll_msg__unpack(NULL, len, buf);
- if (reply == NULL) {
- log_dbg("No enrollment response.");
- return -1;
- }
-
- if (reply->code != ENROLL_CODE__ENROLL_BOOT) {
- log_dbg("Failed to unpack enrollment response.");
- enroll_msg__free_unpacked(reply, NULL);
- return -1;
- }
-
- if (!(reply->has_t_sec && reply->has_t_nsec)) {
- log_dbg("No time in response message.");
- enroll_msg__free_unpacked(reply, NULL);
- return -1;
- }
-
- clock_gettime(CLOCK_REALTIME, &rtt);
-
- delta_t = ts_diff_ms(&t0, &rtt);
-
- rtt.tv_sec = reply->t_sec;
- rtt.tv_nsec = reply->t_nsec;
-
- if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET)
- log_warn("Clock offset above threshold.");
-
- strcpy(enroll.conf.layer_info.layer_name,
- reply->conf->layer_info->layer_name);
- enroll.conf.type = reply->conf->ipcp_type;
- enroll.conf.addr_size = reply->conf->addr_size;
- enroll.conf.eid_size = reply->conf->eid_size;
- enroll.conf.max_ttl = reply->conf->max_ttl;
- enroll.conf.addr_auth_type = reply->conf->addr_auth_type;
- enroll.conf.routing_type = reply->conf->routing_type;
- enroll.conf.layer_info.dir_hash_algo
- = reply->conf->layer_info->dir_hash_algo;
-
- enroll_msg__free_unpacked(reply, NULL);
-
- return 0;
-}
-
-static ssize_t enroll_pack(uint8_t ** buf)
-{
- enroll_msg_t msg = ENROLL_MSG__INIT;
- ipcp_config_msg_t config = IPCP_CONFIG_MSG__INIT;
- layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT;
- struct timespec now;
- ssize_t len;
-
- clock_gettime(CLOCK_REALTIME, &now);
-
- msg.code = ENROLL_CODE__ENROLL_BOOT;
- msg.has_t_sec = true;
- msg.t_sec = now.tv_sec;
- msg.has_t_nsec = true;
- msg.t_nsec = now.tv_nsec;
- msg.conf = &config;
-
- config.ipcp_type = enroll.conf.type;
- config.has_addr_size = true;
- config.addr_size = enroll.conf.addr_size;
- config.has_eid_size = true;
- config.eid_size = enroll.conf.eid_size;
- config.has_max_ttl = true;
- config.max_ttl = enroll.conf.max_ttl;
- config.has_addr_auth_type = true;
- config.addr_auth_type = enroll.conf.addr_auth_type;
- config.has_routing_type = true;
- config.routing_type = enroll.conf.routing_type;
- config.layer_info = &layer_info;
-
- layer_info.layer_name = (char *) enroll.conf.layer_info.layer_name;
- layer_info.dir_hash_algo = enroll.conf.layer_info.dir_hash_algo;
-
- len = enroll_msg__get_packed_size(&msg);
-
- *buf = malloc(len);
- if (*buf == NULL)
- return -1;
-
- enroll_msg__pack(&msg, *buf);
-
- return len;
-}
-
-static void * enroll_handle(void * o)
-{
- struct conn conn;
- uint8_t buf[ENROLL_BUF_LEN];
- uint8_t * reply;
- ssize_t len;
- enroll_msg_t * msg;
-
- (void) o;
-
- while (true) {
- if (connmgr_wait(COMPID_ENROLL, &conn)) {
- log_err("Failed to get next connection.");
- continue;
- }
-
- len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN);
- if (len < 0) {
- log_err("Failed to read from flow.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- msg = enroll_msg__unpack(NULL, len, buf);
- if (msg == NULL) {
- log_err("Failed to unpack message.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- if (msg->code != ENROLL_CODE__ENROLL_REQ) {
- log_err("Wrong message type.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- enroll_msg__free_unpacked(msg, NULL);
- continue;
- }
-
- log_dbg("Enrolling a new neighbor.");
-
- enroll_msg__free_unpacked(msg, NULL);
-
- len = enroll_pack(&reply);
- if (reply == NULL) {
- log_err("Failed to pack enrollment message.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- log_dbg("Sending enrollment info (%zd bytes).", len);
-
- if (flow_write(conn.flow_info.fd, reply, len) < 0) {
- log_err("Failed respond to enrollment request.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- free(reply);
- continue;
- }
-
- free(reply);
-
- len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN);
- if (len < 0) {
- log_err("Failed to read from flow.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- msg = enroll_msg__unpack(NULL, len, buf);
- if (msg == NULL) {
- log_err("Failed to unpack message.");
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- if (msg->code != ENROLL_CODE__ENROLL_DONE || !msg->has_result) {
- log_err("Wrong message type.");
- enroll_msg__free_unpacked(msg, NULL);
- connmgr_dealloc(COMPID_ENROLL, &conn);
- continue;
- }
-
- if (msg->result == 0)
- log_dbg("Neighbor enrollment successful.");
- else
- log_dbg("Neigbor reported failed enrollment.");
-
- enroll_msg__free_unpacked(msg, NULL);
-
- connmgr_dealloc(COMPID_ENROLL, &conn);
- }
-
- return 0;
-}
-
-int enroll_boot(struct conn * conn)
-{
- log_dbg("Getting boot information.");
-
- if (send_rcv_enroll_msg(conn->flow_info.fd)) {
- log_err("Failed to enroll.");
- return -1;
- }
-
- return 0;
-}
-
-int enroll_done(struct conn * conn,
- int result)
-{
- enroll_msg_t msg = ENROLL_MSG__INIT;
- uint8_t buf[ENROLL_BUF_LEN];
- ssize_t len;
-
- msg.code = ENROLL_CODE__ENROLL_DONE;
- msg.has_result = true;
- msg.result = result;
-
- len = enroll_msg__get_packed_size(&msg);
- if (len < 0) {
- log_dbg("Failed pack request message.");
- return -1;
- }
-
- enroll_msg__pack(&msg, buf);
-
- if (flow_write(conn->flow_info.fd, buf, len) < 0) {
- log_dbg("Failed to send acknowledgment.");
- return -1;
- }
-
- return 0;
-}
-
-void enroll_bootstrap(const struct ipcp_config * conf)
-{
- assert(conf);
-
- memcpy(&enroll.conf, conf, sizeof(enroll.conf));
-}
-
-struct ipcp_config * enroll_get_conf(void)
-{
- return &enroll.conf;
-}
-
-int enroll_init(void)
-{
- struct conn_info info;
-
- memset(&info, 0, sizeof(info));
-
- strcpy(info.comp_name, ENROLL_COMP);
- strcpy(info.protocol, ENROLL_PROTO);
- info.pref_version = 1;
- info.pref_syntax = PROTO_GPB;
- info.addr = 0;
-
- if (connmgr_comp_init(COMPID_ENROLL, &info)) {
- log_err("Failed to register with connmgr.");
- return -1;
- }
-
- enroll.state = ENROLL_INIT;
-
- return 0;
-}
-
-void enroll_fini(void)
-{
- if (enroll.state == ENROLL_RUNNING)
- pthread_join(enroll.listener, NULL);
-
- connmgr_comp_fini(COMPID_ENROLL);
-}
-
-int enroll_start(void)
-{
- if (pthread_create(&enroll.listener, NULL, enroll_handle, NULL))
- return -1;
-
- enroll.state = ENROLL_RUNNING;
-
- return 0;
-}
-
-void enroll_stop(void)
-{
- if (enroll.state == ENROLL_RUNNING)
- pthread_cancel(enroll.listener);
-}
diff --git a/src/ipcpd/unicast/enroll.h b/src/ipcpd/unicast/enroll.h
deleted file mode 100644
index 804f5d5b..00000000
--- a/src/ipcpd/unicast/enroll.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * Enrollment Task
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IPCPD_UNICAST_ENROLL_H
-#define OUROBOROS_IPCPD_UNICAST_ENROLL_H
-
-#include <ouroboros/ipcp.h>
-
-#include "comp.h"
-
-int enroll_init(void);
-
-void enroll_fini(void);
-
-int enroll_start(void);
-
-void enroll_stop(void);
-
-void enroll_bootstrap(const struct ipcp_config * conf);
-
-int enroll_boot(struct conn * conn);
-
-int enroll_done(struct conn * conn,
- int result);
-
-struct ipcp_config * enroll_get_conf(void);
-
-#endif /* OUROBOROS_IPCPD_UNICAST_ENROLL_H */
diff --git a/src/ipcpd/unicast/fa.c b/src/ipcpd/unicast/fa.c
index e0727e85..3631fd7b 100644
--- a/src/ipcpd/unicast/fa.c
+++ b/src/ipcpd/unicast/fa.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Flow allocator of the IPC Process
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,43 +31,57 @@
#define FA "flow-allocator"
#define OUROBOROS_PREFIX FA
+#include <ouroboros/endian.h>
#include <ouroboros/logs.h>
#include <ouroboros/fqueue.h>
#include <ouroboros/errno.h>
#include <ouroboros/dev.h>
#include <ouroboros/ipcp-dev.h>
+#include <ouroboros/rib.h>
+#include <ouroboros/random.h>
+#include <ouroboros/pthread.h>
#include "dir.h"
#include "fa.h"
#include "psched.h"
#include "ipcp.h"
#include "dt.h"
+#include "ca.h"
-#include <pthread.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
-#define TIMEOUT 10000 /* nanoseconds */
+#if defined (IPCP_FLOW_STATS) && !defined(CLOCK_REALTIME_COARSE)
+#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
+#endif
+
+#define TIMEOUT 10 * MILLION /* nanoseconds */
+
+#define FLOW_REQ 0
+#define FLOW_REPLY 1
+#define FLOW_UPDATE 2
+#define MSGBUFSZ 2048
-#define FLOW_REQ 0
-#define FLOW_REPLY 1
-#define MSGBUFSZ 2048
+#define STAT_FILE_LEN 0
struct fa_msg {
uint64_t s_addr;
- uint32_t r_eid;
- uint32_t s_eid;
+ uint64_t r_eid;
+ uint64_t s_eid;
uint8_t code;
int8_t response;
+ uint16_t ece;
/* QoS parameters from spec, aligned */
- uint8_t availability;
- uint8_t in_order;
uint32_t delay;
uint64_t bandwidth;
uint32_t loss;
uint32_t ber;
uint32_t max_gap;
+ uint32_t timeout;
uint16_t cypher_s;
+ uint8_t availability;
+ uint8_t in_order;
} __attribute__((packed));
struct cmd {
@@ -75,11 +89,33 @@ struct cmd {
struct shm_du_buff * sdb;
};
+struct fa_flow {
+#ifdef IPCP_FLOW_STATS
+ time_t stamp; /* Flow creation */
+ size_t p_snd; /* Packets sent */
+ size_t p_snd_f; /* Packets sent fail */
+ size_t b_snd; /* Bytes sent */
+ size_t b_snd_f; /* Bytes sent fail */
+ size_t p_rcv; /* Packets received */
+ size_t p_rcv_f; /* Packets received fail */
+ size_t b_rcv; /* Bytes received */
+ size_t b_rcv_f; /* Bytes received fail */
+ size_t u_snd; /* Flow updates sent */
+ size_t u_rcv; /* Flow updates received */
+#endif
+ uint64_t s_eid; /* Local endpoint id */
+ uint64_t r_eid; /* Remote endpoint id */
+ uint64_t r_addr; /* Remote address */
+ void * ctx; /* Congestion avoidance context */
+};
+
struct {
pthread_rwlock_t flows_lock;
- int r_eid[PROG_MAX_FLOWS];
- uint64_t r_addr[PROG_MAX_FLOWS];
- int fd;
+ struct fa_flow flows[PROG_MAX_FLOWS];
+#ifdef IPCP_FLOW_STATS
+ size_t n_flows;
+#endif
+ uint32_t eid;
struct list_head cmds;
pthread_cond_t cond;
@@ -89,26 +125,289 @@ struct {
struct psched * psched;
} fa;
+static int fa_rib_read(const char * path,
+ char * buf,
+ size_t len)
+{
+#ifdef IPCP_FLOW_STATS
+ struct fa_flow * flow;
+ int fd;
+ char r_addrstr[21];
+ char s_eidstr[21];
+ char r_eidstr[21];
+ char tmstr[20];
+ char castr[1024];
+ char * entry;
+ struct tm * tm;
+
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
+
+ fd = atoi(entry);
+
+ if (fd < 0 || fd >= PROG_MAX_FLOWS)
+ return -1;
+
+ if (len < 1536)
+ return 0;
+
+ flow = &fa.flows[fd];
+
+ buf[0] = '\0';
+
+ pthread_rwlock_rdlock(&fa.flows_lock);
+
+ if (flow->stamp ==0) {
+ pthread_rwlock_unlock(&fa.flows_lock);
+ return 0;
+ }
+
+ sprintf(r_addrstr, "%" PRIu64, flow->r_addr);
+ sprintf(s_eidstr, "%" PRIu64, flow->s_eid);
+ sprintf(r_eidstr, "%" PRIu64, flow->r_eid);
+
+ tm = localtime(&flow->stamp);
+ strftime(tmstr, sizeof(tmstr), "%F %T", tm);
+
+ ca_print_stats(flow->ctx, castr, 1024);
+
+ sprintf(buf,
+ "Flow established at: %20s\n"
+ "Remote address: %20s\n"
+ "Local endpoint ID: %20s\n"
+ "Remote endpoint ID: %20s\n"
+ "Sent (packets): %20zu\n"
+ "Sent (bytes): %20zu\n"
+ "Send failed (packets): %20zu\n"
+ "Send failed (bytes): %20zu\n"
+ "Received (packets): %20zu\n"
+ "Received (bytes): %20zu\n"
+ "Receive failed (packets): %20zu\n"
+ "Receive failed (bytes): %20zu\n"
+ "Sent flow updates (packets): %20zu\n"
+ "Received flow updates (packets): %20zu\n"
+ "%s",
+ tmstr, r_addrstr,
+ s_eidstr, r_eidstr,
+ flow->p_snd, flow->b_snd,
+ flow->p_snd_f, flow->b_snd_f,
+ flow->p_rcv, flow->b_rcv,
+ flow->b_rcv_f, flow->b_rcv_f,
+ flow->u_snd, flow->u_rcv,
+ castr);
+
+ pthread_rwlock_unlock(&fa.flows_lock);
+
+ return strlen(buf);
+#else
+ (void) path;
+ (void) buf;
+ (void) len;
+ return 0;
+#endif
+}
+
+static int fa_rib_readdir(char *** buf)
+{
+#ifdef IPCP_FLOW_STATS
+ char entry[RIB_PATH_LEN + 1];
+ size_t i;
+ int idx = 0;
+
+ pthread_rwlock_rdlock(&fa.flows_lock);
+
+ if (fa.n_flows < 1) {
+ pthread_rwlock_unlock(&fa.flows_lock);
+ return 0;
+ }
+
+ *buf = malloc(sizeof(**buf) * fa.n_flows);
+ if (*buf == NULL) {
+ pthread_rwlock_unlock(&fa.flows_lock);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < PROG_MAX_FLOWS; ++i) {
+ struct fa_flow * flow;
+
+ flow = &fa.flows[i];
+ if (flow->stamp == 0)
+ continue;
+
+ sprintf(entry, "%zu", i);
+
+ (*buf)[idx] = malloc(strlen(entry) + 1);
+ if ((*buf)[idx] == NULL) {
+ while (idx-- > 0)
+ free((*buf)[idx]);
+ free(*buf);
+ pthread_rwlock_unlock(&fa.flows_lock);
+ return -ENOMEM;
+ }
+
+ strcpy((*buf)[idx++], entry);
+ }
+
+ assert((size_t) idx == fa.n_flows);
+
+ pthread_rwlock_unlock(&fa.flows_lock);
+
+ return idx;
+#else
+ (void) buf;
+ return 0;
+#endif
+}
+
+static int fa_rib_getattr(const char * path,
+ struct rib_attr * attr)
+{
+#ifdef IPCP_FLOW_STATS
+ int fd;
+ char * entry;
+ struct fa_flow * flow;
+
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
+
+ fd = atoi(entry);
+
+ flow = &fa.flows[fd];
+
+ pthread_rwlock_rdlock(&fa.flows_lock);
+
+ if (flow->stamp != 0) {
+ attr->size = 1536;
+ attr->mtime = flow->stamp;
+ } else {
+ attr->size = 0;
+ attr->mtime = 0;
+ }
+
+ pthread_rwlock_unlock(&fa.flows_lock);
+#else
+ (void) path;
+ (void) attr;
+#endif
+ return 0;
+}
+
+static struct rib_ops r_ops = {
+ .read = fa_rib_read,
+ .readdir = fa_rib_readdir,
+ .getattr = fa_rib_getattr
+};
+
+static int eid_to_fd(uint64_t eid)
+{
+ struct fa_flow * flow;
+ int fd;
+
+ fd = eid & 0xFFFFFFFF;
+
+ if (fd < 0 || fd >= PROG_MAX_FLOWS)
+ return -1;
+
+ flow = &fa.flows[fd];
+
+ if (flow->s_eid == eid)
+ return fd;
+
+ return -1;
+}
+
+static uint64_t gen_eid(int fd)
+{
+ uint32_t rnd;
+
+ if (random_buffer(&rnd, sizeof(rnd)) < 0)
+ return fa.eid; /* INVALID */
+
+ fd &= 0xFFFFFFFF;
+
+ return ((uint64_t) rnd << 32) + fd;
+}
+
static void packet_handler(int fd,
qoscube_t qc,
struct shm_du_buff * sdb)
{
- pthread_rwlock_rdlock(&fa.flows_lock);
+ struct fa_flow * flow;
+ uint64_t r_addr;
+ uint64_t r_eid;
+ ca_wnd_t wnd;
+ size_t len;
- if (dt_write_packet(fa.r_addr[fd], qc, fa.r_eid[fd], sdb)) {
- pthread_rwlock_unlock(&fa.flows_lock);
+ flow = &fa.flows[fd];
+
+ pthread_rwlock_wrlock(&fa.flows_lock);
+
+ len = shm_du_buff_len(sdb);
+
+#ifdef IPCP_FLOW_STATS
+ ++flow->p_snd;
+ flow->b_snd += len;
+#endif
+ wnd = ca_ctx_update_snd(flow->ctx, len);
+
+ r_addr = flow->r_addr;
+ r_eid = flow->r_eid;
+
+ pthread_rwlock_unlock(&fa.flows_lock);
+
+ ca_wnd_wait(wnd);
+
+ if (dt_write_packet(r_addr, qc, r_eid, sdb)) {
ipcp_sdb_release(sdb);
- log_warn("Failed to forward packet.");
+ log_dbg("Failed to forward packet.");
+#ifdef IPCP_FLOW_STATS
+ pthread_rwlock_wrlock(&fa.flows_lock);
+ ++flow->p_snd_f;
+ flow->b_snd_f += len;
+ pthread_rwlock_unlock(&fa.flows_lock);
+#endif
return;
}
+}
- pthread_rwlock_unlock(&fa.flows_lock);
+static int fa_flow_init(struct fa_flow * flow)
+{
+#ifdef IPCP_FLOW_STATS
+ struct timespec now;
+#endif
+ memset(flow, 0, sizeof(*flow));
+
+ flow->r_eid = -1;
+ flow->s_eid = -1;
+ flow->r_addr = INVALID_ADDR;
+
+ flow->ctx = ca_ctx_create();
+ if (flow->ctx == NULL)
+ return -1;
+
+#ifdef IPCP_FLOW_STATS
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ flow->stamp = now.tv_sec;
+
+ ++fa.n_flows;
+#endif
+ return 0;
}
-static void destroy_conn(int fd)
+static void fa_flow_fini(struct fa_flow * flow)
{
- fa.r_eid[fd] = -1;
- fa.r_addr[fd] = INVALID_ADDR;
+ ca_ctx_destroy(flow->ctx);
+
+ memset(flow, 0, sizeof(*flow));
+
+ flow->r_eid = -1;
+ flow->s_eid = -1;
+ flow->r_addr = INVALID_ADDR;
+
+#ifdef IPCP_FLOW_STATS
+ --fa.n_flows;
+#endif
}
static void fa_post_packet(void * comp,
@@ -138,146 +437,200 @@ static void fa_post_packet(void * comp,
pthread_mutex_unlock(&fa.mtx);
}
-static void * fa_handle_packet(void * o)
+static size_t fa_wait_for_fa_msg(struct fa_msg * msg)
{
- struct timespec ts = {0, TIMEOUT * 1000};
+ struct cmd * cmd;
+ size_t len;
- (void) o;
+ pthread_mutex_lock(&fa.mtx);
- while (true) {
- struct timespec abstime;
- int fd;
- uint8_t buf[MSGBUFSZ];
- struct fa_msg * msg;
- qosspec_t qs;
- struct cmd * cmd;
- size_t len;
- size_t msg_len;
+ pthread_cleanup_push(__cleanup_mutex_unlock, &fa.mtx);
- pthread_mutex_lock(&fa.mtx);
+ while (list_is_empty(&fa.cmds))
+ pthread_cond_wait(&fa.cond, &fa.mtx);
- pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock,
- &fa.mtx);
+ cmd = list_last_entry(&fa.cmds, struct cmd, next);
+ list_del(&cmd->next);
- while (list_is_empty(&fa.cmds))
- pthread_cond_wait(&fa.cond, &fa.mtx);
+ pthread_cleanup_pop(true);
- cmd = list_last_entry(&fa.cmds, struct cmd, next);
- list_del(&cmd->next);
+ len = shm_du_buff_len(cmd->sdb);
+ if (len > MSGBUFSZ || len < sizeof(*msg)) {
+ log_warn("Invalid flow allocation message (len: %zd).", len);
+ free(cmd);
+ return 0; /* No valid message */
+ }
- pthread_cleanup_pop(true);
+ memcpy(msg, shm_du_buff_head(cmd->sdb), len);
- len = shm_du_buff_tail(cmd->sdb) - shm_du_buff_head(cmd->sdb);
+ ipcp_sdb_release(cmd->sdb);
- if (len > MSGBUFSZ) {
- log_err("Message over buffer size.");
- free(cmd);
- continue;
- }
+ free(cmd);
- msg = (struct fa_msg *) buf;
+ return len;
+}
- /* Depending on the message call the function in ipcp-dev.h */
+static int fa_handle_flow_req(struct fa_msg * msg,
+ size_t len)
+{
+ size_t msg_len;
+ int fd;
+ qosspec_t qs;
+ struct fa_flow * flow;
+ uint8_t * dst;
+ buffer_t data; /* Piggbacked data on flow alloc request. */
+
+ msg_len = sizeof(*msg) + ipcp_dir_hash_len();
+ if (len < msg_len) {
+ log_err("Invalid flow allocation request");
+ return -EPERM;
+ }
- memcpy(msg, shm_du_buff_head(cmd->sdb), len);
+ dst = (uint8_t *)(msg + 1);
+ data.data = (uint8_t *) msg + msg_len;
+ data.len = len - msg_len;
- ipcp_sdb_release(cmd->sdb);
+ qs.delay = ntoh32(msg->delay);
+ qs.bandwidth = ntoh64(msg->bandwidth);
+ qs.availability = msg->availability;
+ qs.loss = ntoh32(msg->loss);
+ qs.ber = ntoh32(msg->ber);
+ qs.in_order = msg->in_order;
+ qs.max_gap = ntoh32(msg->max_gap);
+ qs.cypher_s = ntoh16(msg->cypher_s);
+ qs.timeout = ntoh32(msg->timeout);
- free(cmd);
+ fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UNICAST_MPL, &data);
+ if (fd < 0)
+ return fd;
- switch (msg->code) {
- case FLOW_REQ:
- msg_len = sizeof(*msg) + ipcp_dir_hash_len();
-
- assert(len >= msg_len);
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != -1 &&
- ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- log_dbg("Won't allocate over non-operational"
- "IPCP.");
- continue;
- }
-
- assert(ipcpi.alloc_id == -1);
-
- qs.delay = ntoh32(msg->delay);
- qs.bandwidth = ntoh64(msg->bandwidth);
- qs.availability = msg->availability;
- qs.loss = ntoh32(msg->loss);
- qs.ber = ntoh32(msg->ber);
- qs.in_order = msg->in_order;
- qs.max_gap = ntoh32(msg->max_gap);
- qs.cypher_s = ntoh16(msg->cypher_s);
-
- fd = ipcp_flow_req_arr((uint8_t *) (msg + 1),
- ipcp_dir_hash_len(),
- qs,
- buf + msg_len,
- len - msg_len);
- if (fd < 0) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- log_err("Failed to get fd for flow.");
- continue;
- }
-
- pthread_rwlock_wrlock(&fa.flows_lock);
-
- fa.r_eid[fd] = ntoh32(msg->s_eid);
- fa.r_addr[fd] = ntoh64(msg->s_addr);
+ flow = &fa.flows[fd];
- pthread_rwlock_unlock(&fa.flows_lock);
+ pthread_rwlock_wrlock(&fa.flows_lock);
- ipcpi.alloc_id = fd;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
+ fa_flow_init(flow);
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ flow->s_eid = gen_eid(fd);
+ flow->r_eid = ntoh64(msg->s_eid);
+ flow->r_addr = ntoh64(msg->s_addr);
- break;
- case FLOW_REPLY:
- assert(len >= sizeof(*msg));
+ pthread_rwlock_unlock(&fa.flows_lock);
- pthread_rwlock_wrlock(&fa.flows_lock);
+ return fd;
+}
- fa.r_eid[ntoh32(msg->r_eid)] = ntoh32(msg->s_eid);
+static int fa_handle_flow_reply(struct fa_msg * msg,
+ size_t len)
+{
+ int fd;
+ struct fa_flow * flow;
+ buffer_t data; /* Piggbacked data on flow alloc request. */
+ time_t mpl = IPCP_UNICAST_MPL;
- ipcp_flow_alloc_reply(ntoh32(msg->r_eid),
- msg->response,
- buf + sizeof(*msg),
- len - sizeof(*msg));
+ assert(len >= sizeof(*msg));
- if (msg->response < 0)
- destroy_conn(ntoh32(msg->r_eid));
- else
- psched_add(fa.psched, ntoh32(msg->r_eid));
+ data.data = (uint8_t *) msg + sizeof(*msg);
+ data.len = len - sizeof(*msg);
- pthread_rwlock_unlock(&fa.flows_lock);
+ pthread_rwlock_wrlock(&fa.flows_lock);
+
+ fd = eid_to_fd(ntoh64(msg->r_eid));
+ if (fd < 0) {
+ pthread_rwlock_unlock(&fa.flows_lock);
+ log_err("Flow reply for unknown EID %" PRIu64 ".",
+ ntoh64(msg->r_eid));
+ return -ENOTALLOC;
+ }
+
+ flow = &fa.flows[fd];
+
+ flow->r_eid = ntoh64(msg->s_eid);
+
+ if (msg->response < 0)
+ fa_flow_fini(flow);
+ else
+ psched_add(fa.psched, fd);
+
+ pthread_rwlock_unlock(&fa.flows_lock);
+
+ if (ipcp_flow_alloc_reply(fd, msg->response, mpl, &data) < 0) {
+ log_err("Failed to reply for flow allocation on fd %d.", fd);
+ return -EIRMD;
+ }
+
+ return 0;
+}
+
+static int fa_handle_flow_update(struct fa_msg * msg,
+ size_t len)
+{
+ struct fa_flow * flow;
+ int fd;
+
+ (void) len;
+ assert(len >= sizeof(*msg));
+
+ pthread_rwlock_wrlock(&fa.flows_lock);
+
+ fd = eid_to_fd(ntoh64(msg->r_eid));
+ if (fd < 0) {
+ pthread_rwlock_unlock(&fa.flows_lock);
+ log_err("Flow update for unknown EID %" PRIu64 ".",
+ ntoh64(msg->r_eid));
+ return -EPERM;
+ }
+
+ flow = &fa.flows[fd];
+#ifdef IPCP_FLOW_STATS
+ flow->u_rcv++;
+#endif
+ ca_ctx_update_ece(flow->ctx, ntoh16(msg->ece));
+
+ pthread_rwlock_unlock(&fa.flows_lock);
+
+ return 0;
+}
+
+static void * fa_handle_packet(void * o)
+{
+ (void) o;
+
+ while (true) {
+ uint8_t buf[MSGBUFSZ];
+ struct fa_msg * msg;
+ size_t len;
+
+ msg = (struct fa_msg *) buf;
+
+ len = fa_wait_for_fa_msg(msg);
+ if (len == 0)
+ continue;
+ switch (msg->code) {
+ case FLOW_REQ:
+ if (fa_handle_flow_req(msg, len) < 0)
+ log_err("Error handling flow alloc request.");
+ break;
+ case FLOW_REPLY:
+ if (fa_handle_flow_reply(msg, len) < 0)
+ log_err("Error handling flow reply.");
+ break;
+ case FLOW_UPDATE:
+ if (fa_handle_flow_update(msg, len) < 0)
+ log_err("Error handling flow update.");
break;
default:
- log_err("Got an unknown flow allocation message.");
+ log_warn("Recieved unknown flow allocation message.");
break;
}
}
+
+ return (void *) 0;
}
int fa_init(void)
{
- int i;
-
- for (i = 0; i < PROG_MAX_FLOWS; ++i)
- destroy_conn(i);
+ pthread_condattr_t cattr;
if (pthread_rwlock_init(&fa.flows_lock, NULL))
goto fail_rwlock;
@@ -285,26 +638,45 @@ int fa_init(void)
if (pthread_mutex_init(&fa.mtx, NULL))
goto fail_mtx;
- if (pthread_cond_init(&fa.cond, NULL))
+ if (pthread_condattr_init(&cattr))
+ goto fail_cattr;
+
+#ifndef __APPLE__
+ pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
+#endif
+ if (pthread_cond_init(&fa.cond, &cattr))
goto fail_cond;
+ pthread_condattr_destroy(&cattr);
+
list_head_init(&fa.cmds);
- fa.fd = dt_reg_comp(&fa, &fa_post_packet, FA);
+ if (rib_reg(FA, &r_ops))
+ goto fail_rib_reg;
+
+ fa.eid = dt_reg_comp(&fa, &fa_post_packet, FA);
+ if ((int) fa.eid < 0)
+ goto fail_rib_reg;
return 0;
+ fail_rib_reg:
+ pthread_cond_destroy(&fa.cond);
fail_cond:
+ pthread_condattr_destroy(&cattr);
+ fail_cattr:
pthread_mutex_destroy(&fa.mtx);
fail_mtx:
pthread_rwlock_destroy(&fa.flows_lock);
fail_rwlock:
- log_err("Failed to initialize flow allocator.");
+
return -1;
}
void fa_fini(void)
{
+ rib_unreg(FA);
+
pthread_cond_destroy(&fa.cond);;
pthread_mutex_destroy(&fa.mtx);
pthread_rwlock_destroy(&fa.flows_lock);
@@ -316,7 +688,7 @@ int fa_start(void)
int pol;
int max;
- fa.psched = psched_create(packet_handler);
+ fa.psched = psched_create(packet_handler, np1_flow_read);
if (fa.psched == NULL) {
log_err("Failed to start packet scheduler.");
goto fail_psched;
@@ -353,7 +725,6 @@ int fa_start(void)
fail_thread:
psched_destroy(fa.psched);
fail_psched:
- log_err("Failed to start flow allocator.");
return -1;
}
@@ -365,17 +736,18 @@ void fa_stop(void)
psched_destroy(fa.psched);
}
-int fa_alloc(int fd,
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t dlen)
+int fa_alloc(int fd,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
struct fa_msg * msg;
- uint64_t addr;
struct shm_du_buff * sdb;
- qoscube_t qc;
+ struct fa_flow * flow;
+ uint64_t addr;
+ qoscube_t qc = QOS_CUBE_BE;
size_t len;
+ uint64_t eid;
addr = dir_query(dst);
if (addr == 0)
@@ -383,12 +755,16 @@ int fa_alloc(int fd,
len = sizeof(*msg) + ipcp_dir_hash_len();
- if (ipcp_sdb_reserve(&sdb, len + dlen))
+ if (ipcp_sdb_reserve(&sdb, len + data->len))
return -1;
- msg = (struct fa_msg *) shm_du_buff_head(sdb);
+ msg = (struct fa_msg *) shm_du_buff_head(sdb);
+ memset(msg, 0, sizeof(*msg));
+
+ eid = gen_eid(fd);
+
msg->code = FLOW_REQ;
- msg->s_eid = hton32(fd);
+ msg->s_eid = hton64(eid);
msg->s_addr = hton64(ipcpi.dt_addr);
msg->delay = hton32(qs.delay);
msg->bandwidth = hton64(qs.bandwidth);
@@ -398,111 +774,196 @@ int fa_alloc(int fd,
msg->in_order = qs.in_order;
msg->max_gap = hton32(qs.max_gap);
msg->cypher_s = hton16(qs.cypher_s);
+ msg->timeout = hton32(qs.timeout);
memcpy(msg + 1, dst, ipcp_dir_hash_len());
- memcpy(shm_du_buff_head(sdb) + len, data, dlen);
-
- qc = qos_spec_to_cube(qs);
+ if (data->len > 0)
+ memcpy(shm_du_buff_head(sdb) + len, data->data, data->len);
- if (dt_write_packet(addr, qc, fa.fd, sdb)) {
+ if (dt_write_packet(addr, qc, fa.eid, sdb)) {
+ log_err("Failed to send flow allocation request packet.");
ipcp_sdb_release(sdb);
return -1;
}
+ flow = &fa.flows[fd];
+
pthread_rwlock_wrlock(&fa.flows_lock);
- assert(fa.r_eid[fd] == -1);
- fa.r_addr[fd] = addr;
+ fa_flow_init(flow);
+ flow->r_addr = addr;
+ flow->s_eid = eid;
pthread_rwlock_unlock(&fa.flows_lock);
return 0;
}
-int fa_alloc_resp(int fd,
- int response,
- const void * data,
- size_t len)
+int fa_alloc_resp(int fd,
+ int response,
+ const buffer_t * data)
{
- struct timespec ts = {0, TIMEOUT * 1000};
- struct timespec abstime;
struct fa_msg * msg;
struct shm_du_buff * sdb;
- qoscube_t qc;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ struct fa_flow * flow;
+ qoscube_t qc = QOS_CUBE_BE;
- pthread_mutex_lock(&ipcpi.alloc_lock);
+ flow = &fa.flows[fd];
- while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
+ if (ipcp_wait_flow_resp(fd) < 0) {
+ log_err("Failed to wait for flow response.");
+ goto fail_alloc_resp;
}
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- return -1;
+ if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + data->len)) {
+ log_err("Failed to reserve sdb (%zu bytes).",
+ sizeof(*msg) + data->len);
+ goto fail_reserve;
}
- ipcpi.alloc_id = -1;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
+ msg = (struct fa_msg *) shm_du_buff_head(sdb);
+ memset(msg, 0, sizeof(*msg));
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ msg->code = FLOW_REPLY;
+ msg->response = response;
+ if (data->len > 0)
+ memcpy(msg + 1, data->data, data->len);
- if (ipcp_sdb_reserve(&sdb, sizeof(*msg) + len)) {
- destroy_conn(fd);
- return -1;
- }
+ pthread_rwlock_rdlock(&fa.flows_lock);
- pthread_rwlock_wrlock(&fa.flows_lock);
+ msg->r_eid = hton64(flow->r_eid);
+ msg->s_eid = hton64(flow->s_eid);
- msg = (struct fa_msg *) shm_du_buff_head(sdb);
- msg->code = FLOW_REPLY;
- msg->r_eid = hton32(fa.r_eid[fd]);
- msg->s_eid = hton32(fd);
- msg->response = response;
+ pthread_rwlock_unlock(&fa.flows_lock);
- memcpy(msg + 1, data, len);
+ if (dt_write_packet(flow->r_addr, qc, fa.eid, sdb)) {
+ log_err("Failed to send flow allocation response packet.");
+ goto fail_packet;
+ }
if (response < 0) {
- destroy_conn(fd);
- ipcp_sdb_release(sdb);
+ pthread_rwlock_rdlock(&fa.flows_lock);
+ fa_flow_fini(flow);
+ pthread_rwlock_unlock(&fa.flows_lock);
} else {
psched_add(fa.psched, fd);
}
- ipcp_flow_get_qoscube(fd, &qc);
+ return 0;
+
+ fail_packet:
+ ipcp_sdb_release(sdb);
+ fail_reserve:
+ pthread_rwlock_wrlock(&fa.flows_lock);
+ fa_flow_fini(flow);
+ pthread_rwlock_unlock(&fa.flows_lock);
+ fail_alloc_resp:
+ return -1;
+}
+
+int fa_dealloc(int fd)
+{
+ if (ipcp_flow_fini(fd) < 0)
+ return 0;
+
+ psched_del(fa.psched, fd);
- assert(qc >= 0 && qc < QOS_CUBE_MAX);
+ pthread_rwlock_wrlock(&fa.flows_lock);
- if (dt_write_packet(fa.r_addr[fd], qc, fa.fd, sdb)) {
- destroy_conn(fd);
- pthread_rwlock_unlock(&fa.flows_lock);
- ipcp_sdb_release(sdb);
+ fa_flow_fini(&fa.flows[fd]);
+
+ pthread_rwlock_unlock(&fa.flows_lock);
+
+ ipcp_flow_dealloc(fd);
+
+ return 0;
+}
+
+static int fa_update_remote(int fd,
+ uint16_t ece)
+{
+ struct fa_msg * msg;
+ struct shm_du_buff * sdb;
+ qoscube_t qc = QOS_CUBE_BE;
+ struct fa_flow * flow;
+ uint64_t r_addr;
+
+ if (ipcp_sdb_reserve(&sdb, sizeof(*msg))) {
+ log_err("Failed to reserve sdb (%zu bytes).", sizeof(*msg));
return -1;
}
+ msg = (struct fa_msg *) shm_du_buff_head(sdb);
+
+ memset(msg, 0, sizeof(*msg));
+
+ flow = &fa.flows[fd];
+
+ pthread_rwlock_wrlock(&fa.flows_lock);
+
+ msg->code = FLOW_UPDATE;
+ msg->r_eid = hton64(flow->r_eid);
+ msg->ece = hton16(ece);
+
+ r_addr = flow->r_addr;
+#ifdef IPCP_FLOW_STATS
+ flow->u_snd++;
+#endif
pthread_rwlock_unlock(&fa.flows_lock);
+
+ if (dt_write_packet(r_addr, qc, fa.eid, sdb)) {
+ log_err("Failed to send flow update packet.");
+ ipcp_sdb_release(sdb);
+ return -1;
+ }
+
return 0;
}
-int fa_dealloc(int fd)
+void fa_np1_rcv(uint64_t eid,
+ uint8_t ecn,
+ struct shm_du_buff * sdb)
{
- if (ipcp_flow_fini(fd) < 0)
- return 0;
+ struct fa_flow * flow;
+ bool update;
+ uint16_t ece;
+ int fd;
+ size_t len;
+
+ len = shm_du_buff_len(sdb);
pthread_rwlock_wrlock(&fa.flows_lock);
- psched_del(fa.psched, fd);
+ fd = eid_to_fd(eid);
+ if (fd < 0) {
+ pthread_rwlock_unlock(&fa.flows_lock);
+ log_dbg("Received packet for unknown EID %" PRIu64 ".", eid);
+ ipcp_sdb_release(sdb);
+ return;
+ }
+
+ flow = &fa.flows[fd];
- destroy_conn(fd);
+#ifdef IPCP_FLOW_STATS
+ ++flow->p_rcv;
+ flow->b_rcv += len;
+#endif
+ update = ca_ctx_update_rcv(flow->ctx, len, ecn, &ece);
pthread_rwlock_unlock(&fa.flows_lock);
- flow_dealloc(fd);
+ if (ipcp_flow_write(fd, sdb) < 0) {
+ log_dbg("Failed to write to flow %d.", fd);
+ ipcp_sdb_release(sdb);
+#ifdef IPCP_FLOW_STATS
+ pthread_rwlock_wrlock(&fa.flows_lock);
+ ++flow->p_rcv_f;
+ flow->b_rcv_f += len;
+ pthread_rwlock_unlock(&fa.flows_lock);
+#endif
+ }
- return 0;
+ if (update)
+ fa_update_remote(eid, ece);
}
diff --git a/src/ipcpd/unicast/fa.h b/src/ipcpd/unicast/fa.h
index 12a10a0c..1e716966 100644
--- a/src/ipcpd/unicast/fa.h
+++ b/src/ipcpd/unicast/fa.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Flow allocator of the IPC Process
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -34,17 +34,19 @@ int fa_start(void);
void fa_stop(void);
-int fa_alloc(int fd,
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t len);
+int fa_alloc(int fd,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data);
-int fa_alloc_resp(int fd,
- int response,
- const void * data,
- size_t len);
+int fa_alloc_resp(int fd,
+ int response,
+ const buffer_t * data);
int fa_dealloc(int fd);
+void fa_np1_rcv(uint64_t eid,
+ uint8_t ecn,
+ struct shm_du_buff * sdb);
+
#endif /* OUROBOROS_IPCPD_UNICAST_FA_H */
diff --git a/src/ipcpd/unicast/main.c b/src/ipcpd/unicast/main.c
index 43052209..e6cb2994 100644
--- a/src/ipcpd/unicast/main.c
+++ b/src/ipcpd/unicast/main.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Unicast IPC Process
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -29,20 +29,22 @@
#include "config.h"
#define OUROBOROS_PREFIX "unicast-ipcp"
+#define THIS_TYPE IPCP_UNICAST
#include <ouroboros/errno.h>
-#include <ouroboros/hash.h>
#include <ouroboros/ipcp-dev.h>
#include <ouroboros/logs.h>
#include <ouroboros/notifier.h>
+#include <ouroboros/random.h>
#include <ouroboros/rib.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/time.h>
-#include "addr_auth.h"
-#include "connmgr.h"
+#include "common/connmgr.h"
+#include "common/enroll.h"
+#include "addr-auth.h"
+#include "ca.h"
#include "dir.h"
#include "dt.h"
-#include "enroll.h"
#include "fa.h"
#include "ipcp.h"
@@ -53,22 +55,17 @@
#include <assert.h>
#include <inttypes.h>
-#define THIS_TYPE IPCP_UNICAST
+struct ipcp ipcpi;
static int initialize_components(const struct ipcp_config * conf)
{
- ipcpi.layer_name = strdup(conf->layer_info.layer_name);
- if (ipcpi.layer_name == NULL) {
- log_err("Failed to set layer name.");
- goto fail_layer_name;
- }
-
- ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo;
+ strcpy(ipcpi.layer_name, conf->layer_info.name);
+ ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo;
assert(ipcp_dir_hash_len() != 0);
- if (addr_auth_init(conf->addr_auth_type,
- &conf->addr_size)) {
+ if (addr_auth_init(conf->unicast.addr_auth_type,
+ &conf->unicast.dt.addr_size)) {
log_err("Failed to init address authority.");
goto fail_addr_auth;
}
@@ -79,12 +76,14 @@ static int initialize_components(const struct ipcp_config * conf)
goto fail_addr_auth;
}
- log_dbg("IPCP got address %" PRIu64 ".", ipcpi.dt_addr);
+ log_info("IPCP got address %" PRIu64 ".", ipcpi.dt_addr);
+
+ if (ca_init(conf->unicast.cong_avoid)) {
+ log_err("Failed to initialize congestion avoidance.");
+ goto fail_ca;
+ }
- if (dt_init(conf->routing_type,
- conf->addr_size,
- conf->eid_size,
- conf->max_ttl)) {
+ if (dt_init(conf->unicast.dt)) {
log_err("Failed to initialize data transfer component.");
goto fail_dt;
}
@@ -108,10 +107,10 @@ static int initialize_components(const struct ipcp_config * conf)
fail_fa:
dt_fini();
fail_dt:
+ ca_fini();
+ fail_ca:
addr_auth_fini();
fail_addr_auth:
- free(ipcpi.layer_name);
- fail_layer_name:
return -1;
}
@@ -123,28 +122,29 @@ static void finalize_components(void)
dt_fini();
- addr_auth_fini();
+ ca_fini();
- free(ipcpi.layer_name);
+ addr_auth_fini();
}
static int start_components(void)
{
- assert(ipcp_get_state() == IPCP_INIT);
-
- ipcp_set_state(IPCP_OPERATIONAL);
+ if (dt_start() < 0) {
+ log_err("Failed to start data transfer.");
+ goto fail_dt_start;
+ }
- if (fa_start()) {
+ if (fa_start() < 0) {
log_err("Failed to start flow allocator.");
goto fail_fa_start;
}
- if (enroll_start()) {
+ if (enroll_start() < 0) {
log_err("Failed to start enrollment.");
goto fail_enroll_start;
}
- if (connmgr_start()) {
+ if (connmgr_start() < 0) {
log_err("Failed to start AP connection manager.");
goto fail_connmgr_start;
}
@@ -156,21 +156,22 @@ static int start_components(void)
fail_enroll_start:
fa_stop();
fail_fa_start:
+ dt_stop();
+ fail_dt_start:
ipcp_set_state(IPCP_INIT);
return -1;
}
static void stop_components(void)
{
- assert(ipcp_get_state() == IPCP_OPERATIONAL ||
- ipcp_get_state() == IPCP_SHUTDOWN);
-
connmgr_stop();
enroll_stop();
fa_stop();
+ dt_stop();
+
ipcp_set_state(IPCP_INIT);
}
@@ -178,7 +179,6 @@ static int bootstrap_components(void)
{
if (dir_bootstrap()) {
log_err("Failed to bootstrap directory.");
- dt_stop();
return -1;
}
@@ -189,53 +189,54 @@ static int unicast_ipcp_enroll(const char * dst,
struct layer_info * info)
{
struct conn conn;
+ uint8_t id[ENROLL_ID_LEN];
- if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn)) {
- log_err("Failed to get connection.");
- goto fail_er_flow;
+ if (random_buffer(id, ENROLL_ID_LEN) < 0) {
+ log_err("Failed to generate enrollment ID.");
+ goto fail_id;
}
- /* Get boot state from peer. */
- if (enroll_boot(&conn)) {
- log_err("Failed to get boot information.");
- goto fail_enroll_boot;
+ log_info_id(id, "Requesting enrollment.");
+
+ if (connmgr_alloc(COMPID_ENROLL, dst, NULL, &conn) < 0) {
+ log_err_id(id, "Failed to get connection.");
+ goto fail_id;
}
- if (initialize_components(enroll_get_conf())) {
- log_err("Failed to initialize IPCP components.");
+ /* Get boot state from peer. */
+ if (enroll_boot(&conn, id) < 0) {
+ log_err_id(id, "Failed to get boot information.");
goto fail_enroll_boot;
}
- if (dt_start()) {
- log_err("Failed to initialize IPCP components.");
- goto fail_dt_start;
+ if (initialize_components(enroll_get_conf()) < 0) {
+ log_err_id(id, "Failed to initialize components.");
+ goto fail_enroll_boot;
}
- if (start_components()) {
- log_err("Failed to start components.");
+ if (start_components() < 0) {
+ log_err_id(id, "Failed to start components.");
goto fail_start_comp;
}
- if (enroll_done(&conn, 0))
- log_warn("Failed to confirm enrollment with peer.");
+ if (enroll_ack(&conn, id, 0) < 0)
+ log_err_id(id, "Failed to confirm enrollment.");
- if (connmgr_dealloc(COMPID_ENROLL, &conn))
- log_warn("Failed to deallocate enrollment flow.");
+ if (connmgr_dealloc(COMPID_ENROLL, &conn) < 0)
+ log_warn_id(id, "Failed to dealloc enrollment flow.");
- log_info("Enrolled with %s.", dst);
+ log_info_id(id, "Enrolled with %s.", dst);
- info->dir_hash_algo = ipcpi.dir_hash_algo;
- strcpy(info->layer_name, ipcpi.layer_name);
+ info->dir_hash_algo = (enum pol_dir_hash) ipcpi.dir_hash_algo;
+ strcpy(info->name, ipcpi.layer_name);
return 0;
fail_start_comp:
- dt_stop();
- fail_dt_start:
finalize_components();
fail_enroll_boot:
connmgr_dealloc(COMPID_ENROLL, &conn);
- fail_er_flow:
+ fail_id:
return -1;
}
@@ -246,35 +247,26 @@ static int unicast_ipcp_bootstrap(const struct ipcp_config * conf)
enroll_bootstrap(conf);
- if (initialize_components(conf)) {
+ if (initialize_components(conf) < 0) {
log_err("Failed to init IPCP components.");
goto fail_init;
}
- if (dt_start()) {
- log_err("Failed to initialize IPCP components.");
- goto fail_dt_start;
- };
-
- if (start_components()) {
+ if (start_components() < 0) {
log_err("Failed to init IPCP components.");
goto fail_start;
}
- if (bootstrap_components()) {
+ if (bootstrap_components() < 0) {
log_err("Failed to bootstrap IPCP components.");
goto fail_bootstrap;
}
- log_dbg("Bootstrapped in layer %s.", conf->layer_info.layer_name);
-
return 0;
fail_bootstrap:
stop_components();
fail_start:
- dt_stop();
- fail_dt_start:
finalize_components();
fail_init:
return -1;
@@ -302,76 +294,58 @@ static struct ipcp_ops unicast_ops = {
int main(int argc,
char * argv[])
{
- if (ipcp_init(argc, argv, &unicast_ops) < 0) {
+ if (ipcp_init(argc, argv, &unicast_ops, THIS_TYPE) < 0) {
log_err("Failed to init IPCP.");
goto fail_init;
}
- /* These components must be init at creation. */
- if (rib_init(ipcpi.name)) {
- log_err("Failed to initialize RIB.");
- goto fail_rib_init;
- }
-
- if (notifier_init()) {
+ if (notifier_init() < 0) {
log_err("Failed to initialize notifier component.");
goto fail_notifier_init;
}
- if (connmgr_init()) {
+ if (connmgr_init() < 0) {
log_err("Failed to initialize connection manager.");
goto fail_connmgr_init;
}
- if (enroll_init()) {
+ if (enroll_init() < 0) {
log_err("Failed to initialize enrollment component.");
goto fail_enroll_init;
}
- if (ipcp_boot() < 0) {
- log_err("Failed to boot IPCP.");
- goto fail_boot;
- }
-
- if (ipcp_create_r(0)) {
- log_err("Failed to notify IRMd we are initialized.");
- ipcp_set_state(IPCP_NULL);
- goto fail_create_r;
+ if (ipcp_start() < 0) {
+ log_err("Failed to start IPCP.");
+ goto fail_start;
}
- ipcp_shutdown();
+ ipcp_sigwait();
if (ipcp_get_state() == IPCP_SHUTDOWN) {
- dt_stop();
stop_components();
finalize_components();
}
+ ipcp_stop();
+
enroll_fini();
connmgr_fini();
notifier_fini();
- rib_fini();
-
ipcp_fini();
exit(EXIT_SUCCESS);
- fail_create_r:
- ipcp_shutdown();
- fail_boot:
+ fail_start:
enroll_fini();
fail_enroll_init:
connmgr_fini();
fail_connmgr_init:
notifier_fini();
fail_notifier_init:
- rib_fini();
- fail_rib_init:
- ipcp_fini();
+ ipcp_fini();
fail_init:
- ipcp_create_r(-1);
exit(EXIT_FAILURE);
}
diff --git a/src/ipcpd/unicast/pff.c b/src/ipcpd/unicast/pff.c
index 19432972..9b2aa2b4 100644
--- a/src/ipcpd/unicast/pff.c
+++ b/src/ipcpd/unicast/pff.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* PDU Forwarding Function
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,14 +26,11 @@
#include <ouroboros/logs.h>
#include "pff.h"
-#include "pol-pff-ops.h"
-#include "pol/alternate_pff.h"
-#include "pol/multipath_pff.h"
-#include "pol/simple_pff.h"
+#include "pff/pol.h"
struct pff {
- struct pol_pff_ops * ops;
- struct pff_i * pff_i;
+ struct pff_ops * ops;
+ struct pff_i * pff_i;
};
struct pff * pff_create(enum pol_pff pol)
@@ -62,8 +59,10 @@ struct pff * pff_create(enum pol_pff pol)
}
pff->pff_i = pff->ops->create();
- if (pff->pff_i == NULL)
+ if (pff->pff_i == NULL) {
+ log_err("Failed to create PFF instance.");
goto err;
+ }
return pff;
err:
diff --git a/src/ipcpd/unicast/pff.h b/src/ipcpd/unicast/pff.h
index 962ae594..f44e5531 100644
--- a/src/ipcpd/unicast/pff.h
+++ b/src/ipcpd/unicast/pff.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* PDU Forwarding Function
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/unicast/pol/alternate_pff.c b/src/ipcpd/unicast/pff/alternate.c
index f26bb047..85e85914 100644
--- a/src/ipcpd/unicast/pol/alternate_pff.c
+++ b/src/ipcpd/unicast/pff/alternate.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Policy for PFF with alternate next hops
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -28,7 +28,7 @@
#include <ouroboros/list.h>
#include "pft.h"
-#include "alternate_pff.h"
+#include "alternate.h"
#include <string.h>
#include <assert.h>
@@ -54,7 +54,7 @@ struct pff_i {
pthread_rwlock_t lock;
};
-struct pol_pff_ops alternate_pff_ops = {
+struct pff_ops alternate_pff_ops = {
.create = alternate_pff_create,
.destroy = alternate_pff_destroy,
.lock = alternate_pff_lock,
diff --git a/src/ipcpd/unicast/pol/alternate_pff.h b/src/ipcpd/unicast/pff/alternate.h
index 5e5fca3d..96207e74 100644
--- a/src/ipcpd/unicast/pol/alternate_pff.h
+++ b/src/ipcpd/unicast/pff/alternate.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Policy for PFF with alternate next hops
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,7 +23,7 @@
#ifndef OUROBOROS_IPCPD_UNICAST_ALTERNATE_PFF_H
#define OUROBOROS_IPCPD_UNICAST_ALTERNATE_PFF_H
-#include "pol-pff-ops.h"
+#include "ops.h"
struct pff_i * alternate_pff_create(void);
@@ -56,6 +56,6 @@ int alternate_flow_state_change(struct pff_i * pff_i,
int fd,
bool up);
-struct pol_pff_ops alternate_pff_ops;
+extern struct pff_ops alternate_pff_ops;
#endif /* OUROBOROS_IPCPD_UNICAST_ALTERNATE_PFF_H */
diff --git a/src/ipcpd/unicast/pol/multipath_pff.c b/src/ipcpd/unicast/pff/multipath.c
index 0fe101bc..cbab0f5f 100644
--- a/src/ipcpd/unicast/pol/multipath_pff.c
+++ b/src/ipcpd/unicast/pff/multipath.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Policy for PFF supporting multipath routing
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
* Nick Aerts <nick.aerts@ugent.be>
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
#include <ouroboros/errno.h>
#include "pft.h"
-#include "multipath_pff.h"
+#include "multipath.h"
#include <string.h>
#include <assert.h>
@@ -39,7 +39,7 @@ struct pff_i {
pthread_rwlock_t lock;
};
-struct pol_pff_ops multipath_pff_ops = {
+struct pff_ops multipath_pff_ops = {
.create = multipath_pff_create,
.destroy = multipath_pff_destroy,
.lock = multipath_pff_lock,
@@ -58,21 +58,23 @@ struct pff_i * multipath_pff_create(void)
tmp = malloc(sizeof(*tmp));
if (tmp == NULL)
- return NULL;
+ goto fail_malloc;
- if (pthread_rwlock_init(&tmp->lock, NULL)) {
- free(tmp);
- return NULL;
- }
+ if (pthread_rwlock_init(&tmp->lock, NULL))
+ goto fail_rwlock;
tmp->pft = pft_create(PFT_SIZE, false);
- if (tmp->pft == NULL) {
- pthread_rwlock_destroy(&tmp->lock);
- free(tmp);
- return NULL;
- }
+ if (tmp->pft == NULL)
+ goto fail_pft;
return tmp;
+
+ fail_pft:
+ pthread_rwlock_destroy(&tmp->lock);
+ fail_rwlock:
+ free(tmp);
+ fail_malloc:
+ return NULL;
}
void multipath_pff_destroy(struct pff_i * pff_i)
@@ -80,8 +82,8 @@ void multipath_pff_destroy(struct pff_i * pff_i)
assert(pff_i);
pft_destroy(pff_i->pft);
-
pthread_rwlock_destroy(&pff_i->lock);
+
free(pff_i);
}
@@ -177,7 +179,7 @@ int multipath_pff_nhop(struct pff_i * pff_i,
assert(pff_i);
- pthread_rwlock_rdlock(&pff_i->lock);
+ pthread_rwlock_wrlock(&pff_i->lock);
if (pft_lookup(pff_i->pft, addr, &fds, &len)) {
pthread_rwlock_unlock(&pff_i->lock);
@@ -189,7 +191,7 @@ int multipath_pff_nhop(struct pff_i * pff_i,
assert(len > 0);
/* Rotate fds left. */
- memcpy(fds, fds + 1, (len - 1) * sizeof(*fds));
+ memmove(fds, fds + 1, (len - 1) * sizeof(*fds));
fds[len - 1] = fd;
pthread_rwlock_unlock(&pff_i->lock);
diff --git a/src/ipcpd/unicast/pol/multipath_pff.h b/src/ipcpd/unicast/pff/multipath.h
index a8ee088f..0eb03476 100644
--- a/src/ipcpd/unicast/pol/multipath_pff.h
+++ b/src/ipcpd/unicast/pff/multipath.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Policy for PFF supporting multipath routing
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
* Nick Aerts <nick.aerts@ugent.be>
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
#ifndef OUROBOROS_IPCPD_UNICAST_MULTIPATH_PFF_H
#define OUROBOROS_IPCPD_UNICAST_MULTIPATH_PFF_H
-#include "pol-pff-ops.h"
+#include "ops.h"
struct pff_i * multipath_pff_create(void);
@@ -53,6 +53,6 @@ void multipath_pff_flush(struct pff_i * pff_i);
int multipath_pff_nhop(struct pff_i * pff_i,
uint64_t addr);
-struct pol_pff_ops multipath_pff_ops;
+extern struct pff_ops multipath_pff_ops;
#endif /* OUROBOROS_IPCPD_UNICAST_MULTIPATH_PFF_H */
diff --git a/src/ipcpd/unicast/pol-pff-ops.h b/src/ipcpd/unicast/pff/ops.h
index 9e126cb5..16a31273 100644
--- a/src/ipcpd/unicast/pol-pff-ops.h
+++ b/src/ipcpd/unicast/pff/ops.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Pff policy ops
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,14 +20,14 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_IPCPD_UNICAST_POL_PFF_OPS_H
-#define OUROBOROS_IPCPD_UNICAST_POL_PFF_OPS_H
+#ifndef OUROBOROS_IPCPD_UNICAST_PFF_OPS_H
+#define OUROBOROS_IPCPD_UNICAST_PFF_OPS_H
#include <stdbool.h>
struct pff_i;
-struct pol_pff_ops {
+struct pff_ops {
struct pff_i * (* create)(void);
void (* destroy)(struct pff_i * pff_i);
@@ -60,4 +60,4 @@ struct pol_pff_ops {
bool up);
};
-#endif /* OUROBOROS_IPCPD_UNICAST_POL_PFF_OPS_H */
+#endif /* OUROBOROS_IPCPD_UNICAST_PFF_OPS_H */
diff --git a/src/ipcpd/unicast/pol/pft.c b/src/ipcpd/unicast/pff/pft.c
index 53acc08e..8c436113 100644
--- a/src/ipcpd/unicast/pol/pft.c
+++ b/src/ipcpd/unicast/pff/pft.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Packet forwarding table (PFT) with chaining on collisions
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -115,19 +115,11 @@ void pft_flush(struct pft * pft)
static uint64_t hash(uint64_t key)
{
- void * res;
- uint64_t ret;
- uint8_t keys[4];
+ uint64_t res[2];
- memcpy(keys, &key, 4);
+ mem_hash(HASH_MD5, res, (uint8_t *) &key, sizeof(key));
- mem_hash(HASH_MD5, &res, keys, 4);
-
- ret = (* (uint64_t *) res);
-
- free(res);
-
- return ret;
+ return res[0];
}
static uint64_t calc_key(struct pft * pft,
diff --git a/src/ipcpd/unicast/pol/pft.h b/src/ipcpd/unicast/pff/pft.h
index aed4dba8..711dabcb 100644
--- a/src/ipcpd/unicast/pol/pft.h
+++ b/src/ipcpd/unicast/pff/pft.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Packet forwarding table (PFT) with chaining on collisions
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/unicast/pff/pol.h b/src/ipcpd/unicast/pff/pol.h
new file mode 100644
index 00000000..245b03c4
--- /dev/null
+++ b/src/ipcpd/unicast/pff/pol.h
@@ -0,0 +1,25 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * PDU Forwarding Function policies
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "alternate.h"
+#include "multipath.h"
+#include "simple.h"
diff --git a/src/ipcpd/unicast/pol/simple_pff.c b/src/ipcpd/unicast/pff/simple.c
index 5bd73d8a..5f95e3ce 100644
--- a/src/ipcpd/unicast/pol/simple_pff.c
+++ b/src/ipcpd/unicast/pff/simple.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Simple PDU Forwarding Function
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -27,7 +27,7 @@
#include <ouroboros/errno.h>
#include "pft.h"
-#include "simple_pff.h"
+#include "simple.h"
#include <assert.h>
#include <pthread.h>
@@ -37,7 +37,7 @@ struct pff_i {
pthread_rwlock_t lock;
};
-struct pol_pff_ops simple_pff_ops = {
+struct pff_ops simple_pff_ops = {
.create = simple_pff_create,
.destroy = simple_pff_destroy,
.lock = simple_pff_lock,
diff --git a/src/ipcpd/unicast/pol/simple_pff.h b/src/ipcpd/unicast/pff/simple.h
index 2dfce45c..0966a186 100644
--- a/src/ipcpd/unicast/pol/simple_pff.h
+++ b/src/ipcpd/unicast/pff/simple.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Simple policy for PFF
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,7 +23,7 @@
#ifndef OUROBOROS_IPCPD_UNICAST_SIMPLE_PFF_H
#define OUROBOROS_IPCPD_UNICAST_SIMPLE_PFF_H
-#include "pol-pff-ops.h"
+#include "ops.h"
struct pff_i * simple_pff_create(void);
@@ -52,6 +52,6 @@ void simple_pff_flush(struct pff_i * pff_i);
int simple_pff_nhop(struct pff_i * pff_i,
uint64_t addr);
-struct pol_pff_ops simple_pff_ops;
+extern struct pff_ops simple_pff_ops;
#endif /* OUROBOROS_IPCPD_UNICAST_SIMPLE_PFF_H */
diff --git a/src/ipcpd/unicast/tests/CMakeLists.txt b/src/ipcpd/unicast/pff/tests/CMakeLists.txt
index 482711d5..65705714 100644
--- a/src/ipcpd/unicast/tests/CMakeLists.txt
+++ b/src/ipcpd/unicast/pff/tests/CMakeLists.txt
@@ -17,19 +17,20 @@ get_filename_component(PARENT_DIR ${PARENT_PATH} NAME)
create_test_sourcelist(${PARENT_DIR}_tests test_suite.c
# Add new tests here
- dht_test.c
+ pft_test.c
)
-protobuf_generate_c(KAD_PROTO_SRCS KAD_PROTO_HDRS ../kademlia.proto)
-
-add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}
- ${KAD_PROTO_SRCS})
+add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests})
target_link_libraries(${PARENT_DIR}_test ouroboros-common)
add_dependencies(check ${PARENT_DIR}_test)
set(tests_to_run ${${PARENT_DIR}_tests})
-remove(tests_to_run test_suite.c)
+if(CMAKE_VERSION VERSION_LESS "3.29.0")
+ remove(tests_to_run test_suite.c)
+else ()
+ list(POP_FRONT tests_to_run)
+endif()
foreach (test ${tests_to_run})
get_filename_component(test_name ${test} NAME_WE)
diff --git a/src/ipcpd/unicast/pol/tests/pft_test.c b/src/ipcpd/unicast/pff/tests/pft_test.c
index 4e23898b..18287fb8 100644
--- a/src/ipcpd/unicast/pol/tests/pft_test.c
+++ b/src/ipcpd/unicast/pff/tests/pft_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the hash table
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/unicast/psched.c b/src/ipcpd/unicast/psched.c
index 1ac3fc12..7e12148b 100644
--- a/src/ipcpd/unicast/psched.c
+++ b/src/ipcpd/unicast/psched.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Packet scheduler component
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,9 +31,9 @@
#include <ouroboros/errno.h>
#include <ouroboros/notifier.h>
+#include "common/connmgr.h"
#include "ipcp.h"
#include "psched.h"
-#include "connmgr.h"
#include <assert.h>
#include <sched.h>
@@ -50,6 +50,7 @@ static int qos_prio [] = {
struct psched {
fset_t * set[QOS_CUBE_MAX];
next_packet_fn_t callback;
+ read_fn_t read;
pthread_t readers[QOS_CUBE_MAX * IPCP_SCHED_THR_MUL];
};
@@ -101,7 +102,7 @@ static void * packet_reader(void * o)
notifier_event(NOTIFY_DT_FLOW_UP, &fd);
break;
case FLOW_PKT:
- if (ipcp_flow_read(fd, &sdb))
+ if (sched->read(fd, &sdb) < 0)
continue;
sched->callback(fd, qc, sdb);
@@ -117,7 +118,8 @@ static void * packet_reader(void * o)
return (void *) 0;
}
-struct psched * psched_create(next_packet_fn_t callback)
+struct psched * psched_create(next_packet_fn_t callback,
+ read_fn_t read)
{
struct psched * psched;
struct sched_info * infos[QOS_CUBE_MAX * IPCP_SCHED_THR_MUL];
@@ -131,6 +133,7 @@ struct psched * psched_create(next_packet_fn_t callback)
goto fail_malloc;
psched->callback = callback;
+ psched->read = read;
for (i = 0; i < QOS_CUBE_MAX; ++i) {
psched->set[i] = fset_create();
@@ -160,7 +163,7 @@ struct psched * psched_create(next_packet_fn_t callback)
for (j = 0; j < i; ++j)
pthread_join(psched->readers[j], NULL);
for (j = i; j < QOS_CUBE_MAX * IPCP_SCHED_THR_MUL; ++j)
- free(infos[i]);
+ free(infos[j]);
goto fail_infos;
}
}
diff --git a/src/ipcpd/unicast/psched.h b/src/ipcpd/unicast/psched.h
index 85f32b9a..831f8084 100644
--- a/src/ipcpd/unicast/psched.h
+++ b/src/ipcpd/unicast/psched.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Packet scheduler component
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -30,7 +30,11 @@ typedef void (* next_packet_fn_t)(int fd,
qoscube_t qc,
struct shm_du_buff * sdb);
-struct psched * psched_create(next_packet_fn_t callback);
+typedef int (* read_fn_t)(int fd,
+ struct shm_du_buff ** sdb);
+
+struct psched * psched_create(next_packet_fn_t callback,
+ read_fn_t read);
void psched_destroy(struct psched * psched);
diff --git a/src/ipcpd/unicast/routing.c b/src/ipcpd/unicast/routing.c
index 0ac43f9f..f5417c24 100644
--- a/src/ipcpd/unicast/routing.c
+++ b/src/ipcpd/unicast/routing.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Routing component of the IPCP
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,9 +26,9 @@
#include "pff.h"
#include "routing.h"
-#include "pol/link_state.h"
+#include "routing/pol.h"
-struct pol_routing_ops * r_ops;
+struct routing_ops * r_ops;
int routing_init(enum pol_routing pr)
{
diff --git a/src/ipcpd/unicast/routing.h b/src/ipcpd/unicast/routing.h
index 38e875e7..d5d833ae 100644
--- a/src/ipcpd/unicast/routing.h
+++ b/src/ipcpd/unicast/routing.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Routing component of the IPCP
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/unicast/pol/graph.c b/src/ipcpd/unicast/routing/graph.c
index ba2ce553..32f3e6fb 100644
--- a/src/ipcpd/unicast/pol/graph.c
+++ b/src/ipcpd/unicast/routing/graph.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Undirected graph structure
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
* Nick Aerts <nick.aerts@ugent.be>
*
* This program is free software; you can redistribute it and/or modify
@@ -834,7 +834,7 @@ int graph_routing_table(struct graph * graph,
break;
default:
log_err("Unsupported algorithm.");
- goto fail_algo;
+ goto fail_table;
}
pthread_mutex_unlock(&graph->lock);
@@ -843,8 +843,6 @@ int graph_routing_table(struct graph * graph,
return 0;
- fail_algo:
- free(s_dist);
fail_table:
pthread_mutex_unlock(&graph->lock);
return -1;
diff --git a/src/ipcpd/unicast/pol/graph.h b/src/ipcpd/unicast/routing/graph.h
index 473a5163..8190cc6c 100644
--- a/src/ipcpd/unicast/pol/graph.h
+++ b/src/ipcpd/unicast/routing/graph.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Undirected graph structure
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/ipcpd/unicast/pol/link_state.c b/src/ipcpd/unicast/routing/link-state.c
index d9482876..57c0c7cb 100644
--- a/src/ipcpd/unicast/pol/link_state.c
+++ b/src/ipcpd/unicast/routing/link-state.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Link state routing policy
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -38,21 +38,21 @@
#include <ouroboros/list.h>
#include <ouroboros/logs.h>
#include <ouroboros/notifier.h>
+#include <ouroboros/pthread.h>
#include <ouroboros/rib.h>
#include <ouroboros/utils.h>
-#include "comp.h"
-#include "connmgr.h"
+#include "common/comp.h"
+#include "common/connmgr.h"
#include "graph.h"
#include "ipcp.h"
-#include "link_state.h"
+#include "link-state.h"
#include "pff.h"
#include <assert.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
-#include <pthread.h>
#define RECALC_TIME 4
#define LS_UPDATE_TIME 15
@@ -127,7 +127,7 @@ struct {
enum routing_algo routing_algo;
} ls;
-struct pol_routing_ops link_state_ops = {
+struct routing_ops link_state_ops = {
.init = link_state_init,
.fini = link_state_fini,
.routing_i_create = link_state_routing_i_create,
@@ -179,53 +179,56 @@ static struct adjacency * get_adj(const char * path)
return NULL;
}
-static int lsdb_getattr(const char * path,
- struct stat * st)
+static int lsdb_rib_getattr(const char * path,
+ struct rib_attr * attr)
{
struct adjacency * adj;
struct timespec now;
+ char * entry;
assert(path);
- assert(st);
+ assert(attr);
+
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
clock_gettime(CLOCK_REALTIME_COARSE, &now);
pthread_rwlock_rdlock(&ls.db_lock);
- adj = get_adj(path);
+ adj = get_adj(entry);
if (adj != NULL) {
- st->st_mtime = adj->stamp;
- st->st_size = LS_ENTRY_SIZE;
+ attr->mtime = adj->stamp;
+ attr->size = LS_ENTRY_SIZE;
} else {
- st->st_mtime = now.tv_sec;
- st->st_size = 0;
+ attr->mtime = now.tv_sec;
+ attr->size = 0;
}
- st->st_mode = S_IFREG | 0755;
- st->st_nlink = 1;
- st->st_uid = getuid();
- st->st_gid = getgid();
-
pthread_rwlock_unlock(&ls.db_lock);
return 0;
}
-static int lsdb_read(const char * path,
- char * buf,
- size_t len)
+static int lsdb_rib_read(const char * path,
+ char * buf,
+ size_t len)
{
struct adjacency * a;
+ char * entry;
int size;
assert(path);
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
+
pthread_rwlock_rdlock(&ls.db_lock);
if (ls.db_len + ls.nbs_len == 0)
goto fail;
- a = get_adj(path);
+ a = get_adj(entry);
if (a == NULL)
goto fail;
@@ -241,7 +244,7 @@ static int lsdb_read(const char * path,
return -1;
}
-static int lsdb_readdir(char *** buf)
+static int lsdb_rib_readdir(char *** buf)
{
struct list_head * p;
char entry[RIB_PATH_LEN + 1];
@@ -270,7 +273,7 @@ static int lsdb_readdir(char *** buf)
if ((*buf)[idx] == NULL) {
while (idx-- > 0)
free((*buf)[idx]);
- free(buf);
+ free(*buf);
pthread_rwlock_unlock(&ls.db_lock);
return -ENOMEM;
}
@@ -304,9 +307,9 @@ static int lsdb_readdir(char *** buf)
}
static struct rib_ops r_ops = {
- .read = lsdb_read,
- .readdir = lsdb_readdir,
- .getattr = lsdb_getattr
+ .read = lsdb_rib_read,
+ .readdir = lsdb_rib_readdir,
+ .getattr = lsdb_rib_getattr
};
static int lsdb_add_nb(uint64_t addr,
@@ -648,8 +651,7 @@ static void * lsupdate(void * o)
pthread_rwlock_wrlock(&ls.db_lock);
- pthread_cleanup_push((void (*) (void *)) pthread_rwlock_unlock,
- (void *) &ls.db_lock);
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock);
list_for_each_safe(p, h, &ls.db) {
struct adjacency * adj;
@@ -709,8 +711,7 @@ static void forward_lsm(uint8_t * buf,
pthread_rwlock_rdlock(&ls.db_lock);
- pthread_cleanup_push((void (*))(void *) pthread_rwlock_unlock,
- &ls.db_lock);
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock);
list_for_each(p, &ls.nbs) {
struct nb * nb = list_entry(p, struct nb, next);
@@ -721,6 +722,11 @@ static void forward_lsm(uint8_t * buf,
pthread_cleanup_pop(true);
}
+static void cleanup_fqueue(void * fq)
+{
+ fqueue_destroy((fqueue_t *) fq);
+}
+
static void * lsreader(void * o)
{
fqueue_t * fq;
@@ -739,8 +745,7 @@ static void * lsreader(void * o)
if (fq == NULL)
return (void *) -1;
- pthread_cleanup_push((void (*) (void *)) fqueue_destroy,
- (void *) fq);
+ pthread_cleanup_push(cleanup_fqueue, fq);
while (true) {
ret = fevent(ls.mgmt_set, fq, NULL);
@@ -812,8 +817,11 @@ static void handle_event(void * self,
switch (event) {
case NOTIFY_DT_CONN_ADD:
pthread_rwlock_rdlock(&ls.db_lock);
+
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock);
+
send_lsm(ipcpi.dt_addr, c->conn_info.addr, 0);
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_cleanup_pop(true);
if (lsdb_add_nb(c->conn_info.addr, c->flow_info.fd, NB_DT))
log_dbg("Failed to add neighbor to LSDB.");
diff --git a/src/ipcpd/unicast/pol/link_state.h b/src/ipcpd/unicast/routing/link-state.h
index 9d4858e1..d77d72df 100644
--- a/src/ipcpd/unicast/pol/link_state.h
+++ b/src/ipcpd/unicast/routing/link-state.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Link state routing policy
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,7 +26,7 @@
#define LS_COMP "Management"
#define LS_PROTO "LSP"
-#include "pol-routing-ops.h"
+#include "ops.h"
int link_state_init(enum pol_routing pr);
@@ -36,6 +36,6 @@ struct routing_i * link_state_routing_i_create(struct pff * pff);
void link_state_routing_i_destroy(struct routing_i * instance);
-struct pol_routing_ops link_state_ops;
+extern struct routing_ops link_state_ops;
#endif /* OUROBOROS_IPCPD_UNICAST_POL_LINK_STATE_H */
diff --git a/src/ipcpd/unicast/pol-routing-ops.h b/src/ipcpd/unicast/routing/ops.h
index 3fa1d573..8a79b7ec 100644
--- a/src/ipcpd/unicast/pol-routing-ops.h
+++ b/src/ipcpd/unicast/routing/ops.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Routing policy ops
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,12 +20,12 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_IPCPD_UNICAST_POL_ROUTING_OPS_H
-#define OUROBOROS_IPCPD_UNICAST_POL_ROUTING_OPS_H
+#ifndef OUROBOROS_IPCPD_UNICAST_ROUTING_OPS_H
+#define OUROBOROS_IPCPD_UNICAST_ROUTING_OPS_H
#include "pff.h"
-struct pol_routing_ops {
+struct routing_ops {
int (* init)(enum pol_routing pr);
void (* fini)(void);
@@ -35,4 +35,4 @@ struct pol_routing_ops {
void (* routing_i_destroy)(struct routing_i * instance);
};
-#endif /* OUROBOROS_IPCPD_UNICAST_POL_ROUTING_OPS_H */
+#endif /* OUROBOROS_IPCPD_UNICAST_ROUTING_OPS_H */
diff --git a/src/ipcpd/unicast/routing/pol.h b/src/ipcpd/unicast/routing/pol.h
new file mode 100644
index 00000000..b6a6f150
--- /dev/null
+++ b/src/ipcpd/unicast/routing/pol.h
@@ -0,0 +1,23 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Routing policies
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "link-state.h"
diff --git a/src/ipcpd/unicast/pol/tests/CMakeLists.txt b/src/ipcpd/unicast/routing/tests/CMakeLists.txt
index 34d80e8d..9d24bf03 100644
--- a/src/ipcpd/unicast/pol/tests/CMakeLists.txt
+++ b/src/ipcpd/unicast/routing/tests/CMakeLists.txt
@@ -18,7 +18,6 @@ get_filename_component(PARENT_DIR ${PARENT_PATH} NAME)
create_test_sourcelist(${PARENT_DIR}_tests test_suite.c
# Add new tests here
graph_test.c
- pft_test.c
)
add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests})
@@ -27,7 +26,11 @@ target_link_libraries(${PARENT_DIR}_test ouroboros-common)
add_dependencies(check ${PARENT_DIR}_test)
set(tests_to_run ${${PARENT_DIR}_tests})
-remove(tests_to_run test_suite.c)
+if(CMAKE_VERSION VERSION_LESS "3.29.0")
+ remove(tests_to_run test_suite.c)
+else ()
+ list(POP_FRONT tests_to_run)
+endif()
foreach (test ${tests_to_run})
get_filename_component(test_name ${test} NAME_WE)
diff --git a/src/ipcpd/unicast/pol/tests/graph_test.c b/src/ipcpd/unicast/routing/tests/graph_test.c
index ea4c0e59..d805640c 100644
--- a/src/ipcpd/unicast/pol/tests/graph_test.c
+++ b/src/ipcpd/unicast/routing/tests/graph_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the graph structure
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt
index 59d0d103..c9c2e553 100644
--- a/src/irmd/CMakeLists.txt
+++ b/src/irmd/CMakeLists.txt
@@ -4,42 +4,84 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
-set(IRMD_REQ_ARR_TIMEOUT 500 CACHE STRING
+find_library(LIBTOML_LIBRARIES toml QUIET)
+if (LIBTOML_LIBRARIES)
+ set(DISABLE_CONFIGFILE FALSE CACHE BOOL
+ "Disable configuration file support")
+ if (NOT DISABLE_CONFIGFILE)
+ set(OUROBOROS_CONFIG_DIR /etc/ouroboros/ CACHE STRING
+ "Configuration directory")
+ set(OUROBOROS_CONFIG_FILE irmd.conf CACHE STRING
+ "Name of the IRMd configuration file")
+ set(HAVE_TOML TRUE)
+ message(STATUS "Found TOML C99 library: " ${LIBTOML_LIBRARIES})
+ message(STATUS "Configuration file support enabled")
+ message(STATUS "Configuration directory: ${OUROBOROS_CONFIG_DIR}")
+ set(INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
+ configure_file("${CMAKE_SOURCE_DIR}/irmd.conf.in"
+ "${CMAKE_BINARY_DIR}/irmd.conf.example" @ONLY)
+ install(FILES "${CMAKE_BINARY_DIR}/irmd.conf.example"
+ DESTINATION "${OUROBOROS_CONFIG_DIR}")
+ unset(INSTALL_DIR)
+ mark_as_advanced(LIBTOML_LIBRARIES)
+ else ()
+ message(STATUS "Configuration file support disabled by user")
+ unset(OUROBOROS_CONFIG_FILE CACHE)
+ unset(OUROBOROS_CONFIG_DIR CACHE)
+ set(HAVE_TOML FALSE)
+ endif ()
+else ()
+ message(STATUS "Install tomlc99 for config file support")
+ message(STATUS " https://github.com/cktan/tomlc99")
+ set(LIBTOML_LIBRARIES "")
+ unset(DISABLE_CONFIGFILE CACHE)
+ unset(HAVE_TOML)
+endif ()
+
+set(IRMD_REQ_ARR_TIMEOUT 1000 CACHE STRING
"Timeout for an application to respond to a new flow (ms)")
-set(IRMD_FLOW_TIMEOUT 5000 CACHE STRING
- "Timeout for a flow allocation response (ms)")
+
set(BOOTSTRAP_TIMEOUT 5000 CACHE STRING
"Timeout for an IPCP to bootstrap (ms)")
-set(ENROLL_TIMEOUT 60000 CACHE STRING
+set(ENROLL_TIMEOUT 20000 CACHE STRING
"Timeout for an IPCP to enroll (ms)")
-set(REG_TIMEOUT 10000 CACHE STRING
+set(REG_TIMEOUT 20000 CACHE STRING
"Timeout for registering a name (ms)")
-set(QUERY_TIMEOUT 3000 CACHE STRING
+set(QUERY_TIMEOUT 20000 CACHE STRING
"Timeout to query a name with an IPCP (ms)")
-set(CONNECT_TIMEOUT 60000 CACHE STRING
+set(CONNECT_TIMEOUT 20000 CACHE STRING
"Timeout to connect an IPCP to another IPCP (ms)")
+set(FLOW_ALLOC_TIMEOUT 20000 CACHE STRING
+ "Timeout for a flow allocation response (ms)")
set(IRMD_MIN_THREADS 8 CACHE STRING
- "Minimum number of worker threads in the IRMd.")
+ "Minimum number of worker threads in the IRMd")
set(IRMD_ADD_THREADS 8 CACHE STRING
"Number of extra threads to start when the IRMD faces thread starvation")
+set(IRMD_PKILL_TIMEOUT 30 CACHE STRING
+ "Number of seconds to wait before sending SIGKILL to subprocesses on exit")
+set(IRMD_KILL_ALL_PROCESSES TRUE CACHE BOOL
+ "Kill all processes on exit")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
set(SOURCE_FILES
# Add source files here
- proc_table.c
- prog_table.c
ipcp.c
- irm_flow.c
+ configfile.c
main.c
- registry.c
- utils.c
+ reg/flow.c
+ reg/ipcp.c
+ reg/proc.c
+ reg/prog.c
+ reg/name.c
+ reg/reg.c
)
add_executable (irmd ${SOURCE_FILES})
-target_link_libraries (irmd LINK_PUBLIC ouroboros-common)
+target_link_libraries (irmd LINK_PUBLIC ouroboros-common
+ ${LIBTOML_LIBRARIES})
include(AddCompileFlags)
if (CMAKE_BUILD_TYPE MATCHES "Debug*")
@@ -49,4 +91,5 @@ endif ()
install(TARGETS irmd RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
# Enable once irmd has tests
-# add_subdirectory(tests)
+#add_subdirectory(tests)
+add_subdirectory(reg)
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index 0576a757..fa1156b9 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Configuration for the IPC Resource Manager
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,37 +20,78 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#define IPCP_UDP_EXEC "@IPCP_UDP_TARGET@"
-#define IPCP_ETH_LLC_EXEC "@IPCP_ETH_LLC_TARGET@"
-#define IPCP_ETH_DIX_EXEC "@IPCP_ETH_DIX_TARGET@"
-#define IPCP_UNICAST_EXEC "@IPCP_UNICAST_TARGET@"
-#define IPCP_BROADCAST_EXEC "@IPCP_BROADCAST_TARGET@"
-#define IPCP_LOCAL_EXEC "@IPCP_LOCAL_TARGET@"
-#define IPCP_RAPTOR_EXEC "@IPCP_RAPTOR_TARGET@"
-#define INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
+#define IPCP_UDP_EXEC "@IPCP_UDP_TARGET@"
+#define IPCP_ETH_LLC_EXEC "@IPCP_ETH_LLC_TARGET@"
+#define IPCP_ETH_DIX_EXEC "@IPCP_ETH_DIX_TARGET@"
+#define IPCP_UNICAST_EXEC "@IPCP_UNICAST_TARGET@"
+#define IPCP_BROADCAST_EXEC "@IPCP_BROADCAST_TARGET@"
+#define IPCP_LOCAL_EXEC "@IPCP_LOCAL_TARGET@"
-#define PTHREAD_COND_CLOCK @PTHREAD_COND_CLOCK@
+#define INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
+#define INSTALL_SBINDIR "@CMAKE_INSTALL_SBINDIR@"
-#define SOCKET_TIMEOUT @SOCKET_TIMEOUT@
+#define PTHREAD_COND_CLOCK @PTHREAD_COND_CLOCK@
-#define IRMD_REQ_ARR_TIMEOUT @IRMD_REQ_ARR_TIMEOUT@
-#define IRMD_FLOW_TIMEOUT @IRMD_FLOW_TIMEOUT@
+#define SOCKET_TIMEOUT @SOCKET_TIMEOUT@
-#define BOOTSTRAP_TIMEOUT @BOOTSTRAP_TIMEOUT@
-#define ENROLL_TIMEOUT @ENROLL_TIMEOUT@
-#define REG_TIMEOUT @REG_TIMEOUT@
-#define QUERY_TIMEOUT @QUERY_TIMEOUT@
-#define CONNECT_TIMEOUT @CONNECT_TIMEOUT@
+#define IRMD_REQ_ARR_TIMEOUT @IRMD_REQ_ARR_TIMEOUT@
-#define SYS_MAX_FLOWS @SYS_MAX_FLOWS@
+#define FLOW_ALLOC_TIMEOUT @FLOW_ALLOC_TIMEOUT@
+#define FLOW_DEALLOC_TIMEOUT @FLOW_DEALLOC_TIMEOUT@
+
+#define BOOTSTRAP_TIMEOUT @BOOTSTRAP_TIMEOUT@
+#define ENROLL_TIMEOUT @ENROLL_TIMEOUT@
+#define REG_TIMEOUT @REG_TIMEOUT@
+#define QUERY_TIMEOUT @QUERY_TIMEOUT@
+#define CONNECT_TIMEOUT @CONNECT_TIMEOUT@
+
+#define SYS_MAX_FLOWS @SYS_MAX_FLOWS@
+#define IRMD_MIN_THREADS @IRMD_MIN_THREADS@
+#define IRMD_ADD_THREADS @IRMD_ADD_THREADS@
-#define IRMD_MIN_THREADS @IRMD_MIN_THREADS@
-#define IRMD_ADD_THREADS @IRMD_ADD_THREADS@
#cmakedefine HAVE_FUSE
#ifdef HAVE_FUSE
-#define FUSE_PREFIX "@FUSE_PREFIX@"
+#define FUSE_PREFIX "@FUSE_PREFIX@"
+#endif
+
+#cmakedefine HAVE_TOML
+#ifdef HAVE_TOML
+#define OUROBOROS_CONFIG_DIR "@OUROBOROS_CONFIG_DIR@"
+#define OUROBOROS_CONFIG_FILE "@OUROBOROS_CONFIG_FILE@"
#endif
+#define IRMD_PKILL_TIMEOUT @IRMD_PKILL_TIMEOUT@
+
+#cmakedefine IRMD_KILL_ALL_PROCESSES
#cmakedefine HAVE_LIBGCRYPT
+
+#define O7S_ASCII_ART \
+"\n" \
+" ▄▄█████▄▄▄\n" \
+" ▄█▀▀ ▀▀███▄ " \
+"â–ˆ\n" \
+" ██ ▄▄▄ ▄███▄ " \
+"â–„ â–„ â–„ â–„â–„" \
+" â–„â–„ â–ˆ â–„â–„ " \
+" â–„â–„ â–„ â–„â–„ " \
+"â–„â–„ â–„â–„\n" \
+" ██ █ █ " \
+"[38;5;4m█████ █ █ " \
+"█▀ ▀ █ █" \
+" █▀ █ █ " \
+"█ █▀ ▀ █" \
+" █ ▀▄ ▀\n" \
+" ██ ▀▄▄▄▀ ▀█▀ " \
+"â–ˆ â–ˆ â–ˆ " \
+"█ █ █▄ █ " \
+"â–ˆ â–ˆ â–ˆ â–ˆ" \
+" █ ▄ ▀▄\n" \
+" █▄ █ ▀▀▀" \
+" ▀ ▀ ▀▀" \
+" ▀ ▀▀ ▀▀ " \
+"▀ ▀▀ ▀▀\n" \
+" ▀█▄▄▄▄▄▄▄▄▀\n" \
+" ▀▀▀▀▀▀\n" \
+"\n"
diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c
new file mode 100644
index 00000000..688c4ade
--- /dev/null
+++ b/src/irmd/configfile.c
@@ -0,0 +1,871 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager / Configuration from file
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+
+#include "config.h"
+
+#if defined (HAVE_TOML)
+
+#define _POSIX_C_SOURCE 200809L
+#define _XOPEN_SOURCE 500
+
+#define OUROBOROS_PREFIX "irmd/configuration"
+
+#include <ouroboros/errno.h>
+#include <ouroboros/ipcp.h>
+#include <ouroboros/logs.h>
+#include <ouroboros/utils.h>
+
+#include "irmd.h"
+#include "configfile.h"
+
+#include "reg/reg.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <toml.h>
+#include <arpa/inet.h>
+
+#define ERRBUFSZ 200
+
+static int toml_hash(toml_table_t * table,
+ struct layer_info * info)
+{
+ toml_datum_t hash;
+
+ hash = toml_string_in(table, "hash");
+ if (!hash.ok) {
+ log_dbg("No hash specified, using default.");
+ return 0;
+ }
+
+ if (strcmp(hash.u.s, "SHA3_224") == 0) {
+ info->dir_hash_algo = DIR_HASH_SHA3_224;
+ } else if (strcmp(hash.u.s, "SHA3_256") == 0) {
+ info->dir_hash_algo = DIR_HASH_SHA3_256;
+ } else if (strcmp(hash.u.s, "SHA3_384") == 0) {
+ info->dir_hash_algo = DIR_HASH_SHA3_384;
+ } else if (strcmp(hash.u.s, "SHA3_512") == 0) {
+ info->dir_hash_algo = DIR_HASH_SHA3_512;
+ } else {
+ log_err("Unknown hash algorithm: %s.", hash.u.s);
+ free(hash.u.s);
+ return -1;
+ }
+
+ free(hash.u.s);
+
+ return 0;
+}
+
+static int toml_local(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ *conf = local_default_conf;
+
+ return toml_hash(table, &conf->layer_info);
+}
+
+static int toml_eth_dev(toml_table_t * table,
+ struct eth_config * conf)
+{
+ toml_datum_t dev;
+
+ dev = toml_string_in(table, "dev");
+ if (!dev.ok) {
+ log_err("Missing device.");
+ return -1;
+ }
+
+ if (strlen(dev.u.s) > DEV_NAME_SIZE) {
+ log_err("Device name too long: %s", dev.u.s);
+ free(dev.u.s);
+ return -1;
+ }
+
+ strcpy(conf->dev, dev.u.s);
+ free(dev.u.s);
+
+ return 0;
+}
+
+static int toml_eth_llc(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ *conf = eth_llc_default_conf;
+
+ if (toml_hash(table, &conf->layer_info) < 0)
+ return -1;
+
+ return toml_eth_dev(table, &conf->eth);
+}
+
+
+static int toml_ethertype(toml_table_t * table,
+ struct eth_config * conf)
+{
+ toml_datum_t ethertype;
+
+ ethertype = toml_int_in(table, "ethertype");
+ if (ethertype.ok)
+ conf->ethertype = ethertype.u.i;
+
+ if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF)
+ return -1;
+
+ return 0;
+}
+
+static int toml_eth_dix(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ *conf = eth_dix_default_conf;
+
+ if (toml_hash(table, &conf->layer_info) < 0)
+ return -1;
+
+ if (toml_eth_dev(table, &conf->eth) < 0)
+ return -1;
+
+ if (toml_ethertype(table, &conf->eth) < 0) {
+ log_err("Ethertype not in valid range.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_udp(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ toml_datum_t ip;
+ toml_datum_t port;
+ toml_datum_t dns;
+
+ *conf = udp_default_conf;
+
+ ip = toml_string_in(table, "ip");
+ if (!ip.ok) {
+ log_err("No IP address specified!");
+ goto fail_ip;
+ }
+
+ if (inet_pton (AF_INET, ip.u.s, &conf->udp.ip_addr) != 1) {
+ log_err("Failed to parse IPv4 address %s.", ip.u.s);
+ goto fail_addr;
+ }
+
+ port = toml_int_in(table, "port");
+ if (port.ok)
+ conf->udp.port = port.u.i;
+
+ dns = toml_string_in(table, "dns");
+ if (dns.ok) {
+ if (inet_pton(AF_INET, dns.u.s, &conf->udp.dns_addr) < 0) {
+ log_err("Failed to parse DNS address %s.", ip.u.s);
+ goto fail_dns;
+ }
+
+ free(dns.u.s);
+ }
+
+ free(ip.u.s);
+
+ return 0;
+
+ fail_dns:
+ free(dns.u.s);
+ fail_addr:
+ free(ip.u.s);
+ fail_ip:
+ return -1;
+}
+
+static int toml_broadcast(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ (void) table;
+ (void) conf;
+
+ /* Nothing to do here. */
+
+ return 0;
+}
+
+static int toml_routing(toml_table_t * table,
+ struct dt_config * conf)
+{
+ toml_datum_t routing;
+
+ routing = toml_string_in(table, "routing");
+ if (routing.ok) {
+ if (strcmp(routing.u.s, "link-state") == 0)
+ conf->routing_type = ROUTING_LINK_STATE;
+ else if (strcmp(routing.u.s, "lfa") == 0)
+ conf->routing_type = ROUTING_LINK_STATE_LFA;
+ else if (strcmp(routing.u.s, "ecmp") == 0)
+ conf->routing_type = ROUTING_LINK_STATE_ECMP;
+ else
+ conf->routing_type = ROUTING_INVALID;
+ free(routing.u.s);
+ }
+
+ if (conf->routing_type == ROUTING_INVALID)
+ return -1;
+
+ return 0;
+}
+
+static int toml_addr_auth(toml_table_t * table,
+ struct uni_config * conf)
+{
+ toml_datum_t addr_auth;
+
+ addr_auth = toml_string_in(table, "addr-auth");
+ if (addr_auth.ok) {
+ if (strcmp(addr_auth.u.s, "flat") == 0)
+ conf->addr_auth_type = ADDR_AUTH_FLAT_RANDOM;
+ else
+ conf->addr_auth_type = ADDR_AUTH_INVALID;
+ free(addr_auth.u.s);
+ }
+
+ if (conf->addr_auth_type == ADDR_AUTH_INVALID)
+ return -1;
+
+ return 0;
+}
+
+static int toml_congestion(toml_table_t * table,
+ struct uni_config * conf)
+{
+ toml_datum_t congestion;
+
+ congestion = toml_string_in(table, "congestion");
+ if (congestion.ok) {
+ if (strcmp(congestion.u.s, "none") == 0)
+ conf->cong_avoid = CA_NONE;
+ else if (strcmp(congestion.u.s, "lfa") == 0)
+ conf->cong_avoid = CA_MB_ECN;
+ else
+ conf->cong_avoid = CA_INVALID;
+ free(congestion.u.s);
+
+ }
+
+ if (conf->cong_avoid == CA_INVALID)
+ return -1;
+
+ return 0;
+}
+
+static int toml_dt(toml_table_t * table,
+ struct dt_config * conf)
+{
+ toml_datum_t addr;
+ toml_datum_t eid;
+ toml_datum_t ttl;
+
+ addr = toml_int_in(table, "addr_size");
+ if (addr.ok)
+ conf->addr_size = addr.u.i;
+
+ eid = toml_int_in(table, "eid_size");
+ if (eid.ok)
+ conf->eid_size = eid.u.i;
+
+ ttl = toml_int_in(table, "max_ttl");
+ if (ttl.ok)
+ conf->max_ttl = ttl.u.i;
+
+ if (toml_routing(table, conf) < 0) {
+ log_err("Invalid routing option.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_unicast(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+
+
+ *conf = uni_default_conf;
+
+ if (toml_hash(table, &conf->layer_info) < 0)
+ return -1;
+
+ if (toml_dt(table, &conf->unicast.dt) < 0) {
+ log_err("Invalid DT configuration.");
+ return -1;
+ }
+
+ if (toml_addr_auth(table, &conf->unicast) < 0) {
+ log_err("Invalid address authority");
+ return -1;
+ }
+
+ if (toml_congestion(table, &conf->unicast) < 0) {
+ log_err("Invalid congestion avoidance algorithm.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_autobind(toml_table_t * table,
+ pid_t pid,
+ const char * name,
+ const char * layer)
+{
+ toml_datum_t autobind;
+
+ autobind = toml_bool_in(table, "autobind");
+ if (!autobind.ok)
+ return 0;
+
+ if (bind_process(pid, name) < 0) {
+ log_err("Failed to bind IPCP process %d to %s.", pid, name);
+ return -1;
+ }
+
+ if (layer != NULL && bind_process(pid, layer) < 0) {
+ log_err("Failed to bind IPCP process %d to %s.", pid, layer);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_register(toml_table_t * table,
+ pid_t pid)
+{
+ toml_array_t * reg;
+ int i;
+ int ret = 0;
+ struct name_info info = {
+ .pol_lb = LB_SPILL
+ };
+
+ reg = toml_array_in(table, "reg");
+ if (reg == NULL)
+ return 0;
+
+ for (i = 0; ret == 0; i++) {
+ toml_datum_t name;
+
+ name = toml_string_at(reg, i);
+ if (!name.ok)
+ break;
+
+ log_dbg("Registering %s in %d", name.u.s, pid);
+
+ strcpy(info.name, name.u.s);
+
+ ret = name_create(&info);
+ if (ret < 0 && ret != -ENAME) {
+ free(name.u.s);
+ break;
+ }
+
+ ret = name_reg(name.u.s, pid);
+ free(name.u.s);
+ }
+
+ return ret;
+}
+
+static int toml_connect(toml_table_t * table,
+ pid_t pid)
+{
+ toml_array_t * conn;
+ int i;
+ int ret = 0;
+
+ conn = toml_array_in(table, "conn");
+ if (conn == NULL)
+ return 0;
+
+ for (i=0; ret == 0; i++) {
+ toml_datum_t dst;
+ qosspec_t qs = qos_raw;
+
+ dst = toml_string_at(conn, i);
+ if (!dst.ok)
+ break;
+
+ log_dbg("Connecting %d to %s", pid, dst.u.s);
+
+ ret = connect_ipcp(pid, dst.u.s, MGMT_COMP, qs);
+ if (ret == 0)
+ ret = connect_ipcp(pid, dst.u.s, DT_COMP, qs);
+
+ free(dst.u.s);
+ }
+
+ return ret;
+}
+
+static int toml_ipcp(toml_table_t * table,
+ struct ipcp_info * info,
+ struct ipcp_config * conf)
+{
+ toml_datum_t bootstrap;
+ toml_datum_t enrol;
+ int ret;
+
+ log_dbg("Found IPCP %s in configuration file.", info->name);
+
+ if (create_ipcp(info) < 0) {
+ log_err("Failed to create IPCP %s.", info->name);
+ return -1;
+ }
+
+ bootstrap = toml_string_in(table, "bootstrap");
+ enrol = toml_string_in(table, "enrol");
+
+ if (bootstrap.ok && enrol.ok) {
+ log_err("Ignoring bootstrap for IPCP %s.", info->name);
+ free(bootstrap.u.s);
+ bootstrap.ok = false;
+ }
+
+ if (!bootstrap.ok && !enrol.ok) {
+ log_dbg("Nothing more to do for %s.", info->name);
+ return 0;
+ }
+
+ if (enrol.ok) {
+ struct layer_info layer;
+ ret = enroll_ipcp(info->pid, enrol.u.s);
+ free(enrol.u.s);
+ if (ret < 0) {
+ log_err("Failed to enrol %s.", info->name);
+ return -1;
+ }
+
+ if (reg_get_ipcp(info, &layer) < 0)
+ return -1;
+
+ if (toml_autobind(table, info->pid, info->name, layer.name))
+ return -1;
+
+ if (toml_register(table, info->pid) < 0) {
+ log_err("Failed to register names.");
+ return -1;
+ }
+
+ if (toml_connect(table, info->pid) < 0) {
+ log_err("Failed to register names.");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ assert(bootstrap.ok);
+
+ if (strlen(bootstrap.u.s) > LAYER_NAME_SIZE) {
+ log_err("Layer name too long: %s", bootstrap.u.s);
+ free(bootstrap.u.s);
+ return -1;
+ }
+
+ switch (conf->type) {
+ case IPCP_LOCAL:
+ ret = toml_local(table, conf);
+ break;
+ case IPCP_ETH_DIX:
+ ret = toml_eth_dix(table, conf);
+ break;
+ case IPCP_ETH_LLC:
+ ret = toml_eth_llc(table, conf);
+ break;
+ case IPCP_UDP:
+ ret = toml_udp(table, conf);
+ break;
+ case IPCP_BROADCAST:
+ ret = toml_broadcast(table, conf);
+ break;
+ case IPCP_UNICAST:
+ ret = toml_unicast(table, conf);
+ break;
+ default:
+ log_err("Invalid IPCP type");
+ ret = -1;
+ }
+
+ if (ret < 0)
+ return -1;
+
+ strcpy(conf->layer_info.name, bootstrap.u.s);
+ free(bootstrap.u.s);
+
+ if (bootstrap_ipcp(info->pid, conf) < 0)
+ return -1;
+
+ if (toml_autobind(table, info->pid, info->name,
+ conf->layer_info.name) < 0)
+ return -1;
+
+ if (toml_register(table, info->pid) < 0) {
+ log_err("Failed to register names.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int toml_ipcp_list(toml_table_t * table,
+ enum ipcp_type type)
+{
+ int i = 0;
+ int ret = 0;
+
+ for (i = 0; ret == 0; i++) {
+ const char * key;
+ struct ipcp_info info;
+ struct ipcp_config conf;
+
+ memset(&conf, 0, sizeof(conf));
+ memset(&info, 0, sizeof(info));
+
+ key = toml_key_in(table, i);
+ if (key == NULL)
+ break;
+
+ if (strlen(key) > IPCP_NAME_SIZE) {
+ log_err("IPCP name too long: %s,", key);
+ return -1;
+ }
+
+ info.type = type;
+ strcpy(info.name,key);
+ conf.type = type;
+
+ ret = toml_ipcp(toml_table_in(table, key), &info, &conf);
+ }
+
+ return ret;
+}
+
+static int args_to_argv(const char * prog,
+ const char * args,
+ char *** argv)
+{
+ char * tok;
+ char * str;
+ int argc = 0;
+
+ str = (char *) args;
+
+ if (str != NULL) {
+ tok = str;
+ while (*(tok += strspn(tok, " ")) != '\0') {
+ tok += strcspn(tok, " ");
+ argc++;
+ }
+ }
+
+ *argv = malloc((argc + 2) * sizeof(**argv));
+ if (*argv == NULL)
+ goto fail_malloc;
+
+ (*argv)[0] = strdup(prog);
+ if ((*argv)[0] == NULL)
+ goto fail_malloc2;
+
+ argc = 1;
+
+ if (str == NULL)
+ goto finish;
+
+ tok = str;
+ while (*(tok += strspn(tok, " ")) != '\0') {
+ size_t toklen = strcspn(tok, " ");
+ (*argv)[argc] = malloc((toklen + 1) * sizeof(***argv));
+ if ((*argv)[argc] == NULL)
+ goto fail_malloc2;
+
+ strncpy((*argv)[argc], tok, toklen);
+ (*argv)[argc++][toklen] = '\0';
+ tok += toklen;
+ }
+
+ finish:
+ (*argv)[argc] = NULL;
+
+ return argc;
+
+ fail_malloc2:
+ argvfree(*argv);
+ fail_malloc:
+ return -1;
+
+}
+
+static int toml_prog(const char * prog,
+ const char * args,
+ const char * name)
+{
+ uint16_t flags = 0;
+ int argc;
+ char ** exec;
+ int ret;
+
+ if (args != NULL)
+ flags |= BIND_AUTO;
+
+ argc = args_to_argv(prog, args, &exec);
+ if (argc < 0) {
+ log_err("Failed to parse arguments: %s", args);
+ return -1;
+ }
+
+ ret = bind_program(exec, name, flags);
+ if (ret < 0)
+ log_err("Failed to bind program %s %s for name %s.",
+ prog, args, name);
+
+ argvfree(exec);
+
+ return ret;
+}
+
+static int toml_prog_list(toml_array_t * progs,
+ toml_array_t * args,
+ const char * name)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; ret == 0; i++) {
+ toml_datum_t prog;
+ toml_datum_t arg;
+
+ prog = toml_string_at(progs, i);
+ if (!prog.ok)
+ break;
+
+ if (args == NULL) {
+ ret = toml_prog(prog.u.s, NULL, name);
+ } else {
+ arg = toml_string_at(args, i);
+ if (!arg.ok) {
+ args = NULL; /* no more arguments in list. */
+ assert(arg.u.s == NULL);
+ }
+
+ ret = toml_prog(prog.u.s, arg.u.s, name);
+
+ if (arg.ok)
+ free(arg.u.s);
+ }
+
+ free(prog.u.s);
+ }
+
+ return ret;
+}
+
+static int toml_name(toml_table_t * table,
+ const char * name)
+{
+ toml_array_t * progs;
+ toml_array_t * args;
+ toml_datum_t lb;
+ struct name_info info = {
+ .pol_lb = LB_SPILL
+ };
+
+ log_dbg("Found service name %s in configuration file.", name);
+
+ lb = toml_string_in(table, "lb");
+ if (lb.ok) {
+ if (strcmp(lb.u.s, "spill") == 0)
+ info.pol_lb = LB_SPILL;
+ else if (strcmp(lb.u.s, "round-robin") == 0)
+ info.pol_lb = LB_RR;
+ else
+ info.pol_lb = LB_INVALID;
+ free(lb.u.s);
+ }
+
+ if (info.pol_lb == LB_INVALID) {
+ log_err("Invalid load-balancing policy for %s.", name);
+ return -1;
+ }
+
+ strcpy(info.name, name);
+
+ if (name_create(&info) < 0) {
+ log_err("Failed to create name %s.", name);
+ return -1;
+ }
+
+ progs = toml_array_in(table, "prog");
+ if (progs == NULL)
+ return 0;
+
+ args = toml_array_in(table, "args");
+ if (toml_prog_list(progs, args, name) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int toml_name_list(toml_table_t * table)
+{
+ int i = 0;
+ int ret = 0;
+
+ for (i = 0; ret == 0; i++) {
+ const char * key;
+
+ key = toml_key_in(table, i);
+ if (key == NULL)
+ break;
+
+ ret = toml_name(toml_table_in(table, key), key);
+ }
+
+ return ret;
+ return 0;
+}
+
+static int toml_toplevel(toml_table_t * table,
+ const char * key)
+{
+ toml_table_t * subtable;
+
+ subtable = toml_table_in(table, key);
+
+ if (strcmp(key, "local") == 0)
+ return toml_ipcp_list(subtable, IPCP_LOCAL);
+ else if (strcmp(key, "eth-dix") == 0)
+ return toml_ipcp_list(subtable, IPCP_ETH_DIX);
+ else if (strcmp(key, "eth-llc") == 0)
+ return toml_ipcp_list(subtable, IPCP_ETH_LLC);
+ else if (strcmp(key, "udp") == 0)
+ return toml_ipcp_list(subtable, IPCP_UDP);
+ else if (strcmp(key, "broadcast") == 0)
+ return toml_ipcp_list(subtable, IPCP_BROADCAST);
+ else if (strcmp(key, "unicast") == 0)
+ return toml_ipcp_list(subtable, IPCP_UNICAST);
+ else if (strcmp(key, "name") == 0)
+ return toml_name_list(subtable);
+
+ log_err("Unkown toplevel key: %s.", key);
+ return -1;
+}
+
+static int toml_load(toml_table_t * table)
+{
+ int i = 0;
+ int ret = 0;
+
+ for (i = 0; ret == 0; i++) {
+ const char * key;
+
+ key = toml_key_in(table, i);
+ if (key == NULL)
+ break;
+
+ ret = toml_toplevel(table, key);
+ }
+
+ return ret;
+}
+
+static int toml_cfg(FILE * fp)
+{
+ toml_table_t * table;
+ char errbuf[ERRBUFSZ + 1];
+
+ assert(fp != NULL);
+
+ table = toml_parse_file(fp, errbuf, sizeof(errbuf));
+ if (table == NULL) {
+ log_err("Failed to parse config file: %s.", errbuf);
+ goto fail_parse;
+ }
+
+ if (toml_load(table) < 0) {
+ log_err("Failed to load configuration.");
+ goto fail_load;
+ }
+
+ toml_free(table);
+
+ return 0;
+
+ fail_load:
+ toml_free(table);
+ fail_parse:
+ return -1;
+}
+
+int irm_configure(const char * path)
+{
+ FILE * fp;
+ char * rp;
+
+ if (path == NULL)
+ return 0;
+
+ rp = realpath(path, NULL);
+ if (rp == NULL) {
+ log_err("Failed to resolve path for %s", path);
+ goto fail_resolve;
+ }
+
+ log_info("Reading configuration from file %s", rp);
+
+ fp = fopen(rp, "r");
+ if (fp == NULL) {
+ log_err("Failed to open config file: %s\n", strerror(errno));
+ goto fail_fopen;
+ }
+
+ if (toml_cfg(fp) < 0) {
+ log_err("Failed to load config file.");
+ goto fail_cfg;
+ }
+
+ fclose(fp);
+ free(rp);
+
+ return 0;
+
+ fail_cfg:
+ fclose(fp);
+ fail_fopen:
+ free(rp);
+ fail_resolve:
+ return -1;
+}
+
+#endif /* HAVE_TOML */
diff --git a/src/irmd/utils.h b/src/irmd/configfile.h
index 076bbfd8..3ccf53fd 100644
--- a/src/irmd/utils.h
+++ b/src/irmd/configfile.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
- * Utils of the IPC Resource Manager
+ * The IPC Resource Manager / Configuration from file
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,24 +20,10 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#ifndef OUROBOROS_IRMD_UTILS_H
-#define OUROBOROS_IRMD_UTILS_H
-#include <sys/types.h>
+#ifndef OUROBOROS_IRMD_CONFIGURATION_H
+#define OUROBOROS_IRMD_CONFIGURATION_H
-struct str_el {
- struct list_head next;
- char * str;
-};
+int irm_configure(const char * path);
-struct pid_el {
- struct list_head next;
- pid_t pid;
-};
-
-/* functions for copying and destroying arguments list */
-char ** argvdup(char ** argv);
-
-void argvfree(char ** argv);
-
-#endif /* OUROBOROS_IRM_UTILS_H */
+#endif /* OUROBOROS_IRMD_CONFIGURATION_H */
diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c
index 78408185..5a9a79d3 100644
--- a/src/irmd/ipcp.c
+++ b/src/irmd/ipcp.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* The API to instruct IPCPs
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,203 +20,182 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#define _POSIX_C_SOURCE 199309L
+#define _POSIX_C_SOURCE 200112L
#include "config.h"
#define OUROBOROS_PREFIX "irmd/ipcp"
-#include <ouroboros/logs.h>
#include <ouroboros/errno.h>
-#include <ouroboros/utils.h>
+#include <ouroboros/flow.h>
+#include <ouroboros/logs.h>
#include <ouroboros/sockets.h>
+#include <ouroboros/time.h>
+#include <ouroboros/utils.h>
#include "ipcp.h"
-#include <stdlib.h>
-#include <string.h>
+#include <fcntl.h>
+#include <pthread.h>
#include <signal.h>
+#include <spawn.h>
#include <stdbool.h>
-#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/time.h>
-#include <spawn.h>
-static void close_ptr(void * o)
+static char * str_ipcp_cmd(int code)
{
- close(*(int *) o);
+ switch (code) {
+ case IPCP_MSG_CODE__IPCP_BOOTSTRAP:
+ return "bootstrap";
+ case IPCP_MSG_CODE__IPCP_ENROLL:
+ return "enroll";
+ case IPCP_MSG_CODE__IPCP_CONNECT:
+ return "connect";
+ case IPCP_MSG_CODE__IPCP_DISCONNECT:
+ return "disconnect";
+ case IPCP_MSG_CODE__IPCP_REG:
+ return "reg";
+ case IPCP_MSG_CODE__IPCP_UNREG:
+ return "unreg";
+ case IPCP_MSG_CODE__IPCP_QUERY:
+ return "query";
+ case IPCP_MSG_CODE__IPCP_FLOW_JOIN:
+ return "join";
+ case IPCP_MSG_CODE__IPCP_FLOW_ALLOC:
+ return "alloc";
+ case IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP:
+ return "alloc_resp";
+ case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
+ return "dealloc";
+ default:
+ assert(false);
+ return "unknown";
+ }
}
ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
ipcp_msg_t * msg)
{
- int sockfd = 0;
- uint8_t buf[SOCK_BUF_SIZE];
- char * sock_path = NULL;
- ssize_t len;
- ipcp_msg_t * recv_msg = NULL;
- struct timeval tv;
-
- if (kill(pid, 0) < 0)
- return NULL;
-
- sock_path = ipcp_sock_path(pid);
- if (sock_path == NULL)
- return NULL;
-
- sockfd = client_socket_open(sock_path);
- if (sockfd < 0) {
- free(sock_path);
- return NULL;
- }
-
- free(sock_path);
-
- len = ipcp_msg__get_packed_size(msg);
- if (len == 0) {
- close(sockfd);
- return NULL;
- }
-
- switch (msg->code) {
- case IPCP_MSG_CODE__IPCP_BOOTSTRAP:
- tv.tv_sec = BOOTSTRAP_TIMEOUT / 1000;
- tv.tv_usec = (BOOTSTRAP_TIMEOUT % 1000) * 1000;
- break;
- case IPCP_MSG_CODE__IPCP_ENROLL:
- tv.tv_sec = ENROLL_TIMEOUT / 1000;
- tv.tv_usec = (ENROLL_TIMEOUT % 1000) * 1000;
- break;
- case IPCP_MSG_CODE__IPCP_REG:
- tv.tv_sec = REG_TIMEOUT / 1000;
- tv.tv_usec = (REG_TIMEOUT % 1000) * 1000;
- break;
- case IPCP_MSG_CODE__IPCP_QUERY:
- tv.tv_sec = QUERY_TIMEOUT / 1000;
- tv.tv_usec = (QUERY_TIMEOUT % 1000) * 1000;
- break;
- case IPCP_MSG_CODE__IPCP_CONNECT:
- tv.tv_sec = CONNECT_TIMEOUT / 1000;
- tv.tv_usec = (CONNECT_TIMEOUT % 1000) * 1000;
- break;
- default:
- tv.tv_sec = SOCKET_TIMEOUT / 1000;
- tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
- break;
- }
-
- if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,
- (void *) &tv, sizeof(tv)))
- log_warn("Failed to set timeout on socket.");
-
- pthread_cleanup_push(close_ptr, (void *) &sockfd);
-
- ipcp_msg__pack(msg, buf);
-
- if (write(sockfd, buf, len) != -1)
- len = read(sockfd, buf, SOCK_BUF_SIZE);
-
- if (len > 0)
- recv_msg = ipcp_msg__unpack(NULL, len, buf);
-
- pthread_cleanup_pop(true);
-
- return recv_msg;
-}
+ int sockfd;
+ uint8_t buf[SOCK_BUF_SIZE];
+ char * sock_path;
+ ssize_t len;
+ ipcp_msg_t * recv_msg;
+ struct timeval tv;
+ struct timespec tic;
+ struct timespec toc;
+ bool dealloc = false;
+
+ if (kill(pid, 0) < 0)
+ return NULL;
+
+ sock_path = ipcp_sock_path(pid);
+ if (sock_path == NULL)
+ return NULL;
+
+ sockfd = client_socket_open(sock_path);
+ if (sockfd < 0) {
+ free(sock_path);
+ return NULL;
+ }
-pid_t ipcp_create(const char * name,
- enum ipcp_type ipcp_type)
-{
- pid_t pid = -1;
- char * ipcp_dir = "/sbin/";
- char * exec_name = NULL;
- char irmd_pid[10];
- char full_name[256];
- char * argv[5];
-
- switch(ipcp_type) {
- case IPCP_UNICAST:
- exec_name = IPCP_UNICAST_EXEC;
+ free(sock_path);
+
+ len = ipcp_msg__get_packed_size(msg);
+ if (len == 0 || len >= SOCK_BUF_SIZE) {
+ log_warn("IPCP message has invalid size: %zd.", len);
+ close(sockfd);
+ return NULL;
+ }
+
+ switch (msg->code) {
+ case IPCP_MSG_CODE__IPCP_BOOTSTRAP:
+ tv.tv_sec = BOOTSTRAP_TIMEOUT / 1000;
+ tv.tv_usec = (BOOTSTRAP_TIMEOUT % 1000) * 1000;
break;
- case IPCP_BROADCAST:
- exec_name = IPCP_BROADCAST_EXEC;
+ case IPCP_MSG_CODE__IPCP_ENROLL:
+ tv.tv_sec = ENROLL_TIMEOUT / 1000;
+ tv.tv_usec = (ENROLL_TIMEOUT % 1000) * 1000;
break;
- case IPCP_UDP:
- exec_name = IPCP_UDP_EXEC;
+ case IPCP_MSG_CODE__IPCP_REG:
+ tv.tv_sec = REG_TIMEOUT / 1000;
+ tv.tv_usec = (REG_TIMEOUT % 1000) * 1000;
break;
- case IPCP_ETH_LLC:
- exec_name = IPCP_ETH_LLC_EXEC;
+ case IPCP_MSG_CODE__IPCP_QUERY:
+ tv.tv_sec = QUERY_TIMEOUT / 1000;
+ tv.tv_usec = (QUERY_TIMEOUT % 1000) * 1000;
break;
- case IPCP_ETH_DIX:
- exec_name = IPCP_ETH_DIX_EXEC;
+ case IPCP_MSG_CODE__IPCP_CONNECT:
+ tv.tv_sec = CONNECT_TIMEOUT / 1000;
+ tv.tv_usec = (CONNECT_TIMEOUT % 1000) * 1000;
break;
- case IPCP_LOCAL:
- exec_name = IPCP_LOCAL_EXEC;
+ case IPCP_MSG_CODE__IPCP_FLOW_ALLOC:
+ tv.tv_sec = FLOW_ALLOC_TIMEOUT / 1000;
+ tv.tv_usec = (FLOW_ALLOC_TIMEOUT % 1000) * 1000;
break;
- case IPCP_RAPTOR:
- exec_name = IPCP_RAPTOR_EXEC;
+ case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
+ dealloc = true;
+ tv.tv_sec = 0; /* FIX DEALLOC: don't wait for dealloc */
+ tv.tv_usec = 500;
break;
default:
- return -1;
+ tv.tv_sec = SOCKET_TIMEOUT / 1000;
+ tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
+ break;
}
- if (strlen(exec_name) == 0) {
- log_err("IPCP type not installed.");
- return -1;
- }
+ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,
+ (void *) &tv, sizeof(tv)))
+ log_warn("Failed to set timeout on socket.");
- sprintf(irmd_pid, "%u", getpid());
+ pthread_cleanup_push(__cleanup_close_ptr, (void *) &sockfd);
- strcpy(full_name, INSTALL_PREFIX);
- strcat(full_name, ipcp_dir);
- strcat(full_name, exec_name);
+ ipcp_msg__pack(msg, buf);
- /* log_file to be placed at the end */
- argv[0] = full_name;
- argv[1] = irmd_pid;
- argv[2] = (char *) name;
- if (log_syslog)
- argv[3] = "1";
- else
- argv[3] = NULL;
+ clock_gettime(CLOCK_REALTIME, &tic);
- argv[4] = NULL;
+ if (write(sockfd, buf, len) != -1)
+ len = read(sockfd, buf, SOCK_BUF_SIZE);
- if (posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL)) {
- log_err("Failed to spawn new process");
- return -1;
- }
+ clock_gettime(CLOCK_REALTIME, &toc);
- return pid;
-}
+ pthread_cleanup_pop(true); /* close socket */
-int ipcp_destroy(pid_t pid)
-{
- if (kill(pid, SIGTERM)) {
- log_err("Failed to destroy IPCP");
- return -1;
+ if (len > 0)
+ recv_msg = ipcp_msg__unpack(NULL, len, buf);
+ else {
+ if (errno == EAGAIN && !dealloc) {
+ int diff = ts_diff_ms(&tic, &toc);
+ log_warn("IPCP %s timed out after %d ms.",
+ str_ipcp_cmd(msg->code), diff);
+ }
+ return NULL;
}
- return 0;
+ return recv_msg;
}
-int ipcp_bootstrap(pid_t pid,
- ipcp_config_msg_t * conf,
- struct layer_info * info)
+int ipcp_bootstrap(pid_t pid,
+ struct ipcp_config * conf,
+ struct layer_info * info)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
if (conf == NULL)
return -EINVAL;
msg.code = IPCP_MSG_CODE__IPCP_BOOTSTRAP;
- msg.conf = conf;
+ msg.conf = ipcp_config_s_to_msg(conf);
recv_msg = send_recv_ipcp_msg(pid, &msg);
+ ipcp_config_msg__free_unpacked(msg.conf, NULL);
if (recv_msg == NULL)
return -EIPCP;
@@ -237,7 +216,7 @@ int ipcp_bootstrap(pid_t pid,
}
info->dir_hash_algo = recv_msg->layer_info->dir_hash_algo;
- strcpy(info->layer_name, recv_msg->layer_info->layer_name);
+ strcpy(info->name, recv_msg->layer_info->name);
ret = recv_msg->result;
ipcp_msg__free_unpacked(recv_msg, NULL);
@@ -249,9 +228,9 @@ int ipcp_enroll(pid_t pid,
const char * dst,
struct layer_info * info)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
if (dst == NULL)
return -EINVAL;
@@ -280,7 +259,7 @@ int ipcp_enroll(pid_t pid,
}
info->dir_hash_algo = recv_msg->layer_info->dir_hash_algo;
- strcpy(info->layer_name, recv_msg->layer_info->layer_name);
+ strcpy(info->name, recv_msg->layer_info->name);
ipcp_msg__free_unpacked(recv_msg, NULL);
@@ -292,20 +271,19 @@ int ipcp_connect(pid_t pid,
const char * component,
qosspec_t qs)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT;
- int ret = -1;
+ ipcp_msg_t msg = IPCP_MSG__INIT;
ipcp_msg_t * recv_msg;
+ int ret;
msg.code = IPCP_MSG_CODE__IPCP_CONNECT;
msg.dst = (char *) dst;
msg.comp = (char *) component;
msg.has_pid = true;
msg.pid = pid;
- qs_msg = spec_to_msg(&qs);
- msg.qosspec = &qs_msg;
+ msg.qosspec = qos_spec_s_to_msg(&qs);
recv_msg = send_recv_ipcp_msg(pid, &msg);
+ free(msg.qosspec);
if (recv_msg == NULL)
return -EIPCP;
@@ -324,9 +302,9 @@ int ipcp_disconnect(pid_t pid,
const char * dst,
const char * component)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
msg.code = IPCP_MSG_CODE__IPCP_DISCONNECT;
msg.dst = (char *) dst;
@@ -349,20 +327,17 @@ int ipcp_disconnect(pid_t pid,
return ret;
}
-int ipcp_reg(pid_t pid,
- const uint8_t * hash,
- size_t len)
+int ipcp_reg(pid_t pid,
+ const buffer_t hash)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
-
- assert(hash);
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
msg.code = IPCP_MSG_CODE__IPCP_REG;
msg.has_hash = true;
- msg.hash.len = len;
- msg.hash.data = (uint8_t *)hash;
+ msg.hash.data = (uint8_t *) hash.data;
+ msg.hash.len = hash.len;
recv_msg = send_recv_ipcp_msg(pid, &msg);
if (recv_msg == NULL)
@@ -379,18 +354,17 @@ int ipcp_reg(pid_t pid,
return ret;
}
-int ipcp_unreg(pid_t pid,
- const uint8_t * hash,
- size_t len)
+int ipcp_unreg(pid_t pid,
+ const buffer_t hash)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
msg.code = IPCP_MSG_CODE__IPCP_UNREG;
msg.has_hash = true;
- msg.hash.len = len;
- msg.hash.data = (uint8_t *) hash;
+ msg.hash.data = (uint8_t *) hash.data;
+ msg.hash.len = hash.len;
recv_msg = send_recv_ipcp_msg(pid, &msg);
if (recv_msg == NULL)
@@ -407,18 +381,17 @@ int ipcp_unreg(pid_t pid,
return ret;
}
-int ipcp_query(pid_t pid,
- const uint8_t * hash,
- size_t len)
+int ipcp_query(pid_t pid,
+ const buffer_t dst)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
msg.code = IPCP_MSG_CODE__IPCP_QUERY;
msg.has_hash = true;
- msg.hash.len = len;
- msg.hash.data = (uint8_t *) hash;
+ msg.hash.data = (uint8_t *) dst.data;
+ msg.hash.len = dst.len;
recv_msg = send_recv_ipcp_msg(pid, &msg);
if (recv_msg == NULL)
@@ -435,39 +408,25 @@ int ipcp_query(pid_t pid,
return ret;
}
-static int __ipcp_flow_alloc(pid_t pid,
- int flow_id,
- pid_t n_pid,
- const uint8_t * dst,
- size_t len,
- qosspec_t qs,
- bool join,
- const void * data,
- size_t dlen)
+int ipcp_flow_join(const struct flow_info * flow,
+ const buffer_t dst)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- qosspec_msg_t qs_msg;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
-
- assert(dst);
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
- msg.code = join ? IPCP_MSG_CODE__IPCP_FLOW_JOIN
- : IPCP_MSG_CODE__IPCP_FLOW_ALLOC;
+ msg.code = IPCP_MSG_CODE__IPCP_FLOW_JOIN;
msg.has_flow_id = true;
- msg.flow_id = flow_id;
+ msg.flow_id = flow->id;
msg.has_pid = true;
- msg.pid = n_pid;
+ msg.pid = flow->n_pid;
msg.has_hash = true;
- msg.hash.len = len;
- msg.hash.data = (uint8_t *) dst;
- qs_msg = spec_to_msg(&qs);
- msg.qosspec = &qs_msg;
- msg.has_pk = true;
- msg.pk.data = (uint8_t *) data;
- msg.pk.len = (uint32_t) dlen;
+ msg.hash.data = (uint8_t *) dst.data;
+ msg.hash.len = dst.len;
+ msg.has_pk = false;
- recv_msg = send_recv_ipcp_msg(pid, &msg);
+ recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg);
+ free(msg.qosspec);
if (recv_msg == NULL)
return -EIPCP;
@@ -482,53 +441,66 @@ static int __ipcp_flow_alloc(pid_t pid,
return ret;
}
-int ipcp_flow_alloc(pid_t pid,
- int flow_id,
- pid_t n_pid,
- const uint8_t * dst,
- size_t len,
- qosspec_t qs,
- const void * data,
- size_t dlen)
+int ipcp_flow_alloc(const struct flow_info * flow,
+ const buffer_t dst,
+ const buffer_t data)
{
- return __ipcp_flow_alloc(pid, flow_id, n_pid, dst, len, qs, false,
- data, dlen);
-}
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
-int ipcp_flow_join(pid_t pid,
- int flow_id,
- pid_t n_pid,
- const uint8_t * dst,
- size_t len,
- qosspec_t qs)
-{
- return __ipcp_flow_alloc(pid, flow_id, n_pid, dst, len, qs, true,
- NULL, 0);
+ msg.code = IPCP_MSG_CODE__IPCP_FLOW_ALLOC;
+ msg.has_flow_id = true;
+ msg.flow_id = flow->id;
+ msg.has_pid = true;
+ msg.pid = flow->n_pid;
+ msg.qosspec = qos_spec_s_to_msg(&flow->qs);
+ msg.has_hash = true;
+ msg.hash.data = (uint8_t *) dst.data;
+ msg.hash.len = dst.len;
+ msg.has_pk = true;
+ msg.pk.data = data.data;
+ msg.pk.len = data.len;
+
+ recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg);
+ free(msg.qosspec);
+ if (recv_msg == NULL) {
+ log_err("Did not receive message.");
+ return -EIPCP;
+ }
+
+ if (!recv_msg->has_result) {
+ log_err("Message has no result");
+ ipcp_msg__free_unpacked(recv_msg, NULL);
+ return -EIPCP;
+ }
+
+ ret = recv_msg->result;
+ ipcp_msg__free_unpacked(recv_msg, NULL);
+
+ return ret;
}
-int ipcp_flow_alloc_resp(pid_t pid,
- int flow_id,
- pid_t n_pid,
- int response,
- const void * data,
- size_t len)
+int ipcp_flow_alloc_resp(const struct flow_info * flow,
+ int response,
+ const buffer_t data)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
msg.code = IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP;
msg.has_flow_id = true;
- msg.flow_id = flow_id;
+ msg.flow_id = flow->id;
msg.has_pid = true;
- msg.pid = n_pid;
+ msg.pid = flow->n_pid;
msg.has_response = true;
msg.response = response;
msg.has_pk = true;
- msg.pk.data = (uint8_t *) data;
- msg.pk.len = (uint32_t) len;
+ msg.pk.data = data.data;
+ msg.pk.len = data.len;
- recv_msg = send_recv_ipcp_msg(pid, &msg);
+ recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg);
if (recv_msg == NULL)
return -EIPCP;
@@ -543,16 +515,19 @@ int ipcp_flow_alloc_resp(pid_t pid,
return ret;
}
-int ipcp_flow_dealloc(pid_t pid,
- int flow_id)
+int ipcp_flow_dealloc(pid_t pid,
+ int flow_id,
+ time_t timeo)
{
- ipcp_msg_t msg = IPCP_MSG__INIT;
- ipcp_msg_t * recv_msg = NULL;
- int ret = -1;
-
- msg.code = IPCP_MSG_CODE__IPCP_FLOW_DEALLOC;
- msg.has_flow_id = true;
- msg.flow_id = flow_id;
+ ipcp_msg_t msg = IPCP_MSG__INIT;
+ ipcp_msg_t * recv_msg;
+ int ret;
+
+ msg.code = IPCP_MSG_CODE__IPCP_FLOW_DEALLOC;
+ msg.has_flow_id = true;
+ msg.flow_id = flow_id;
+ msg.has_timeo_sec = true;
+ msg.timeo_sec = timeo;
recv_msg = send_recv_ipcp_msg(pid, &msg);
if (recv_msg == NULL)
diff --git a/src/irmd/ipcp.h b/src/irmd/ipcp.h
index ae00792b..b7413cd2 100644
--- a/src/irmd/ipcp.h
+++ b/src/irmd/ipcp.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* The API for the IRM to instruct IPCPs
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,25 +21,19 @@
*/
#include <ouroboros/ipcp.h>
+#include <ouroboros/protobuf.h>
#include <ouroboros/sockets.h>
-#include <sys/types.h>
-
#ifndef OUROBOROS_IRMD_IPCP_H
#define OUROBOROS_IRMD_IPCP_H
-pid_t ipcp_create(const char * name,
- enum ipcp_type ipcp_type);
-
-int ipcp_destroy(pid_t pid);
-
int ipcp_enroll(pid_t pid,
const char * dst,
struct layer_info * info);
-int ipcp_bootstrap(pid_t pid,
- ipcp_config_msg_t * conf,
- struct layer_info * info);
+int ipcp_bootstrap(pid_t pid,
+ struct ipcp_config * conf,
+ struct layer_info * info);
int ipcp_connect(pid_t pid,
const char * dst,
@@ -50,42 +44,28 @@ int ipcp_disconnect(pid_t pid,
const char * dst,
const char * component);
-int ipcp_reg(pid_t pid,
- const uint8_t * hash,
- size_t len);
+int ipcp_reg(pid_t pid,
+ const buffer_t hash);
-int ipcp_unreg(pid_t pid,
- const uint8_t * hash,
- size_t len);
+int ipcp_unreg(pid_t pid,
+ const buffer_t hash);
-int ipcp_query(pid_t pid,
- const uint8_t * hash,
- size_t len);
+int ipcp_query(pid_t pid,
+ const buffer_t dst);
-int ipcp_flow_alloc(pid_t pid,
- int flow_id,
- pid_t n_pid,
- const uint8_t * dst,
- size_t len,
- qosspec_t qs,
- const void * data,
- size_t dlen);
+int ipcp_flow_alloc(const struct flow_info * flow,
+ const buffer_t hash,
+ const buffer_t data);
-int ipcp_flow_join(pid_t pid,
- int flow_id,
- pid_t n_pid,
- const uint8_t * dst,
- size_t len,
- qosspec_t qs);
+int ipcp_flow_join(const struct flow_info * flow,
+ const buffer_t dst);
-int ipcp_flow_alloc_resp(pid_t pid,
- int flow_id,
- pid_t n_pid,
- int response,
- const void * data,
- size_t len);
+int ipcp_flow_alloc_resp(const struct flow_info * flow,
+ int response,
+ const buffer_t data);
-int ipcp_flow_dealloc(pid_t pid,
- int flow_id);
+int ipcp_flow_dealloc(pid_t pid,
+ int flow_id,
+ time_t timeo);
#endif /* OUROBOROS_IRMD_IPCP_H */
diff --git a/src/irmd/irm_flow.c b/src/irmd/irm_flow.c
deleted file mode 100644
index 10395a35..00000000
--- a/src/irmd/irm_flow.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Flows
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define _POSIX_C_SOURCE 200112L
-
-#include "config.h"
-
-#define OUROBOROS_PREFIX "irm_flow"
-
-#include <ouroboros/errno.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/time_utils.h>
-
-#include "irm_flow.h"
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <assert.h>
-
-struct irm_flow * irm_flow_create(pid_t n_pid,
- pid_t n_1_pid,
- int flow_id,
- qosspec_t qs)
-{
- pthread_condattr_t cattr;
- struct irm_flow * f = malloc(sizeof(*f));
- if (f == NULL)
- goto fail_malloc;
-
- if (pthread_condattr_init(&cattr))
- goto fail_cattr;
-
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
- if (pthread_cond_init(&f->state_cond, &cattr))
- goto fail_state_cond;
-
- if (pthread_mutex_init(&f->state_lock, NULL))
- goto fail_mutex;
-
- f->n_pid = n_pid;
- f->n_1_pid = n_1_pid;
- f->flow_id = flow_id;
- f->qs = qs;
- f->data = NULL;
- f->len = 0;
-
- f->n_rb = shm_rbuff_create(n_pid, flow_id);
- if (f->n_rb == NULL) {
- log_err("Could not create ringbuffer for process %d.", n_pid);
- goto fail_n_rbuff;
- }
-
- f->n_1_rb = shm_rbuff_create(n_1_pid, flow_id);
- if (f->n_1_rb == NULL) {
- log_err("Could not create ringbuffer for process %d.", n_1_pid);
- goto fail_n_1_rbuff;
- }
-
- f->state = FLOW_ALLOC_PENDING;
-
- if (clock_gettime(CLOCK_MONOTONIC, &f->t0) < 0)
- log_warn("Failed to set timestamp.");
-
- pthread_condattr_destroy(&cattr);
-
- return f;
-
- fail_n_1_rbuff:
- shm_rbuff_destroy(f->n_rb);
- fail_n_rbuff:
- pthread_mutex_destroy(&f->state_lock);
- fail_mutex:
- pthread_cond_destroy(&f->state_cond);
- fail_state_cond:
- pthread_condattr_destroy(&cattr);
- fail_cattr:
- free(f);
- fail_malloc:
- return NULL;
-}
-
-static void cancel_irm_destroy(void * o)
-{
- struct irm_flow * f = (struct irm_flow *) o;
-
- pthread_mutex_unlock(&f->state_lock);
-
- pthread_cond_destroy(&f->state_cond);
- pthread_mutex_destroy(&f->state_lock);
-
- shm_rbuff_destroy(f->n_rb);
- shm_rbuff_destroy(f->n_1_rb);
-
- free(f);
-}
-
-void irm_flow_destroy(struct irm_flow * f)
-{
- assert(f);
-
- pthread_mutex_lock(&f->state_lock);
-
- assert(f->len == 0);
-
- if (f->state == FLOW_DESTROY) {
- pthread_mutex_unlock(&f->state_lock);
- return;
- }
-
- if (f->state == FLOW_ALLOC_PENDING)
- f->state = FLOW_DESTROY;
- else
- f->state = FLOW_NULL;
-
- pthread_cond_signal(&f->state_cond);
-
- pthread_cleanup_push(cancel_irm_destroy, f);
-
- while (f->state != FLOW_NULL)
- pthread_cond_wait(&f->state_cond, &f->state_lock);
-
- pthread_cleanup_pop(true);
-}
-
-enum flow_state irm_flow_get_state(struct irm_flow * f)
-{
- enum flow_state state;
-
- assert(f);
-
- pthread_mutex_lock(&f->state_lock);
-
- state = f->state;
-
- pthread_mutex_unlock(&f->state_lock);
-
- return state;
-}
-
-void irm_flow_set_state(struct irm_flow * f,
- enum flow_state state)
-{
- assert(f);
- assert(state != FLOW_DESTROY);
-
- pthread_mutex_lock(&f->state_lock);
-
- f->state = state;
- pthread_cond_broadcast(&f->state_cond);
-
- pthread_mutex_unlock(&f->state_lock);
-}
-
-int irm_flow_wait_state(struct irm_flow * f,
- enum flow_state state,
- struct timespec * timeo)
-{
- int ret = 0;
- int s;
-
- struct timespec dl;
-
- assert(f);
- assert(state != FLOW_NULL);
- assert(state != FLOW_DESTROY);
- assert(state != FLOW_DEALLOC_PENDING);
-
- if (timeo != NULL) {
- clock_gettime(PTHREAD_COND_CLOCK, &dl);
- ts_add(&dl, timeo, &dl);
- }
-
- pthread_mutex_lock(&f->state_lock);
-
- assert(f->state != FLOW_NULL);
-
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &f->state_lock);
-
- while (!(f->state == state ||
- f->state == FLOW_DESTROY ||
- f->state == FLOW_DEALLOC_PENDING) &&
- ret != -ETIMEDOUT) {
- if (timeo == NULL)
- ret = -pthread_cond_wait(&f->state_cond,
- &f->state_lock);
- else
- ret = -pthread_cond_timedwait(&f->state_cond,
- &f->state_lock,
- &dl);
- }
-
- if (f->state == FLOW_DESTROY ||
- f->state == FLOW_DEALLOC_PENDING ||
- ret == -ETIMEDOUT) {
- f->state = FLOW_NULL;
- pthread_cond_broadcast(&f->state_cond);
- }
-
- s = f->state;
-
- pthread_cleanup_pop(true);
-
- return ret ? ret : s;
-}
diff --git a/src/irmd/irm_flow.h b/src/irmd/irm_flow.h
deleted file mode 100644
index 051a60a6..00000000
--- a/src/irmd/irm_flow.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Flows
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IRMD_IRM_FLOW_H
-#define OUROBOROS_IRMD_IRM_FLOW_H
-
-#include <ouroboros/list.h>
-#include <ouroboros/qos.h>
-#include <ouroboros/shm_rbuff.h>
-
-#include <sys/types.h>
-#include <pthread.h>
-#include <time.h>
-
-enum flow_state {
- FLOW_NULL = 0,
- FLOW_ALLOC_PENDING,
- FLOW_ALLOCATED,
- FLOW_DEALLOC_PENDING,
- FLOW_DESTROY
-};
-
-struct irm_flow {
- struct list_head next;
-
- int flow_id;
-
- pid_t n_pid;
- pid_t n_1_pid;
-
- qosspec_t qs;
- void * data;
- size_t len;
-
- struct shm_rbuff * n_rb;
- struct shm_rbuff * n_1_rb;
-
- struct timespec t0;
-
- enum flow_state state;
- pthread_cond_t state_cond;
- pthread_mutex_t state_lock;
-};
-
-struct irm_flow * irm_flow_create(pid_t n_pid,
- pid_t n_1_pid,
- int flow_id,
- qosspec_t qs);
-
-void irm_flow_destroy(struct irm_flow * f);
-
-enum flow_state irm_flow_get_state(struct irm_flow * f);
-
-
-void irm_flow_set_state(struct irm_flow * f,
- enum flow_state state);
-
-int irm_flow_wait_state(struct irm_flow * f,
- enum flow_state state,
- struct timespec * timeo);
-
-#endif /* OUROBOROS_IRMD_IRM_FLOW_H */
diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h
new file mode 100644
index 00000000..cf8f6953
--- /dev/null
+++ b/src/irmd/irmd.h
@@ -0,0 +1,54 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_H
+#define OUROBOROS_IRMD_H
+
+#include <ouroboros/ipcp.h>
+#include <ouroboros/irm.h>
+
+int create_ipcp(struct ipcp_info * info);
+
+int bootstrap_ipcp(pid_t pid,
+ struct ipcp_config * conf);
+
+int enroll_ipcp(pid_t pid,
+ const char * dst);
+
+int connect_ipcp(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs);
+
+int name_create(const struct name_info * info);
+
+int name_reg(const char * name,
+ pid_t pid);
+
+int bind_process(pid_t pid,
+ const char * name);
+
+int bind_program(char ** exec,
+ const char * name,
+ uint8_t flags);
+
+#endif /* OUROBOROS_IRMD_H*/
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 1c928dca..5d91baf0 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* The IPC Resource Manager
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -30,27 +30,28 @@
#define OUROBOROS_PREFIX "irmd"
-#include <ouroboros/hash.h>
+#include <ouroboros/bitmap.h>
+#include <ouroboros/crypt.h>
#include <ouroboros/errno.h>
-#include <ouroboros/sockets.h>
-#include <ouroboros/list.h>
-#include <ouroboros/utils.h>
+#include <ouroboros/flow.h>
+#include <ouroboros/hash.h>
#include <ouroboros/irm.h>
+#include <ouroboros/list.h>
#include <ouroboros/lockfile.h>
-#include <ouroboros/shm_rbuff.h>
+#include <ouroboros/logs.h>
+#include <ouroboros/pthread.h>
+#include <ouroboros/rib.h>
#include <ouroboros/shm_rdrbuff.h>
-#include <ouroboros/bitmap.h>
-#include <ouroboros/qos.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/sockets.h>
+#include <ouroboros/time.h>
#include <ouroboros/tpm.h>
-#include <ouroboros/logs.h>
+#include <ouroboros/utils.h>
#include <ouroboros/version.h>
-#include "utils.h"
-#include "registry.h"
-#include "irm_flow.h"
-#include "proc_table.h"
+#include "irmd.h"
#include "ipcp.h"
+#include "reg/reg.h"
+#include "configfile.h"
#include <sys/socket.h>
#include <sys/un.h>
@@ -58,7 +59,6 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
-#include <pthread.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <spawn.h>
@@ -68,60 +68,31 @@
#endif
#define IRMD_CLEANUP_TIMER ((IRMD_FLOW_TIMEOUT / 20) * MILLION) /* ns */
-#define SHM_SAN_HOLDOFF 1000 /* ms */
-#define IPCP_HASH_LEN(e) hash_len(e->dir_hash_algo)
-#define IB_LEN SOCK_BUF_SIZE
-#define BIND_TIMEOUT 10 /* ms */
-
-enum init_state {
- IPCP_NULL = 0,
- IPCP_BOOT,
- IPCP_LIVE
-};
-
-struct ipcp_entry {
- struct list_head next;
-
- char * name;
- pid_t pid;
- enum ipcp_type type;
- enum hash_algo dir_hash_algo;
- char * layer;
-
- enum init_state state;
- pthread_cond_t cond;
- pthread_mutex_t lock;
-};
+#define SHM_SAN_HOLDOFF 1000 /* ms */
+#define IPCP_HASH_LEN(p) hash_len((p)->dir_hash_algo)
+#define BIND_TIMEOUT 10 /* ms */
+#define DEALLOC_TIME 300 /* s */
+#define MSGBUFSZ 2048
enum irm_state {
IRMD_NULL = 0,
- IRMD_RUNNING
+ IRMD_RUNNING,
+ IRMD_SHUTDOWN
};
struct cmd {
struct list_head next;
- uint8_t cbuf[IB_LEN];
+ uint8_t cbuf[SOCK_BUF_SIZE];
size_t len;
int fd;
};
struct {
- struct list_head registry; /* registered names known */
- size_t n_names; /* number of names */
-
- struct list_head ipcps; /* list of ipcps in system */
- size_t n_ipcps; /* number of ipcps */
-
- struct list_head proc_table; /* processes */
- struct list_head prog_table; /* programs known */
- struct list_head spawned_pids; /* child processes */
- pthread_rwlock_t reg_lock; /* lock for registration info */
-
- struct bmp * flow_ids; /* flow_ids for flows */
- struct list_head irm_flows; /* flow information */
- pthread_rwlock_t flows_lock; /* lock for flows */
-
+ bool log_stdout; /* log to stdout */
+#ifdef HAVE_TOML
+ char * cfg_file; /* configuration file path */
+#endif
struct lockfile * lf; /* single irmd per system */
struct shm_rdrbuff * rdrb; /* rdrbuff for packets */
@@ -162,492 +133,260 @@ static void irmd_set_state(enum irm_state state)
pthread_rwlock_unlock(&irmd.state_lock);
}
-static void clear_irm_flow(struct irm_flow * f) {
- ssize_t idx;
-
- assert(f);
-
- if (f->len != 0) {
- free(f->data);
- f->len = 0;
- }
-
- while ((idx = shm_rbuff_read(f->n_rb)) >= 0)
- shm_rdrbuff_remove(irmd.rdrb, idx);
-
- while ((idx = shm_rbuff_read(f->n_1_rb)) >= 0)
- shm_rdrbuff_remove(irmd.rdrb, idx);
-}
-
-static struct irm_flow * get_irm_flow(int flow_id)
+static pid_t spawn_program(char ** argv)
{
- struct list_head * pos = NULL;
+ pid_t pid;
+ struct stat s;
- list_for_each(pos, &irmd.irm_flows) {
- struct irm_flow * e = list_entry(pos, struct irm_flow, next);
- if (e->flow_id == flow_id)
- return e;
+ if (stat(argv[0], &s) != 0) {
+ log_warn("Program %s does not exist.", argv[0]);
+ return -1;
}
- return NULL;
-}
-
-static struct irm_flow * get_irm_flow_n(pid_t n_pid)
-{
- struct list_head * pos = NULL;
-
- list_for_each(pos, &irmd.irm_flows) {
- struct irm_flow * e = list_entry(pos, struct irm_flow, next);
- if (e->n_pid == n_pid &&
- irm_flow_get_state(e) == FLOW_ALLOC_PENDING)
- return e;
+ if (!(s.st_mode & S_IXUSR)) {
+ log_warn("Program %s is not executable.", argv[0]);
+ return -1;
}
- return NULL;
-}
-
-static struct ipcp_entry * ipcp_entry_create(const char * name,
- enum ipcp_type type)
-{
- struct ipcp_entry * e;
- pthread_condattr_t cattr;
-
- e = malloc(sizeof(*e));
- if (e == NULL)
- goto fail_malloc;
-
- e->layer = NULL;
- e->type = type;
- e->state = IPCP_BOOT;
- e->name = strdup(name);
- if (e->name == NULL)
- goto fail_name;
-
- if (pthread_condattr_init(&cattr))
- goto fail_cattr;
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
- if (pthread_cond_init(&e->cond, &cattr))
- goto fail_cond;
-
- if (pthread_mutex_init(&e->lock, NULL))
- goto fail_mutex;
-
-
- list_head_init(&e->next);
-
- pthread_condattr_destroy(&cattr);
-
- return e;
-
- fail_mutex:
- pthread_cond_destroy(&e->cond);
- fail_cond:
- pthread_condattr_destroy(&cattr);
- fail_cattr:
- free(e->name);
- fail_name:
- free(e);
- fail_malloc:
- return NULL;
-}
-
-static void ipcp_entry_destroy(struct ipcp_entry * e)
-{
- assert(e);
-
- pthread_mutex_lock(&e->lock);
-
- while (e->state == IPCP_BOOT)
- pthread_cond_wait(&e->cond, &e->lock);
-
- pthread_mutex_unlock(&e->lock);
+ if (posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL)) {
+ log_err("Failed to spawn new process for %s.", argv[0]);
+ return -1;
+ }
- free(e->name);
- free(e->layer);
- free(e);
-}
+ log_info("Instantiated %s as process %d.", argv[0], pid);
-static void ipcp_entry_set_state(struct ipcp_entry * e,
- enum init_state state)
-{
- pthread_mutex_lock(&e->lock);
- e->state = state;
- pthread_cond_broadcast(&e->cond);
- pthread_mutex_unlock(&e->lock);
+ return pid;
}
-static int ipcp_entry_wait_boot(struct ipcp_entry * e)
+static pid_t spawn_ipcp(struct ipcp_info * info)
{
- int ret = 0;
- struct timespec dl;
- struct timespec to = {SOCKET_TIMEOUT / 1000,
- (SOCKET_TIMEOUT % 1000) * MILLION};
-
- clock_gettime(PTHREAD_COND_CLOCK, &dl);
- ts_add(&dl, &to, &dl);
-
- pthread_mutex_lock(&e->lock);
-
- while (e->state == IPCP_BOOT && ret != ETIMEDOUT)
- ret = pthread_cond_timedwait(&e->cond, &e->lock, &dl);
-
- if (ret == ETIMEDOUT) {
- kill(e->pid, SIGTERM);
- e->state = IPCP_NULL;
- pthread_cond_signal(&e->cond);
+ char * exec_name = NULL;
+ char irmd_pid[10];
+ char full_name[256];
+ char * argv[5];
+ pid_t pid;
+
+ switch(info->type) {
+ case IPCP_UNICAST:
+ exec_name = IPCP_UNICAST_EXEC;
+ break;
+ case IPCP_BROADCAST:
+ exec_name = IPCP_BROADCAST_EXEC;
+ break;
+ case IPCP_UDP:
+ exec_name = IPCP_UDP_EXEC;
+ break;
+ case IPCP_ETH_LLC:
+ exec_name = IPCP_ETH_LLC_EXEC;
+ break;
+ case IPCP_ETH_DIX:
+ exec_name = IPCP_ETH_DIX_EXEC;
+ break;
+ case IPCP_LOCAL:
+ exec_name = IPCP_LOCAL_EXEC;
+ break;
+ default:
+ assert(false);
}
- if (e->state != IPCP_LIVE) {
- pthread_mutex_unlock(&e->lock);
+ if (exec_name == NULL) {
+ log_err("IPCP type not installed.");
return -1;
}
- pthread_mutex_unlock(&e->lock);
+ sprintf(irmd_pid, "%u", getpid());
- return 0;
-}
+ strcpy(full_name, INSTALL_PREFIX"/"INSTALL_SBINDIR"/");
+ strcat(full_name, exec_name);
-static struct ipcp_entry * get_ipcp_entry_by_pid(pid_t pid)
-{
- struct list_head * p;
-
- list_for_each(p, &irmd.ipcps) {
- struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- if (e->pid == pid)
- return e;
- }
-
- return NULL;
-}
+ /* log_file to be placed at the end */
+ argv[0] = full_name;
+ argv[1] = irmd_pid;
+ argv[2] = (char *) info->name;
+ if (log_syslog)
+ argv[3] = "1";
+ else
+ argv[3] = NULL;
-static struct ipcp_entry * get_ipcp_entry_by_name(const char * name)
-{
- struct list_head * p;
+ argv[4] = NULL;
- list_for_each(p, &irmd.ipcps) {
- struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- if (strcmp(name, e->name) == 0)
- return e;
+ pid = spawn_program(argv);
+ if (pid < 0) {
+ log_err("Failed to spawn IPCP %s.", info->name);
+ return -1;
}
- return NULL;
-}
-
-static struct ipcp_entry * get_ipcp_entry_by_layer(const char * layer)
-{
- struct list_head * p;
-
- list_for_each(p, &irmd.ipcps) {
- struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- if (strcmp(layer, e->layer) == 0)
- return e;
- }
+ info->pid = pid;
+ info->state = IPCP_BOOT;
- return NULL;
+ return 0;
}
-static struct ipcp_entry * get_ipcp_by_dst_name(const char * name,
- pid_t src)
+static int kill_ipcp(pid_t pid)
{
- struct list_head * p;
- struct list_head * h;
- uint8_t * hash;
- pid_t pid;
- size_t len;
-
- pthread_rwlock_rdlock(&irmd.reg_lock);
-
- list_for_each_safe(p, h, &irmd.ipcps) {
- struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- if (e->layer == NULL || e->pid == src)
- continue;
+ int status;
- len = IPCP_HASH_LEN(e);
-
- hash = malloc(len);
- if (hash == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return NULL;
- }
-
- str_hash(e->dir_hash_algo, hash, name);
-
- pid = e->pid;
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- if (ipcp_query(pid, hash, len) == 0) {
- free(hash);
- return e;
- }
-
- free(hash);
-
- pthread_rwlock_rdlock(&irmd.reg_lock);
+ if (kill(pid, SIGTERM) < 0) {
+ log_err("Failed to destroy IPCP: %s.", strerror(errno));
+ return -1;
}
- pthread_rwlock_unlock(&irmd.reg_lock);
+ waitpid(pid, &status, 0);
- return NULL;
+ return 0;
}
-static pid_t create_ipcp(const char * name,
- enum ipcp_type type)
+int create_ipcp(struct ipcp_info * info)
{
- struct pid_el * ppid;
- struct ipcp_entry * entry;
- struct list_head * p;
- pid_t pid;
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_MS(SOCKET_TIMEOUT);
+ int status;
- pthread_rwlock_rdlock(&irmd.reg_lock);
-
- entry = get_ipcp_entry_by_name(name);
- if (entry != NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("IPCP by that name already exists.");
- return -EPERM;
- }
+ assert(info->pid == 0);
- pthread_rwlock_unlock(&irmd.reg_lock);
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
- ppid = malloc(sizeof(*ppid));
- if (ppid == NULL)
- goto fail_ppid;
-
- entry = ipcp_entry_create(name, type);
- if (entry == NULL) {
- log_err("Failed to create IPCP entry.");
- goto fail_ipcp_entry;
- }
-
- pid = ipcp_create(name, type);
- if (pid == -1) {
+ if (spawn_ipcp(info) < 0) {
log_err("Failed to create IPCP.");
goto fail_ipcp;
}
- entry->pid = pid;
-
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- list_for_each(p, &irmd.ipcps) {
- if (list_entry(p, struct ipcp_entry, next)->type > type)
- break;
+ if (reg_create_ipcp(info) < 0) {
+ log_err("Failed to create IPCP entry.");
+ goto fail_reg_ipcp;
}
- list_add_tail(&entry->next, p);
- ++irmd.n_ipcps;
-
- ppid->pid = entry->pid;
- list_add(&ppid->next, &irmd.spawned_pids);
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- /* IRMd maintenance will clean up if booting fails. */
- if (ipcp_entry_wait_boot(entry)) {
- log_err("IPCP %d failed to boot.", pid);
- return -1;
+ if (reg_wait_ipcp_boot(info, &abstime)) {
+ log_err("IPCP %d failed to boot.", info->pid);
+ goto fail_boot;
}
- log_info("Created IPCP %d.", pid);
+ log_info("Created IPCP %d.", info->pid);
- return pid;
+ return 0;
- fail_ipcp:
- ipcp_entry_destroy(entry);
- fail_ipcp_entry:
- free(ppid);
- fail_ppid:
+ fail_boot:
+ waitpid(info->pid, &status, 0);
+ reg_destroy_proc(info->pid);
return -1;
-}
-
-static int create_ipcp_r(pid_t pid,
- int result)
-{
- struct list_head * p;
-
- pthread_rwlock_rdlock(&irmd.reg_lock);
-
- list_for_each(p, &irmd.ipcps) {
- struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- if (e->pid == pid) {
- ipcp_entry_set_state(e, result ? IPCP_NULL : IPCP_LIVE);
- break;
- }
- }
-
- pthread_rwlock_unlock(&irmd.reg_lock);
- return 0;
+ fail_reg_ipcp:
+ kill_ipcp(info->pid);
+ fail_ipcp:
+ return -1;
}
-static void clear_spawned_process(pid_t pid)
+static int create_ipcp_r(struct ipcp_info * info)
{
- struct list_head * p;
- struct list_head * h;
-
- list_for_each_safe(p, h, &(irmd.spawned_pids)) {
- struct pid_el * a = list_entry(p, struct pid_el, next);
- if (a->pid == pid) {
- list_del(&a->next);
- free(a);
- }
- }
+ return reg_respond_ipcp(info);
}
static int destroy_ipcp(pid_t pid)
{
- struct list_head * p;
- struct list_head * h;
-
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- list_for_each_safe(p, h, &irmd.ipcps) {
- struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- if (e->pid == pid) {
- clear_spawned_process(pid);
- if (ipcp_destroy(pid))
- log_err("Could not destroy IPCP.");
- list_del(&e->next);
- ipcp_entry_destroy(e);
- --irmd.n_ipcps;
- log_info("Destroyed IPCP %d.", pid);
- }
+ if (kill_ipcp(pid)) {
+ log_err("Could not destroy IPCP.");
+ goto fail;
}
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (reg_destroy_proc(pid)) {
+ log_err("Failed to remove IPCP from registry.");
+ goto fail;
+ }
return 0;
+ fail:
+ return -1;
}
-static int bootstrap_ipcp(pid_t pid,
- ipcp_config_msg_t * conf)
+int bootstrap_ipcp(pid_t pid,
+ struct ipcp_config * conf)
{
- struct ipcp_entry * entry;
- struct layer_info info;
+ struct ipcp_info info;
+ struct layer_info layer;
- pthread_rwlock_wrlock(&irmd.reg_lock);
+ info.pid = pid;
- entry = get_ipcp_entry_by_pid(pid);
- if (entry == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("No such IPCP.");
- return -1;
+ if (reg_get_ipcp(&info, NULL) < 0) {
+ log_err("Could not find IPCP %d.", pid);
+ goto fail;
}
- if (entry->type != (enum ipcp_type) conf->ipcp_type) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Configuration does not match IPCP type.");
- return -1;
- }
+ if (conf->type == IPCP_UDP)
+ conf->layer_info.dir_hash_algo = (enum pol_dir_hash) HASH_MD5;
- if (ipcp_bootstrap(entry->pid, conf, &info)) {
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (ipcp_bootstrap(pid, conf, &layer)) {
log_err("Could not bootstrap IPCP.");
- return -1;
- }
-
- entry->layer = strdup(info.layer_name);
- if (entry->layer == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_warn("Failed to set name of layer.");
- return -ENOMEM;
+ goto fail;
}
- entry->dir_hash_algo = info.dir_hash_algo;
+ info.state = IPCP_BOOTSTRAPPED;
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (reg_set_layer_for_ipcp(&info, &layer) < 0) {
+ log_err("Failed to set layer info for IPCP.");
+ goto fail;
+ }
- log_info("Bootstrapped IPCP %d in layer %s.",
- pid, conf->layer_info->layer_name);
+ log_info("Bootstrapped IPCP %d.", pid);
return 0;
+ fail:
+ return -1;
}
-static int enroll_ipcp(pid_t pid,
- char * dst)
+int enroll_ipcp(pid_t pid,
+ const char * dst)
{
- struct ipcp_entry * entry = NULL;
- struct layer_info info;
-
- pthread_rwlock_wrlock(&irmd.reg_lock);
+ struct layer_info layer;
+ struct ipcp_info info;
- entry = get_ipcp_entry_by_pid(pid);
- if (entry == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("No such IPCP.");
- return -1;
- }
+ info.pid = pid;
- if (entry->layer != NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("IPCP in wrong state");
- return -1;
+ if (reg_get_ipcp(&info, NULL) < 0) {
+ log_err("Could not find IPCP.");
+ goto fail;
}
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- if (ipcp_enroll(pid, dst, &info) < 0) {
+ if (ipcp_enroll(pid, dst, &layer) < 0) {
log_err("Could not enroll IPCP %d.", pid);
- return -1;
- }
-
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- entry = get_ipcp_entry_by_pid(pid);
- if (entry == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("No such IPCP.");
- return -1;
+ goto fail;
}
- entry->layer = strdup(info.layer_name);
- if (entry->layer == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Failed to strdup layer_name.");
- return -ENOMEM;
+ if (reg_set_layer_for_ipcp(&info, &layer) < 0) {
+ log_err("Failed to set layer info for IPCP.");
+ goto fail;
}
- entry->dir_hash_algo = info.dir_hash_algo;
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- log_info("Enrolled IPCP %d in layer %s.",
- pid, info.layer_name);
+ log_info("Enrolled IPCP %d in layer %s.", pid, layer.name);
return 0;
+ fail:
+ return -1;
}
-static int connect_ipcp(pid_t pid,
- const char * dst,
- const char * component,
- qosspec_t qs)
+int connect_ipcp(pid_t pid,
+ const char * dst,
+ const char * component,
+ qosspec_t qs)
{
- struct ipcp_entry * entry = NULL;
+ struct ipcp_info info;
- pthread_rwlock_rdlock(&irmd.reg_lock);
+ info.pid = pid;
- entry = get_ipcp_entry_by_pid(pid);
- if (entry == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (reg_get_ipcp(&info, NULL) < 0) {
log_err("No such IPCP.");
return -EIPCP;
}
- if (entry->type != IPCP_UNICAST && entry->type != IPCP_BROADCAST) {
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (info.type != IPCP_UNICAST && info.type != IPCP_BROADCAST) {
log_err("Cannot establish connections for this IPCP type.");
return -EIPCP;
}
- pthread_rwlock_unlock(&irmd.reg_lock);
-
log_dbg("Connecting %s to %s.", component, dst);
if (ipcp_connect(pid, dst, component, qs)) {
- log_err("Could not connect IPCP.");
+ log_err("Could not connect IPCP %d to %s.", pid, dst);
return -EPERM;
}
@@ -661,25 +400,20 @@ static int disconnect_ipcp(pid_t pid,
const char * dst,
const char * component)
{
- struct ipcp_entry * entry = NULL;
+ struct ipcp_info info;
- pthread_rwlock_rdlock(&irmd.reg_lock);
+ info.pid = pid;
- entry = get_ipcp_entry_by_pid(pid);
- if (entry == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (reg_get_ipcp(&info, NULL) < 0) {
log_err("No such IPCP.");
return -EIPCP;
}
- if (entry->type != IPCP_UNICAST) {
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (info.type != IPCP_UNICAST && info.type != IPCP_BROADCAST) {
log_err("Cannot tear down connections for this IPCP type.");
return -EIPCP;
}
- pthread_rwlock_unlock(&irmd.reg_lock);
-
if (ipcp_disconnect(pid, dst, component)) {
log_err("Could not disconnect IPCP.");
return -EPERM;
@@ -691,183 +425,120 @@ static int disconnect_ipcp(pid_t pid,
return 0;
}
-static int bind_program(char * prog,
- char * name,
- uint16_t flags,
- int argc,
- char ** argv)
+int bind_program(char ** exec,
+ const char * name,
+ uint8_t flags)
{
- char * progs;
- char * progn;
- char ** argv_dup = NULL;
- int i;
- char * name_dup = NULL;
- struct prog_entry * e = NULL;
- struct reg_entry * re = NULL;
-
- if (prog == NULL || name == NULL)
- return -EINVAL;
+ struct prog_info prog;
+ struct name_info ni;
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- e = prog_table_get(&irmd.prog_table, path_strip(prog));
- if (e == NULL) {
- progs = strdup(path_strip(prog));
- if (progs == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return -ENOMEM;
- }
+ if (name == NULL || exec == NULL || exec[0] == NULL)
+ return -EINVAL;
- progn = strdup(name);
- if (progn == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- free(progs);
- return -ENOMEM;
- }
+ memset(&prog, 0, sizeof(prog));
+ memset(&ni, 0, sizeof(ni));
- if ((flags & BIND_AUTO) && argc) {
- /* We need to duplicate argv and set argv[0] to prog. */
- argv_dup = malloc((argc + 2) * sizeof(*argv_dup));
- argv_dup[0] = strdup(prog);
- for (i = 1; i <= argc; ++i) {
- argv_dup[i] = strdup(argv[i - 1]);
- if (argv_dup[i] == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- argvfree(argv_dup);
- log_err("Failed to bind program "
- "%s to %s.",
- prog, name);
- free(progs);
- free(progn);
- return -ENOMEM;
- }
- }
- argv_dup[argc + 1] = NULL;
- }
- e = prog_entry_create(progn, progs, flags, argv_dup);
- if (e == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- free(progs);
- free(progn);
- argvfree(argv_dup);
- return -ENOMEM;
- }
- prog_table_add(&irmd.prog_table, e);
+ if (!reg_has_prog(exec[0])) {
+ strcpy(prog.name, path_strip(exec[0]));
+ strcpy(prog.path, exec[0]);
+ if (reg_create_prog(&prog) < 0)
+ goto fail_prog;
}
- name_dup = strdup(name);
- if (name_dup == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return -ENOMEM;
+ if (!reg_has_name(name)) {
+ ni.pol_lb = LB_SPILL;
+ strcpy(ni.name, name);
+ if (reg_create_name(&ni) < 0) {
+ log_err("Failed to create name %s.", name);
+ goto fail_name;
+ }
}
- if (prog_entry_add_name(e, name_dup)) {
- log_err("Failed adding name.");
- pthread_rwlock_unlock(&irmd.reg_lock);
- free(name_dup);
- return -ENOMEM;
+ if (reg_bind_prog(name, exec, flags) < 0) {
+ log_err("Failed to bind program %s to name %s", exec[0], name);
+ goto fail_bind;
}
- re = registry_get_entry(&irmd.registry, name);
- if (re != NULL && reg_entry_add_prog(re, e) < 0)
- log_err("Failed adding program %s for name %s.", prog, name);
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- log_info("Bound program %s to name %s.", prog, name);
+ log_info("Bound program %s to name %s.", exec[0], name);
return 0;
+
+ fail_bind:
+ if (strlen(ni.name) > 0)
+ reg_destroy_name(name);
+ fail_name:
+ if (strlen(prog.name) > 0)
+ reg_destroy_prog(exec[0]);
+ fail_prog:
+ return -1;
}
-static int bind_process(pid_t pid,
- char * name)
+int bind_process(pid_t pid,
+ const char * name)
{
- char * name_dup = NULL;
- struct proc_entry * e = NULL;
- struct reg_entry * re = NULL;
- struct timespec now;
- struct timespec dl = {0, 10 * MILLION};
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_MS(10);
+ struct name_info ni;
if (name == NULL)
return -EINVAL;
- clock_gettime(PTHREAD_COND_CLOCK, &now);
-
- ts_add(&dl, &now, &dl);
-
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- while (!kill(pid, 0)) {
- e = proc_table_get(&irmd.proc_table, pid);
- if (e != NULL || ts_diff_ms(&now, &dl) > 0)
- break;
- clock_gettime(PTHREAD_COND_CLOCK, &now);
- sched_yield();
- }
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
- if (e == NULL) {
+ if (reg_wait_proc(pid, &abstime) < 0) {
log_err("Process %d does not %s.", pid,
kill(pid, 0) ? "exist" : "respond");
- pthread_rwlock_unlock(&irmd.reg_lock);
- return -1;
+ goto fail;
}
- name_dup = strdup(name);
- if (name_dup == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return -ENOMEM;
+ memset(&ni, 0, sizeof(ni));
+
+ if (!reg_has_name(name)) {
+ ni.pol_lb = LB_SPILL;
+ strcpy(ni.name, name);
+ if (reg_create_name(&ni) < 0) {
+ log_err("Failed to create name %s.", name);
+ goto fail;
+ }
}
- if (proc_entry_add_name(e, name_dup)) {
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (reg_bind_proc(name, pid) < 0) {
log_err("Failed to add name %s to process %d.", name, pid);
- free(name_dup);
- return -1;
+ goto fail_bind;
}
- re = registry_get_entry(&irmd.registry, name);
- if (re != NULL && reg_entry_add_pid(re, pid) < 0)
- log_err("Failed adding process %d for name %s.", pid, name);
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
log_info("Bound process %d to name %s.", pid, name);
return 0;
+
+ fail_bind:
+ if (strlen(ni.name) > 0)
+ reg_destroy_name(name);
+ fail:
+ return -1;
+
}
-static int unbind_program(char * prog,
- char * name)
+static int unbind_program(const char * prog,
+ const char * name)
{
- struct reg_entry * e;
-
if (prog == NULL)
return -EINVAL;
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- if (name == NULL)
- prog_table_del(&irmd.prog_table, prog);
- else {
- struct prog_entry * en = prog_table_get(&irmd.prog_table, prog);
- if (en == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return -EINVAL;
+ if (name == NULL) {
+ if (reg_destroy_prog(prog) < 0) {
+ log_err("Failed to unbind %s.", prog);
+ return -1;
}
-
- prog_entry_del_name(en, name);
-
- e = registry_get_entry(&irmd.registry, name);
- if (e != NULL)
- reg_entry_del_prog(e, prog);
- }
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- if (name == NULL)
log_info("Program %s unbound.", prog);
- else
- log_info("All names matching %s unbound for %s.", name, prog);
+ } else {
+ if (reg_unbind_prog(name, prog) < 0) {
+ log_err("Failed to unbind %s from %s", prog, name);
+ return -1;
+ }
+ log_info("Name %s unbound for %s.", name, prog);
+ }
return 0;
}
@@ -875,1100 +546,732 @@ static int unbind_program(char * prog,
static int unbind_process(pid_t pid,
const char * name)
{
- struct reg_entry * e;
-
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- if (name == NULL)
- proc_table_del(&irmd.proc_table, pid);
- else {
- struct proc_entry * en = proc_table_get(&irmd.proc_table, pid);
- if (en != NULL)
- proc_entry_del_name(en, name);
-
- e = registry_get_entry(&irmd.registry, name);
- if (e != NULL)
- reg_entry_del_pid(e, pid);
- }
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- if (name == NULL)
+ if (name == NULL) {
+ if (reg_destroy_proc(pid) < 0) {
+ log_err("Failed to unbind %d.", pid);
+ return -1;
+ }
log_info("Process %d unbound.", pid);
- else
- log_info("All names matching %s unbound for %d.", name, pid);
+ } else {
+ if (reg_unbind_proc(name, pid) < 0) {
+ log_err("Failed to unbind %d from %s", pid, name);
+ return -1;
+ }
+ log_info("Name %s unbound for process %d.", name, pid);
+ }
return 0;
}
-static ssize_t list_ipcps(ipcp_info_msg_t *** ipcps,
- size_t * n_ipcps)
+static int list_ipcps(ipcp_list_msg_t *** ipcps,
+ size_t * n_ipcps)
{
- struct list_head * p;
- int i = 0;
-
- pthread_rwlock_rdlock(&irmd.reg_lock);
-
- *n_ipcps = irmd.n_ipcps;
- if (*n_ipcps == 0) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return 0;
- }
-
- *ipcps = malloc(irmd.n_ipcps * sizeof(**ipcps));
- if (*ipcps == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- *n_ipcps = 0;
- return -ENOMEM;
- }
-
- list_for_each(p, &irmd.ipcps) {
- struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- (*ipcps)[i] = malloc(sizeof(***ipcps));
- if ((*ipcps)[i] == NULL) {
- --i;
- goto fail;
- }
+ int n;
- ipcp_info_msg__init((*ipcps)[i]);
- (*ipcps)[i]->name = strdup(e->name);
- if ((*ipcps)[i]->name == NULL)
- goto fail;
-
- (*ipcps)[i]->layer = strdup(
- e->layer != NULL ? e->layer : "Not enrolled");
- if ((*ipcps)[i]->layer == NULL)
- goto fail;
-
- (*ipcps)[i]->pid = e->pid;
- (*ipcps)[i++]->type = e->type;
- }
+ n = reg_list_ipcps(ipcps);
+ if (n < 0)
+ goto fail;
- pthread_rwlock_unlock(&irmd.reg_lock);
+ *n_ipcps = (size_t) n;
return 0;
-
fail:
- pthread_rwlock_unlock(&irmd.reg_lock);
- while (i >= 0) {
- free((*ipcps)[i]->layer);
- free((*ipcps)[i]->name);
- free(*ipcps[i--]);
- }
- free(*ipcps);
+ *ipcps = NULL;
*n_ipcps = 0;
- return -ENOMEM;
+ return -1;
}
-static int name_create(const char * name,
- enum pol_balance pol)
+int name_create(const struct name_info * info)
{
- struct reg_entry * re;
- struct list_head * p;
-
- assert(name);
+ int ret;
- pthread_rwlock_wrlock(&irmd.reg_lock);
+ assert(info != NULL);
- if (registry_has_name(&irmd.registry, name)) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Registry entry for %s already exists.", name);
- return -ENAME;
- }
-
- re = registry_add_name(&irmd.registry, name);
- if (re == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Failed creating registry entry for %s.", name);
- return -ENOMEM;
- }
- ++irmd.n_names;
- reg_entry_set_policy(re, pol);
-
- /* check the tables for existing bindings */
- list_for_each(p, &irmd.proc_table) {
- struct list_head * q;
- struct proc_entry * e;
- e = list_entry(p, struct proc_entry, next);
- list_for_each(q, &e->names) {
- struct str_el * s;
- s = list_entry(q, struct str_el, next);
- if (!strcmp(s->str, name))
- reg_entry_add_pid(re, e->pid);
- }
+ ret = reg_create_name(info);
+ if (ret == -EEXIST) {
+ log_info("Name %s already exists.", info->name);
+ return 0;
}
- list_for_each(p, &irmd.prog_table) {
- struct list_head * q;
- struct prog_entry * e;
- e = list_entry(p, struct prog_entry, next);
- list_for_each(q, &e->names) {
- struct str_el * s;
- s = list_entry(q, struct str_el, next);
- if (!strcmp(s->str, name))
- reg_entry_add_prog(re, e);
- }
+ if (ret < 0) {
+ log_err("Failed to create name %s.", info->name);
+ return -1;
}
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- log_info("Created new name: %s.", name);
+ log_info("Created new name: %s.", info->name);
return 0;
}
static int name_destroy(const char * name)
{
- assert(name);
- pthread_rwlock_wrlock(&irmd.reg_lock);
+ assert(name != NULL);
- if (!registry_has_name(&irmd.registry, name)) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_warn("Registry entry for %s does not exist.", name);
- return -ENAME;
+ if (reg_destroy_name(name) < 0) {
+ log_err("Failed to destroy name %s.", name);
+ return -1;
}
- registry_del_name(&irmd.registry, name);
- --irmd.n_names;
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
log_info("Destroyed name: %s.", name);
return 0;
}
-static ssize_t list_names(name_info_msg_t *** names,
- size_t * n_names)
+static int list_names(name_info_msg_t *** names,
+ size_t * n_names)
{
- struct list_head * p;
- int i = 0;
-
- pthread_rwlock_rdlock(&irmd.reg_lock);
-
- *n_names = irmd.n_names;
- if (*n_names == 0) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return 0;
- }
-
- *names = malloc(irmd.n_names * sizeof(**names));
- if (*names == NULL) {
- *n_names = 0;
- pthread_rwlock_unlock(&irmd.reg_lock);
- return -ENOMEM;
- }
-
- list_for_each(p, &irmd.registry) {
- struct reg_entry * e = list_entry(p, struct reg_entry, next);
-
- (*names)[i] = malloc(sizeof(***names));
- if ((*names)[i] == NULL) {
- --i;
- goto fail;
- }
+ int n;
- name_info_msg__init((*names)[i]);
- (*names)[i]->name = strdup(e->name);
- if ((*names)[i]->name == NULL)
- goto fail;
-
- (*names)[i++]->pol_lb = e->pol_lb;
- }
+ n = reg_list_names(names);
+ if (n < 0)
+ goto fail;
- pthread_rwlock_unlock(&irmd.reg_lock);
+ *n_names = (size_t) n;
return 0;
-
fail:
- pthread_rwlock_unlock(&irmd.reg_lock);
- while (i >= 0) {
- free((*names)[i]->name);
- free(*names[i--]);
- }
- free(*names);
+ *names = NULL;
*n_names = 0;
- return -ENOMEM;
+ return -1;
}
-static int name_reg(const char * name,
- pid_t pid)
+int name_reg(const char * name,
+ pid_t pid)
{
- size_t len;
- struct ipcp_entry * ipcp;
- uint8_t * hash;
- int err;
+ struct ipcp_info info;
+ struct layer_info layer;
+ buffer_t hash;
assert(name);
- pthread_rwlock_wrlock(&irmd.reg_lock);
+ info.pid = pid;
- if (!registry_has_name(&irmd.registry, name)) {
- err = -ENAME;
- goto fail;
- }
-
- ipcp = get_ipcp_entry_by_pid(pid);
- if (ipcp == NULL) {
- err = -EIPCP;
- goto fail;
+ if (!reg_has_name(name)) {
+ log_err("Failed to get name %s.", name);
+ return -ENAME;
}
- if (ipcp->layer == NULL) {
- err = -EPERM;
- goto fail;
+ if (reg_get_ipcp(&info, &layer) < 0) {
+ log_err("Failed to get IPCP %d.", pid);
+ return -EIPCP;
}
- len = IPCP_HASH_LEN(ipcp);
-
- hash = malloc(len);
- if (hash == NULL) {
- err = -ENOMEM;
- goto fail;
+ hash.len = hash_len((enum hash_algo) layer.dir_hash_algo);
+ hash.data = malloc(hash.len);
+ if (hash.data == NULL) {
+ log_err("Failed to malloc hash.");
+ return -ENOMEM;
}
- str_hash(ipcp->dir_hash_algo, hash, name);
- pthread_rwlock_unlock(&irmd.reg_lock);
+ str_hash((enum hash_algo) layer.dir_hash_algo, hash.data, name);
- if (ipcp_reg(pid, hash, len)) {
- log_err("Could not register " HASH_FMT " with IPCP %d.",
- HASH_VAL(hash), pid);
- free(hash);
+ if (ipcp_reg(pid, hash)) {
+ log_err("Could not register " HASH_FMT32 " with IPCP %d.",
+ HASH_VAL32(hash.data), pid);
+ freebuf(hash);
return -1;
}
- log_info("Registered %s with IPCP %d as " HASH_FMT ".",
- name, pid, HASH_VAL(hash));
+ log_info("Registered %s with IPCP %d as " HASH_FMT32 ".",
+ name, pid, HASH_VAL32(hash.data));
- free(hash);
+ freebuf(hash);
return 0;
-
-fail:
- pthread_rwlock_unlock(&irmd.reg_lock);
- return err;
}
static int name_unreg(const char * name,
pid_t pid)
{
- struct ipcp_entry * ipcp;
- int err;
- uint8_t * hash;
- size_t len;
+ struct ipcp_info info;
+ struct layer_info layer;
+ buffer_t hash;
assert(name);
- pthread_rwlock_wrlock(&irmd.reg_lock);
+ info.pid = pid;
- ipcp = get_ipcp_entry_by_pid(pid);
- if (ipcp == NULL) {
- err = -EIPCP;
- goto fail;
+ if (!reg_has_name(name)) {
+ log_err("Failed to get name %s.", name);
+ return -ENAME;
}
- if (ipcp->layer == NULL) {
- err = -EPERM;
- goto fail;
+ if (reg_get_ipcp(&info, &layer) < 0) {
+ log_err("Failed to get IPCP %d.", pid);
+ return -EIPCP;
}
- len = IPCP_HASH_LEN(ipcp);
-
- hash = malloc(len);
- if (hash == NULL) {
- err = -ENOMEM;
- goto fail;
+ hash.len = hash_len((enum hash_algo) layer.dir_hash_algo);
+ hash.data = malloc(hash.len);
+ if (hash.data == NULL) {
+ log_err("Failed to malloc hash.");
+ return -ENOMEM;
}
- str_hash(ipcp->dir_hash_algo, hash, name);
-
- pthread_rwlock_unlock(&irmd.reg_lock);
+ str_hash((enum hash_algo) layer.dir_hash_algo, hash.data, name);
- if (ipcp_unreg(pid, hash, len)) {
+ if (ipcp_unreg(pid, hash)) {
log_err("Could not unregister %s with IPCP %d.", name, pid);
- free(hash);
+ freebuf(hash);
return -1;
}
log_info("Unregistered %s from %d.", name, pid);
- free(hash);
+ freebuf(hash);
return 0;
-
- fail:
- pthread_rwlock_unlock(&irmd.reg_lock);
- return err;
}
-static int proc_announce(pid_t pid,
- char * prog)
+static int proc_announce(const struct proc_info * info)
{
- struct proc_entry * e;
- struct prog_entry * a;
- char * prog_dup;
-
- assert(prog);
-
- prog_dup = strdup(prog);
- if (prog_dup == NULL)
- return -ENOMEM;
-
- e = proc_entry_create(pid, prog_dup);
- if (e == NULL) {
- free(prog_dup);
- return -ENOMEM;
+ if (reg_create_proc(info) < 0) {
+ log_err("Failed to add process %d.", info->pid);
+ goto fail_proc;
}
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- proc_table_add(&irmd.proc_table, e);
+ log_info("Process added: %d (%s).", info->pid, info->prog);
- /* Copy listen names from program if it exists. */
- a = prog_table_get(&irmd.prog_table, e->prog);
- if (a != NULL) {
- struct list_head * p;
- list_for_each(p, &a->names) {
- struct str_el * s = list_entry(p, struct str_el, next);
- struct str_el * n = malloc(sizeof(*n));
- if (n == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return -ENOMEM;
- }
+ return 0;
- n->str = strdup(s->str);
- if (n->str == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- free(n);
- return -ENOMEM;
- }
+ fail_proc:
+ return -1;
+}
- list_add(&n->next, &e->names);
- log_dbg("Process %d inherits name %s from program %s.",
- pid, n->str, e->prog);
- }
- }
+static int proc_exit(pid_t pid)
+{
+ if (reg_destroy_proc(pid) < 0)
+ log_err("Failed to remove process %d.", pid);
- pthread_rwlock_unlock(&irmd.reg_lock);
+ log_info("Process removed: %d.", pid);
return 0;
}
-static int flow_accept(pid_t pid,
- struct timespec * timeo,
- struct irm_flow ** fl,
- const void * data,
- size_t len)
+static void __cleanup_pkp(void * pkp)
{
- struct irm_flow * f = NULL;
- struct proc_entry * e = NULL;
- struct reg_entry * re = NULL;
- struct list_head * p = NULL;
-
- pid_t pid_n1;
- pid_t pid_n;
- int flow_id;
- int ret;
-
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- e = proc_table_get(&irmd.proc_table, pid);
- if (e == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Unknown process %d calling accept.", pid);
- return -EINVAL;
- }
+ if (pkp != NULL)
+ crypt_dh_pkp_destroy(pkp);
+}
- log_dbg("New instance (%d) of %s added.", pid, e->prog);
- log_dbg("This process accepts flows for:");
+static void __cleanup_flow(void * flow)
+{
+ reg_destroy_flow(((struct flow_info *) flow)->id);
+}
- list_for_each(p, &e->names) {
- struct str_el * s = list_entry(p, struct str_el, next);
- log_dbg(" %s", s->str);
- re = registry_get_entry(&irmd.registry, s->str);
- if (re != NULL)
- reg_entry_add_pid(re, pid);
+static int flow_accept(struct flow_info * flow,
+ buffer_t * data,
+ struct timespec * abstime)
+{
+ uint8_t buf[MSGBUFSZ];
+ buffer_t lpk; /* local public key */
+ buffer_t rpk; /* remote public key */
+ void * pkp; /* my public/private key pair */
+ ssize_t key_len;
+ uint8_t * s;
+ int err;
+
+ /* piggyback of user data not yet implemented */
+ assert(data != NULL && data->len == 0 && data->data == NULL);
+
+ if (!reg_has_proc(flow->n_pid)) {
+ log_err("Unknown process %d calling accept.", flow->n_pid);
+ err = -EINVAL;
+ goto fail;
}
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- ret = proc_entry_sleep(e, timeo);
- if (ret == -ETIMEDOUT)
- return -ETIMEDOUT;
-
- if (ret == -1)
- return -EPIPE;
-
- if (irmd_get_state() != IRMD_RUNNING)
- return -EIRMD;
-
- pthread_rwlock_rdlock(&irmd.flows_lock);
-
- f = get_irm_flow_n(pid);
- if (f == NULL) {
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_warn("Port_id was not created yet.");
- return -EPERM;
+ s = malloc(SYMMKEYSZ);
+ if (s == NULL) {
+ log_err("Failed to malloc symmkey.");
+ err = -ENOMEM;
+ goto fail;
}
- pid_n = f->n_pid;
- pid_n1 = f->n_1_pid;
- flow_id = f->flow_id;
-
- pthread_rwlock_unlock(&irmd.flows_lock);
- pthread_rwlock_rdlock(&irmd.reg_lock);
-
- e = proc_table_get(&irmd.proc_table, pid);
- if (e == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- pthread_rwlock_wrlock(&irmd.flows_lock);
- list_del(&f->next);
- bmp_release(irmd.flow_ids, f->flow_id);
- pthread_rwlock_unlock(&irmd.flows_lock);
- ipcp_flow_alloc_resp(pid_n1, flow_id, pid_n, -1, NULL, 0);
- clear_irm_flow(f);
- irm_flow_set_state(f, FLOW_NULL);
- irm_flow_destroy(f);
- log_dbg("Process gone while accepting flow.");
- return -EPERM;
+ key_len = crypt_dh_pkp_create(&pkp, buf);
+ if (key_len < 0) {
+ log_err("Failed to generate key pair.");
+ err = -ECRYPT;
+ goto fail_pkp;
}
- pthread_mutex_lock(&e->lock);
-
- re = e->re;
+ lpk.data = buf;
+ lpk.len = (size_t) key_len;
- pthread_mutex_unlock(&e->lock);
+ log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
- if (reg_entry_get_state(re) != REG_NAME_FLOW_ARRIVED) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- pthread_rwlock_wrlock(&irmd.flows_lock);
- list_del(&f->next);
- bmp_release(irmd.flow_ids, f->flow_id);
- pthread_rwlock_unlock(&irmd.flows_lock);
- ipcp_flow_alloc_resp(pid_n1, flow_id, pid_n, -1, NULL, 0);
- clear_irm_flow(f);
- irm_flow_set_state(f, FLOW_NULL);
- irm_flow_destroy(f);
- log_err("Entry in wrong state.");
- return -EPERM;
+ if (reg_create_flow(flow) < 0) {
+ log_err("Failed to create flow.");
+ err = -EBADF;
+ goto fail_flow;
}
- registry_del_process(&irmd.registry, pid);
-
- pthread_rwlock_unlock(&irmd.reg_lock);
-
- if (ipcp_flow_alloc_resp(pid_n1, flow_id, pid_n, 0, data, len)) {
- pthread_rwlock_wrlock(&irmd.flows_lock);
- list_del(&f->next);
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_dbg("Failed to respond to alloc. Port_id invalidated.");
- clear_irm_flow(f);
- irm_flow_set_state(f, FLOW_NULL);
- irm_flow_destroy(f);
- return -EPERM;
+ if (reg_prepare_flow_accept(flow, &lpk) < 0) {
+ log_err("Failed to prepare accept.");
+ err = -EBADF;
+ goto fail_wait;
}
- irm_flow_set_state(f, FLOW_ALLOCATED);
+ pthread_cleanup_push(__cleanup_flow, flow);
+ pthread_cleanup_push(__cleanup_pkp, pkp);
+ pthread_cleanup_push(free, s);
- log_info("Flow on flow_id %d allocated.", f->flow_id);
-
- *fl = f;
-
- return 0;
-}
+ err = reg_wait_flow_accepted(flow, &rpk, abstime);
-static int flow_alloc(pid_t pid,
- const char * dst,
- qosspec_t qs,
- struct timespec * timeo,
- struct irm_flow ** e,
- bool join,
- const void * data,
- size_t len)
-{
- struct irm_flow * f;
- struct ipcp_entry * ipcp;
- int flow_id;
- int state;
- uint8_t * hash;
-
- ipcp = join ? get_ipcp_entry_by_layer(dst)
- : get_ipcp_by_dst_name(dst, pid);
- if (ipcp == NULL) {
- log_info("Destination %s unreachable.", dst);
- return -1;
- }
+ pthread_cleanup_pop(false);
+ pthread_cleanup_pop(false);
+ pthread_cleanup_pop(false);
- pthread_rwlock_wrlock(&irmd.flows_lock);
- flow_id = bmp_allocate(irmd.flow_ids);
- if (!bmp_is_id_valid(irmd.flow_ids, flow_id)) {
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_err("Could not allocate flow_id.");
- return -EBADF;
+ if (err == -ETIMEDOUT) {
+ log_err("Flow accept timed out.");
+ goto fail_wait;
}
- f = irm_flow_create(pid, ipcp->pid, flow_id, qs);
- if (f == NULL) {
- bmp_release(irmd.flow_ids, flow_id);
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_err("Could not allocate flow_id.");
- return -ENOMEM;
+ if (err == -1) {
+ log_dbg("Flow accept terminated.");
+ err = -EPIPE;
+ goto fail_wait;
}
- list_add(&f->next, &irmd.irm_flows);
+ assert(err == 0);
- pthread_rwlock_unlock(&irmd.flows_lock);
-
- assert(irm_flow_get_state(f) == FLOW_ALLOC_PENDING);
-
- hash = malloc(IPCP_HASH_LEN(ipcp));
- if (hash == NULL)
- /* sanitizer cleans this */
- return -ENOMEM;
-
- str_hash(ipcp->dir_hash_algo, hash, dst);
-
- if (join) {
- if (ipcp_flow_join(ipcp->pid, flow_id, pid, hash,
- IPCP_HASH_LEN(ipcp), qs)) {
- /* sanitizer cleans this */
- log_info("Flow_join failed.");
- free(hash);
- return -EAGAIN;
+ if (flow->qs.cypher_s != 0) { /* crypto requested */
+ if (crypt_dh_derive(pkp, rpk, s) < 0) {
+ log_err("Failed to derive secret for %d.", flow->id);
+ err = -ECRYPT;
+ goto fail_derive;
}
+ freebuf(rpk);
+ data->data = s;
+ data->len = SYMMKEYSZ;
+ s= NULL;
} else {
- if (ipcp_flow_alloc(ipcp->pid, flow_id, pid, hash,
- IPCP_HASH_LEN(ipcp), qs, data, len)) {
- /* sanitizer cleans this */
- log_info("Flow_allocation failed.");
- free(hash);
- return -EAGAIN;
- }
+ clrbuf(lpk);
}
- free(hash);
-
- state = irm_flow_wait_state(f, FLOW_ALLOCATED, timeo);
- if (state != FLOW_ALLOCATED) {
- if (state == -ETIMEDOUT) {
- log_dbg("Flow allocation timed out");
- return -ETIMEDOUT;
- }
-
- log_info("Pending flow to %s torn down.", dst);
- return -EPIPE;
+ if (ipcp_flow_alloc_resp(flow, 0, lpk) < 0) {
+ log_err("Failed to respond to flow allocation.");
+ err = -EIPCP;
+ goto fail_alloc_resp;
}
- assert(irm_flow_get_state(f) == FLOW_ALLOCATED);
-
- *e = f;
-
- log_info("Flow on flow_id %d allocated.", flow_id);
+ crypt_dh_pkp_destroy(pkp);
+ free(s);
return 0;
+
+ fail_derive:
+ freebuf(rpk);
+ clrbuf(lpk);
+ ipcp_flow_alloc_resp(flow, err, lpk);
+ fail_alloc_resp:
+ flow->state = FLOW_NULL;
+ fail_wait:
+ reg_destroy_flow(flow->id);
+ fail_flow:
+ crypt_dh_pkp_destroy(pkp);
+ fail_pkp:
+ free(s);
+ fail:
+ return err;
}
-static int flow_dealloc(pid_t pid,
- int flow_id)
+static int flow_join(struct flow_info * flow,
+ const char * dst,
+ struct timespec * abstime)
{
- pid_t n_1_pid = -1;
- int ret = 0;
-
- struct irm_flow * f = NULL;
+ struct ipcp_info ipcp;
+ struct layer_info layer;
+ buffer_t hash;
+ buffer_t pbuf = {NULL, 0}; /* nothing to piggyback */
+ int err;
- pthread_rwlock_wrlock(&irmd.flows_lock);
+ log_info("Allocating flow for %d to %s.", flow->n_pid, dst);
- f = get_irm_flow(flow_id);
- if (f == NULL) {
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_dbg("Deallocate unknown port %d by %d.", flow_id, pid);
- return 0;
+ if (reg_create_flow(flow) < 0) {
+ log_err("Failed to create flow.");
+ err = -EBADF;
+ goto fail_flow;
}
- if (pid == f->n_pid) {
- f->n_pid = -1;
- n_1_pid = f->n_1_pid;
- } else if (pid == f->n_1_pid) {
- f->n_1_pid = -1;
- } else {
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_dbg("Dealloc called by wrong process.");
- return -EPERM;
+ strcpy(layer.name, dst);
+ if (reg_get_ipcp_by_layer(&ipcp, &layer) < 0) {
+ log_err("Failed to get IPCP for layer %s.", dst);
+ err = -EIPCP;
+ goto fail_ipcp;
}
- if (irm_flow_get_state(f) == FLOW_DEALLOC_PENDING) {
- list_del(&f->next);
- if ((kill(f->n_pid, 0) < 0 && f->n_1_pid == -1) ||
- (kill(f->n_1_pid, 0) < 0 && f->n_pid == -1))
- irm_flow_set_state(f, FLOW_NULL);
- clear_irm_flow(f);
- irm_flow_destroy(f);
- bmp_release(irmd.flow_ids, flow_id);
- log_info("Completed deallocation of flow_id %d by process %d.",
- flow_id, pid);
- } else {
- irm_flow_set_state(f, FLOW_DEALLOC_PENDING);
- log_dbg("Partial deallocation of flow_id %d by process %d.",
- flow_id, pid);
+ hash.len = hash_len((enum hash_algo) layer.dir_hash_algo);
+ hash.data = malloc(hash.len);
+ if (hash.data == NULL) {
+ log_err("Failed to malloc hash buffer.");
+ err = -ENOMEM;
+ goto fail_ipcp;
}
- pthread_rwlock_unlock(&irmd.flows_lock);
+ reg_prepare_flow_alloc(flow);
- if (n_1_pid != -1)
- ret = ipcp_flow_dealloc(n_1_pid, flow_id);
+ if (ipcp_flow_join(flow, hash)) {
+ log_err("Flow join with layer %s failed.", dst);
+ err = -ENOTALLOC;
+ goto fail_alloc;
+ }
- return ret;
-}
+ pthread_cleanup_push(__cleanup_flow, flow);
+ pthread_cleanup_push(free, hash.data);
-static pid_t auto_execute(char ** argv)
-{
- pid_t pid;
- struct stat s;
+ err = reg_wait_flow_allocated(flow, &pbuf, abstime);
- if (stat(argv[0], &s) != 0) {
- log_warn("Program %s does not exist.", argv[0]);
- return -1;
- }
+ pthread_cleanup_pop(false);
+ pthread_cleanup_pop(false);
- if (!(s.st_mode & S_IXUSR)) {
- log_warn("Program %s is not executable.", argv[0]);
- return -1;
+ if (err == -ETIMEDOUT) {
+ log_err("Flow join timed out.");
+ goto fail_alloc;
}
- if (posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL)) {
- log_err("Failed to spawn new process");
- return -1;
+ if (err == -1) {
+ log_dbg("Flow join terminated.");
+ err = -EPIPE;
+ goto fail_alloc;
}
- log_info("Instantiated %s as process %d.", argv[0], pid);
+ assert(err == 0);
- return pid;
+ freebuf(hash);
+
+ return 0;
+
+ fail_alloc:
+ freebuf(hash);
+ fail_ipcp:
+ reg_destroy_flow(flow->id);
+ fail_flow:
+ return err;
}
-static struct irm_flow * flow_req_arr(pid_t pid,
- const uint8_t * hash,
- qosspec_t qs,
- const void * data,
- size_t len)
+static int get_ipcp_by_dst(const char * dst,
+ pid_t * pid,
+ buffer_t * hash)
{
- struct reg_entry * re = NULL;
- struct prog_entry * a = NULL;
- struct proc_entry * e = NULL;
- struct irm_flow * f = NULL;
+ ipcp_list_msg_t ** ipcps;
+ int n;
+ int i;
+ int err = -EIPCP;
- struct pid_el * c_pid;
- struct ipcp_entry * ipcp;
- pid_t h_pid = -1;
- int flow_id = -1;
+ n = reg_list_ipcps(&ipcps);
- struct timespec wt = {IRMD_REQ_ARR_TIMEOUT / 1000,
- (IRMD_REQ_ARR_TIMEOUT % 1000) * MILLION};
+ /* Clean up the ipcp_msgs in this loop */
+ for (i = 0; i < n; ++i) {
+ enum hash_algo algo;
+ enum ipcp_type type;
+ pid_t tmp;
+ bool enrolled;
- log_dbg("Flow req arrived from IPCP %d for " HASH_FMT ".",
- pid, HASH_VAL(hash));
+ type = ipcps[i]->type;
+ algo = ipcps[i]->hash_algo;
+ tmp = ipcps[i]->pid;
- pthread_rwlock_rdlock(&irmd.reg_lock);
+ enrolled = strcmp(ipcps[i]->layer, "Not enrolled.") != 0;
- ipcp = get_ipcp_entry_by_pid(pid);
- if (ipcp == NULL) {
- log_err("IPCP died.");
- return NULL;
- }
-
- re = registry_get_entry_by_hash(&irmd.registry, ipcp->dir_hash_algo,
- hash, IPCP_HASH_LEN(ipcp));
- if (re == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Unknown hash: " HASH_FMT ".", HASH_VAL(hash));
- return NULL;
- }
+ ipcp_list_msg__free_unpacked(ipcps[i], NULL);
- log_info("Flow request arrived for %s.", re->name);
+ if (type == IPCP_BROADCAST)
+ continue;
- pthread_rwlock_unlock(&irmd.reg_lock);
+ if (err == 0 /* solution found */ || !enrolled)
+ continue;
- /* Give the process a bit of slop time to call accept */
- if (reg_entry_leave_state(re, REG_NAME_IDLE, &wt) == -1) {
- log_err("No processes for " HASH_FMT ".", HASH_VAL(hash));
- return NULL;
- }
+ hash->len = hash_len(algo);
+ hash->data = malloc(hash->len);
+ if (hash->data == NULL) {
+ log_warn("Failed to malloc hash for query.");
+ err = -ENOMEM;
+ continue;
+ }
- pthread_rwlock_wrlock(&irmd.reg_lock);
+ str_hash(algo, hash->data, dst);
- switch (reg_entry_get_state(re)) {
- case REG_NAME_IDLE:
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("No processes for " HASH_FMT ".", HASH_VAL(hash));
- return NULL;
- case REG_NAME_AUTO_ACCEPT:
- c_pid = malloc(sizeof(*c_pid));
- if (c_pid == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- return NULL;
+ if (ipcp_query(tmp, *hash) < 0) {
+ freebuf(*hash);
+ continue;
}
- reg_entry_set_state(re, REG_NAME_AUTO_EXEC);
- a = prog_table_get(&irmd.prog_table,
- reg_entry_get_prog(re));
-
- if (a == NULL || (c_pid->pid = auto_execute(a->argv)) < 0) {
- reg_entry_set_state(re, REG_NAME_AUTO_ACCEPT);
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Could not start program for reg_entry %s.",
- re->name);
- free(c_pid);
- return NULL;
- }
+ *pid = tmp;
- list_add(&c_pid->next, &irmd.spawned_pids);
+ err = 0;
+ }
- pthread_rwlock_unlock(&irmd.reg_lock);
+ free(ipcps);
- if (reg_entry_leave_state(re, REG_NAME_AUTO_EXEC, NULL))
- return NULL;
+ return err;
+}
- pthread_rwlock_wrlock(&irmd.reg_lock);
- /* FALLTHRU */
- case REG_NAME_FLOW_ACCEPT:
- h_pid = reg_entry_get_pid(re);
- if (h_pid == -1) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("Invalid process id returned.");
- return NULL;
+static int flow_alloc(struct flow_info * flow,
+ const char * dst,
+ buffer_t * data,
+ struct timespec * abstime)
+{
+ uint8_t buf[MSGBUFSZ];
+ buffer_t lpk ={NULL, 0}; /* local public key */
+ buffer_t rpk; /* remote public key */
+ void * pkp = NULL; /* my public/private key pair */
+ uint8_t * s = NULL;
+ buffer_t hash;
+ int err;
+ /* piggyback of user data not yet implemented */
+ assert(data != NULL && data->len == 0 && data->data == NULL);
+
+ log_info("Allocating flow for %d to %s.", flow->n_pid, dst);
+
+
+ if (flow->qs.cypher_s > 0) {
+ ssize_t key_len;
+
+ s = malloc(SYMMKEYSZ);
+ if (s == NULL) {
+ log_err("Failed to malloc symmetric key");
+ err = -ENOMEM;
+ goto fail_malloc;
}
- break;
- default:
- pthread_rwlock_unlock(&irmd.reg_lock);
- log_err("IRMd in wrong state.");
- return NULL;
- }
+ key_len = crypt_dh_pkp_create(&pkp, buf);
+ if (key_len < 0) {
+ log_err("Failed to generate key pair.");
+ err = -ECRYPT;
+ goto fail_pkp;
+ }
- pthread_rwlock_unlock(&irmd.reg_lock);
- pthread_rwlock_wrlock(&irmd.flows_lock);
+ lpk.data = buf;
+ lpk.len = (size_t) key_len;
- flow_id = bmp_allocate(irmd.flow_ids);
- if (!bmp_is_id_valid(irmd.flow_ids, flow_id)) {
- pthread_rwlock_unlock(&irmd.flows_lock);
- return NULL;
+ log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
}
- f = irm_flow_create(h_pid, pid, flow_id, qs);
- if (f == NULL) {
- bmp_release(irmd.flow_ids, flow_id);
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_err("Could not allocate flow_id.");
- return NULL;
+ if (reg_create_flow(flow) < 0) {
+ log_err("Failed to create flow.");
+ err = -EBADF;
+ goto fail_flow;
}
- if (len != 0) {
- assert(data);
- f->data = malloc(len);
- if (f->data == NULL) {
- bmp_release(irmd.flow_ids, flow_id);
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_err("Could not piggyback data.");
- return NULL;
- }
-
- f->len = len;
-
- memcpy(f->data, data, len);
+ if (get_ipcp_by_dst(dst, &flow->n_1_pid, &hash) < 0) {
+ log_err("Failed to find IPCP for %s.", dst);
+ err = -EIPCP;
+ goto fail_ipcp;
}
- list_add(&f->next, &irmd.irm_flows);
-
- pthread_rwlock_unlock(&irmd.flows_lock);
- pthread_rwlock_rdlock(&irmd.reg_lock);
+ reg_prepare_flow_alloc(flow);
- reg_entry_set_state(re, REG_NAME_FLOW_ARRIVED);
-
- e = proc_table_get(&irmd.proc_table, h_pid);
- if (e == NULL) {
- pthread_rwlock_unlock(&irmd.reg_lock);
- pthread_rwlock_wrlock(&irmd.flows_lock);
- clear_irm_flow(f);
- bmp_release(irmd.flow_ids, f->flow_id);
- list_del(&f->next);
- pthread_rwlock_unlock(&irmd.flows_lock);
- log_err("Could not get process table entry for %d.", h_pid);
- free(f->data);
- f->len = 0;
- irm_flow_destroy(f);
- return NULL;
+ if (ipcp_flow_alloc(flow, hash, lpk)) {
+ log_err("Flow allocation %d failed.", flow->id);
+ err = -ENOTALLOC;
+ goto fail_alloc;
}
- proc_entry_wake(e, re);
+ pthread_cleanup_push(__cleanup_flow, flow);
+ pthread_cleanup_push(__cleanup_pkp, pkp);
+ pthread_cleanup_push(free, hash.data);
+ pthread_cleanup_push(free, s);
- pthread_rwlock_unlock(&irmd.reg_lock);
+ err = reg_wait_flow_allocated(flow, &rpk, abstime);
- reg_entry_leave_state(re, REG_NAME_FLOW_ARRIVED, NULL);
-
- return f;
-}
+ pthread_cleanup_pop(false);
+ pthread_cleanup_pop(false);
+ pthread_cleanup_pop(false);
+ pthread_cleanup_pop(false);
-static int flow_alloc_reply(int flow_id,
- int response,
- const void * data,
- size_t len)
-{
- struct irm_flow * f;
-
- pthread_rwlock_rdlock(&irmd.flows_lock);
+ if (err == -ETIMEDOUT) {
+ log_err("Flow allocation timed out.");
+ goto fail_alloc;
+ }
- f = get_irm_flow(flow_id);
- if (f == NULL) {
- pthread_rwlock_unlock(&irmd.flows_lock);
- return -1;
+ if (err == -1) {
+ log_dbg("Flow allocation terminated.");
+ err = -EPIPE;
+ goto fail_alloc;
}
- if (!response)
- irm_flow_set_state(f, FLOW_ALLOCATED);
- else
- irm_flow_set_state(f, FLOW_NULL);
+ assert(err == 0);
- f->data = malloc(len);
- if (f->data == NULL) {
- pthread_rwlock_unlock(&irmd.flows_lock);
- return -1;
+ if (flow->qs.cypher_s != 0) { /* crypto requested */
+ if (crypt_dh_derive(pkp, rpk, s) < 0) {
+ log_err("Failed to derive secret for %d.", flow->id);
+ err = -ECRYPT;
+ goto fail_derive;
+ }
+ crypt_dh_pkp_destroy(pkp);
+ freebuf(rpk);
+ data->data = s;
+ data->len = SYMMKEYSZ;
+ s = NULL;
}
- memcpy(f->data, data, len);
- f->len = len;
- pthread_rwlock_unlock(&irmd.flows_lock);
+ freebuf(hash);
+ free(s);
return 0;
+
+ fail_derive:
+ freebuf(rpk);
+ flow->state = FLOW_DEALLOCATED;
+ fail_alloc:
+ freebuf(hash);
+ fail_ipcp:
+ reg_destroy_flow(flow->id);
+ fail_flow:
+ if (flow->qs.cypher_s > 0)
+ crypt_dh_pkp_destroy(pkp);
+ fail_pkp:
+ free(s);
+ fail_malloc:
+ return err;
}
-static void irm_fini(void)
+static int wait_for_accept(enum hash_algo algo,
+ const uint8_t * hash)
{
- struct list_head * p;
- struct list_head * h;
-
- if (irmd_get_state() != IRMD_NULL)
- log_warn("Unsafe destroy.");
+ struct timespec timeo = TIMESPEC_INIT_MS(IRMD_REQ_ARR_TIMEOUT);
+ struct timespec abstime;
+ char ** exec;
+ int ret;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ ret = reg_wait_flow_accepting(algo, hash, &abstime);
+ if (ret == -ETIMEDOUT) {
+ if (reg_get_exec(algo, hash, &exec) < 0) {
+ log_dbg("No program bound to " HASH_FMT32 ".",
+ HASH_VAL32(hash));
+ goto fail;
+ }
- pthread_rwlock_wrlock(&irmd.reg_lock);
+ log_info("Autostarting %s.", exec[0]);
- /* Clear the lists. */
- list_for_each_safe(p, h, &irmd.ipcps) {
- struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next);
- list_del(&e->next);
- ipcp_entry_destroy(e);
- }
+ if (spawn_program(exec) < 0) {
+ log_dbg("Failed to autostart " HASH_FMT32 ".",
+ HASH_VAL32(hash));
+ goto fail_spawn;
+ }
- list_for_each(p, &irmd.spawned_pids) {
- struct pid_el * e = list_entry(p, struct pid_el, next);
- if (kill(e->pid, SIGTERM))
- log_dbg("Could not send kill signal to %d.", e->pid);
- }
+ ts_add(&abstime, &timeo, &abstime);
- list_for_each_safe(p, h, &irmd.spawned_pids) {
- struct pid_el * e = list_entry(p, struct pid_el, next);
- int status;
- if (waitpid(e->pid, &status, 0) < 0)
- log_dbg("Error waiting for %d to exit.", e->pid);
- list_del(&e->next);
- registry_del_process(&irmd.registry, e->pid);
- free(e);
- }
+ ret = reg_wait_flow_accepting(algo, hash, &abstime);
+ if (ret == -ETIMEDOUT)
+ goto fail_spawn;
- list_for_each_safe(p, h, &irmd.prog_table) {
- struct prog_entry * e = list_entry(p, struct prog_entry, next);
- list_del(&e->next);
- prog_entry_destroy(e);
+ argvfree(exec);
}
- list_for_each_safe(p, h, &irmd.proc_table) {
- struct proc_entry * e = list_entry(p, struct proc_entry, next);
- list_del(&e->next);
- e->state = PROC_INIT; /* sanitizer already joined */
- proc_entry_destroy(e);
- }
-
- registry_destroy(&irmd.registry);
-
- pthread_rwlock_unlock(&irmd.reg_lock);
+ return ret;
- close(irmd.sockfd);
+ fail_spawn:
+ argvfree(exec);
+ fail:
+ return -1;
+}
- if (unlink(IRM_SOCK_PATH))
- log_dbg("Failed to unlink %s.", IRM_SOCK_PATH);
+static int flow_req_arr(struct flow_info * flow,
+ const uint8_t * hash,
+ buffer_t * data)
+{
+ struct ipcp_info info;
+ struct layer_info layer;
+ enum hash_algo algo;
+ int ret;
- pthread_rwlock_wrlock(&irmd.flows_lock);
+ info.pid = flow->n_1_pid;
- if (irmd.flow_ids != NULL)
- bmp_destroy(irmd.flow_ids);
+ log_info("Flow req arrived from IPCP %d for " HASH_FMT32 ".",
+ info.pid, HASH_VAL32(hash));
- list_for_each_safe(p, h, &irmd.irm_flows) {
- struct irm_flow * f = list_entry(p, struct irm_flow, next);
- list_del(&f->next);
- irm_flow_destroy(f);
+ if (reg_get_ipcp(&info, &layer) < 0) {
+ log_err("No IPCP with pid %d.", info.pid);
+ ret = -EIPCP;
+ goto fail;
}
- pthread_rwlock_unlock(&irmd.flows_lock);
-
+ algo = (enum hash_algo) layer.dir_hash_algo;
- if (irmd.rdrb != NULL)
- shm_rdrbuff_destroy(irmd.rdrb);
+ ret = wait_for_accept(algo, hash);
+ if (ret < 0) {
+ log_err("No activeprocess for " HASH_FMT32 ".",
+ HASH_VAL32(hash));
+ goto fail;
+ }
- if (irmd.lf != NULL)
- lockfile_destroy(irmd.lf);
+ flow->id = ret;
+ flow->state = FLOW_ALLOCATED;
- pthread_mutex_destroy(&irmd.cmd_lock);
- pthread_cond_destroy(&irmd.cmd_cond);
- pthread_rwlock_destroy(&irmd.flows_lock);
- pthread_rwlock_destroy(&irmd.reg_lock);
- pthread_rwlock_destroy(&irmd.state_lock);
+ ret = reg_respond_accept(flow, data);
+ if (ret < 0) {
+ log_err("Failed to respond to flow %d.", flow->id);
+ goto fail;
+ }
-#ifdef HAVE_FUSE
- if (rmdir(FUSE_PREFIX))
- log_dbg("Failed to remove " FUSE_PREFIX);
-#endif
+ return 0;
+ fail:
+ return ret;
}
-void * irm_sanitize(void * o)
+static int flow_alloc_reply(struct flow_info * flow,
+ int response,
+ buffer_t * data)
{
- struct timespec now;
- struct list_head * p = NULL;
- struct list_head * h = NULL;
-
- struct timespec timeout = {IRMD_CLEANUP_TIMER / BILLION,
- IRMD_CLEANUP_TIMER % BILLION};
- int s;
+ flow->state = response ? FLOW_DEALLOCATED : FLOW_ALLOCATED;
- (void) o;
+ if (reg_respond_alloc(flow, data) < 0) {
+ log_err("Failed to reply to flow %d.", flow->id);
+ flow->state = FLOW_DEALLOCATED;
+ return -EBADF;
+ }
- while (true) {
- if (clock_gettime(CLOCK_MONOTONIC, &now) < 0)
- log_warn("Failed to get time.");
-
- if (irmd_get_state() != IRMD_RUNNING)
- return (void *) 0;
-
- pthread_rwlock_wrlock(&irmd.reg_lock);
-
- list_for_each_safe(p, h, &irmd.spawned_pids) {
- struct pid_el * e = list_entry(p, struct pid_el, next);
- waitpid(e->pid, &s, WNOHANG);
- if (kill(e->pid, 0) >= 0)
- continue;
- log_dbg("Child process %d died, error %d.", e->pid, s);
- list_del(&e->next);
- free(e);
- }
+ return 0;
+}
- list_for_each_safe(p, h, &irmd.proc_table) {
- struct proc_entry * e =
- list_entry(p, struct proc_entry, next);
- if (kill(e->pid, 0) >= 0)
- continue;
- log_dbg("Dead process removed: %d.", e->pid);
- list_del(&e->next);
- proc_entry_destroy(e);
- }
+static int flow_dealloc(struct flow_info * flow,
+ struct timespec * ts)
+{
+ log_info("Deallocating flow %d for process %d (timeout: %zd s).",
+ flow->id, flow->n_pid, ts->tv_sec);
- list_for_each_safe(p, h, &irmd.ipcps) {
- struct ipcp_entry * e =
- list_entry(p, struct ipcp_entry, next);
- if (kill(e->pid, 0) >= 0)
- continue;
- log_dbg("Dead IPCP removed: %d.", e->pid);
- list_del(&e->next);
- ipcp_entry_destroy(e);
- }
+ reg_dealloc_flow(flow);
- list_for_each_safe(p, h, &irmd.registry) {
- struct list_head * p2;
- struct list_head * h2;
- struct reg_entry * e =
- list_entry(p, struct reg_entry, next);
- list_for_each_safe(p2, h2, &e->reg_pids) {
- struct pid_el * a =
- list_entry(p2, struct pid_el, next);
- if (kill(a->pid, 0) >= 0)
- continue;
- log_dbg("Dead process removed from: %d %s.",
- a->pid, e->name);
- reg_entry_del_pid_el(e, a);
- }
- }
+ if (ipcp_flow_dealloc(flow->n_1_pid, flow->id, ts->tv_sec) < 0) {
+ log_err("Failed to request dealloc from %d.", flow->n_1_pid);
+ return -EIPCP;
+ }
- pthread_rwlock_unlock(&irmd.reg_lock);
- pthread_rwlock_wrlock(&irmd.flows_lock);
-
- list_for_each_safe(p, h, &irmd.irm_flows) {
- int ipcpi;
- int flow_id;
- struct irm_flow * f =
- list_entry(p, struct irm_flow, next);
-
- if (irm_flow_get_state(f) == FLOW_ALLOC_PENDING
- && ts_diff_ms(&f->t0, &now) > IRMD_FLOW_TIMEOUT) {
- log_dbg("Pending flow_id %d timed out.",
- f->flow_id);
- f->n_pid = -1;
- irm_flow_set_state(f, FLOW_DEALLOC_PENDING);
- continue;
- }
+ return 0;
+}
- if (kill(f->n_pid, 0) < 0) {
- log_dbg("Process %d gone, deallocating "
- "flow %d.",
- f->n_pid, f->flow_id);
- f->n_pid = -1;
- irm_flow_set_state(f, FLOW_DEALLOC_PENDING);
- ipcpi = f->n_1_pid;
- flow_id = f->flow_id;
- pthread_rwlock_unlock(&irmd.flows_lock);
- ipcp_flow_dealloc(ipcpi, flow_id);
- pthread_rwlock_wrlock(&irmd.flows_lock);
- continue;
- }
+static int flow_dealloc_resp(struct flow_info * flow)
+{
+ reg_dealloc_flow_resp(flow);
- if (kill(f->n_1_pid, 0) < 0) {
- struct shm_flow_set * set;
- log_err("IPCP %d gone, flow %d removed.",
- f->n_1_pid, f->flow_id);
- set = shm_flow_set_open(f->n_pid);
- if (set != NULL)
- shm_flow_set_destroy(set);
- f->n_1_pid = -1;
- irm_flow_set_state(f, FLOW_DEALLOC_PENDING);
- }
- }
+ assert(flow->state == FLOW_DEALLOCATED);
- pthread_rwlock_unlock(&irmd.flows_lock);
+ reg_destroy_flow(flow->id);
- nanosleep(&timeout, NULL);
- }
-}
+ log_info("Completed deallocation of flow_id %d by process %d.",
+ flow->id, flow->n_1_pid);
-static void close_ptr(void * o)
-{
- close(*((int *) o));
+ return 0;
}
static void * acceptloop(void * o)
{
int csockfd;
- struct timeval tv = {(SOCKET_TIMEOUT / 1000),
- (SOCKET_TIMEOUT % 1000) * 1000};
(void) o;
- while (irmd_get_state() == IRMD_RUNNING) {
+ while (true) {
struct cmd * cmd;
csockfd = accept(irmd.sockfd, 0, 0);
if (csockfd < 0)
continue;
- if (setsockopt(csockfd, SOL_SOCKET, SO_RCVTIMEO,
- (void *) &tv, sizeof(tv)))
- log_warn("Failed to set timeout on socket.");
-
cmd = malloc(sizeof(*cmd));
if (cmd == NULL) {
log_err("Out of memory.");
@@ -1976,7 +1279,7 @@ static void * acceptloop(void * o)
break;
}
- pthread_cleanup_push(close_ptr, &csockfd);
+ pthread_cleanup_push(__cleanup_close_ptr, &csockfd);
pthread_cleanup_push(free, cmd);
cmd->len = read(csockfd, cmd->cbuf, SOCK_BUF_SIZE);
@@ -2010,6 +1313,198 @@ static void free_msg(void * o)
irm_msg__free_unpacked((irm_msg_t *) o, NULL);
}
+static irm_msg_t * do_command_msg(irm_msg_t * msg)
+{
+ struct ipcp_config conf;
+ struct ipcp_info ipcp;
+ struct flow_info flow;
+ struct proc_info proc;
+ struct name_info name;
+ struct timespec * abstime;
+ struct timespec max = TIMESPEC_INIT_MS(FLOW_ALLOC_TIMEOUT);
+ struct timespec now;
+ struct timespec ts = TIMESPEC_INIT_S(0); /* static analysis */
+ int res;
+ irm_msg_t * ret_msg;
+ buffer_t data;
+
+ memset(&flow, 0, sizeof(flow));
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ if (msg->timeo != NULL) {
+ ts = timespec_msg_to_s(msg->timeo);
+ ts_add(&ts, &now, &ts);
+ abstime = &ts;
+ } else {
+ ts_add(&max, &now, &max);
+ abstime = NULL;
+ }
+
+ ret_msg = malloc(sizeof(*ret_msg));
+ if (ret_msg == NULL) {
+ log_err("Failed to malloc return msg.");
+ return NULL;
+ }
+
+ irm_msg__init(ret_msg);
+
+ ret_msg->code = IRM_MSG_CODE__IRM_REPLY;
+
+ pthread_cleanup_push(free_msg, ret_msg);
+
+ switch (msg->code) {
+ case IRM_MSG_CODE__IRM_CREATE_IPCP:
+ ipcp = ipcp_info_msg_to_s(msg->ipcp_info);
+ res = create_ipcp(&ipcp);
+ break;
+ case IRM_MSG_CODE__IPCP_CREATE_R:
+ ipcp = ipcp_info_msg_to_s(msg->ipcp_info);
+ res = create_ipcp_r(&ipcp);
+ break;
+ case IRM_MSG_CODE__IRM_DESTROY_IPCP:
+ res = destroy_ipcp(msg->pid);
+ break;
+ case IRM_MSG_CODE__IRM_BOOTSTRAP_IPCP:
+ conf = ipcp_config_msg_to_s(msg->conf);
+ res = bootstrap_ipcp(msg->pid, &conf);
+ break;
+ case IRM_MSG_CODE__IRM_ENROLL_IPCP:
+ res = enroll_ipcp(msg->pid, msg->dst);
+ break;
+ case IRM_MSG_CODE__IRM_CONNECT_IPCP:
+ flow.qs = qos_spec_msg_to_s(msg->qosspec);
+ res = connect_ipcp(msg->pid, msg->dst, msg->comp, flow.qs);
+ break;
+ case IRM_MSG_CODE__IRM_DISCONNECT_IPCP:
+ res = disconnect_ipcp(msg->pid, msg->dst, msg->comp);
+ break;
+ case IRM_MSG_CODE__IRM_BIND_PROGRAM:
+ /* Make exec NULL terminated instead of empty string terminated */
+ free(msg->exec[msg->n_exec - 1]);
+ msg->exec[msg->n_exec - 1] = NULL;
+ res = bind_program(msg->exec, msg->name, msg->opts);
+ break;
+ case IRM_MSG_CODE__IRM_UNBIND_PROGRAM:
+ res = unbind_program(msg->prog, msg->name);
+ break;
+ case IRM_MSG_CODE__IRM_PROC_ANNOUNCE:
+ proc.pid = msg->pid;
+ strcpy(proc.prog, msg->prog);
+ res = proc_announce(&proc);
+ break;
+ case IRM_MSG_CODE__IRM_PROC_EXIT:
+ res = proc_exit(msg->pid);
+ break;
+ case IRM_MSG_CODE__IRM_BIND_PROCESS:
+ res = bind_process(msg->pid, msg->name);
+ break;
+ case IRM_MSG_CODE__IRM_UNBIND_PROCESS:
+ res = unbind_process(msg->pid, msg->name);
+ break;
+ case IRM_MSG_CODE__IRM_LIST_IPCPS:
+ res = list_ipcps(&ret_msg->ipcps, &ret_msg->n_ipcps);
+ break;
+ case IRM_MSG_CODE__IRM_CREATE_NAME:
+ strcpy(name.name, msg->names[0]->name);
+ name.pol_lb = msg->names[0]->pol_lb;
+ res = name_create(&name);
+ break;
+ case IRM_MSG_CODE__IRM_DESTROY_NAME:
+ res = name_destroy(msg->name);
+ break;
+ case IRM_MSG_CODE__IRM_LIST_NAMES:
+ res = list_names(&ret_msg->names, &ret_msg->n_names);
+ break;
+ case IRM_MSG_CODE__IRM_REG_NAME:
+ res = name_reg(msg->name, msg->pid);
+ break;
+ case IRM_MSG_CODE__IRM_UNREG_NAME:
+ res = name_unreg(msg->name, msg->pid);
+ break;
+ case IRM_MSG_CODE__IRM_FLOW_ACCEPT:
+ data.len = msg->pk.len;
+ data.data = msg->pk.data;
+ msg->has_pk = false;
+ assert(data.len > 0 ? data.data != NULL : data.data == NULL);
+ flow = flow_info_msg_to_s(msg->flow_info);
+ res = flow_accept(&flow, &data, abstime);
+ if (res == 0) {
+ ret_msg->flow_info = flow_info_s_to_msg(&flow);
+ ret_msg->has_symmkey = data.len != 0;
+ ret_msg->symmkey.data = data.data;
+ ret_msg->symmkey.len = data.len;
+ }
+ break;
+ case IRM_MSG_CODE__IRM_FLOW_ALLOC:
+ data.len = msg->pk.len;
+ data.data = msg->pk.data;
+ msg->has_pk = false;
+ assert(data.len > 0 ? data.data != NULL : data.data == NULL);
+ flow = flow_info_msg_to_s(msg->flow_info);
+ abstime = abstime == NULL ? &max : abstime;
+ res = flow_alloc(&flow, msg->dst, &data, abstime);
+ if (res == 0) {
+ ret_msg->flow_info = flow_info_s_to_msg(&flow);
+ ret_msg->has_symmkey = data.len != 0;
+ ret_msg->symmkey.data = data.data;
+ ret_msg->symmkey.len = data.len;
+ }
+ break;
+ case IRM_MSG_CODE__IRM_FLOW_JOIN:
+ assert(msg->pk.len == 0 && msg->pk.data == NULL);
+ flow = flow_info_msg_to_s(msg->flow_info);
+ abstime = abstime == NULL ? &max : abstime;
+ res = flow_join(&flow, msg->dst, abstime);
+ if (res == 0)
+ ret_msg->flow_info = flow_info_s_to_msg(&flow);
+ break;
+ case IRM_MSG_CODE__IRM_FLOW_DEALLOC:
+ flow = flow_info_msg_to_s(msg->flow_info);
+ ts = timespec_msg_to_s(msg->timeo);
+ res = flow_dealloc(&flow, &ts);
+ break;
+ case IRM_MSG_CODE__IPCP_FLOW_DEALLOC:
+ flow = flow_info_msg_to_s(msg->flow_info);
+ res = flow_dealloc_resp(&flow);
+ break;
+ case IRM_MSG_CODE__IPCP_FLOW_REQ_ARR:
+ data.len = msg->pk.len;
+ data.data = msg->pk.data;
+ msg->pk.data = NULL; /* pass data */
+ msg->pk.len = 0;
+ assert(data.len > 0 ? data.data != NULL : data.data == NULL);
+ flow = flow_info_msg_to_s(msg->flow_info);
+ res = flow_req_arr(&flow, msg->hash.data, &data);
+ if (res == 0)
+ ret_msg->flow_info = flow_info_s_to_msg(&flow);
+ break;
+ case IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY:
+ data.len = msg->pk.len;
+ data.data = msg->pk.data;
+ msg->pk.data = NULL; /* pass data */
+ msg->pk.len = 0;
+ assert(data.len > 0 ? data.data != NULL : data.data == NULL);
+ flow = flow_info_msg_to_s(msg->flow_info);
+ res = flow_alloc_reply(&flow, msg->response, &data);
+ break;
+ default:
+ log_err("Don't know that message code.");
+ res = -1;
+ break;
+ }
+
+ pthread_cleanup_pop(false);
+
+ ret_msg->has_result = true;
+ if (abstime == &max && res == -ETIMEDOUT)
+ ret_msg->result = -EPERM; /* No timeout requested */
+ else
+ ret_msg->result = res;
+
+ return ret_msg;
+}
+
static void * mainloop(void * o)
{
int sfd;
@@ -2019,26 +1514,12 @@ static void * mainloop(void * o)
(void) o;
while (true) {
- irm_msg_t * ret_msg;
- struct irm_flow * e = NULL;
- struct timespec * timeo = NULL;
- struct timespec ts = {0, 0};
- struct cmd * cmd;
- int result;
-
- ret_msg = malloc(sizeof(*ret_msg));
- if (ret_msg == NULL)
- return (void *) -1;
-
- irm_msg__init(ret_msg);
-
- ret_msg->code = IRM_MSG_CODE__IRM_REPLY;
+ irm_msg_t * ret_msg;
+ struct cmd * cmd;
pthread_mutex_lock(&irmd.cmd_lock);
- pthread_cleanup_push(free_msg, ret_msg);
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &irmd.cmd_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &irmd.cmd_lock);
while (list_is_empty(&irmd.cmds))
pthread_cond_wait(&irmd.cmd_cond, &irmd.cmd_lock);
@@ -2047,7 +1528,6 @@ static void * mainloop(void * o)
list_del(&cmd->next);
pthread_cleanup_pop(true);
- pthread_cleanup_pop(false);
msg = irm_msg__unpack(NULL, cmd->len, cmd->cbuf);
sfd = cmd->fd;
@@ -2055,177 +1535,35 @@ static void * mainloop(void * o)
free(cmd);
if (msg == NULL) {
+ log_err("Failed to unpack command message.");
close(sfd);
- irm_msg__free_unpacked(msg, NULL);
continue;
}
tpm_dec(irmd.tpm);
- if (msg->has_timeo_sec) {
- assert(msg->has_timeo_nsec);
-
- ts.tv_sec = msg->timeo_sec;
- ts.tv_nsec = msg->timeo_nsec;
- timeo = &ts;
- }
-
- pthread_cleanup_push(close_ptr, &sfd);
+ pthread_cleanup_push(__cleanup_close_ptr, &sfd);
pthread_cleanup_push(free_msg, msg);
- pthread_cleanup_push(free_msg, ret_msg);
- switch (msg->code) {
- case IRM_MSG_CODE__IRM_CREATE_IPCP:
- result = create_ipcp(msg->name, msg->ipcp_type);
- break;
- case IRM_MSG_CODE__IPCP_CREATE_R:
- result = create_ipcp_r(msg->pid, msg->result);
- break;
- case IRM_MSG_CODE__IRM_DESTROY_IPCP:
- result = destroy_ipcp(msg->pid);
- break;
- case IRM_MSG_CODE__IRM_BOOTSTRAP_IPCP:
- result = bootstrap_ipcp(msg->pid, msg->conf);
- break;
- case IRM_MSG_CODE__IRM_ENROLL_IPCP:
- result = enroll_ipcp(msg->pid, msg->dst);
- break;
- case IRM_MSG_CODE__IRM_CONNECT_IPCP:
- result = connect_ipcp(msg->pid, msg->dst, msg->comp,
- msg_to_spec(msg->qosspec));
- break;
- case IRM_MSG_CODE__IRM_DISCONNECT_IPCP:
- result = disconnect_ipcp(msg->pid, msg->dst, msg->comp);
- break;
- case IRM_MSG_CODE__IRM_BIND_PROGRAM:
- result = bind_program(msg->prog,
- msg->name,
- msg->opts,
- msg->n_args,
- msg->args);
- break;
- case IRM_MSG_CODE__IRM_UNBIND_PROGRAM:
- result = unbind_program(msg->prog, msg->name);
- break;
- case IRM_MSG_CODE__IRM_PROC_ANNOUNCE:
- result = proc_announce(msg->pid, msg->prog);
- break;
- case IRM_MSG_CODE__IRM_BIND_PROCESS:
- result = bind_process(msg->pid, msg->name);
- break;
- case IRM_MSG_CODE__IRM_UNBIND_PROCESS:
- result = unbind_process(msg->pid, msg->name);
- break;
- case IRM_MSG_CODE__IRM_LIST_IPCPS:
- result = list_ipcps(&ret_msg->ipcps, &ret_msg->n_ipcps);
- break;
- case IRM_MSG_CODE__IRM_CREATE_NAME:
- result = name_create(msg->names[0]->name,
- msg->names[0]->pol_lb);
- break;
- case IRM_MSG_CODE__IRM_DESTROY_NAME:
- result = name_destroy(msg->name);
- break;
- case IRM_MSG_CODE__IRM_LIST_NAMES:
- result = list_names(&ret_msg->names, &ret_msg->n_names);
- break;
- case IRM_MSG_CODE__IRM_REG_NAME:
- result = name_reg(msg->name, msg->pid);
- break;
- case IRM_MSG_CODE__IRM_UNREG_NAME:
- result = name_unreg(msg->name, msg->pid);
- break;
- case IRM_MSG_CODE__IRM_FLOW_ACCEPT:
- assert(msg->pk.len > 0 ? msg->pk.data != NULL
- : msg->pk.data == NULL);
- result = flow_accept(msg->pid, timeo, &e,
- msg->pk.data, msg->pk.len);
- if (result == 0) {
- qosspec_msg_t qs_msg;
- ret_msg->has_flow_id = true;
- ret_msg->flow_id = e->flow_id;
- ret_msg->has_pid = true;
- ret_msg->pid = e->n_1_pid;
- qs_msg = spec_to_msg(&e->qs);
- ret_msg->qosspec = &qs_msg;
- ret_msg->has_pk = true;
- ret_msg->pk.data = e->data;
- ret_msg->pk.len = e->len;
- e->len = 0; /* Data is free'd with ret_msg */
- }
- break;
- case IRM_MSG_CODE__IRM_FLOW_ALLOC:
- assert(msg->pk.len > 0 ? msg->pk.data != NULL
- : msg->pk.data == NULL);
- result = flow_alloc(msg->pid, msg->dst,
- msg_to_spec(msg->qosspec),
- timeo, &e, false, msg->pk.data,
- msg->pk.len);
- if (result == 0) {
- ret_msg->has_flow_id = true;
- ret_msg->flow_id = e->flow_id;
- ret_msg->has_pid = true;
- ret_msg->pid = e->n_1_pid;
- ret_msg->has_pk = true;
- ret_msg->pk.data = e->data;
- ret_msg->pk.len = e->len;
- e->len = 0; /* Data is free'd with ret_msg */
- }
- break;
- case IRM_MSG_CODE__IRM_FLOW_JOIN:
- assert(msg->pk.len == 0 && msg->pk.data == NULL);
- result = flow_alloc(msg->pid, msg->dst,
- msg_to_spec(msg->qosspec),
- timeo, &e, true, NULL, 0);
- if (result == 0) {
- ret_msg->has_flow_id = true;
- ret_msg->flow_id = e->flow_id;
- ret_msg->has_pid = true;
- ret_msg->pid = e->n_1_pid;
- }
- break;
- case IRM_MSG_CODE__IRM_FLOW_DEALLOC:
- result = flow_dealloc(msg->pid, msg->flow_id);
- break;
- case IRM_MSG_CODE__IPCP_FLOW_REQ_ARR:
- assert(msg->pk.len > 0 ? msg->pk.data != NULL
- : msg->pk.data == NULL);
- e = flow_req_arr(msg->pid,
- msg->hash.data,
- msg_to_spec(msg->qosspec),
- msg->pk.data,
- msg->pk.len);
- result = (e == NULL ? -1 : 0);
- if (result == 0) {
- ret_msg->has_flow_id = true;
- ret_msg->flow_id = e->flow_id;
- ret_msg->has_pid = true;
- ret_msg->pid = e->n_pid;
- }
- break;
- case IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY:
- assert(msg->pk.len > 0 ? msg->pk.data != NULL
- : msg->pk.data == NULL);
- result = flow_alloc_reply(msg->flow_id,
- msg->response,
- msg->pk.data,
- msg->pk.len);
- break;
- default:
- log_err("Don't know that message code.");
- result = -1;
- break;
- }
+ ret_msg = do_command_msg(msg);
- pthread_cleanup_pop(false);
pthread_cleanup_pop(true);
pthread_cleanup_pop(false);
- if (result == -EPIPE)
+ if (ret_msg == NULL) {
+ log_err("Failed to create return message.");
+ goto fail_msg;
+ }
+
+ if (ret_msg->result == -EPIPE) {
+ log_dbg("Terminated command: application closed socket.");
goto fail;
+ }
- ret_msg->has_result = true;
- ret_msg->result = result;
+ if (ret_msg->result == -EIRMD) {
+ log_dbg("Terminated command: IRMd not in running state.");
+ goto fail;
+ }
buffer.len = irm_msg__get_packed_size(ret_msg);
if (buffer.len == 0) {
@@ -2241,25 +1579,29 @@ static void * mainloop(void * o)
irm_msg__pack(ret_msg, buffer.data);
- /* Can't free the qosspec. */
- ret_msg->qosspec = NULL;
irm_msg__free_unpacked(ret_msg, NULL);
- pthread_cleanup_push(close_ptr, &sfd);
+ pthread_cleanup_push(__cleanup_close_ptr, &sfd);
+ pthread_cleanup_push(free, buffer.data);
- if (write(sfd, buffer.data, buffer.len) == -1)
- if (result != -EIRMD)
- log_warn("Failed to send reply message.");
-
- free(buffer.data);
+ if (write(sfd, buffer.data, buffer.len) == -1) {
+ if (errno != EPIPE)
+ log_warn("Failed to send reply message: %s.",
+ strerror(errno));
+ else
+ log_dbg("Failed to send reply message: %s.",
+ strerror(errno));
+ }
pthread_cleanup_pop(true);
+ pthread_cleanup_pop(true);
tpm_inc(irmd.tpm);
continue;
fail:
irm_msg__free_unpacked(ret_msg, NULL);
+ fail_msg:
close(sfd);
tpm_inc(irmd.tpm);
continue;
@@ -2268,26 +1610,161 @@ static void * mainloop(void * o)
return (void *) 0;
}
+static void irm_fini(void)
+{
+#ifdef HAVE_FUSE
+ struct timespec wait = TIMESPEC_INIT_MS(1);
+ int retries = 5;
+#endif
+ if (irmd_get_state() != IRMD_NULL)
+ log_warn("Unsafe destroy.");
+
+ tpm_destroy(irmd.tpm);
+
+ close(irmd.sockfd);
+
+ if (unlink(IRM_SOCK_PATH))
+ log_dbg("Failed to unlink %s.", IRM_SOCK_PATH);
+
+ if (irmd.rdrb != NULL)
+ shm_rdrbuff_destroy(irmd.rdrb);
+
+ if (irmd.lf != NULL)
+ lockfile_destroy(irmd.lf);
+
+ pthread_mutex_destroy(&irmd.cmd_lock);
+ pthread_cond_destroy(&irmd.cmd_cond);
+ pthread_rwlock_destroy(&irmd.state_lock);
+
+#ifdef HAVE_FUSE
+ while (rmdir(FUSE_PREFIX) < 0 && retries-- > 0)
+ nanosleep(&wait, NULL);
+ if (retries < 0)
+ log_err("Failed to remove " FUSE_PREFIX);
+#endif
+}
+
+#ifdef HAVE_FUSE
+static void destroy_mount(char * mnt)
+{
+ struct stat st;
+
+ if (stat(mnt, &st) == -1){
+ switch(errno) {
+ case ENOENT:
+ log_dbg("Fuse mountpoint %s not found: %s",
+ mnt, strerror(errno));
+ break;
+ case ENOTCONN:
+ /* FALLTHRU */
+ case ECONNABORTED:
+ log_dbg("Cleaning up fuse mountpoint %s.",
+ mnt);
+ rib_cleanup(mnt);
+ break;
+ default:
+ log_err("Unhandled fuse error on mnt %s: %s.",
+ mnt, strerror(errno));
+ }
+ }
+}
+#endif
+
+static int ouroboros_reset(void)
+{
+ shm_rdrbuff_purge();
+ lockfile_destroy(irmd.lf);
+
+ return 0;
+}
+
+static void cleanup_pid(pid_t pid)
+{
+#ifdef HAVE_FUSE
+ char mnt[RIB_PATH_LEN + 1];
+
+ if (reg_has_ipcp(pid)) {
+ struct ipcp_info info;
+ info.pid = pid;
+ reg_get_ipcp(&info, NULL);
+ sprintf(mnt, FUSE_PREFIX "/%s", info.name);
+ } else {
+ sprintf(mnt, FUSE_PREFIX "/proc.%d", pid);
+ }
+
+ destroy_mount(mnt);
+
+#else
+ (void) pid;
+#endif
+}
+
+void * irm_sanitize(void * o)
+{
+ pid_t pid;
+ struct timespec ts = TIMESPEC_INIT_MS(FLOW_ALLOC_TIMEOUT / 20);
+
+ (void) o;
+
+ while (true) {
+ while((pid = reg_get_dead_proc()) != -1) {
+ log_info("Process %d died.", pid);
+ cleanup_pid(pid);
+ reg_destroy_proc(pid);
+ }
+
+ nanosleep(&ts, NULL);
+ }
+
+ return (void *) 0;
+}
+
+
static int irm_init(void)
{
struct stat st;
pthread_condattr_t cattr;
-
+#ifdef HAVE_FUSE
+ mode_t mask;
+#endif
memset(&st, 0, sizeof(st));
- if (pthread_rwlock_init(&irmd.state_lock, NULL)) {
- log_err("Failed to initialize rwlock.");
- goto fail_state_lock;
+ log_init(!irmd.log_stdout);
+
+ irmd.lf = lockfile_create();
+ if (irmd.lf == NULL) {
+ irmd.lf = lockfile_open();
+ if (irmd.lf == NULL) {
+ log_err("Lockfile error.");
+ goto fail_lockfile;
+ }
+
+ if (kill(lockfile_owner(irmd.lf), 0) < 0) {
+ log_warn("IRMd didn't properly shut down last time.");
+ if (ouroboros_reset() < 0) {
+ log_err("Failed to clean stale resources.");
+ lockfile_close(irmd.lf);
+ goto fail_lockfile;
+ }
+
+ log_warn("Stale resources cleaned.");
+ irmd.lf = lockfile_create();
+ } else {
+ log_warn("IRMd already running (%d), exiting.",
+ lockfile_owner(irmd.lf));
+ lockfile_close(irmd.lf);
+ goto fail_lockfile;
+ }
}
- if (pthread_rwlock_init(&irmd.reg_lock, NULL)) {
- log_err("Failed to initialize rwlock.");
- goto fail_reg_lock;
+ if (irmd.lf == NULL) {
+ log_err("Failed to create lockfile.");
+ goto fail_lockfile;
}
- if (pthread_rwlock_init(&irmd.flows_lock, NULL)) {
+ if (pthread_rwlock_init(&irmd.state_lock, NULL)) {
log_err("Failed to initialize rwlock.");
- goto fail_flows_lock;
+ goto fail_state_lock;
}
if (pthread_mutex_init(&irmd.cmd_lock, NULL)) {
@@ -2311,45 +1788,8 @@ static int irm_init(void)
pthread_condattr_destroy(&cattr);
- list_head_init(&irmd.ipcps);
- list_head_init(&irmd.proc_table);
- list_head_init(&irmd.prog_table);
- list_head_init(&irmd.spawned_pids);
- list_head_init(&irmd.registry);
- list_head_init(&irmd.irm_flows);
list_head_init(&irmd.cmds);
- irmd.flow_ids = bmp_create(SYS_MAX_FLOWS, 0);
- if (irmd.flow_ids == NULL) {
- log_err("Failed to create flow_ids bitmap.");
- goto fail_flow_ids;
- }
-
- if ((irmd.lf = lockfile_create()) == NULL) {
- if ((irmd.lf = lockfile_open()) == NULL) {
- log_err("Lockfile error.");
- goto fail_lockfile;
- }
-
- if (kill(lockfile_owner(irmd.lf), 0) < 0) {
- log_info("IRMd didn't properly shut down last time.");
- shm_rdrbuff_purge();
- log_info("Stale resources cleaned.");
- lockfile_destroy(irmd.lf);
- irmd.lf = lockfile_create();
- } else {
- log_info("IRMd already running (%d), exiting.",
- lockfile_owner(irmd.lf));
- lockfile_close(irmd.lf);
- goto fail_lockfile;
- }
- }
-
- if (irmd.lf == NULL) {
- log_err("Failed to create lockfile.");
- goto fail_lockfile;
- }
-
if (stat(SOCK_PATH, &st) == -1) {
if (mkdir(SOCK_PATH, 0777)) {
log_err("Failed to create sockets directory.");
@@ -2372,11 +1812,22 @@ static int irm_init(void)
log_err("Failed to create rdrbuff.");
goto fail_rdrbuff;
}
+
+ irmd.tpm = tpm_create(IRMD_MIN_THREADS, IRMD_ADD_THREADS,
+ mainloop, NULL);
+ if (irmd.tpm == NULL) {
+ log_err("Failed to greate thread pool.");
+ goto fail_tpm_create;
+ }
#ifdef HAVE_FUSE
+ mask = umask(0);
+
if (stat(FUSE_PREFIX, &st) != -1)
log_warn(FUSE_PREFIX " already exists...");
else
mkdir(FUSE_PREFIX, 0777);
+
+ umask(mask);
#endif
#ifdef HAVE_LIBGCRYPT
@@ -2392,68 +1843,124 @@ static int irm_init(void)
gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
#endif
- irmd_set_state(IRMD_RUNNING);
-
- log_info("Ouroboros IPC Resource Manager daemon started...");
return 0;
#ifdef HAVE_LIBGCRYPT
fail_gcry_version:
-#ifdef HAVE_FUSE
+ #ifdef HAVE_FUSE
rmdir(FUSE_PREFIX);
+ #endif
+ tpm_destroy(irmd.tpm);
#endif
+ fail_tpm_create:
shm_rdrbuff_destroy(irmd.rdrb);
-#endif
fail_rdrbuff:
close(irmd.sockfd);
fail_sock_path:
unlink(IRM_SOCK_PATH);
fail_stat:
- lockfile_destroy(irmd.lf);
- fail_lockfile:
- bmp_destroy(irmd.flow_ids);
- fail_flow_ids:
pthread_cond_destroy(&irmd.cmd_cond);
fail_cmd_cond:
pthread_mutex_destroy(&irmd.cmd_lock);
fail_cmd_lock:
- pthread_rwlock_destroy(&irmd.flows_lock);
- fail_flows_lock:
- pthread_rwlock_destroy(&irmd.reg_lock);
- fail_reg_lock:
pthread_rwlock_destroy(&irmd.state_lock);
fail_state_lock:
+ lockfile_destroy(irmd.lf);
+ fail_lockfile:
+ log_fini();
return -1;
}
static void usage(void)
{
printf("Usage: irmd \n"
+#ifdef HAVE_TOML
+ " [--config <path> (Path to configuration file)]\n"
+#endif
" [--stdout (Log to stdout instead of system log)]\n"
" [--version (Print version number and exit)]\n"
"\n");
}
-int main(int argc,
- char ** argv)
+static int irm_start(void)
{
- sigset_t sigset;
- bool use_stdout = false;
- int sig;
+ if (tpm_start(irmd.tpm))
+ goto fail_tpm_start;
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGINT);
- sigaddset(&sigset, SIGQUIT);
- sigaddset(&sigset, SIGHUP);
- sigaddset(&sigset, SIGTERM);
- sigaddset(&sigset, SIGPIPE);
+ irmd_set_state(IRMD_RUNNING);
+
+ if (pthread_create(&irmd.irm_sanitize, NULL, irm_sanitize, NULL))
+ goto fail_irm_sanitize;
+
+ if (pthread_create(&irmd.acceptor, NULL, acceptloop, NULL))
+ goto fail_acceptor;
+
+ log_info("Ouroboros IPC Resource Manager daemon started...");
+
+ return 0;
+
+ fail_acceptor:
+ pthread_cancel(irmd.irm_sanitize);
+ pthread_join(irmd.irm_sanitize, NULL);
+ fail_irm_sanitize:
+ irmd_set_state(IRMD_NULL);
+ tpm_stop(irmd.tpm);
+ fail_tpm_start:
+ return -1;
+}
+
+static void irm_sigwait(sigset_t sigset)
+{
+ int sig;
+
+ while (irmd_get_state() != IRMD_SHUTDOWN) {
+ if (sigwait(&sigset, &sig) != 0) {
+ log_warn("Bad signal.");
+ continue;
+ }
+
+ switch(sig) {
+ case SIGINT:
+ case SIGQUIT:
+ case SIGTERM:
+ case SIGHUP:
+ log_info("IRMd shutting down...");
+ irmd_set_state(IRMD_SHUTDOWN);
+ break;
+ case SIGPIPE:
+ log_dbg("Ignored SIGPIPE.");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void irm_stop(void)
+{
+ pthread_cancel(irmd.acceptor);
+ pthread_cancel(irmd.irm_sanitize);
+
+ pthread_join(irmd.acceptor, NULL);
+ pthread_join(irmd.irm_sanitize, NULL);
+
+ tpm_stop(irmd.tpm);
+
+ irmd_set_state(IRMD_NULL);
+}
+static void irm_argparse(int argc,
+ char ** argv)
+{
+#ifdef HAVE_TOML
+ irmd.cfg_file = NULL;
+#endif
argc--;
argv++;
while (argc > 0) {
if (strcmp(*argv, "--stdout") == 0) {
- use_stdout = true;
+ irmd.log_stdout = true;
argc--;
argv++;
} else if (strcmp(*argv, "--version") == 0) {
@@ -2462,96 +1969,141 @@ int main(int argc,
OUROBOROS_VERSION_MINOR,
OUROBOROS_VERSION_PATCH);
exit(EXIT_SUCCESS);
+#ifdef HAVE_TOML
+ } else if (strcmp (*argv, "--config") == 0) {
+ irmd.cfg_file = *(argv + 1);
+ argc -= 2;
+ argv += 2;
+#endif
} else {
usage();
exit(EXIT_FAILURE);
}
}
+}
+
+static void * kill_dash_nine(void * o)
+{
+ time_t slept = 0;
+#ifdef IRMD_KILL_ALL_PROCESSES
+ struct timespec ts = TIMESPEC_INIT_MS(FLOW_ALLOC_TIMEOUT / 19);
+#endif
+ (void) o;
+
+ while (slept < IRMD_PKILL_TIMEOUT) {
+ time_t intv = 1;
+ if (reg_first_spawned() == -1)
+ goto finish;
+ sleep(intv);
+ slept += intv;
+ }
+
+ log_dbg("I am become Death, destroyer of hung processes.");
+
+#ifdef IRMD_KILL_ALL_PROCESSES
+ reg_kill_all_proc(SIGKILL);
+ nanosleep(&ts, NULL);
+#else
+ reg_kill_all_spawned(SIGKILL);
+#endif
+ finish:
+ return (void *) 0;
+}
+
+static void kill_all_spawned(void)
+{
+ pid_t pid;
+ pthread_t grimreaper;
+
+#ifdef IRMD_KILL_ALL_PROCESSES
+ reg_kill_all_proc(SIGTERM);
+#else
+ reg_kill_all_spawned(SIGTERM);
+#endif
+ pthread_create(&grimreaper, NULL, kill_dash_nine, NULL);
+
+ pid = reg_first_spawned();
+ while (pid != -1) {
+ int s;
+ if (kill(pid, 0) == 0)
+ waitpid(pid, &s, 0);
+ else {
+ log_warn("Child process %d died.", pid);
+ cleanup_pid(pid);
+ reg_destroy_proc(pid);
+ }
+ pid = reg_first_spawned();
+ }
+
+ pthread_join(grimreaper, NULL);
+}
+
+int main(int argc,
+ char ** argv)
+{
+ sigset_t sigset;
+ int ret = EXIT_SUCCESS;
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGINT);
+ sigaddset(&sigset, SIGQUIT);
+ sigaddset(&sigset, SIGHUP);
+ sigaddset(&sigset, SIGTERM);
+ sigaddset(&sigset, SIGPIPE);
+
+ irm_argparse(argc, argv);
+
+ if (irmd.log_stdout)
+ printf(O7S_ASCII_ART);
if (geteuid() != 0) {
printf("IPC Resource Manager must be run as root.\n");
exit(EXIT_FAILURE);
}
- log_init(!use_stdout);
-
if (irm_init() < 0)
goto fail_irm_init;
- irmd.tpm = tpm_create(IRMD_MIN_THREADS, IRMD_ADD_THREADS,
- mainloop, NULL);
- if (irmd.tpm == NULL) {
- irmd_set_state(IRMD_NULL);
- goto fail_tpm_create;
+ if (reg_init() < 0) {
+ log_err("Failed to initialize registry.");
+ goto fail_reg;
}
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
- if (tpm_start(irmd.tpm)) {
- irmd_set_state(IRMD_NULL);
- goto fail_tpm_start;
- }
+ if (irm_start() < 0)
+ goto fail_irm_start;
- if (pthread_create(&irmd.irm_sanitize, NULL, irm_sanitize, NULL)) {
- irmd_set_state(IRMD_NULL);
- goto fail_irm_sanitize;
+#ifdef HAVE_TOML
+ if (irm_configure(irmd.cfg_file) < 0) {
+ irmd_set_state(IRMD_SHUTDOWN);
+ ret = EXIT_FAILURE;
}
+#endif
+ irm_sigwait(sigset);
- if (pthread_create(&irmd.acceptor, NULL, acceptloop, NULL)) {
- irmd_set_state(IRMD_NULL);
- goto fail_acceptor;
- }
+ kill_all_spawned();
- while (irmd_get_state() != IRMD_NULL) {
- if (sigwait(&sigset, &sig) != 0) {
- log_warn("Bad signal.");
- continue;
- }
+ irm_stop();
- switch(sig) {
- case SIGINT:
- case SIGQUIT:
- case SIGTERM:
- case SIGHUP:
- log_info("IRMd shutting down...");
- irmd_set_state(IRMD_NULL);
- break;
- case SIGPIPE:
- log_dbg("Ignored SIGPIPE.");
- break;
- default:
- break;
- }
- }
-
- pthread_cancel(irmd.acceptor);
-
- pthread_join(irmd.acceptor, NULL);
- pthread_join(irmd.irm_sanitize, NULL);
+ pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
- tpm_stop(irmd.tpm);
+ reg_clear();
- tpm_destroy(irmd.tpm);
+ reg_fini();
irm_fini();
- pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
-
- log_info("Bye.");
+ log_info("Ouroboros IPC Resource Manager daemon exited. Bye.");
log_fini();
- exit(EXIT_SUCCESS);
+ exit(ret);
- fail_acceptor:
- pthread_join(irmd.irm_sanitize, NULL);
- fail_irm_sanitize:
- tpm_stop(irmd.tpm);
- fail_tpm_start:
- tpm_destroy(irmd.tpm);
- fail_tpm_create:
+ fail_irm_start:
+ reg_fini();
+ fail_reg:
irm_fini();
fail_irm_init:
- log_fini();
exit(EXIT_FAILURE);
}
diff --git a/src/irmd/proc_table.c b/src/irmd/proc_table.c
deleted file mode 100644
index 80d5f304..00000000
--- a/src/irmd/proc_table.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Process Table
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-#include "config.h"
-
-#include <ouroboros/list.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/time_utils.h>
-
-#include "proc_table.h"
-#include "registry.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-#include <assert.h>
-
-struct proc_entry * proc_entry_create(pid_t pid,
- char * prog)
-{
- struct proc_entry * e;
- pthread_condattr_t cattr;
-
- assert(prog);
-
- e = malloc(sizeof(*e));
- if (e == NULL)
- goto fail_malloc;
-
- if (pthread_condattr_init(&cattr))
- goto fail_condattr;
-
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
-
- if (pthread_mutex_init(&e->lock, NULL))
- goto fail_mutex;
-
- if (pthread_cond_init(&e->cond, &cattr))
- goto fail_cond;
-
- e->set = shm_flow_set_create(pid);
- if (e->set == NULL)
- goto fail_set;
-
- list_head_init(&e->next);
- list_head_init(&e->names);
-
- e->pid = pid;
- e->prog = prog;
- e->re = NULL;
- e->state = PROC_INIT;
-
- return e;
- fail_set:
- pthread_cond_destroy(&e->cond);;
- fail_cond:
- pthread_mutex_destroy(&e->lock);
- fail_mutex:
- pthread_condattr_destroy(&cattr);
- fail_condattr:
- free(e);
- fail_malloc:
- return NULL;
-}
-
-static void cancel_proc_entry(void * o)
-{
- struct proc_entry * e = (struct proc_entry *) o;
-
- e->state = PROC_NULL;
-
- pthread_mutex_unlock(&e->lock);
-}
-
-void proc_entry_destroy(struct proc_entry * e)
-{
- struct list_head * p;
- struct list_head * h;
-
- assert(e);
-
- pthread_mutex_lock(&e->lock);
-
- if (e->state == PROC_DESTROY) {
- pthread_mutex_unlock(&e->lock);
- return;
- }
-
- if (e->state == PROC_SLEEP)
- e->state = PROC_DESTROY;
-
- pthread_cond_signal(&e->cond);
-
- pthread_cleanup_push(cancel_proc_entry, e);
-
- while (e->state != PROC_INIT)
- pthread_cond_wait(&e->cond, &e->lock);
-
- pthread_cleanup_pop(false);
-
- pthread_mutex_unlock(&e->lock);
-
- shm_flow_set_destroy(e->set);
-
- pthread_cond_destroy(&e->cond);
- pthread_mutex_destroy(&e->lock);
-
- if (e->prog != NULL)
- free(e->prog);
-
- list_for_each_safe(p, h, &e->names) {
- struct str_el * n = list_entry(p, struct str_el, next);
- list_del(&n->next);
- if (n->str != NULL)
- free(n->str);
- free(n);
- }
-
- free(e);
-}
-
-int proc_entry_add_name(struct proc_entry * e,
- char * name)
-{
- struct str_el * s;
-
- assert(e);
- assert(name);
-
- s = malloc(sizeof(*s));
- if (s == NULL)
- return -ENOMEM;
-
- s->str = name;
- list_add(&s->next, &e->names);
-
- return 0;
-}
-
-void proc_entry_del_name(struct proc_entry * e,
- const char * name)
-{
- struct list_head * p = NULL;
- struct list_head * h = NULL;
-
- assert(e);
- assert(name);
-
- list_for_each_safe(p, h, &e->names) {
- struct str_el * s = list_entry(p, struct str_el, next);
- if (!strcmp(name, s->str)) {
- list_del(&s->next);
- free(s->str);
- free(s);
- }
- }
-}
-
-int proc_entry_sleep(struct proc_entry * e,
- struct timespec * timeo)
-{
- struct timespec dl;
-
- int ret = 0;
-
- assert(e);
-
- if (timeo != NULL) {
- clock_gettime(PTHREAD_COND_CLOCK, &dl);
- ts_add(&dl, timeo, &dl);
- }
-
- pthread_mutex_lock(&e->lock);
-
- if (e->state != PROC_WAKE && e->state != PROC_DESTROY)
- e->state = PROC_SLEEP;
-
- pthread_cleanup_push(cancel_proc_entry, e);
-
- while (e->state == PROC_SLEEP && ret != -ETIMEDOUT)
- if (timeo)
- ret = -pthread_cond_timedwait(&e->cond, &e->lock, &dl);
- else
- ret = -pthread_cond_wait(&e->cond, &e->lock);
-
- pthread_cleanup_pop(false);
-
- if (e->state == PROC_DESTROY) {
- if (e->re != NULL)
- reg_entry_del_pid(e->re, e->pid);
- ret = -1;
- }
-
- e->state = PROC_INIT;
-
- pthread_cond_broadcast(&e->cond);
- pthread_mutex_unlock(&e->lock);
-
- return ret;
-}
-
-void proc_entry_wake(struct proc_entry * e,
- struct reg_entry * re)
-{
- assert(e);
- assert(re);
-
- pthread_mutex_lock(&e->lock);
-
- if (e->state != PROC_SLEEP) {
- pthread_mutex_unlock(&e->lock);
- return;
- }
-
- e->state = PROC_WAKE;
- e->re = re;
-
- pthread_cond_broadcast(&e->cond);
-
- pthread_cleanup_push(cancel_proc_entry, e);
-
- while (e->state == PROC_WAKE)
- pthread_cond_wait(&e->cond, &e->lock);
-
- pthread_cleanup_pop(false);
-
- if (e->state == PROC_DESTROY)
- e->state = PROC_INIT;
-
- pthread_mutex_unlock(&e->lock);
-}
-
-int proc_table_add(struct list_head * proc_table,
- struct proc_entry * e)
-{
-
- assert(proc_table);
- assert(e);
-
- list_add(&e->next, proc_table);
-
- return 0;
-}
-
-void proc_table_del(struct list_head * proc_table,
- pid_t pid)
-{
- struct list_head * p;
- struct list_head * h;
-
- assert(proc_table);
-
- list_for_each_safe(p, h, proc_table) {
- struct proc_entry * e = list_entry(p, struct proc_entry, next);
- if (pid == e->pid) {
- list_del(&e->next);
- proc_entry_destroy(e);
- }
- }
-}
-
-struct proc_entry * proc_table_get(struct list_head * proc_table,
- pid_t pid)
-{
- struct list_head * h;
-
- assert(proc_table);
-
- list_for_each(h, proc_table) {
- struct proc_entry * e = list_entry(h, struct proc_entry, next);
- if (pid == e->pid)
- return e;
- }
-
- return NULL;
-}
diff --git a/src/irmd/proc_table.h b/src/irmd/proc_table.h
deleted file mode 100644
index 48daaa45..00000000
--- a/src/irmd/proc_table.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Process Table
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IRMD_PROC_TABLE_H
-#define OUROBOROS_IRMD_PROC_TABLE_H
-
-#include <ouroboros/shm_flow_set.h>
-
-#include "utils.h"
-
-#include <unistd.h>
-#include <pthread.h>
-
-enum proc_state {
- PROC_NULL = 0,
- PROC_INIT,
- PROC_SLEEP,
- PROC_WAKE,
- PROC_DESTROY
-};
-
-struct proc_entry {
- struct list_head next;
- pid_t pid;
- char * prog; /* program instantiated */
- struct list_head names; /* names for which process accepts flows */
- struct shm_flow_set * set;
-
- struct reg_entry * re; /* reg_entry for which a flow arrived */
-
- /* The process will block on this */
- enum proc_state state;
- pthread_cond_t cond;
- pthread_mutex_t lock;
-};
-
-struct proc_entry * proc_entry_create(pid_t proc,
- char * prog);
-
-void proc_entry_destroy(struct proc_entry * e);
-
-int proc_entry_sleep(struct proc_entry * e,
- struct timespec * timeo);
-
-void proc_entry_wake(struct proc_entry * e,
- struct reg_entry * re);
-
-void proc_entry_cancel(struct proc_entry * e);
-
-int proc_entry_add_name(struct proc_entry * e,
- char * name);
-
-void proc_entry_del_name(struct proc_entry * e,
- const char * name);
-
-int proc_table_add(struct list_head * proc_table,
- struct proc_entry * e);
-
-void proc_table_del(struct list_head * proc_table,
- pid_t pid);
-
-struct proc_entry * proc_table_get(struct list_head * proc_table,
- pid_t pid);
-
-#endif /* OUROBOROS_IRMD_PROC_TABLE_H */
diff --git a/src/irmd/prog_table.c b/src/irmd/prog_table.c
deleted file mode 100644
index 0dd8201b..00000000
--- a/src/irmd/prog_table.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Program Table
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#include <ouroboros/errno.h>
-#include <ouroboros/irm.h>
-
-#include "prog_table.h"
-#include "utils.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-struct prog_entry * prog_entry_create(char * progn,
- char * prog,
- uint32_t flags,
- char ** argv)
-{
- struct prog_entry * e;
-
- assert(progn);
- assert(prog);
-
- e = malloc(sizeof(*e));
- if (e == NULL)
- return NULL;
-
- list_head_init(&e->next);
- list_head_init(&e->names);
-
- e->progn = progn;
- e->prog = prog;
- e->flags = flags;
-
- if (flags & BIND_AUTO) {
- e->argv = argv;
- } else {
- e->argv = NULL;
- argvfree(argv);
- argv = NULL;
- }
-
- return e;
-}
-void prog_entry_destroy(struct prog_entry * e)
-{
- struct list_head * p = NULL;
- struct list_head * h = NULL;
-
- if (e == NULL)
- return;
-
- if (e->progn != NULL)
- free(e->progn);
-
- if (e->prog != NULL)
- free(e->prog);
-
- if (e->argv != NULL)
- argvfree(e->argv);
-
- list_for_each_safe(p, h, &e->names) {
- struct str_el * s = list_entry(p, struct str_el, next);
- list_del(&s->next);
- free(s->str);
- free(s);
- }
-
- free(e);
-}
-
-int prog_entry_add_name(struct prog_entry * e,
- char * name)
-{
- struct str_el * s;
-
- if (e == NULL || name == NULL)
- return -EINVAL;
-
- s = malloc(sizeof(*s));
- if (s == NULL)
- return -ENOMEM;
-
- s->str = name;
- list_add(&s->next, &e->names);
-
- return 0;
-}
-
-void prog_entry_del_name(struct prog_entry * e,
- char * name)
-{
- struct list_head * p = NULL;
- struct list_head * h = NULL;
-
- list_for_each_safe(p, h, &e->names) {
- struct str_el * s = list_entry(p, struct str_el, next);
- if (!strcmp(name, s->str)) {
- list_del(&s->next);
- if (s->str != NULL)
- free(s->str);
- free(s);
- }
- }
-}
-
-int prog_table_add(struct list_head * prog_table,
- struct prog_entry * e)
-{
- assert(prog_table);
- assert(e);
-
- list_add(&e->next, prog_table);
-
- return 0;
-}
-
-void prog_table_del(struct list_head * prog_table,
- char * prog)
-{
- struct list_head * p;
- struct list_head * h;
-
- assert(prog_table);
- assert(prog);
-
- list_for_each_safe(p, h, prog_table) {
- struct prog_entry * e = list_entry(p, struct prog_entry, next);
- if (!strcmp(prog, e->prog)) {
- list_del(&e->next);
- prog_entry_destroy(e);
- }
- }
-}
-
-struct prog_entry * prog_table_get(struct list_head * prog_table,
- char * prog)
-{
- struct list_head * p;
-
- assert(prog_table);
- assert(prog);
-
- list_for_each(p, prog_table) {
- struct prog_entry * e = list_entry(p, struct prog_entry, next);
- if (!strcmp(e->prog, prog))
- return e;
- }
-
- return NULL;
-}
-
-struct prog_entry * prog_table_get_by_progn(struct list_head * prog_table,
- char * progn)
-{
- struct list_head * p;
-
- assert(prog_table);
- assert(progn);
-
- list_for_each(p, prog_table) {
- struct prog_entry * e = list_entry(p, struct prog_entry, next);
- if (!strcmp(e->progn, progn))
- return e;
- }
-
- return NULL;
-}
diff --git a/src/irmd/prog_table.h b/src/irmd/prog_table.h
deleted file mode 100644
index 63718646..00000000
--- a/src/irmd/prog_table.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Program Table
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IRMD_PROG_TABLE_H
-#define OUROBOROS_IRMD_PROG_TABLE_H
-
-#include <ouroboros/list.h>
-
-#include <unistd.h>
-#include <stdint.h>
-
-struct prog_entry {
- struct list_head next;
- char * progn; /* name for irmd */
- char * prog; /* name of binary */
- uint32_t flags;
- char ** argv;
- struct list_head names; /* names that all instances will listen for */
-};
-
-struct prog_entry * prog_entry_create(char * progn,
- char * prog,
- uint32_t flags,
- char ** argv);
-
-void prog_entry_destroy(struct prog_entry * e);
-
-int prog_entry_add_name(struct prog_entry * e,
- char * name);
-
-void prog_entry_del_name(struct prog_entry * e,
- char * name);
-
-int prog_table_add(struct list_head * prog_table,
- struct prog_entry * e);
-
-void prog_table_del(struct list_head * prog_table,
- char * prog);
-
-struct prog_entry * prog_table_get(struct list_head * prog_table,
- char * prog);
-
-struct prog_entry * prog_table_get_by_progn(struct list_head * prog_table,
- char * progn);
-
-#endif /* OUROBOROS_IRMD_PROG_TABLE_H */
diff --git a/src/irmd/reg/CMakeLists.txt b/src/irmd/reg/CMakeLists.txt
new file mode 100644
index 00000000..ff9d2e99
--- /dev/null
+++ b/src/irmd/reg/CMakeLists.txt
@@ -0,0 +1,7 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+add_subdirectory(tests)
diff --git a/src/irmd/reg/flow.c b/src/irmd/reg/flow.c
new file mode 100644
index 00000000..4d091b23
--- /dev/null
+++ b/src/irmd/reg/flow.c
@@ -0,0 +1,208 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Flows
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#define OUROBOROS_PREFIX "reg/flow"
+
+#include <ouroboros/logs.h>
+
+#include "flow.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct reg_flow * reg_flow_create(const struct flow_info * info)
+{
+ struct reg_flow * flow;
+
+ assert(info != NULL);
+ assert(info->id > 0);
+ assert(info->n_pid != 0);
+ assert(info->n_1_pid == 0);
+ assert(info->mpl == 0);
+ assert(info->state == FLOW_INIT);
+
+ flow = malloc(sizeof(*flow));
+ if (flow == NULL) {
+ log_err("Failed to malloc flow.");
+ goto fail_malloc;
+ }
+
+ memset(flow, 0, sizeof(*flow));
+
+ clock_gettime(PTHREAD_COND_CLOCK, &flow->t0);
+ list_head_init(&flow->next);
+
+ flow->info = *info;
+
+ return flow;
+
+ fail_malloc:
+ return NULL;
+}
+
+static void destroy_rbuffs(struct reg_flow * flow)
+{
+ if (flow->n_rb != NULL)
+ shm_rbuff_destroy(flow->n_rb);
+ flow->n_rb = NULL;
+
+ if (flow->n_1_rb != NULL)
+ shm_rbuff_destroy(flow->n_1_rb);
+ flow->n_1_rb = NULL;
+}
+
+void reg_flow_destroy(struct reg_flow * flow)
+{
+ assert(flow != NULL);
+
+ switch(flow->info.state) {
+ case FLOW_ACCEPT_PENDING:
+ clrbuf(flow->data);
+ /* FALLTHRU */
+ default:
+ destroy_rbuffs(flow);
+ break;
+ }
+
+ assert(flow->n_rb == NULL);
+ assert(flow->n_1_rb == NULL);
+ assert(flow->data.data == NULL);
+ assert(flow->data.len == 0);
+
+ assert(list_is_empty(&flow->next));
+
+ free(flow);
+}
+
+static int create_rbuffs(struct reg_flow * flow,
+ struct flow_info * info)
+{
+ assert(flow != NULL);
+ assert(info != NULL);
+
+ flow->n_rb = shm_rbuff_create(info->n_pid, info->id);
+ if (flow->n_rb == NULL)
+ goto fail_n_rb;
+
+ assert(flow->info.n_1_pid == 0);
+ assert(flow->n_1_rb == NULL);
+
+ flow->info.n_1_pid = info->n_1_pid;
+ flow->n_1_rb = shm_rbuff_create(info->n_1_pid, info->id);
+ if (flow->n_1_rb == NULL)
+ goto fail_n_1_rb;
+
+ return 0;
+
+ fail_n_1_rb:
+ shm_rbuff_destroy(flow->n_rb);
+ fail_n_rb:
+ return -ENOMEM;
+}
+
+int reg_flow_update(struct reg_flow * flow,
+ struct flow_info * info)
+{
+ assert(flow != NULL);
+ assert(info != NULL);
+
+ assert(flow->info.id == info->id);
+
+ switch(info->state) {
+ case FLOW_ACCEPT_PENDING:
+ assert(flow->info.state == FLOW_INIT);
+ flow->info.n_pid = info->n_pid;
+ break;
+ case FLOW_ALLOC_PENDING:
+ assert(flow->info.state == FLOW_INIT);
+ assert(info->n_1_pid != 0);
+
+ if (create_rbuffs(flow, info) < 0)
+ goto fail;
+
+ break;
+ case FLOW_ALLOCATED:
+ assert(info->n_1_pid != 0);
+ assert(flow->info.state > FLOW_INIT);
+ assert(flow->info.state < FLOW_ALLOCATED);
+ assert(flow->info.n_pid != 0);
+ assert(info->mpl != 0);
+
+ flow->info.mpl = info->mpl;
+
+ if (flow->info.state == FLOW_ALLOC_PENDING)
+ break;
+
+ flow->info.qs = info->qs;
+
+ if (create_rbuffs(flow, info) < 0)
+ goto fail;
+ break;
+ case FLOW_DEALLOCATED:
+ destroy_rbuffs(flow);
+ break;
+ case FLOW_DEALLOC_PENDING:
+ break;
+ default:
+ assert(false);
+ return -EPERM;
+ }
+
+ flow->info.state = info->state;
+
+ *info = flow->info;
+
+ return 0;
+ fail:
+ return -ENOMEM;
+}
+
+void reg_flow_set_data(struct reg_flow * flow,
+ const buffer_t * buf)
+{
+ assert(flow != NULL);
+ assert(buf != NULL);
+ assert(flow->data.data == NULL);
+ assert(flow->data.len == 0);
+
+ flow->data = *buf;
+}
+
+void reg_flow_get_data(struct reg_flow * flow,
+ buffer_t * buf)
+{
+ assert(flow != NULL);
+ assert(buf != NULL);
+
+ *buf = flow->data;
+
+ clrbuf(flow->data);
+}
+
+void reg_flow_free_data(struct reg_flow * flow)
+{
+ freebuf(flow->data);
+}
diff --git a/src/irmd/reg/flow.h b/src/irmd/reg/flow.h
new file mode 100644
index 00000000..75ada971
--- /dev/null
+++ b/src/irmd/reg/flow.h
@@ -0,0 +1,63 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Flows
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_REG_FLOW_H
+#define OUROBOROS_IRMD_REG_FLOW_H
+
+#include <ouroboros/list.h>
+#include <ouroboros/flow.h>
+#include <ouroboros/pthread.h>
+#include <ouroboros/qos.h>
+#include <ouroboros/shm_rbuff.h>
+#include <ouroboros/utils.h>
+
+#include <sys/types.h>
+#include <time.h>
+
+struct reg_flow {
+ struct list_head next;
+
+ struct flow_info info;
+
+ buffer_t data;
+ struct timespec t0;
+
+ struct shm_rbuff * n_rb;
+ struct shm_rbuff * n_1_rb;
+};
+
+struct reg_flow * reg_flow_create(const struct flow_info * info);
+
+void reg_flow_destroy(struct reg_flow * flow);
+
+int reg_flow_update(struct reg_flow * flow,
+ struct flow_info * info);
+
+void reg_flow_set_data(struct reg_flow * flow,
+ const buffer_t * buf);
+
+void reg_flow_get_data(struct reg_flow * flow,
+ buffer_t * buf);
+
+void reg_flow_free_data(struct reg_flow * flow);
+
+#endif /* OUROBOROS_IRMD_REG_FLOW_H */
diff --git a/src/irmd/reg/ipcp.c b/src/irmd/reg/ipcp.c
new file mode 100644
index 00000000..6580cb5b
--- /dev/null
+++ b/src/irmd/reg/ipcp.c
@@ -0,0 +1,92 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - IPCPs
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#define OUROBOROS_PREFIX "reg/ipcp"
+
+#include <ouroboros/logs.h>
+#include <ouroboros/time.h>
+
+#include "ipcp.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct reg_ipcp * reg_ipcp_create(const struct ipcp_info * info)
+{
+ struct reg_ipcp * ipcp;
+
+ assert(info != NULL);
+ assert(info->state == IPCP_BOOT);
+
+ ipcp = malloc(sizeof(*ipcp));
+ if (ipcp == NULL) {
+ log_err("Failed to malloc ipcp.");
+ goto fail_malloc;
+ }
+
+ memset(ipcp, 0, sizeof(*ipcp));
+ memset(&ipcp->layer, 0, sizeof(ipcp->layer));
+
+ list_head_init(&ipcp->next);
+
+ ipcp->info = *info;
+ ipcp->info.state = IPCP_BOOT;
+
+ strcpy(ipcp->layer.name, "Not enrolled.");
+
+ return ipcp;
+
+ fail_malloc:
+ return NULL;
+}
+
+void reg_ipcp_destroy(struct reg_ipcp * ipcp)
+{
+ assert(ipcp != NULL);
+
+ assert(list_is_empty(&ipcp->next));
+
+ free(ipcp);
+}
+
+void reg_ipcp_update(struct reg_ipcp * ipcp,
+ const struct ipcp_info * info)
+{
+ assert(ipcp != NULL);
+ assert(info->state != IPCP_INIT);
+
+ ipcp->info = *info;
+}
+
+void reg_ipcp_set_layer(struct reg_ipcp * ipcp,
+ const struct layer_info * info)
+{
+ assert(ipcp != NULL);
+ assert(ipcp->info.state == IPCP_OPERATIONAL);
+
+ ipcp->layer = *info;
+}
diff --git a/src/irmd/reg/ipcp.h b/src/irmd/reg/ipcp.h
new file mode 100644
index 00000000..375973a7
--- /dev/null
+++ b/src/irmd/reg/ipcp.h
@@ -0,0 +1,47 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - IPCPs
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_REG_IPCP_H
+#define OUROBOROS_IRMD_REG_IPCP_H
+
+#include <ouroboros/list.h>
+#include <ouroboros/ipcp.h>
+
+struct reg_ipcp {
+ struct list_head next;
+
+ struct ipcp_info info;
+
+ struct layer_info layer;
+};
+
+struct reg_ipcp * reg_ipcp_create(const struct ipcp_info * info);
+
+void reg_ipcp_destroy(struct reg_ipcp * ipcp);
+
+void reg_ipcp_update(struct reg_ipcp * ipcp,
+ const struct ipcp_info * info);
+
+void reg_ipcp_set_layer(struct reg_ipcp * ipcp,
+ const struct layer_info * info);
+
+#endif /* OUROBOROS_IRMD_REG_IPCP_H */
diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c
new file mode 100644
index 00000000..1ac939a5
--- /dev/null
+++ b/src/irmd/reg/name.c
@@ -0,0 +1,375 @@
+
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Names
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#define OUROBOROS_PREFIX "reg/name"
+
+#include <ouroboros/logs.h>
+#include <ouroboros/utils.h>
+
+#include "name.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct prog_entry {
+ struct list_head next;
+ char ** exec;
+};
+
+struct proc_entry {
+ struct list_head next;
+ pid_t pid;
+};
+
+static void __free_prog_entry(struct prog_entry * entry)
+{
+ assert(entry != NULL);
+ assert(entry->exec != NULL);
+
+ argvfree(entry->exec);
+ free(entry);
+}
+
+struct reg_name * reg_name_create(const struct name_info * info)
+{
+ struct reg_name * name;
+
+ assert(info != NULL);
+
+ name = malloc(sizeof(*name));
+ if (name == NULL) {
+ log_err("Failed to malloc name.");
+ goto fail_malloc;
+ }
+
+ list_head_init(&name->next);
+ list_head_init(&name->progs);
+ list_head_init(&name->procs);
+ list_head_init(&name->active);
+
+ name->info = *info;
+ name->n_progs = 0;
+ name->n_procs = 0;
+ name->n_active = 0;
+
+ return name;
+
+ fail_malloc:
+ return NULL;
+}
+
+void reg_name_destroy(struct reg_name * name)
+{
+ assert(name != NULL);
+
+ assert(list_is_empty(&name->next));
+
+ assert(name->n_progs == 0);
+ assert(name->n_procs == 0);
+ assert(name->n_active == 0);
+
+ assert(list_is_empty(&name->progs));
+ assert(list_is_empty(&name->procs));
+ assert(list_is_empty(&name->active));
+
+ free(name);
+}
+
+static struct proc_entry * __reg_name_get_active(const struct reg_name * name,
+ pid_t pid)
+{
+ struct list_head * p;
+
+ assert(name != NULL);
+ assert(pid > 0);
+
+ list_for_each(p, &name->active) {
+ struct proc_entry * entry;
+ entry = list_entry(p, struct proc_entry, next);
+ if (entry->pid == pid)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static void __reg_name_del_all_active(struct reg_name * name,
+ pid_t pid)
+{
+ struct list_head * p;
+ struct list_head * h;
+
+ list_for_each_safe(p, h, &name->active) {
+ struct proc_entry * entry;
+ entry = list_entry(p, struct proc_entry, next);
+ if (entry->pid == pid) {
+ list_del(&entry->next);
+ free(entry);
+ name->n_active--;
+ }
+ }
+}
+
+static struct proc_entry * __reg_name_get_proc(const struct reg_name * name,
+ pid_t pid)
+{
+ struct list_head * p;
+
+ assert(name != NULL);
+ assert(pid > 0);
+
+ list_for_each(p, &name->procs) {
+ struct proc_entry * entry;
+ entry = list_entry(p, struct proc_entry, next);
+ if (entry->pid == pid)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct prog_entry * __reg_name_get_prog(const struct reg_name * name,
+ const char * prog)
+{
+ struct list_head * p;
+
+ assert(name != NULL);
+ assert(prog != NULL);
+
+ list_for_each(p, &name->progs) {
+ struct prog_entry * entry;
+ entry = list_entry(p, struct prog_entry, next);
+ if (strcmp(entry->exec[0], prog) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+int reg_name_add_active(struct reg_name * name,
+ pid_t pid)
+{
+ struct proc_entry * entry;
+
+ assert(name != NULL);
+ assert(pid > 0);
+
+ assert(__reg_name_get_proc(name, pid) != NULL);
+
+ log_dbg("Process %d accepting flows for %s.", pid, name->info.name);
+
+ if (__reg_name_get_active(name, pid) != NULL)
+ log_dbg("Process calling accept from multiple threads.");
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to malloc active.");
+ goto fail_malloc;
+ }
+
+ entry->pid = pid;
+
+ switch (name->info.pol_lb) {
+ case LB_RR: /* Round robin policy. */
+ list_add_tail(&entry->next, &name->active);
+ break;
+ case LB_SPILL: /* Keep accepting flows on the current process */
+ list_add(&entry->next, &name->active);
+ break;
+ default:
+ goto fail_unreachable;
+ }
+
+ name->n_active++;
+
+ return 0;
+
+ fail_unreachable:
+ free(entry);
+ assert(false);
+ fail_malloc:
+ return -1;
+}
+
+void reg_name_del_active(struct reg_name * name,
+ pid_t pid)
+{
+ struct proc_entry * entry;
+
+ entry = __reg_name_get_active(name, pid);
+ if (entry == NULL)
+ return;
+
+ list_del(&entry->next);
+
+ name->n_active--;
+
+ free(entry);
+}
+
+pid_t reg_name_get_active(struct reg_name * name)
+{
+ assert(name != NULL);
+
+ if (list_is_empty(&name->active))
+ return -1;
+
+ return list_first_entry(&name->active, struct proc_entry, next)->pid;
+}
+
+int reg_name_add_proc(struct reg_name * name,
+ pid_t pid)
+{
+ struct proc_entry * entry;
+
+ assert(name != NULL);
+ assert(pid > 0);
+
+ assert(__reg_name_get_proc(name, pid) == NULL);
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to malloc proc.");
+ goto fail_malloc;
+ }
+
+ entry->pid = pid;
+
+ list_add(&entry->next, &name->procs);
+
+ name->n_procs++;
+
+ return 0;
+
+ fail_malloc:
+ return -1;
+}
+
+void reg_name_del_proc(struct reg_name * name,
+ pid_t pid)
+{
+ struct proc_entry * entry;
+
+ assert(name != NULL);
+ assert(pid > 0);
+
+ entry = __reg_name_get_proc(name, pid);
+ if (entry == NULL)
+ return;
+
+ __reg_name_del_all_active(name, pid);
+
+ list_del(&entry->next);
+
+ free(entry);
+
+ name->n_procs--;
+
+ assert(__reg_name_get_proc(name, pid) == NULL);
+}
+
+bool reg_name_has_proc(const struct reg_name * name,
+ pid_t pid)
+{
+ return __reg_name_get_proc(name, pid) != NULL;
+} char ** exec;
+
+
+int reg_name_add_prog(struct reg_name * name,
+ char ** exec)
+{
+ struct prog_entry * entry;
+
+ assert(name != NULL);
+ assert(exec != NULL);
+ assert(exec[0] != NULL);
+
+ assert(__reg_name_get_prog(name, exec[0]) == NULL);
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to malloc prog.");
+ goto fail_malloc;
+ }
+
+ entry->exec = argvdup(exec);
+ if (entry->exec == NULL) {
+ log_err("Failed to argvdup prog.");
+ goto fail_exec;
+ }
+
+ list_add(&entry->next, &name->progs);
+
+ log_dbg("Add prog %s to name %s.", exec[0], name->info.name);
+
+ name->n_progs++;
+
+ return 0;
+
+ fail_exec:
+ free(entry);
+ fail_malloc:
+ return -1;
+}
+
+void reg_name_del_prog(struct reg_name * name,
+ const char * prog)
+{
+ struct prog_entry * entry;
+
+ assert(name != NULL);
+ assert(prog != NULL);
+
+ entry = __reg_name_get_prog(name, prog);
+ if (entry == NULL)
+ return;
+
+ list_del(&entry->next);
+
+ __free_prog_entry(entry);
+
+ name->n_progs--;
+
+ assert(__reg_name_get_prog(name, prog) == NULL);
+}
+
+bool reg_name_has_prog(const struct reg_name * name,
+ const char * prog)
+{
+ assert(name != NULL);
+ assert(prog != NULL);
+
+ return __reg_name_get_prog(name, prog) != NULL;
+}
+
+char ** reg_name_get_exec(const struct reg_name * name)
+{
+ if (list_is_empty(&name->progs))
+ return NULL;
+
+ return list_first_entry(&name->progs, struct prog_entry, next)->exec;
+}
diff --git a/src/irmd/reg/name.h b/src/irmd/reg/name.h
new file mode 100644
index 00000000..97ca7f04
--- /dev/null
+++ b/src/irmd/reg/name.h
@@ -0,0 +1,78 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Names
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_REG_NAME_H
+#define OUROBOROS_IRMD_REG_NAME_H
+
+#include <ouroboros/list.h>
+#include <ouroboros/name.h>
+
+#define BIND_AUTO 0x01
+
+struct reg_name {
+ struct list_head next;
+
+ struct name_info info;
+
+ struct list_head progs; /* autostart programs for this name */
+ size_t n_progs; /* number of programs */
+
+ struct list_head procs; /* processes bound to this name */
+ size_t n_procs; /* number of processes */
+
+ struct list_head active; /* processes actively calling accept */
+ size_t n_active; /* number of processes accepting */
+};
+
+struct reg_name * reg_name_create(const struct name_info * info);
+
+void reg_name_destroy(struct reg_name * name);
+
+int reg_name_add_proc(struct reg_name * name,
+ pid_t proc);
+
+void reg_name_del_proc(struct reg_name * name,
+ pid_t proc);
+
+bool reg_name_has_proc(const struct reg_name * name,
+ pid_t proc);
+
+int reg_name_add_prog(struct reg_name * name,
+ char ** exec);
+
+void reg_name_del_prog(struct reg_name * name,
+ const char * prog);
+
+bool reg_name_has_prog(const struct reg_name * name,
+ const char * prog);
+
+char ** reg_name_get_exec(const struct reg_name * name);
+
+int reg_name_add_active(struct reg_name * name,
+ pid_t proc);
+
+pid_t reg_name_get_active(struct reg_name * name);
+
+void reg_name_del_active(struct reg_name * name,
+ pid_t proc);
+
+#endif /* OUROBOROS_IRMD_REG_NAME_H */
diff --git a/src/irmd/reg/proc.c b/src/irmd/reg/proc.c
new file mode 100644
index 00000000..9bbdf0eb
--- /dev/null
+++ b/src/irmd/reg/proc.c
@@ -0,0 +1,183 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Processes
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This procram is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This procram is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this procram; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#define OUROBOROS_PREFIX "reg/proc"
+
+#include <ouroboros/logs.h>
+
+#include "proc.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct name_entry {
+ struct list_head next;
+ char * name;
+};
+
+static void __free_name_entry(struct name_entry * entry)
+{
+ assert(entry != NULL);
+ assert(entry->name != NULL);
+
+ free(entry->name);
+ free(entry);
+}
+
+static void __reg_proc_clear_names(struct reg_proc * proc)
+{
+ struct list_head * p;
+ struct list_head * h;
+
+ assert(proc != NULL);
+
+ list_for_each_safe(p, h, &proc->names) {
+ struct name_entry * entry;
+ entry = list_entry(p, struct name_entry, next);
+ list_del(&entry->next);
+ __free_name_entry(entry);
+ proc->n_names--;
+ }
+}
+
+struct reg_proc * reg_proc_create(const struct proc_info * info)
+{
+ struct reg_proc * proc;
+
+ assert(info != NULL);
+
+ proc = malloc(sizeof(*proc));
+ if (proc == NULL) {
+ log_err("Failed to malloc proc.");
+ goto fail_malloc;
+ }
+
+ proc->set = shm_flow_set_create(info->pid);
+ if (proc->set == NULL) {
+ log_err("Failed to create flow set for %d.", info->pid);
+ goto fail_set;
+ }
+
+ list_head_init(&proc->next);
+ list_head_init(&proc->names);
+
+ proc->info = *info;
+ proc->n_names = 0;
+
+ return proc;
+
+ fail_set:
+ free(proc);
+ fail_malloc:
+ return NULL;
+}
+
+void reg_proc_destroy(struct reg_proc * proc)
+{
+ assert(proc != NULL);
+
+ shm_flow_set_destroy(proc->set);
+
+ __reg_proc_clear_names(proc);
+
+ assert(list_is_empty(&proc->next));
+
+ assert(proc->n_names == 0);
+
+ assert(list_is_empty(&proc->names));
+
+ free(proc);
+}
+
+static struct name_entry * __reg_proc_get_name(const struct reg_proc * proc,
+ const char * name)
+{
+ struct list_head * p;
+
+ list_for_each(p, &proc->names) {
+ struct name_entry * entry;
+ entry = list_entry(p, struct name_entry, next);
+ if (strcmp(entry->name, name) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+int reg_proc_add_name(struct reg_proc * proc,
+ const char * name)
+{
+ struct name_entry * entry;
+
+ assert(__reg_proc_get_name(proc, name) == NULL);
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to malloc name.");
+ goto fail_malloc;
+ }
+
+ entry->name = strdup(name);
+ if (entry == NULL) {
+ log_err("Failed to strdup name.");
+ goto fail_name;
+ }
+
+ list_add(&entry->next, &proc->names);
+
+ proc->n_names++;
+
+ return 0;
+
+ fail_name:
+ free(entry);
+ fail_malloc:
+ return -1;
+}
+
+void reg_proc_del_name(struct reg_proc * proc,
+ const char * name)
+{
+ struct name_entry * entry;
+
+ entry = __reg_proc_get_name(proc, name);
+ if(entry == NULL)
+ return;
+
+ list_del(&entry->next);
+
+ __free_name_entry(entry);
+
+ proc->n_names--;
+
+ assert(__reg_proc_get_name(proc, name) == NULL);
+}
+
+bool reg_proc_has_name(const struct reg_proc * proc,
+ const char * name)
+{
+ return __reg_proc_get_name(proc, name) != NULL;
+}
diff --git a/src/irmd/reg/proc.h b/src/irmd/reg/proc.h
new file mode 100644
index 00000000..99f74fef
--- /dev/null
+++ b/src/irmd/reg/proc.h
@@ -0,0 +1,56 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Processes
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_REG_PROC_H
+#define OUROBOROS_IRMD_REG_PROC_H
+
+#include <ouroboros/list.h>
+#include <ouroboros/proc.h>
+#include <ouroboros/shm_flow_set.h>
+
+struct reg_proc {
+ struct list_head next;
+
+ struct proc_info info;
+
+ struct list_head names; /* names for which process accepts flows */
+ size_t n_names; /* number of names */
+
+ struct shm_flow_set * set;
+};
+
+struct reg_proc * reg_proc_create(const struct proc_info * info);
+
+void reg_proc_destroy(struct reg_proc * proc);
+
+void reg_proc_clear(struct reg_proc * proc);
+
+int reg_proc_add_name(struct reg_proc * proc,
+ const char * name);
+
+void reg_proc_del_name(struct reg_proc * proc,
+ const char * name);
+
+bool reg_proc_has_name(const struct reg_proc * proc,
+ const char * name);
+
+#endif /* OUROBOROS_IRMD_REG_PROC_H */
diff --git a/src/irmd/reg/prog.c b/src/irmd/reg/prog.c
new file mode 100644
index 00000000..9b9e7510
--- /dev/null
+++ b/src/irmd/reg/prog.c
@@ -0,0 +1,174 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Programs
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#define OUROBOROS_PREFIX "reg/prog"
+
+#include <ouroboros/logs.h>
+#include <ouroboros/utils.h>
+
+#include "prog.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct name_entry {
+ struct list_head next;
+ char * name;
+};
+
+static void __free_name_entry(struct name_entry * entry)
+{
+ assert(entry != NULL);
+ assert(entry->name != NULL);
+
+ free(entry->name);
+ free(entry);
+}
+
+static void __reg_prog_clear_names(struct reg_prog * prog)
+{
+ struct list_head * p;
+ struct list_head * h;
+
+ assert(prog != NULL);
+
+ list_for_each_safe(p, h, &prog->names) {
+ struct name_entry * entry;
+ entry = list_entry(p, struct name_entry, next);
+ list_del(&entry->next);
+ __free_name_entry(entry);
+ prog->n_names--;
+ }
+}
+
+struct reg_prog * reg_prog_create(const struct prog_info * info)
+{
+ struct reg_prog * p;
+
+ assert(info != NULL);
+
+ p = malloc(sizeof(*p));
+ if (p == NULL) {
+ log_err("Failed to malloc prog.");
+ goto fail_malloc;
+ }
+
+ list_head_init(&p->next);
+ list_head_init(&p->names);
+
+ p->info = *info;
+ p->n_names = 0;
+
+ return p;
+
+ fail_malloc:
+ return NULL;
+}
+
+void reg_prog_destroy(struct reg_prog * prog)
+{
+ assert(prog != NULL);
+
+ __reg_prog_clear_names(prog);
+
+ assert(list_is_empty(&prog->next));
+
+ assert(prog->n_names == 0);
+
+ assert(list_is_empty(&prog->names));
+
+ free(prog);
+}
+
+static struct name_entry * __reg_prog_get_name(const struct reg_prog * prog,
+ const char * name)
+{
+ struct list_head * p;
+
+ list_for_each(p, &prog->names) {
+ struct name_entry * entry;
+ entry = list_entry(p, struct name_entry, next);
+ if (strcmp(entry->name, name) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+int reg_prog_add_name(struct reg_prog * prog,
+ const char * name)
+{
+ struct name_entry * entry;
+
+ assert(__reg_prog_get_name(prog, name) == NULL);
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to malloc name.");
+ goto fail_malloc;
+ }
+
+ entry->name = strdup(name);
+ if (entry == NULL) {
+ log_err("Failed to strdup name.");
+ goto fail_name;
+ }
+
+ list_add(&entry->next, &prog->names);
+
+ prog->n_names++;
+
+ return 0;
+
+ fail_name:
+ free(entry);
+ fail_malloc:
+ return -1;
+}
+
+void reg_prog_del_name(struct reg_prog * prog,
+ const char * name)
+{
+ struct name_entry * entry;
+
+ entry = __reg_prog_get_name(prog, name);
+ if (entry == NULL)
+ return;
+
+ list_del(&entry->next);
+
+ __free_name_entry(entry);
+
+ prog->n_names--;
+
+ assert(__reg_prog_get_name(prog, name) == NULL);
+}
+
+bool reg_prog_has_name(const struct reg_prog * prog,
+ const char * name)
+{
+ return __reg_prog_get_name(prog, name) != NULL;
+}
diff --git a/src/irmd/reg/prog.h b/src/irmd/reg/prog.h
new file mode 100644
index 00000000..a98fc6a1
--- /dev/null
+++ b/src/irmd/reg/prog.h
@@ -0,0 +1,53 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Programs
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_REG_PROG_H
+#define OUROBOROS_IRMD_REG_PROG_H
+
+#include <ouroboros/list.h>
+#include <ouroboros/proc.h>
+
+#include <stdint.h>
+
+struct reg_prog {
+ struct list_head next;
+
+ struct prog_info info;
+
+ struct list_head names; /* names to listen for */
+ size_t n_names; /* number of names in list */
+ };
+
+struct reg_prog * reg_prog_create(const struct prog_info * info);
+
+void reg_prog_destroy(struct reg_prog * prog);
+
+int reg_prog_add_name(struct reg_prog * prog,
+ const char * name);
+
+void reg_prog_del_name(struct reg_prog * prog,
+ const char * name);
+
+bool reg_prog_has_name(const struct reg_prog * prog,
+ const char * name);
+
+#endif /* OUROBOROS_IRMD_REG_PROG_H */
diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c
new file mode 100644
index 00000000..d95a4722
--- /dev/null
+++ b/src/irmd/reg/reg.c
@@ -0,0 +1,2120 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+The IPC Resource Manager - Registry
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#define OUROBOROS_PREFIX "reg"
+
+#include <ouroboros/bitmap.h>
+#include <ouroboros/errno.h>
+#include <ouroboros/list.h>
+#include <ouroboros/logs.h>
+#include <ouroboros/pthread.h>
+
+#include "reg.h"
+#include "flow.h"
+#include "ipcp.h"
+#include "name.h"
+#include "proc.h"
+#include "prog.h"
+
+#include <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ID_OFFT 1 /* reserve some flow_ids */
+
+struct {
+ struct bmp * flow_ids; /* flow_ids for flows */
+ struct list_head flows; /* flow information */
+ size_t n_flows; /* number of flows */
+
+ struct list_head ipcps; /* list of ipcps in system */
+ size_t n_ipcps; /* number of ipcps */
+
+ struct list_head names; /* registered names known */
+ size_t n_names; /* number of names */
+
+ struct list_head procs; /* processes */
+ size_t n_procs; /* number of processes */
+
+ struct list_head progs; /* programs known */
+ size_t n_progs; /* number of programs */
+
+ struct list_head spawned; /* child processes */
+ size_t n_spawned; /* number of child processes */
+
+ pthread_mutex_t mtx; /* registry lock */
+ pthread_cond_t cond; /* condvar for reg changes */
+} reg;
+
+struct pid_entry {
+ struct list_head next;
+ pid_t pid;
+};
+
+static struct reg_flow * __reg_get_flow(int flow_id)
+{
+ struct list_head * p;
+
+ assert(flow_id >= ID_OFFT);
+
+ list_for_each(p, &reg.flows) {
+ struct reg_flow * entry;
+ entry = list_entry(p, struct reg_flow, next);
+ if (entry->info.id == flow_id)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct reg_flow * __reg_get_accept_flow(pid_t pid)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.flows) {
+ struct reg_flow * entry;
+ entry = list_entry(p, struct reg_flow, next);
+ if (entry->info.state != FLOW_ACCEPT_PENDING)
+ continue;
+ if (entry->info.n_pid == pid)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct list_head * __reg_after_flow(int flow_id)
+{
+ struct list_head * p;
+
+ assert(flow_id >= ID_OFFT);
+
+ list_for_each(p, &reg.flows) {
+ struct reg_flow * entry;
+ entry = list_entry(p, struct reg_flow, next);
+ if (entry->info.id > flow_id)
+ break;
+ }
+
+ return p;
+}
+
+static struct reg_ipcp * __reg_get_ipcp(pid_t pid)
+{
+ struct list_head * p;
+
+ assert(pid > 0);
+
+ list_for_each(p, &reg.ipcps) {
+ struct reg_ipcp * entry;
+ entry = list_entry(p, struct reg_ipcp, next);
+ if (entry->info.pid == pid)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct reg_ipcp * __reg_get_ipcp_by_layer(const char * layer)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.ipcps) {
+ struct reg_ipcp * entry;
+ entry = list_entry(p, struct reg_ipcp, next);
+ if (strcmp(entry->layer.name, layer) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct list_head * __reg_after_ipcp(pid_t pid)
+{
+ struct list_head * p;
+
+ assert(pid > 0);
+
+ list_for_each(p, &reg.ipcps) {
+ struct reg_ipcp * entry;
+ entry = list_entry(p, struct reg_ipcp, next);
+ if (entry->info.pid > pid)
+ break;
+ }
+
+ return p;
+}
+
+static struct reg_name * __reg_get_name(const char * name)
+{
+ struct list_head * p;
+
+ assert(name != NULL);
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * entry;
+ entry = list_entry(p, struct reg_name, next);
+ if (strcmp(entry->info.name, name) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct reg_name * __reg_get_name_by_hash(enum hash_algo algo,
+ const uint8_t * hash)
+{
+ struct list_head * p;
+ uint8_t * thash;
+ size_t len;
+
+ len = hash_len(algo);
+
+ thash = malloc(len);
+ if (thash == NULL)
+ return NULL;
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * n = list_entry(p, struct reg_name, next);
+ str_hash(algo, thash, n->info.name);
+ if (memcmp(thash, hash, len) == 0) {
+ free(thash);
+ return n;
+ }
+ }
+
+ free(thash);
+
+ return NULL;
+}
+
+static int __reg_get_pending_flow_id_for_hash(enum hash_algo algo,
+ const uint8_t * hash)
+{
+ struct reg_name * entry;
+ struct reg_flow * flow;
+ pid_t pid;
+
+ entry =__reg_get_name_by_hash(algo, hash);
+ if (entry == NULL)
+ return -ENAME;
+
+ pid = reg_name_get_active(entry);
+ if (pid < 0)
+ return -EAGAIN;
+
+ flow = __reg_get_accept_flow(pid);
+ assert(flow != NULL);
+
+ return flow->info.id;
+}
+
+static struct list_head * __reg_after_name(const char * name)
+{
+ struct list_head * p;
+
+ assert(name != NULL);
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * entry;
+ entry = list_entry(p, struct reg_name, next);
+ if (strcmp(entry->info.name, name) > 0)
+ break;
+ }
+
+ return p;
+}
+
+static struct reg_proc * __reg_get_proc(pid_t pid)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.procs) {
+ struct reg_proc * entry;
+ entry = list_entry(p, struct reg_proc, next);
+ if (entry->info.pid == pid)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct list_head * __reg_after_proc(pid_t pid)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.procs) {
+ struct reg_proc * entry;
+ entry = list_entry(p, struct reg_proc, next);
+ if (entry->info.pid > pid)
+ break;
+ }
+
+ return p;
+}
+
+static void __reg_kill_all_proc(int signal)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.procs) {
+ struct reg_proc * entry;
+ entry = list_entry(p, struct reg_proc, next);
+ kill(entry->info.pid, signal);
+ }
+}
+
+static pid_t __reg_get_dead_proc(void)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.procs) {
+ struct reg_proc * entry;
+ entry = list_entry(p, struct reg_proc, next);
+ if (kill(entry->info.pid, 0) < 0)
+ return entry->info.pid;
+ }
+
+ return -1;
+}
+
+static void __reg_cancel_flows_for_proc(pid_t pid)
+{
+ struct list_head * p;
+ bool changed = false;
+
+ list_for_each(p, &reg.flows) {
+ struct reg_flow * entry;
+ entry = list_entry(p, struct reg_flow, next);
+ if (entry->info.n_pid != pid)
+ continue;
+
+ switch (entry->info.state) {
+ case FLOW_ALLOC_PENDING:
+ /* FALLTHRU */
+ case FLOW_ACCEPT_PENDING:
+ entry->info.state = FLOW_DEALLOCATED;
+ changed = true;
+ break;
+ default:
+ continue;
+ }
+ }
+
+ if (changed)
+ pthread_cond_broadcast(&reg.cond);
+}
+
+static struct pid_entry * __reg_get_spawned(pid_t pid)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.spawned) {
+ struct pid_entry * entry;
+ entry = list_entry(p, struct pid_entry, next);
+ if (entry->pid == pid)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct list_head * __reg_after_spawned(pid_t pid)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.spawned) {
+ struct pid_entry * entry;
+ entry = list_entry(p, struct pid_entry, next);
+ if (entry->pid > pid)
+ break;
+ }
+
+ return p;
+}
+
+static void __reg_kill_all_spawned(int signal)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.spawned) {
+ struct pid_entry * entry;
+ entry = list_entry(p, struct pid_entry, next);
+ kill(entry->pid, signal);
+ }
+}
+
+static pid_t __reg_first_spawned(void)
+{
+ if (list_is_empty(&reg.spawned))
+ return -1;
+
+ return list_first_entry(&reg.spawned, struct pid_entry, next)->pid;
+}
+
+static struct reg_prog * __reg_get_prog(const char * name)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.progs) {
+ struct reg_prog * entry;
+ entry = list_entry(p, struct reg_prog, next);
+ if (strcmp(entry->info.name, name) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static char ** __reg_get_exec(enum hash_algo algo,
+ const uint8_t * hash)
+{
+ struct list_head * p;
+ uint8_t * buf;
+
+ buf = malloc(hash_len(algo));
+ if (buf == NULL) {
+ log_err("Failed to malloc hash buffer.");
+ return NULL;
+ }
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * entry;
+ entry = list_entry(p, struct reg_name, next);
+ str_hash(algo, buf, entry->info.name);
+ if (memcmp(buf, hash, hash_len(algo)) == 0) {
+ free(buf);
+ return reg_name_get_exec(entry);
+ }
+ }
+
+ free(buf);
+
+ return NULL;
+}
+
+static struct list_head * __reg_after_prog(const char * name)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.progs) {
+ struct reg_prog * entry;
+ entry = list_entry(p, struct reg_prog, next);
+ if (strcmp(entry->info.name, name) > 0)
+ break;
+ }
+
+ return p;
+}
+
+static void __reg_del_name_from_procs(const char * name)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.procs) {
+ struct reg_proc * proc;
+ proc = list_entry(p, struct reg_proc, next);
+ reg_proc_del_name(proc, name);
+ }
+}
+
+static void __reg_del_name_from_progs(const char * name)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.progs) {
+ struct reg_prog * prog;
+ prog = list_entry(p, struct reg_prog, next);
+ reg_prog_del_name(prog, name);
+ }
+}
+
+static void __reg_proc_update_names(struct reg_proc * proc)
+{
+ struct list_head * p;
+ struct reg_prog * prog;
+
+ assert(list_is_empty(&proc->names));
+
+ prog = __reg_get_prog(proc->info.prog);
+ if (prog == NULL)
+ return;
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * name;
+ name = list_entry(p, struct reg_name, next);
+ assert(!reg_name_has_proc(name, proc->info.pid));
+ if (reg_prog_has_name(prog, name->info.name)) {
+ reg_proc_add_name(proc, name->info.name);
+ reg_name_add_proc(name, proc->info.pid);
+ }
+ }
+}
+
+static void __reg_del_proc_from_names(pid_t pid)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * name;
+ name = list_entry(p, struct reg_name, next);
+ reg_name_del_proc(name, pid);
+ }
+}
+
+static void __reg_del_prog_from_names(const char * prog)
+{
+ struct list_head * p;
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * name;
+ name = list_entry(p, struct reg_name, next);
+ reg_name_del_prog(name, prog);
+ }
+}
+
+static int __reg_add_active_proc(pid_t pid)
+{
+ struct list_head * p;
+ size_t n_names = 0;
+ size_t failed = 0;
+
+ assert(pid > 0);
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * name;
+ name = list_entry(p, struct reg_name, next);
+ if (reg_name_has_proc(name, pid)) {
+ if (reg_name_add_active(name, pid) < 0)
+ failed++;
+ n_names++;
+ }
+ }
+
+ if (n_names > 0 && failed == n_names)
+ return -1;
+
+ return 0; /* some were marked */
+}
+
+static void __reg_del_active_proc(pid_t pid)
+{
+ struct list_head * p;
+
+ assert(pid > 0);
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * name;
+ name = list_entry(p, struct reg_name, next);
+ reg_name_del_active(name, pid);
+ }
+}
+
+int reg_init(void)
+{
+ pthread_condattr_t cattr;
+
+ if (pthread_mutex_init(&reg.mtx, NULL) != 0) {
+ log_err("Failed to initialize mutex.");
+ goto fail_mtx;
+ }
+
+ if (pthread_condattr_init(&cattr) != 0) {
+ log_err("Failed to initialize condattr.");
+ goto fail_cattr;
+ }
+
+#ifndef __APPLE__
+ pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
+#endif
+ if (pthread_cond_init(&reg.cond, &cattr) != 0) {
+ log_err("Failed to initialize condvar.");
+ goto fail_cond;
+ }
+
+ reg.flow_ids = bmp_create(SYS_MAX_FLOWS -ID_OFFT, ID_OFFT);
+ if (reg.flow_ids == NULL) {
+ log_err("Failed to create flow_ids bitmap.");
+ goto fail_flow_ids;
+ }
+
+ pthread_condattr_destroy(&cattr);
+
+ list_head_init(&reg.flows);
+ list_head_init(&reg.ipcps);
+ list_head_init(&reg.names);
+ list_head_init(&reg.procs);
+ list_head_init(&reg.progs);
+ list_head_init(&reg.spawned);
+
+ return 0;
+
+ fail_flow_ids:
+ pthread_cond_destroy(&reg.cond);
+ fail_cond:
+ pthread_condattr_destroy(&cattr);
+ fail_cattr:
+ pthread_mutex_destroy(&reg.mtx);
+ fail_mtx:
+ return -1;
+}
+
+void reg_clear(void)
+{
+ struct list_head * p;
+ struct list_head * h;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ list_for_each_safe(p, h, &reg.spawned) {
+ struct pid_entry * entry;
+ entry = list_entry(p, struct pid_entry, next);
+ list_del(&entry->next);
+ free(entry);
+ reg.n_spawned--;
+ }
+
+ list_for_each_safe(p, h, &reg.progs) {
+ struct reg_prog * entry;
+ entry = list_entry(p, struct reg_prog, next);
+ list_del(&entry->next);
+ __reg_del_prog_from_names(entry->info.path);
+ reg_prog_destroy(entry);
+ reg.n_progs--;
+ }
+
+ list_for_each_safe(p, h, &reg.procs) {
+ struct reg_proc * entry;
+ entry = list_entry(p, struct reg_proc, next);
+ list_del(&entry->next);
+ __reg_del_proc_from_names(entry->info.pid);
+ reg_proc_destroy(entry);
+ reg.n_procs--;
+ }
+
+ list_for_each_safe(p, h, &reg.names) {
+ struct reg_name * entry;
+ entry = list_entry(p, struct reg_name, next);
+ list_del(&entry->next);
+ reg_name_destroy(entry);
+ reg.n_names--;
+ }
+
+ list_for_each_safe(p, h, &reg.ipcps) {
+ struct reg_ipcp * entry;
+ entry = list_entry(p, struct reg_ipcp, next);
+ list_del(&entry->next);
+ reg_ipcp_destroy(entry);
+ reg.n_ipcps--;
+ }
+
+ list_for_each_safe(p, h, &reg.flows) {
+ struct reg_flow * entry;
+ entry = list_entry(p, struct reg_flow, next);
+ list_del(&entry->next);
+ reg_flow_destroy(entry);
+ reg.n_flows--;
+ }
+
+ pthread_mutex_unlock(&reg.mtx);
+}
+
+void reg_fini(void)
+{
+ assert(list_is_empty(&reg.spawned));
+ assert(list_is_empty(&reg.progs));
+ assert(list_is_empty(&reg.procs));
+ assert(list_is_empty(&reg.names));
+ assert(list_is_empty(&reg.ipcps));
+ assert(list_is_empty(&reg.flows));
+
+ assert(reg.n_spawned == 0);
+ assert(reg.n_progs == 0);
+ assert(reg.n_procs == 0);
+ assert(reg.n_names == 0);
+ assert(reg.n_ipcps == 0);
+ assert(reg.n_flows == 0);
+
+ bmp_destroy(reg.flow_ids);
+
+ if (pthread_cond_destroy(&reg.cond) != 0)
+ log_warn("Failed to destroy condvar.");
+
+ if (pthread_mutex_destroy(&reg.mtx) != 0)
+ log_warn("Failed to destroy mutex.");
+}
+
+int reg_create_flow(struct flow_info * info)
+{
+ struct reg_flow * f;
+
+ assert(info != NULL);
+ assert(info->id == 0);
+ assert(info->n_pid != 0);
+ assert(info->state == FLOW_INIT);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ info->id = bmp_allocate(reg.flow_ids);
+ if (!bmp_is_id_valid(reg.flow_ids, info->id)) {
+ log_err("Failed to allocate flow id.");
+ goto fail_id;
+ }
+
+ f = reg_flow_create(info);
+ if (f == NULL) {
+ log_err("Failed to create flow %d.", info->id);
+ goto fail_flow;
+ }
+
+ list_add(&f->next, __reg_after_flow(info->id));
+
+ reg.n_flows++;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_flow:
+ bmp_release(reg.flow_ids, info->id);
+ info->id = 0;
+ fail_id:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_destroy_flow(int flow_id)
+{
+ struct reg_flow * f;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ f = __reg_get_flow(flow_id);
+ if (f == NULL) {
+ log_err("Flow %d does not exist.", flow_id);
+ goto no_flow;
+ }
+
+ list_del(&f->next);
+
+ reg.n_flows--;
+
+ bmp_release(reg.flow_ids, flow_id);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ pthread_cond_broadcast(&reg.cond);
+
+ reg_flow_destroy(f);
+
+ return 0;
+
+ no_flow:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+
+}
+
+bool reg_has_flow(int flow_id)
+{
+ bool ret;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ret = __reg_get_flow(flow_id) != NULL;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+int reg_create_ipcp(const struct ipcp_info * info)
+{
+ struct reg_ipcp * ipcp;
+ struct pid_entry * entry;
+
+ assert(info != NULL);
+ assert(info->pid != 0);
+ assert(info->state == IPCP_BOOT);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ if (__reg_get_ipcp(info->pid) != NULL) {
+ log_err("IPCP %d already exists.", info->pid);
+ goto fail_ipcp;
+ }
+
+ ipcp = reg_ipcp_create(info);
+ if (ipcp == NULL) {
+ log_err("Failed to create ipcp %s.", info->name);
+ goto fail_ipcp;
+ }
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to create spawn entry.\n");
+ goto fail_spawn;
+ }
+
+ entry->pid = info->pid;
+
+ list_add(&ipcp->next, __reg_after_ipcp(info->pid));
+ list_add(&entry->next, __reg_after_spawned(info->pid));
+
+ reg.n_ipcps++;
+ reg.n_spawned++;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_spawn:
+ reg_ipcp_destroy(ipcp);
+ fail_ipcp:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+
+}
+
+int reg_update_ipcp(struct ipcp_info * info)
+{
+ struct reg_ipcp * ipcp;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ipcp = __reg_get_ipcp(info->pid);
+ if (ipcp == NULL) {
+ log_err("IPCP %d does not exist.", info->pid);
+ goto no_ipcp;
+
+ }
+
+ reg_ipcp_update(ipcp, info);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ reg_ipcp_destroy(ipcp);
+
+ return 0;
+
+ no_ipcp:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+bool reg_has_ipcp(pid_t pid)
+{
+ bool ret;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ret = __reg_get_ipcp(pid) != NULL;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+static int __get_ipcp_info(ipcp_list_msg_t ** msg,
+ struct reg_ipcp * ipcp)
+{
+ *msg = malloc(sizeof(**msg));
+ if (*msg == NULL)
+ goto fail;
+
+ ipcp_list_msg__init(*msg);
+
+ (*msg)->name = strdup(ipcp->info.name);
+ if ((*msg)->name == NULL)
+ goto fail_name;
+
+ (*msg)->layer = strdup(ipcp->layer.name);
+ if ((*msg)->layer == NULL)
+ goto fail_layer;
+
+ (*msg)->pid = ipcp->info.pid;
+ (*msg)->type = ipcp->info.type;
+ (*msg)->hash_algo = ipcp->layer.dir_hash_algo;
+
+ return 0;
+
+ fail_layer:
+ free((*msg)->name);
+ fail_name:
+ free(*msg);
+ *msg = NULL;
+ fail:
+ return -1;
+}
+
+int reg_list_ipcps(ipcp_list_msg_t *** ipcps)
+{
+ struct list_head * p;
+ int i = 0;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ if (reg.n_ipcps == 0) {
+ *ipcps = NULL;
+ goto finish;
+ }
+
+ *ipcps = malloc(reg.n_ipcps * sizeof(**ipcps));
+ if (*ipcps == NULL) {
+ log_err("Failed to malloc ipcps.");
+ goto fail_malloc;
+ }
+
+ list_for_each(p, &reg.ipcps) {
+ struct reg_ipcp * entry;
+ entry = list_entry(p, struct reg_ipcp, next);
+ if (__get_ipcp_info(&((*ipcps)[i]), entry) < 0) {
+ log_err("Failed to create ipcp list info.");
+ goto fail;
+ }
+
+ ++i;
+ }
+
+ assert(i == (int) reg.n_ipcps);
+ finish:
+ pthread_mutex_unlock(&reg.mtx);
+
+ return i;
+
+ fail:
+ while (i > 0)
+ ipcp_list_msg__free_unpacked((*ipcps)[--i], NULL);
+
+ free(*ipcps);
+ fail_malloc:
+ pthread_mutex_unlock(&reg.mtx);
+ *ipcps = NULL;
+ return -ENOMEM;
+}
+
+int reg_create_name(const struct name_info * info)
+{
+ struct reg_name * n;
+
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ if (__reg_get_name(info->name) != NULL) {
+ log_dbg("Name %s already exists.", info->name);
+ goto exists;
+ }
+
+ n = reg_name_create(info);
+ if (n == NULL) {
+ log_err("Failed to create name %s.", info->name);
+ goto fail_name;
+ }
+
+ list_add(&n->next, __reg_after_name(info->name));
+
+ reg.n_names++;
+
+ pthread_mutex_unlock(&reg.mtx);
+ return 0;
+ exists:
+ pthread_mutex_unlock(&reg.mtx);
+ return -EEXIST;
+
+ fail_name:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+
+}
+
+int reg_destroy_name(const char * name)
+{
+ struct reg_name * n;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Name %s does not exist.", name);
+ goto no_name;
+ }
+
+ __reg_del_name_from_procs(name);
+ __reg_del_name_from_progs(name);
+
+ list_del(&n->next);
+
+ reg.n_names--;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ reg_name_destroy(n);
+
+ return 0;
+
+ no_name:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+bool reg_has_name(const char * name)
+{
+ bool ret;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ret = __reg_get_name(name) != NULL;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+static int __get_name_info(name_info_msg_t ** msg,
+ struct reg_name * n)
+{
+ *msg = malloc(sizeof(**msg));
+ if (*msg == NULL)
+ goto fail;
+
+ name_info_msg__init(*msg);
+
+ (*msg)->name = strdup(n->info.name);
+ if ((*msg)->name == NULL)
+ goto fail_name;
+
+ (*msg)->pol_lb = n->info.pol_lb;
+
+ return 0;
+
+ fail_name:
+ free(*msg);
+ *msg = NULL;
+ fail:
+ return -1;
+}
+
+int reg_list_names(name_info_msg_t *** names)
+{
+ struct list_head * p;
+ int i = 0;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ if (reg.n_names == 0)
+ goto finish;
+
+ *names = malloc(reg.n_names * sizeof(**names));
+ if (*names == NULL) {
+ log_err("Failed to malloc names.");
+ goto fail_malloc;
+ }
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * entry;
+ entry = list_entry(p, struct reg_name, next);
+ if (__get_name_info(&((*names)[i]), entry) < 0) {
+ log_err("Failed to create name list info.");
+ goto fail;
+ }
+
+ ++i;
+ }
+
+ assert(i == (int) reg.n_names);
+ finish:
+ pthread_mutex_unlock(&reg.mtx);
+
+ return i;
+
+ fail:
+ while (i > 0)
+ name_info_msg__free_unpacked((*names)[--i], NULL);
+
+ free(*names);
+ fail_malloc:
+ pthread_mutex_unlock(&reg.mtx);
+ *names = NULL;
+ return -ENOMEM;
+}
+
+int reg_create_proc(const struct proc_info * info)
+{
+ struct reg_proc * proc;
+
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ if (__reg_get_proc(info->pid) != NULL) {
+ log_err("Process %d already exists.", info->pid);
+ goto fail_proc;
+ }
+
+ proc = reg_proc_create(info);
+ if (proc == NULL) {
+ log_err("Failed to create process %d.", info->pid);
+ goto fail_proc;
+ }
+
+ __reg_proc_update_names(proc);
+
+ list_add(&proc->next, __reg_after_proc(info->pid));
+
+ reg.n_procs++;
+
+ pthread_cond_broadcast(&reg.cond);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_proc:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_destroy_proc(pid_t pid)
+{
+ struct reg_proc * proc;
+ struct pid_entry * spawn;
+ struct reg_ipcp * ipcp;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ proc = __reg_get_proc(pid);
+ if (proc != NULL) {
+ list_del(&proc->next);
+ reg.n_procs--;
+ reg_proc_destroy(proc);
+ __reg_del_proc_from_names(pid);
+ __reg_cancel_flows_for_proc(pid);
+ }
+
+ spawn = __reg_get_spawned(pid);
+ if (spawn != NULL) {
+ list_del(&spawn->next);
+ reg.n_spawned--;
+ free(spawn);
+ }
+
+ ipcp = __reg_get_ipcp(pid);
+ if (ipcp != NULL) {
+ list_del(&ipcp->next);
+ reg.n_ipcps--;
+ reg_ipcp_destroy(ipcp);
+ }
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+}
+
+bool reg_has_proc(pid_t pid)
+{
+ bool ret;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ret = __reg_get_proc(pid) != NULL;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+void reg_kill_all_proc(int signal)
+{
+ pthread_mutex_lock(&reg.mtx);
+
+ __reg_kill_all_proc(signal);
+
+ pthread_mutex_unlock(&reg.mtx);
+}
+
+pid_t reg_get_dead_proc(void)
+{
+ pid_t ret;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ret = __reg_get_dead_proc();
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+int reg_create_spawned(pid_t pid)
+{
+ struct pid_entry * entry;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ if (__reg_get_spawned(pid) != NULL) {
+ log_err("Spawned process %d already exists.", pid);
+ goto fail_proc;
+ }
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ log_err("Failed to create pid_entry %d.", pid);
+ goto fail_proc;
+ }
+
+ entry->pid = pid;
+
+ list_add(&entry->next, __reg_after_spawned(pid));
+
+ reg.n_spawned++;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+ fail_proc:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+bool reg_has_spawned(pid_t pid)
+{
+ bool ret;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ret = __reg_get_spawned(pid) != NULL;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+void reg_kill_all_spawned(int signal)
+{
+ pthread_mutex_lock(&reg.mtx);
+
+ __reg_kill_all_spawned(signal);
+
+ pthread_mutex_unlock(&reg.mtx);
+}
+
+pid_t reg_first_spawned(void)
+{
+ pid_t pid;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ pid = __reg_first_spawned();
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return pid;
+}
+
+int reg_bind_proc(const char * name,
+ pid_t pid)
+{
+ struct reg_name * n;
+ struct reg_proc * p;
+
+ assert(name != NULL);
+ assert(pid > 0);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Could not find name %s.", name);
+ goto fail;
+ }
+
+ p = __reg_get_proc(pid);
+ if (p == NULL) {
+ log_err("Could not find process %d.", pid);
+ goto fail;
+ }
+
+ if (reg_name_has_proc(n, pid)) {
+ log_err("Process %d already bound to name %s.", pid, name);
+ goto fail;
+ }
+
+ if (reg_proc_has_name(p, name)) {
+ log_err("Name %s already bound to process %d.", name, pid);
+ }
+
+ if (reg_name_add_proc(n, pid) < 0) {
+ log_err("Failed to add process %d to name %s.", pid, name);
+ goto fail;
+ }
+
+ if (reg_proc_add_name(p, name) < 0) {
+ log_err("Failed to add name %s to process %d.", name, pid);
+ goto fail_proc;
+ }
+
+ if (__reg_get_accept_flow(pid) != NULL) {
+ if (reg_name_add_active(n, pid) < 0) {
+ log_warn("Failed to update name %s with active %d",
+ name, pid);
+ }
+ }
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_proc:
+ reg_name_del_proc(n, pid);
+ fail:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_unbind_proc(const char * name,
+ pid_t pid)
+{
+ struct reg_name * n;
+ struct reg_proc * p;
+
+ assert(name != NULL);
+ assert(pid > 0);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Could not find name %s.", name);
+ goto fail;
+ }
+
+ p = __reg_get_proc(pid);
+ if (p == NULL) {
+ log_err("Could not find process %d.", pid);
+ goto fail;
+ }
+
+ if (!reg_name_has_proc(n, pid)) {
+ log_err("Process %d not bound to name %s.", pid, name);
+ goto fail;
+ }
+
+ if (!reg_proc_has_name(p, name)) {
+ log_err("Name %s not bound to process %d.", name, pid);
+ goto fail;
+ }
+
+ reg_name_del_proc(n, pid);
+
+ reg_proc_del_name(p, name);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_create_prog(const struct prog_info * info)
+{
+ struct reg_prog * prog;
+
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ if (__reg_get_prog(info->name) != NULL) {
+ log_dbg("Program %s already exists.", info->name);
+ goto exists;
+ }
+
+ prog = reg_prog_create(info);
+ if (prog == NULL) {
+ log_err("Failed to create program %s.", info->name);
+ goto fail_prog;
+ }
+
+ list_add(&prog->next, __reg_after_prog(info->name));
+
+ reg.n_progs++;
+ exists:
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_prog:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+
+}
+
+int reg_destroy_prog(const char * name)
+{
+ struct reg_prog * prog;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ prog = __reg_get_prog(name);
+ if (prog == NULL) {
+ log_err("Program %s does not exist.", name);
+ goto no_prog;
+ }
+
+ log_err("Removing %s from names.", prog->info.path);
+
+ __reg_del_prog_from_names(prog->info.path);
+
+ list_del(&prog->next);
+
+ reg.n_progs--;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ reg_prog_destroy(prog);
+
+ return 0;
+
+ no_prog:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+bool reg_has_prog(const char * name)
+{
+ bool ret;
+
+ assert(name != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ret = __reg_get_prog(name) != NULL;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+int reg_get_exec(enum hash_algo algo,
+ const uint8_t * hash,
+ char *** prog)
+{
+ char ** exec;
+ int ret = 0;
+
+ assert(hash != NULL);
+ assert(prog != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ exec = __reg_get_exec(algo, hash);
+ if (exec == NULL) {
+ ret = -EPERM;
+ goto finish;
+ }
+
+ *prog = argvdup(exec);
+ if (*prog == NULL) {
+ log_err("Failed to argvdup exec.");
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ finish:
+ pthread_mutex_unlock(&reg.mtx);
+ return ret;
+}
+
+int reg_bind_prog(const char * name,
+ char ** exec,
+ uint8_t flags)
+{
+ struct reg_name * n;
+ struct reg_prog * p;
+
+ assert(name != NULL);
+ assert(exec != NULL);
+ assert(exec[0] != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Could not find name %s.", name);
+ goto fail;
+ }
+
+ p = __reg_get_prog(path_strip(exec[0]));
+ if (p == NULL) {
+ log_err("Could not find program %s.", exec[0]);
+ goto fail;
+ }
+
+ if (reg_name_has_prog(n, exec[0])) {
+ log_err("Program %s already bound to %s.", exec[0], name);
+ goto fail;
+ }
+
+ if (reg_prog_has_name(p, name)) {
+ log_err("Name %s already bound to program %s.", name, exec[0]);
+ goto fail;
+ }
+
+
+ if (flags & BIND_AUTO && reg_name_add_prog(n, exec) < 0) {
+ log_err("Failed to set autostart %s for %s.", exec[0], name);
+ goto fail;
+ }
+
+ if (reg_prog_add_name(p, name) < 0) {
+ log_err("Failed to add %s to program %s.", name, exec[0]);
+ goto fail_prog;
+ }
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_prog:
+ reg_name_del_prog(n, exec[0]);
+ fail:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_unbind_prog(const char * name,
+ const char * prog)
+{
+ struct reg_name * n;
+ struct reg_prog * p;
+
+ assert(name != NULL);
+ assert(prog != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Could not find name %s.", name);
+ goto fail;
+ }
+
+ p = __reg_get_prog(prog);
+ if (p == NULL) {
+ log_err("Could not find program %s.", prog);
+ goto fail;
+ }
+
+ if (!reg_prog_has_name(p, name)) {
+ log_err("Name %s not bound to program %s.", name, prog);
+ goto fail;
+ }
+
+ reg_name_del_prog(n, prog);
+
+ reg_prog_del_name(p, name);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_set_layer_for_ipcp(struct ipcp_info * info,
+ const struct layer_info * layer)
+{
+ struct reg_ipcp * ipcp;
+
+ assert(info != NULL);
+ assert(info->state > IPCP_BOOT);
+ assert(info->state < IPCP_SHUTDOWN);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ipcp = __reg_get_ipcp(info->pid);
+ if (ipcp == NULL) {
+ log_err("IPCP %d not found.", info->pid);
+ goto fail_ipcp;
+ }
+
+ reg_ipcp_set_layer(ipcp, layer);
+
+ ipcp->info.state = info->state;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+ fail_ipcp:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_get_ipcp(struct ipcp_info * info,
+ struct layer_info * layer)
+{
+ struct reg_ipcp * ipcp;
+
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ipcp = __reg_get_ipcp(info->pid);
+ if (ipcp == NULL) {
+ log_err("IPCP %d not found.", info->pid);
+ goto fail_ipcp;
+ }
+
+ *info = ipcp->info;
+ if (layer != NULL)
+ *layer = ipcp->layer;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+ fail_ipcp:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_get_ipcp_by_layer(struct ipcp_info * info,
+ struct layer_info * layer)
+{
+ struct reg_ipcp * ipcp;
+
+ assert(info != NULL);
+ assert(layer != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ipcp = __reg_get_ipcp_by_layer(layer->name);
+ if (ipcp == NULL) {
+ log_err("No IPCP for %s not found.", layer->name);
+ goto fail_ipcp;
+ }
+
+ *info = ipcp->info;
+ *layer = ipcp->layer;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+ fail_ipcp:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_prepare_flow_alloc(struct flow_info * info)
+{
+ struct reg_flow * flow;
+ int ret;
+
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+
+ assert(flow != NULL);
+ assert(flow->info.state == FLOW_INIT);
+
+ info->state = FLOW_ALLOC_PENDING;
+
+ ret = reg_flow_update(flow, info);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+int reg_wait_flow_allocated(struct flow_info * info,
+ buffer_t * pbuf,
+ const struct timespec * abstime)
+{
+ struct reg_flow * flow;
+ int ret = -1;
+ bool stop = false;
+
+ assert(info != NULL);
+ assert(info->id >= ID_OFFT);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+
+ assert(flow != NULL);
+ assert(info->id == flow->info.id);
+ assert(info->n_pid == flow->info.n_pid);
+
+ assert(info->state == FLOW_ALLOC_PENDING);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &reg.mtx);
+
+ while (!stop) {
+ switch(flow->info.state) {
+ case FLOW_ALLOC_PENDING:
+ ret = -__timedwait(&reg.cond, &reg.mtx, abstime);
+ break;
+ case FLOW_ALLOCATED:
+ ret = 0;
+ stop = true;
+ break;
+ case FLOW_DEALLOCATED:
+ ret = -1;
+ stop = true;
+ break;
+ default:
+ assert(false);
+ }
+
+ flow = __reg_get_flow(flow->info.id);
+ if (flow == NULL) {
+ info->state = FLOW_DEALLOCATED;
+ ret = -1;
+ break;
+ }
+
+ if (ret == -ETIMEDOUT) {
+ info->state = FLOW_DEALLOCATED;
+ reg_flow_update(flow, info);
+ break;
+ }
+ }
+
+ if (flow != NULL) {
+ reg_flow_get_data(flow, pbuf);
+ *info = flow->info;
+ }
+
+ pthread_cleanup_pop(true); /* __cleanup_mutex_unlock */
+
+ return ret;
+}
+
+int reg_respond_alloc(struct flow_info * info,
+ buffer_t * pbuf)
+{
+ struct reg_flow * flow;
+
+ assert(info != NULL);
+ assert(info->state == FLOW_ALLOCATED ||
+ info->state == FLOW_DEALLOCATED);
+ assert(pbuf != NULL);
+ assert(!(info->state == FLOW_DEALLOCATED && pbuf->data != NULL));
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+ if (flow == NULL) {
+ log_warn("Flow %d already destroyed.", info->id);
+ goto fail_flow;
+ }
+
+ if (flow->info.state == FLOW_DEALLOCATED) {
+ log_warn("Flow %d already deallocated.", info->id);
+ goto fail_flow;
+ }
+
+ assert(flow->info.state == FLOW_ALLOC_PENDING);
+ assert(flow->data.len == 0);
+ assert(flow->data.data == NULL);
+
+ info->n_pid = flow->info.n_pid;
+ info->n_1_pid = flow->info.n_pid;
+
+ if (reg_flow_update(flow, info) < 0) {
+ log_err("Failed to create flow structs.");
+ goto fail_flow;
+ };
+
+ if (info->state == FLOW_ALLOCATED)
+ reg_flow_set_data(flow, pbuf);
+
+ pthread_cond_broadcast(&reg.cond);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_flow:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_prepare_flow_accept(struct flow_info * info,
+ buffer_t * pbuf)
+{
+ struct reg_flow * flow;
+ int ret;
+
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+
+ assert(flow != NULL);
+ assert(info->n_pid != 0);
+
+ info->state = FLOW_ACCEPT_PENDING;
+
+ ret = reg_flow_update(flow, info);
+
+ reg_flow_set_data(flow, pbuf);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+void __cleanup_wait_accept(void * o)
+{
+ struct reg_flow * flow;
+
+ flow = (struct reg_flow *) o;
+
+ __reg_del_active_proc(flow->info.n_pid);
+}
+
+int reg_wait_flow_accepted(struct flow_info * info,
+ buffer_t * pbuf,
+ const struct timespec * abstime)
+{
+ struct reg_flow * flow;
+ int ret = -1;
+ bool stop = false;
+
+ assert(info != NULL);
+ assert(info->id >= ID_OFFT);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+
+ assert(flow != NULL);
+ assert(info->id == flow->info.id);
+ assert(info->n_pid == flow->info.n_pid);
+ assert(info->state == flow->info.state);
+ assert(flow->info.state == FLOW_ACCEPT_PENDING);
+
+ if (__reg_add_active_proc(info->n_pid) < 0) {
+ log_err("Failed to mark pid %d active.", info->n_pid);
+ goto fail;
+ }
+
+ pthread_cond_broadcast(&reg.cond);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &reg.mtx);
+ pthread_cleanup_push(__cleanup_wait_accept, flow);
+
+ while (!stop) {
+ switch(flow->info.state) {
+ case FLOW_ACCEPT_PENDING:
+ ret = -__timedwait(&reg.cond, &reg.mtx, abstime);
+ break;
+ case FLOW_ALLOCATED:
+ ret = 0;
+ stop = true;
+ break;
+ case FLOW_DEALLOCATED:
+ ret = -1;
+ stop = true;
+ break;
+ default:
+ assert(false);
+ }
+
+ flow = __reg_get_flow(flow->info.id);
+ if (flow == NULL) {
+ info->state = FLOW_DEALLOCATED;
+ ret = -1;
+ break;
+ }
+
+ if (ret == -ETIMEDOUT) {
+ info->state = FLOW_DEALLOCATED;
+ reg_flow_update(flow, info);
+ break;
+ }
+ }
+
+ pthread_cleanup_pop(true); /* __cleanup_wait_accept */
+
+ if (flow != NULL) {
+ reg_flow_get_data(flow, pbuf);
+ *info = flow->info;
+ }
+
+ pthread_cleanup_pop(true); /* __cleanup_mutex_unlock */
+
+ return ret;
+ fail:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_wait_flow_accepting(enum hash_algo algo,
+ const uint8_t * hash,
+ const struct timespec * abstime)
+{
+ int ret;
+
+ assert(hash != NULL);
+ assert(abstime != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &reg.mtx);
+
+ while (true) {
+ ret = __reg_get_pending_flow_id_for_hash(algo, hash);
+ if (ret != -EAGAIN)
+ break;
+
+ ret = -__timedwait(&reg.cond, &reg.mtx, abstime);
+ if (ret == -ETIMEDOUT)
+ break;
+ }
+
+ pthread_cleanup_pop(true);
+
+ return ret;
+}
+
+int reg_respond_accept(struct flow_info * info,
+ buffer_t * pbuf)
+{
+ struct reg_flow * flow;
+ buffer_t temp;
+
+ assert(info != NULL);
+ assert(info->state == FLOW_ALLOCATED);
+ assert(pbuf != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+ if (flow == NULL) {
+ log_err("Flow not found for request: %d", info->id);
+ goto fail_flow;
+ }
+
+ assert(flow->info.state == FLOW_ACCEPT_PENDING);
+
+ info->n_pid = flow->info.n_pid;
+
+ if (info->qs.cypher_s > 0) {
+ reg_flow_get_data(flow, &temp);
+ reg_flow_set_data(flow, pbuf);
+ *pbuf = temp;
+ }
+
+ if (reg_flow_update(flow, info) < 0) {
+ log_err("Failed to create flow structs.");
+ goto fail_flow;
+ }
+
+ pthread_cond_broadcast(&reg.cond);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_flow:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+void reg_dealloc_flow(struct flow_info * info)
+{
+ struct reg_flow * flow;
+
+ assert(info != NULL);
+ assert(info->id != 0);
+ assert(info->n_pid != 0);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+
+ assert(flow != NULL);
+ assert(flow->data.data == NULL);
+ assert(flow->data.len == 0);
+
+ assert(flow->info.state == FLOW_ALLOCATED);
+ flow->info.state = FLOW_DEALLOC_PENDING;
+ info->state = FLOW_DEALLOC_PENDING;
+ info->n_1_pid = flow->info.n_1_pid;
+
+ reg_flow_update(flow, info);
+
+ pthread_mutex_unlock(&reg.mtx);
+}
+
+void reg_dealloc_flow_resp(struct flow_info * info)
+{
+ struct reg_flow * flow;
+
+ assert(info != NULL);
+ assert(info->id != 0);
+ assert(info->n_1_pid != 0);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+
+ assert(flow != NULL);
+ assert(flow->data.data == NULL);
+ assert(flow->data.len == 0);
+
+ assert(flow->info.state == FLOW_DEALLOC_PENDING);
+ flow->info.state = FLOW_DEALLOCATED;
+ info->state = FLOW_DEALLOCATED;
+
+ reg_flow_update(flow, info);
+
+ pthread_mutex_unlock(&reg.mtx);
+}
+
+int reg_wait_proc(pid_t pid,
+ const struct timespec * abstime)
+{
+ struct reg_proc * proc = NULL;
+ int ret;
+
+ assert(pid > 0);
+ assert(abstime != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &reg.mtx);
+
+ while (true) {
+ proc = __reg_get_proc(pid);
+ if (proc != NULL) {
+ ret = 0;
+ break;
+ }
+
+ ret = -__timedwait(&reg.cond, &reg.mtx, abstime);
+ if (ret == -ETIMEDOUT)
+ break;
+ }
+
+ pthread_cleanup_pop(true);
+
+ return ret;
+}
+
+int reg_wait_ipcp_boot(struct ipcp_info * info,
+ const struct timespec * abstime)
+{
+ struct reg_ipcp * ipcp;
+ int ret;
+ bool stop = false;
+
+ assert(info->state == IPCP_BOOT);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ipcp = __reg_get_ipcp(info->pid);
+
+ if (ipcp->info.state == IPCP_INIT)
+ reg_ipcp_update(ipcp, info);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &reg.mtx);
+
+ while (!stop) {
+ if (ipcp == NULL)
+ break;
+
+ switch(ipcp->info.state) {
+ case IPCP_NULL:
+ ret = -1;
+ stop = true;
+ break;
+ case IPCP_OPERATIONAL:
+ ret = 0;
+ stop = true;
+ break;
+ case IPCP_BOOT:
+ ret = -__timedwait(&reg.cond, &reg.mtx, abstime);
+ break;
+ default:
+ assert(false);
+ continue; /* Shut up static analyzer. */
+ }
+
+ ipcp = __reg_get_ipcp(info->pid);
+
+ if (ret == -ETIMEDOUT)
+ break;
+ }
+
+ if (ipcp != NULL)
+ *info = ipcp->info;
+
+ pthread_cleanup_pop(true);
+
+ return ipcp == NULL? -EIPCP : ret;
+}
+
+int reg_respond_ipcp(const struct ipcp_info * info)
+{
+ struct reg_ipcp * ipcp;
+
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ ipcp = __reg_get_ipcp(info->pid);
+ if (ipcp == NULL) {
+ log_err("IPCP %d not found for response.", info->pid);
+ goto fail_ipcp;
+ }
+
+ assert(strcmp(info->name, ipcp->info.name) == 0);
+ assert(info->type == ipcp->info.type);
+
+ reg_ipcp_update(ipcp, info);
+
+ pthread_cond_broadcast(&reg.cond);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_ipcp:
+ pthread_mutex_unlock(&reg.mtx);
+ return -EIPCP;
+}
diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h
new file mode 100644
index 00000000..17dfcc32
--- /dev/null
+++ b/src/irmd/reg/reg.h
@@ -0,0 +1,148 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_REG_H
+#define OUROBOROS_IRMD_REG_H
+
+#include <ouroboros/flow.h>
+#include <ouroboros/ipcp.h>
+#include <ouroboros/name.h>
+#include <ouroboros/proc.h>
+#include <ouroboros/protobuf.h>
+#include <ouroboros/time.h>
+#include <ouroboros/utils.h>
+
+int reg_init(void);
+
+void reg_clear(void);
+
+void reg_fini(void);
+
+int reg_create_flow(struct flow_info * info);
+
+int reg_destroy_flow(int flow_id);
+
+bool reg_has_flow(int flow_id);
+
+int reg_create_proc(const struct proc_info * info);
+
+/* Use this for all processes, including ipcps */
+int reg_destroy_proc(pid_t pid);
+
+bool reg_has_proc(pid_t pid);
+
+void reg_kill_all_proc(int signal);
+
+pid_t reg_get_dead_proc(void);
+
+int reg_create_spawned(pid_t pid);
+
+bool reg_has_spawned(pid_t pid);
+
+void reg_kill_all_spawned(int signal);
+
+int reg_first_spawned(void);
+
+int reg_bind_proc(const char * name,
+ pid_t proc);
+
+int reg_unbind_proc(const char * name,
+ pid_t proc);
+
+int reg_create_ipcp(const struct ipcp_info * info);
+
+bool reg_has_ipcp(pid_t pid);
+
+int reg_set_layer_for_ipcp(struct ipcp_info * info,
+ const struct layer_info * layer);
+
+int reg_get_ipcp(struct ipcp_info * info,
+ struct layer_info * layer);
+
+int reg_get_ipcp_by_layer(struct ipcp_info * info,
+ struct layer_info * layer);
+
+/* TODO don't rely on protobuf here */
+int reg_list_ipcps(ipcp_list_msg_t *** msg);
+
+int reg_create_name(const struct name_info * info);
+
+int reg_destroy_name(const char * name);
+
+bool reg_has_name(const char * name);
+
+/* TODO don't rely on protobuf here */
+int reg_list_names(name_info_msg_t *** names);
+
+int reg_create_prog(const struct prog_info * info);
+
+int reg_destroy_prog(const char * name);
+
+bool reg_has_prog(const char * name);
+
+int reg_get_exec(enum hash_algo algo,
+ const uint8_t * hash,
+ char *** exec);
+
+int reg_bind_prog(const char * name,
+ char ** exec,
+ uint8_t flags);
+
+int reg_unbind_prog(const char * name,
+ const char * prog);
+
+int reg_prepare_flow_alloc(struct flow_info * info);
+
+int reg_wait_flow_allocated(struct flow_info * info,
+ buffer_t * pbuf,
+ const struct timespec * abstime);
+
+int reg_respond_alloc(struct flow_info * info,
+ buffer_t * pbuf);
+
+int reg_prepare_flow_accept(struct flow_info * info,
+ buffer_t * pbuf);
+
+int reg_wait_flow_accepted(struct flow_info * info,
+ buffer_t * pbuf,
+ const struct timespec * abstime);
+
+int reg_wait_flow_accepting(enum hash_algo algo,
+ const uint8_t * hash,
+ const struct timespec * abstime);
+
+int reg_respond_accept(struct flow_info * info,
+ buffer_t * pbuf);
+
+void reg_dealloc_flow(struct flow_info * info);
+
+void reg_dealloc_flow_resp(struct flow_info * info);
+
+int reg_wait_proc(pid_t pid,
+ const struct timespec * abstime);
+
+int reg_wait_ipcp_boot(struct ipcp_info * ipcp,
+ const struct timespec * abstime);
+
+int reg_respond_ipcp(const struct ipcp_info * info);
+
+#endif /* OUROBOROS_IRMD_REG_H */
diff --git a/src/irmd/reg/tests/CMakeLists.txt b/src/irmd/reg/tests/CMakeLists.txt
new file mode 100644
index 00000000..7bc98571
--- /dev/null
+++ b/src/irmd/reg/tests/CMakeLists.txt
@@ -0,0 +1,33 @@
+get_filename_component(tmp ".." ABSOLUTE)
+get_filename_component(src_folder "${tmp}" NAME)
+
+create_test_sourcelist(${src_folder}_tests test_suite.c
+ # Add new tests here
+ flow_test.c
+ ipcp_test.c
+ name_test.c
+ proc_test.c
+ prog_test.c
+ reg_test.c
+)
+
+add_executable(${src_folder}_test EXCLUDE_FROM_ALL ${${src_folder}_tests})
+target_link_libraries(${src_folder}_test ouroboros-common)
+
+if (CMAKE_BUILD_TYPE MATCHES "Debug*")
+ add_compile_flags(${src_folder}_test -DCONFIG_OUROBOROS_DEBUG)
+endif ()
+
+add_dependencies(check ${src_folder}_test)
+
+set(tests_to_run ${${src_folder}_tests})
+if(CMAKE_VERSION VERSION_LESS "3.29.0")
+ remove(tests_to_run test_suite.c)
+else ()
+ list(POP_FRONT tests_to_run)
+endif()
+
+foreach(test ${tests_to_run})
+ get_filename_component(test_name ${test} NAME_WE)
+ add_test(irmd/reg/${test_name} ${C_TEST_PATH}/${src_folder}_test ${test_name})
+endforeach(test)
diff --git a/src/irmd/reg/tests/flow_test.c b/src/irmd/reg/tests/flow_test.c
new file mode 100644
index 00000000..f9d23fd1
--- /dev/null
+++ b/src/irmd/reg/tests/flow_test.c
@@ -0,0 +1,294 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Flows - Unit Tests
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "../flow.c"
+
+#include <ouroboros/test.h>
+
+#include <string.h>
+
+#define TEST_DATA "testpiggybackdata"
+
+static int test_reg_flow_create(void)
+{
+ struct reg_flow * f;
+
+ struct flow_info info = {
+ .id = 1,
+ .n_pid = 1,
+ .qs = qos_raw,
+ .state = FLOW_INIT
+ };
+
+ TEST_START();
+
+ f = reg_flow_create(&info);
+ if (f == NULL) {
+ printf("Failed to create flow.\n");
+ goto fail;
+ }
+
+ reg_flow_destroy(f);
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_flow_create_no_id(void) {
+ struct flow_info info = {
+ .id = 0,
+ .n_pid = 1,
+ .qs = qos_raw,
+ .state = FLOW_INIT
+ };
+
+ reg_flow_create(&info); /* assert fail */
+
+ return 0;
+}
+
+static int test_reg_flow_create_no_pid(void) {
+ struct flow_info info = {
+ .id = 1,
+ .n_pid = 0,
+ .qs = qos_raw,
+ .state = FLOW_INIT
+ };
+
+ reg_flow_create(&info); /* assert fail */
+
+ return 0;
+}
+
+static int test_reg_flow_create_has_n_1_pid(void) {
+ struct flow_info info = {
+ .id = 1,
+ .n_pid = 0,
+ .n_1_pid = 1,
+ .qs = qos_raw,
+ .state = FLOW_INIT
+ };
+
+ reg_flow_create(&info); /* assert fail */
+
+ return 0;
+}
+
+static int test_reg_flow_create_wrong_state(void) {
+ struct flow_info info = {
+ .id = 1,
+ .n_pid = 0,
+ .n_1_pid = 1,
+ .qs = qos_raw,
+ .state = FLOW_ALLOC_PENDING
+ };
+
+ reg_flow_create(&info); /* assert fail */
+
+ return 0;
+}
+
+static int test_reg_flow_create_has_mpl(void) {
+ struct flow_info info = {
+ .id = 1,
+ .n_pid = 1,
+ .n_1_pid = 0,
+ .mpl = 10,
+ .qs = qos_raw,
+ .state = FLOW_ALLOC_PENDING
+ };
+
+ reg_flow_create(&info); /* assert fail */
+
+ return 0;
+}
+
+static int test_reg_flow_update(void)
+{
+ struct reg_flow * f;
+
+ struct flow_info info = {
+ .id = 1,
+ .n_pid = 1,
+ .qs = qos_raw,
+ .state = FLOW_INIT
+ };
+
+ struct flow_info upd = {
+ .id = 1,
+ .n_pid = 1,
+ .qs = qos_data,
+ .state = FLOW_DEALLOCATED
+ };
+
+ TEST_START();
+
+ f = reg_flow_create(&info);
+ if (f == NULL) {
+ printf("Failed to create flow.\n");
+ goto fail;
+ }
+
+ reg_flow_update(f, &upd);
+
+ if (memcmp(&f->info, &upd, sizeof(upd)) != 0) {
+ printf("Flow info not updated.\n");
+ goto fail;
+ }
+
+ reg_flow_destroy(f);
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_flow_update_wrong_id(void)
+{
+ struct reg_flow * f;
+
+ struct flow_info info = {
+ .id = 1,
+ .n_pid = 1,
+ .qs = qos_raw,
+ .state = FLOW_INIT
+ };
+
+ struct flow_info upd = {
+ .id = 2,
+ .n_pid = 1,
+ .qs = qos_data,
+ .state = FLOW_DEALLOCATED
+ };
+
+ TEST_START();
+
+ f = reg_flow_create(&info);
+ if (f == NULL) {
+ printf("Failed to create flow.\n");
+ goto fail;
+ }
+
+ reg_flow_update(f, &upd); /* assert fail */
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_flow_assert_fails(void)
+{
+ int ret = 0;
+
+ ret |= test_assert_fail(test_reg_flow_create_no_id);
+
+ ret |= test_assert_fail(test_reg_flow_create_no_pid);
+
+ ret |= test_assert_fail(test_reg_flow_create_has_n_1_pid);
+
+ ret |= test_assert_fail(test_reg_flow_create_wrong_state);
+
+ ret |= test_assert_fail(test_reg_flow_create_has_mpl);
+
+ ret |= test_assert_fail(test_reg_flow_update_wrong_id);
+
+ return ret;
+}
+
+static int test_flow_data(void)
+{
+ struct reg_flow * f;
+
+ struct flow_info info = {
+ .id = 1,
+ .n_pid = 1,
+ .qs = qos_raw,
+ .state = FLOW_INIT
+ };
+
+ char * data;
+ buffer_t buf;
+ buffer_t rcv = {NULL, 0};
+
+ TEST_START();
+
+ data = strdup(TEST_DATA);
+ if (data == NULL) {
+ printf("Failed to strdup data.\n");
+ goto fail;
+ }
+
+ buf.data = (uint8_t *) data;
+ buf.len = strlen(data);
+
+ f = reg_flow_create(&info);
+ if (f == NULL) {
+ printf("Failed to create flow.\n");
+ goto fail;
+ }
+
+ reg_flow_set_data(f, &buf);
+
+ reg_flow_get_data(f, &rcv);
+
+ freebuf(buf);
+ clrbuf(rcv);
+
+ reg_flow_destroy(f);
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ free(data);
+ TEST_FAIL();
+ return -1;
+}
+
+int flow_test(int argc,
+ char ** argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_reg_flow_create();
+
+ ret |= test_reg_flow_update();
+
+ ret |= test_reg_flow_assert_fails();
+
+ ret |= test_flow_data();
+
+ return ret;
+}
diff --git a/src/irmd/reg/tests/ipcp_test.c b/src/irmd/reg/tests/ipcp_test.c
new file mode 100644
index 00000000..fb8ba71b
--- /dev/null
+++ b/src/irmd/reg/tests/ipcp_test.c
@@ -0,0 +1,89 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - IPCPs - Unit Tests
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include <ouroboros/test.h>
+
+#include "../ipcp.c"
+
+#define TEST_PID 65535
+
+static int test_reg_ipcp_create(void)
+{
+ struct reg_ipcp * ipcp;
+ struct ipcp_info info = {
+ .pid = TEST_PID,
+ .state = IPCP_BOOT
+ };
+ struct layer_info layer = {
+ .name = "testlayer",
+ .dir_hash_algo = DIR_HASH_SHA3_224
+ };
+
+ TEST_START();
+
+ ipcp = reg_ipcp_create(&info);
+ if (ipcp == NULL) {
+ printf("Failed to create ipcp.\n");
+ goto fail;
+ }
+
+ if (strcmp(ipcp->layer.name, "Not enrolled.") != 0) {
+ printf("Layer name was not set.\n");
+ goto fail;
+ }
+
+ ipcp->info.state = IPCP_OPERATIONAL;
+
+ reg_ipcp_set_layer(ipcp, &layer);
+
+ if (strcmp(ipcp->layer.name, layer.name) != 0) {
+ printf("Layer name was not set.\n");
+ goto fail;
+ }
+
+ if (ipcp->info.state != IPCP_OPERATIONAL) {
+ printf("IPCP state was not set.\n");
+ goto fail;
+ }
+
+ reg_ipcp_destroy(ipcp);
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ TEST_FAIL();
+ return -1;
+}
+
+int ipcp_test(int argc,
+ char ** argv)
+{
+ int res = 0;
+
+ (void) argc;
+ (void) argv;
+
+ res |= test_reg_ipcp_create();
+
+ return res;
+}
diff --git a/src/irmd/reg/tests/name_test.c b/src/irmd/reg/tests/name_test.c
new file mode 100644
index 00000000..48f132e9
--- /dev/null
+++ b/src/irmd/reg/tests/name_test.c
@@ -0,0 +1,283 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Names - Unit Tests
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "../name.c"
+
+#define TEST_PID 65534
+#define TEST_PROG "/usr/bin/testprog"
+#define TEST_NAME "testservicename"
+
+static int test_reg_name_create(void)
+{
+ struct reg_name * n;
+ struct name_info info = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR,
+ };
+
+ n = reg_name_create(&info);
+ if (n == NULL) {
+ printf("Failed to create name %s.\n", info.name);
+ goto fail;
+ }
+
+ reg_name_destroy(n);
+
+ return 0;
+ fail:
+ return -1;
+}
+
+static int test_reg_name_add_proc(void)
+{
+ struct reg_name * n;
+ struct name_info info = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR,
+ };
+
+ n = reg_name_create(&info);
+ if (n == NULL) {
+ printf("Failed to create name %s.\n", info.name);
+ goto fail;
+ }
+
+ if (reg_name_add_proc(n, TEST_PID) < 0) {
+ printf("Failed to add proc.\n");
+ goto fail;
+ }
+
+ if (n->n_procs != 1) {
+ printf("n_procs not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_name_has_proc(n, TEST_PID)) {
+ printf("Proc not found.\n");
+ goto fail;
+ }
+
+ reg_name_del_proc(n, TEST_PID);
+
+ if (n->n_procs != 0) {
+ printf("n_procs not updated.\n");
+ goto fail;
+ }
+
+ reg_name_destroy(n);
+
+ return 0;
+ fail:
+ return -1;
+}
+
+static int test_reg_name_add_prog(void)
+{
+ struct reg_name * n;
+ struct name_info info = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR,
+ };
+
+ char * exec[] = { TEST_PROG, "--argswitch", "argvalue", NULL};
+
+ n = reg_name_create(&info);
+ if (n == NULL) {
+ printf("Failed to create name %s.\n", info.name);
+ goto fail;
+ }
+
+ if (reg_name_add_prog(n, exec) < 0) {
+ printf("Failed to add prog.\n");
+ goto fail;
+ }
+
+ if (n->n_progs != 1) {
+ printf("n_progs not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_name_has_prog(n, TEST_PROG)) {
+ printf("Prog not found.\n");
+ goto fail;
+ }
+
+ reg_name_del_prog(n, TEST_PROG);
+
+ if (n->n_progs != 0) {
+ printf("n_progs not updated.\n");
+ goto fail;
+ }
+
+ reg_name_destroy(n);
+
+ return 0;
+ fail:
+ return -1;
+}
+
+static int test_reg_name_add_active(enum pol_balance lb)
+{
+ struct reg_name * n;
+ pid_t pid;
+ struct name_info info = {
+ .name = TEST_NAME,
+ .pol_lb = lb,
+ };
+
+ n = reg_name_create(&info);
+ if (n == NULL) {
+ printf("Failed to create name %s.\n", info.name);
+ goto fail;
+ }
+
+ if (reg_name_get_active(n) != -1) {
+ printf("Got active from empty actives.\n");
+ goto fail;
+ }
+
+ if (reg_name_add_proc(n, TEST_PID) < 0) {
+ printf("Failed to add proc 0.\n");
+ goto fail;
+ }
+
+ if (reg_name_add_proc(n, TEST_PID + 1) < 0) {
+ printf("Failed to add proc 1.\n");
+ goto fail;
+ }
+
+ if (reg_name_add_proc(n, TEST_PID + 2) < 0) {
+ printf("Failed to add proc 2.\n");
+ goto fail;
+ }
+
+ if (reg_name_add_active(n, TEST_PID) < 0) {
+ printf("Failed to add active.\n");
+ goto fail;
+ }
+
+ if (n->n_active != 1) {
+ printf("n_active not updated.\n");
+ goto fail;
+ }
+
+ if (reg_name_get_active(n) != TEST_PID) {
+ printf("Failed to get active.\n");
+ goto fail;
+ }
+
+ if (reg_name_get_active(n) != TEST_PID) {
+ printf("Failed to get active.\n");
+ goto fail;
+ }
+
+ if (reg_name_add_active(n, TEST_PID + 1) < 0) {
+ printf("Failed to add active 3.\n");
+ goto fail;
+ }
+
+ if (reg_name_add_active(n, TEST_PID + 1) < 0) {
+ printf("Failed to add active 3.\n");
+ goto fail;
+ }
+
+
+ if (reg_name_add_active(n, TEST_PID + 2) < 0) {
+ printf("Failed to add active 4.\n");
+ goto fail;
+ }
+
+ if (n->n_procs != 3) {
+ printf("n_procs not updated.\n");
+ goto fail;
+ }
+
+ if (n->n_active != 4) {
+ printf("n_active not updated.\n");
+ goto fail;
+ }
+
+ pid = info.pol_lb == LB_RR ? TEST_PID : TEST_PID + 2;
+
+ if (reg_name_get_active(n) != pid) {
+ printf("Got wrong active pid 1.\n");
+ goto fail;
+ }
+
+ reg_name_del_active(n, pid);
+
+ if (reg_name_add_active(n, pid) < 0) {
+ printf("Failed to add active 4.\n");
+ goto fail;
+ }
+
+ pid = info.pol_lb == LB_RR ? TEST_PID + 1 : TEST_PID + 2;
+
+ if (reg_name_get_active(n) != pid) {
+ printf("Got wrong active pid 2 %d.\n", pid);
+ goto fail;
+ }
+
+ reg_name_del_proc(n, TEST_PID + 2);
+
+ reg_name_del_proc(n, TEST_PID + 1);
+
+ reg_name_del_proc(n, TEST_PID);
+
+ if (n->n_procs != 0) {
+ printf("n_procs not updated.\n");
+ goto fail;
+ }
+
+ if (n->n_active != 0) {
+ printf("n_active not updated.\n");
+ goto fail;
+ }
+
+ reg_name_destroy(n);
+
+ return 0;
+ fail:
+ return -1;
+}
+
+
+int name_test(int argc,
+ char ** argv)
+{
+ int res = 0;
+
+ (void) argc;
+ (void) argv;
+
+ res |= test_reg_name_create();
+
+ res |= test_reg_name_add_proc();
+
+ res |= test_reg_name_add_prog();
+
+ res |= test_reg_name_add_active(LB_RR);
+
+ res |= test_reg_name_add_active(LB_SPILL);
+
+ return res;
+}
diff --git a/src/irmd/reg/tests/proc_test.c b/src/irmd/reg/tests/proc_test.c
new file mode 100644
index 00000000..5c9dd865
--- /dev/null
+++ b/src/irmd/reg/tests/proc_test.c
@@ -0,0 +1,107 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Processes - Unit Tests
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "../proc.c"
+
+#define TEST_PID 65534
+#define TEST_PROG "usr/bin/testprog"
+
+static int test_reg_proc_create(void)
+{
+ struct reg_proc * proc;
+ struct proc_info info = {
+ .pid = TEST_PID,
+ .prog = TEST_PROG
+ };
+
+ proc = reg_proc_create(&info);
+ if (proc == NULL) {
+ printf("Failed to create proc.\n");
+ goto fail;
+ }
+
+ reg_proc_destroy(proc);
+
+ return 0;
+ fail:
+ return -1;
+}
+
+static int test_reg_proc_add_name(void)
+{
+ struct reg_proc * proc;
+ struct proc_info info = {
+ .pid = TEST_PID,
+ .prog = TEST_PROG
+ };
+
+ char * name = "testname";
+
+ proc = reg_proc_create(&info);
+ if (proc == NULL) {
+ printf("Failed to create proc.\n");
+ goto fail;
+ }
+
+ if (reg_proc_add_name(proc, name) < 0) {
+ printf("Failed to add name.");
+ goto fail;
+ }
+
+ if (proc->n_names != 1) {
+ printf("n_names not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_proc_has_name(proc, name)) {
+ printf("Name not found.\n");
+ goto fail;
+ }
+
+ reg_proc_del_name(proc, name);
+
+ if (proc->n_names != 0) {
+ printf("n_names not updated.\n");
+ goto fail;
+ }
+
+ reg_proc_destroy(proc);
+
+ return 0;
+ fail:
+ return -1;
+}
+
+int proc_test(int argc,
+ char ** argv)
+{
+ int res = 0;
+
+ (void) argc;
+ (void) argv;
+
+ res |= test_reg_proc_create();
+
+ res |= test_reg_proc_add_name();
+
+ return res;
+}
diff --git a/src/irmd/reg/tests/prog_test.c b/src/irmd/reg/tests/prog_test.c
new file mode 100644
index 00000000..5e6931d8
--- /dev/null
+++ b/src/irmd/reg/tests/prog_test.c
@@ -0,0 +1,105 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Programs - Unit Tests
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "../prog.c"
+
+#define TEST_PROG "usr/bin/testprog"
+
+
+static int test_reg_prog_create(void)
+{
+ struct reg_prog * prog;
+ struct prog_info info = {
+ .name = TEST_PROG
+ };
+
+ prog = reg_prog_create(&info);
+ if (prog == NULL) {
+ printf("Failed to create prog.\n");
+ goto fail;
+ }
+
+ reg_prog_destroy(prog);
+
+ return 0;
+ fail:
+ return -1;
+}
+
+static int test_reg_prog_add_name(void)
+{
+ struct reg_prog * prog;
+ struct prog_info info = {
+ .name = TEST_PROG
+ };
+
+ char * name = "testname";
+
+ prog = reg_prog_create(&info);
+ if (prog == NULL) {
+ printf("Failed to create prog.\n");
+ goto fail;
+ }
+
+ if (reg_prog_add_name(prog, name) < 0) {
+ printf("Failed to add name.");
+ goto fail;
+ }
+
+ if (prog->n_names != 1) {
+ printf("n_names not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_prog_has_name(prog, name)) {
+ printf("Name not found.\n");
+ goto fail;
+ }
+
+ reg_prog_del_name(prog, name);
+
+ if (prog->n_names != 0) {
+ printf("n_names not updated.\n");
+ goto fail;
+ }
+
+ reg_prog_destroy(prog);
+
+ return 0;
+ fail:
+ return -1;
+}
+
+int prog_test(int argc,
+ char ** argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_reg_prog_create();
+
+ ret |= test_reg_prog_add_name();
+
+ return ret;
+}
diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c
new file mode 100644
index 00000000..c341c297
--- /dev/null
+++ b/src/irmd/reg/tests/reg_test.c
@@ -0,0 +1,1583 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * The IPC Resource Manager - Registry - Unit Tests
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+
+#include "../reg.c"
+
+#include <ouroboros/test.h>
+
+#define TEST_PID 3666
+#define TEST_N_1_PID 3999
+#define TEST_FAKE_ID 9128349
+#define TEST_MPL 5
+#define TEST_PROG "reg_test" /* own binary for binary check */
+#define TEST_IPCP "testipcp"
+#define TEST_NAME "testname"
+#define TEST_DATA "testpbufdata"
+#define TEST_DATA2 "testpbufdata2"
+#define TEST_LAYER "testlayer"
+#define REG_TEST_FAIL() \
+ do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); } while(0)
+
+static int test_reg_init(void)
+{
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_create_flow(void)
+{
+ struct flow_info info = {
+ .n_pid = TEST_PID,
+ .qs = qos_raw,
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_flow(&info) < 0) {
+ printf("Failed to create flow.\n");
+ goto fail;
+ }
+
+ if (info.id == 0) {
+ printf("Failed to update id.'n");
+ goto fail;
+ }
+
+ if (reg.n_flows != 1) {
+ printf("n_flows was not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_has_flow(info.id)) {
+ printf("Failed to find flow.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_flow(info.id) < 0) {
+ printf("Failed to destroy flow.\n");
+ goto fail;
+ }
+
+ if (reg.n_flows != 0) {
+ printf("n_flows was not updated.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_allocate_flow_timeout(void)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_MS(1);
+ buffer_t pbuf;
+ buffer_t rbuf = {NULL, 0};
+
+ struct flow_info info = {
+ .n_pid = TEST_PID,
+ .qs = qos_raw
+ };
+
+ TEST_START();
+
+ pbuf.data = (uint8_t *) strdup(TEST_DATA);;
+ if (pbuf.data == NULL) {
+ printf("Failed to strdup data.\n");
+ goto fail;
+ }
+
+ pbuf.len = strlen((char *) pbuf.data) + 1;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+
+ ts_add(&abstime, &timeo, &abstime);
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_flow(&info) < 0) {
+ printf("Failed to add flow.\n");
+ goto fail;
+ }
+
+ if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ printf("Failed to prepare flow for accept.\n");
+ goto fail;
+ }
+
+ if (reg_wait_flow_accepted(&info, &rbuf, &abstime) != -ETIMEDOUT) {
+ printf("Wait allocated did not timeout.\n");
+ goto fail;
+ }
+
+ if (info.state != FLOW_DEALLOCATED) {
+ printf("Flow did not timeout in deallocated state.\n");
+ goto fail;
+ }
+
+ if (pbuf.data == NULL) {
+ printf("Flow data was updated on timeout.");
+ goto fail;
+ }
+
+ freebuf(pbuf);
+ reg_destroy_flow(info.id);
+
+ if (reg.n_flows != 0) {
+ printf("Flow did not destroy.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static void * test_flow_respond_alloc(void * o)
+{
+ struct flow_info * info = (struct flow_info *) o;
+ buffer_t pbuf = {NULL, 0};
+
+ if (info->state == FLOW_ALLOCATED) {
+ pbuf.data = (uint8_t *) strdup(TEST_DATA2);
+ if (pbuf.data == NULL) {
+ printf("Failed to strdup data2.\n");
+ goto fail;
+ }
+ pbuf.len = strlen((char *) pbuf.data) + 1;
+ }
+
+ reg_respond_alloc(info, &pbuf);
+
+ return (void *) 0;
+ fail:
+ return (void *) -1;
+}
+
+static void * test_flow_respond_accept(void * o)
+{
+ struct flow_info * info = (struct flow_info *) o;
+ buffer_t pbuf;
+
+ pbuf.data = (uint8_t *) strdup(TEST_DATA2);
+ if (pbuf.data == NULL) {
+ printf("Failed to strdup data2.\n");
+ goto fail;
+ }
+ pbuf.len = strlen((char *) pbuf.data) + 1;
+
+ reg_respond_accept(info, &pbuf);
+
+ if (info->qs.cypher_s == 0) {
+ freebuf(pbuf);
+ } else if (strcmp((char *) pbuf.data, TEST_DATA) != 0) {
+ printf("Data was not passed correctly.\n");
+ goto fail;
+ }
+
+ return (void *) 0;
+ fail:
+ return (void *) -1;
+}
+
+static int test_reg_accept_flow_success(void)
+{
+ pthread_t thr;
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+ buffer_t pbuf = {(uint8_t *) TEST_DATA, strlen(TEST_DATA)};
+ buffer_t rbuf = {NULL, 0};
+
+ struct flow_info info = {
+ .n_pid = TEST_PID,
+ .qs = qos_raw
+ };
+
+ struct flow_info n_1_info = {
+ .n_1_pid = TEST_N_1_PID,
+ .qs = qos_data_crypt,
+ .state = FLOW_ALLOCATED /* RESPONSE SUCCESS */
+ };
+
+ TEST_START();
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+
+ ts_add(&abstime, &timeo, &abstime);
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_flow(&info) < 0) {
+ printf("Failed to add flow.\n");
+ goto fail;
+ }
+
+ if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ printf("Failed to prepare flow for accept.\n");
+ goto fail;
+ }
+
+ n_1_info.id = info.id;
+ n_1_info.mpl = 1;
+
+ pthread_create(&thr, NULL, test_flow_respond_accept, &n_1_info);
+
+ if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0 ) {
+ printf("Flow allocation failed.\n");
+ goto fail;
+ }
+
+ pthread_join(thr, NULL);
+
+ if (info.state != FLOW_ALLOCATED) {
+ printf("Flow succeeded but not in allocated state.\n");
+ goto fail;
+ }
+
+ if (rbuf.data == NULL) {
+ printf("rbuf data not returned.\n");
+ goto fail;
+ }
+
+ if (strcmp((char *) rbuf.data, TEST_DATA2) != 0) {
+ printf("Data2 was not passed correctly.\n");
+ goto fail;
+ }
+
+ freebuf(rbuf);
+
+ reg_dealloc_flow(&info);
+
+ if (info.state != FLOW_DEALLOC_PENDING) {
+ printf("Flow dealloc requested but not in pending state.\n");
+ goto fail;
+ }
+
+ reg_dealloc_flow_resp(&info);
+
+ if (info.state != FLOW_DEALLOCATED) {
+ printf("Flow deallocated but not in deallocated state.\n");
+ goto fail;
+ }
+
+ reg_destroy_flow(n_1_info.id);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_accept_flow_success_no_crypt(void)
+{
+ pthread_t thr;
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+ buffer_t pbuf = {(uint8_t *) TEST_DATA, strlen(TEST_DATA)};
+ buffer_t rbuf = {NULL, 0};
+
+ struct flow_info info = {
+ .n_pid = TEST_PID,
+ .qs = qos_raw
+ };
+
+ struct flow_info n_1_info = {
+ .n_1_pid = TEST_N_1_PID,
+ .qs = qos_data,
+ .state = FLOW_ALLOCATED /* RESPONSE SUCCESS */
+ };
+
+ TEST_START();
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+
+ ts_add(&abstime, &timeo, &abstime);
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_flow(&info) < 0) {
+ printf("Failed to add flow.\n");
+ goto fail;
+ }
+
+ if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ printf("Failed to prepare flow for accept.\n");
+ goto fail;
+ }
+
+ n_1_info.id = info.id;
+ n_1_info.mpl = 1;
+
+ pthread_create(&thr, NULL, test_flow_respond_accept, &n_1_info);
+
+ if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0 ) {
+ printf("Flow allocation failed.\n");
+ goto fail;
+ }
+
+ pthread_join(thr, NULL);
+
+ if (info.state != FLOW_ALLOCATED) {
+ printf("Flow succeeded but not in allocated state.\n");
+ goto fail;
+ }
+
+ if (rbuf.data == NULL) {
+ printf("rbuf data was not returned.\n");
+ goto fail;
+ }
+
+ if (strcmp((char *) rbuf.data, TEST_DATA) != 0) {
+ printf("Data was updated.\n");
+ goto fail;
+ }
+
+ n_1_info.state = FLOW_DEALLOCATED;
+
+ reg_dealloc_flow(&info);
+
+ if (info.state != FLOW_DEALLOC_PENDING) {
+ printf("Flow dealloc requested but not in pending state.\n");
+ goto fail;
+ }
+
+ reg_dealloc_flow_resp(&info);
+
+ if (info.state != FLOW_DEALLOCATED) {
+ printf("Flow deallocated but not in deallocated state.\n");
+ goto fail;
+ }
+
+ reg_destroy_flow(n_1_info.id);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+
+static int test_reg_allocate_flow_fail(void)
+{
+ buffer_t buf = {NULL, 0};
+ pthread_t thr;
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+
+ struct flow_info info = {
+ .n_pid = TEST_PID,
+ .qs = qos_raw
+ };
+
+ struct flow_info n_1_info = {
+ .n_1_pid = TEST_N_1_PID,
+ .qs = qos_data,
+ .state = FLOW_DEALLOCATED /* RESPONSE FAIL */
+ };
+
+ TEST_START();
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+
+ ts_add(&abstime, &timeo, &abstime);
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_flow(&info) < 0) {
+ printf("Failed to add flow.\n");
+ goto fail;
+ }
+
+ info.n_1_pid = TEST_N_1_PID;
+
+ if (reg_prepare_flow_alloc(&info) < 0) {
+ printf("Failed to prepare flow for alloc.\n");
+ goto fail;
+ }
+
+ n_1_info.id = info.id;
+
+ pthread_create(&thr, NULL, test_flow_respond_alloc, &n_1_info);
+
+ if (reg_wait_flow_allocated(&info, &buf, &abstime) == 0 ) {
+ printf("Flow allocation succeeded.\n");
+ goto fail;
+ }
+
+ pthread_join(thr, NULL);
+
+ if (info.state != FLOW_DEALLOCATED) {
+ printf("Flow failed but not in deallocated state.\n");
+ goto fail;
+ }
+
+ reg_destroy_flow(n_1_info.id);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_flow(void) {
+ int ret = 0;
+
+ ret |= test_reg_create_flow();
+
+ ret |= test_reg_allocate_flow_timeout();
+
+ ret |= test_reg_accept_flow_success();
+
+ ret |= test_reg_accept_flow_success_no_crypt();
+
+ ret |= test_reg_allocate_flow_fail();
+
+ return ret;
+}
+
+static int test_reg_create_ipcp(void)
+{
+ struct ipcp_info info = {
+ .name = TEST_IPCP,
+ .pid = TEST_PID,
+ .state = IPCP_BOOT /* set by spawn_ipcp */
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp.\n");
+ goto fail;
+ }
+
+ if (reg.n_ipcps != 1) {
+ printf("n_ipcps was not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_has_ipcp(info.pid)) {
+ printf("Failed to find ipcp.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_proc(info.pid) < 0) {
+ printf("Failed to destroy ipcp.\n");
+ goto fail;
+ }
+
+ if (reg.n_ipcps != 0) {
+ printf("n_ipcps was not updated.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_set_layer(void)
+{
+ struct reg_ipcp * ipcp;
+ struct ipcp_info info = {
+ .name = TEST_IPCP,
+ .pid = TEST_PID,
+ .state = IPCP_BOOT /* set by spawn_ipcp */
+ };
+ struct layer_info layer = {
+ .name = TEST_LAYER,
+ };
+
+ struct ipcp_info get_info = {
+ .pid = TEST_PID
+ };
+ struct layer_info get_layer;
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp.\n");
+ goto fail;
+ }
+
+ ipcp = __reg_get_ipcp(info.pid);
+ ipcp->info.state = IPCP_OPERATIONAL;
+ info.state = IPCP_ENROLLED;
+
+ reg_set_layer_for_ipcp(&info, &layer);
+
+ reg_get_ipcp(&get_info, &get_layer);
+
+ if (memcmp(&get_info, &info, sizeof(ipcp)) != 0) {
+ printf("Failed to set ipcp info.\n");
+ goto fail;
+ }
+
+ if (memcmp(&get_layer, &layer, sizeof(layer)) != 0) {
+ printf("Failed to set layer info.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_proc(info.pid) < 0) {
+ printf("Failed to destroy ipcp.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_ipcp(void)
+{
+ int ret = 0;
+
+ ret |= test_reg_create_ipcp();
+
+ ret |= test_set_layer();
+
+ return ret;
+}
+
+static int test_reg_create_name(void)
+{
+ struct name_info info = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_name(&info) < 0) {
+ printf("Failed to create name.\n");
+ goto fail;
+ }
+
+ if (reg.n_names != 1) {
+ printf("n_names was not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_has_name(info.name)) {
+ printf("Failed to find name.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_name(info.name) < 0) {
+ printf("Failed to destroy name.\n");
+ goto fail;
+ }
+
+ if (reg.n_names != 0) {
+ printf("n_names was not updated.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_name(void)
+{
+ int ret = 0;
+
+ ret |= test_reg_create_name();
+
+ return ret;
+}
+
+static int test_reg_create_proc(void)
+{
+ struct proc_info info = {
+ .pid = TEST_PID,
+ .prog = TEST_PROG
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_proc(&info) < 0) {
+ printf("Failed to create process.\n");
+ goto fail;
+ }
+
+ if (reg.n_procs != 1) {
+ printf("n_procs was not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_has_proc(info.pid)) {
+ printf("Failed to find process.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_proc(info.pid) < 0) {
+ printf("Failed to destroy process.\n");
+ goto fail;
+ }
+
+ if (reg.n_procs != 0) {
+ printf("n_procs was not updated.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_proc(void)
+{
+ int ret = 0;
+
+ ret |= test_reg_create_proc();
+
+ return ret;
+}
+
+static int test_reg_spawned(void)
+{
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_spawned(TEST_PID) < 0) {
+ printf("Failed to create process.\n");
+ goto fail;
+ }
+
+ if (reg.n_spawned != 1) {
+ printf("n_spawned was not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_has_spawned(TEST_PID)) {
+ printf("Failed to find spawned.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_proc(TEST_PID) < 0) {
+ printf("Failed to destroy spawned.\n");
+ goto fail;
+ }
+
+ if (reg.n_spawned != 0) {
+ printf("n_spawned was not updated.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_create_prog(void)
+{
+ struct prog_info info = {
+ .name = TEST_PROG
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_prog(&info) < 0) {
+ printf("Failed to create program.\n");
+ goto fail;
+ }
+
+ if (reg.n_progs != 1) {
+ printf("n_progs was not updated.\n");
+ goto fail;
+ }
+
+ if (!reg_has_prog(info.name)) {
+ printf("Failed to find program.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_prog(info.name) < 0) {
+ printf("Failed to destroy program.\n");
+ goto fail;
+ }
+
+ if (reg.n_progs != 0) {
+ printf("n_progs was not updated.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_reg_prog(void)
+{
+ int ret = 0;
+
+ ret |= test_reg_create_prog();
+
+ return ret;
+}
+
+static int test_bind_proc(void)
+{
+ struct proc_info pinfo = {
+ .pid = TEST_PID,
+ .prog = TEST_PROG
+ };
+
+ struct name_info ninfo = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR
+ };
+
+ TEST_START();
+
+ if (reg_init()) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_name(&ninfo) < 0) {
+ printf("Failed to create name.\n");
+ goto fail;
+ }
+
+ if (reg_create_proc(&pinfo) < 0) {
+ printf("Failed to create proc.\n");
+ goto fail;
+ }
+
+ if (reg_bind_proc(TEST_NAME, TEST_PID) < 0) {
+ printf("Failed to bind proc.\n");
+ goto fail;
+ }
+
+ if (reg_unbind_proc(TEST_NAME, TEST_PID) < 0) {
+ printf("Failed to unbind proc.\n");
+ goto fail;
+ }
+
+ reg_destroy_proc(TEST_PID);
+
+ if (reg_name_has_proc( __reg_get_name(TEST_NAME), TEST_PID)) {
+ printf("Proc still in name after destroy.\n");
+ goto fail;
+ }
+
+ reg_destroy_name(TEST_NAME);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_bind_prog(void)
+{
+ struct prog_info pinfo = {
+ .name = TEST_PROG
+ };
+
+ struct name_info ninfo = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR
+ };
+
+ char * exec[] = { TEST_PROG, "--argswitch", "argvalue", NULL};
+
+ TEST_START();
+
+ if (reg_init()) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_name(&ninfo) < 0) {
+ printf("Failed to create name.\n");
+ goto fail;
+ }
+
+ if (reg_create_prog(&pinfo) < 0) {
+ printf("Failed to create prog.\n");
+ goto fail;
+ }
+
+ if (reg_bind_prog(TEST_NAME, exec, BIND_AUTO) < 0) {
+ printf("Failed to bind prog.\n");
+ goto fail;
+ }
+
+ if (!reg_name_has_prog( __reg_get_name(TEST_NAME), TEST_PROG)) {
+ printf("Prog not found in name.\n");
+ goto fail;
+ }
+
+ if (!reg_prog_has_name( __reg_get_prog(TEST_PROG), TEST_NAME)) {
+ printf("Name not found in prog.\n");
+ goto fail;
+ }
+
+ if (reg_unbind_prog(TEST_NAME, TEST_PROG) < 0) {
+ printf("Failed to unbind prog.\n");
+ goto fail;
+ }
+
+ if (reg_name_has_prog( __reg_get_name(TEST_NAME), TEST_PROG)) {
+ printf("Prog still in name after unbind.\n");
+ goto fail;
+ }
+
+ if (reg_prog_has_name( __reg_get_prog(TEST_PROG), TEST_NAME)) {
+ printf("Name still in prog after unbind.\n");
+ goto fail;
+ }
+
+ if (reg_bind_prog(TEST_NAME, exec, 0) < 0) {
+ printf("Failed to bind prog.\n");
+ goto fail;
+ }
+
+ if (reg_name_has_prog( __reg_get_name(TEST_NAME), TEST_PROG)) {
+ printf("Non-auto prog found in name.\n");
+ goto fail;
+ }
+
+ if (reg_unbind_prog(TEST_NAME, TEST_PROG) < 0) {
+ printf("Failed to unbind prog.\n");
+ goto fail;
+ }
+
+ reg_destroy_prog(TEST_PROG);
+
+ reg_destroy_name(TEST_NAME);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_inherit_prog(void)
+{
+ struct name_info nameinfo = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR
+ };
+
+ struct prog_info proginfo = {
+ .name = TEST_PROG
+ };
+
+ struct proc_info procinfo = {
+ .pid = TEST_PID,
+ .prog = TEST_PROG
+ };
+
+ char * exec[] = { TEST_PROG, NULL};
+
+ TEST_START();
+
+ if (reg_init()) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_name(&nameinfo) < 0) {
+ printf("Failed to create name.\n");
+ goto fail;
+ }
+
+ if (reg_create_prog(&proginfo) < 0) {
+ printf("Failed to create prog.\n");
+ goto fail;
+ }
+
+ if (reg_bind_prog(TEST_NAME, exec, 0) < 0) {
+ printf("Failed to bind prog.\n");
+ goto fail;
+ }
+
+ if (reg_create_proc(&procinfo) < 0) {
+ printf("Failed to create proc.\n");
+ goto fail;
+ }
+
+ if (!reg_name_has_proc(__reg_get_name(TEST_NAME), TEST_PID)) {
+ printf("Failed to update name from prog.\n");
+ goto fail;
+ }
+
+ if (!reg_proc_has_name(__reg_get_proc(TEST_PID), TEST_NAME)) {
+ printf("Failed to update proc from prog.\n");
+ goto fail;
+ }
+
+ reg_destroy_proc(TEST_PID);
+
+ reg_destroy_prog(TEST_PROG);
+
+ reg_destroy_name(TEST_NAME);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_wait_accepting_timeout(void)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_MS(1);
+ int flow_id;
+ uint8_t hash[64];
+ struct name_info ninfo = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR
+ };
+
+ TEST_START();
+
+ if (reg_init()) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_name(&ninfo) < 0) {
+ printf("Failed to create name.\n");
+ goto fail;
+ }
+
+ str_hash(HASH_SHA3_256, hash, ninfo.name);
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ flow_id = reg_wait_flow_accepting(HASH_SHA3_256, hash, &abstime);
+ if (flow_id != -ETIMEDOUT) {
+ printf("Wait accept did not time out: %d.\n", flow_id);
+ goto fail;
+ }
+
+ reg_destroy_name(TEST_NAME);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_wait_accepting_fail_name(void)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+ int flow_id;
+ uint8_t hash[64];
+
+ TEST_START();
+
+ if (reg_init()) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+ str_hash(HASH_SHA3_256, hash, "C0FF33");
+
+ flow_id = reg_wait_flow_accepting(HASH_SHA3_256, hash, &abstime);
+ if (flow_id != -ENAME) {
+ printf("Wait accept did not fail on name: %d.\n", flow_id);
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static void * test_call_flow_accept(void * o)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_MS(1);
+ buffer_t pbuf = {NULL, 0};
+
+ struct proc_info pinfo = {
+ .pid = TEST_PID,
+ .prog = TEST_PROG
+ };
+
+ struct flow_info info = {
+ .n_pid = pinfo.pid,
+ .qs = qos_raw,
+ };
+
+ if (reg_create_proc(&pinfo) < 0) {
+ printf("Failed to create proc.\n");
+ goto fail;
+ }
+
+ if (reg_bind_proc((char *) o, TEST_PID) < 0) {
+ printf("Failed to bind proc.\n");
+ goto fail;
+ }
+
+ if (reg_create_flow(&info) < 0) {
+ printf("Failed to create flow.\n");
+ goto fail;
+ }
+
+ info.state = FLOW_ACCEPT_PENDING;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ reg_prepare_flow_accept(&info, &pbuf);
+
+ if (reg_wait_flow_accepted(&info, &pbuf, &abstime) != -ETIMEDOUT) {
+ printf("Wait allocated did not timeout.\n");
+ goto fail;
+ }
+
+ reg_destroy_flow(info.id);
+ reg_destroy_proc(pinfo.pid);
+
+ return (void *) 0;
+ fail:
+ return (void *) -1;
+}
+
+static int test_wait_accepting_success(void)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+ int flow_id;
+ pthread_t thr;
+ uint8_t hash[64];
+ struct name_info ninfo = {
+ .name = TEST_NAME,
+ .pol_lb = LB_RR
+ };
+
+ TEST_START();
+
+ if (reg_init()) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_name(&ninfo) < 0) {
+ printf("Failed to create name.\n");
+ goto fail;
+ }
+
+ pthread_create(&thr, NULL, test_call_flow_accept, ninfo.name);
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ str_hash(HASH_SHA3_256, hash, ninfo.name);
+
+ flow_id = reg_wait_flow_accepting(HASH_SHA3_256, hash, &abstime);
+ if (flow_id < 0) {
+ printf("Wait accept did not return a flow id: %d.", flow_id);
+ goto fail;
+ }
+
+ pthread_join(thr, NULL);
+
+ reg_destroy_name(TEST_NAME);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_wait_accepting(void)
+{
+ int ret = 0;
+
+ ret |= test_wait_accepting_timeout();
+
+ ret |= test_wait_accepting_fail_name();
+
+ ret |= test_wait_accepting_success();
+
+ return ret;
+}
+
+static int test_wait_ipcp_boot_timeout(void)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_MS(1);
+ struct ipcp_info info = {
+ .name = TEST_IPCP,
+ .pid = TEST_PID,
+ .state = IPCP_BOOT /* set by spawn_ipcp */
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp.\n");
+ goto fail;
+ }
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ if (reg_wait_ipcp_boot(&info, &abstime) != -ETIMEDOUT) {
+ printf("Wait boot did not timeout.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_proc(info.pid) < 0) {
+ printf("Failed to destroy ipcp.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static void * test_ipcp_respond(void * o)
+{
+ (void) o;
+
+ reg_respond_ipcp((struct ipcp_info *) o);
+
+ return (void *) 0;
+}
+
+static int test_wait_ipcp_boot_fail(void)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+ pthread_t thr;
+ struct ipcp_info info = {
+ .name = TEST_IPCP,
+ .pid = TEST_PID,
+ .state = IPCP_BOOT /* set by spawn_ipcp */
+ };
+ struct ipcp_info resp_info = {
+ .name = TEST_IPCP,
+ .pid = TEST_PID,
+ .state = IPCP_NULL
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp.\n");
+ goto fail;
+ }
+
+ pthread_create(&thr, NULL, test_ipcp_respond, &resp_info);
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ info.state = IPCP_BOOT;
+
+ if (reg_wait_ipcp_boot(&info, &abstime) == 0) {
+ printf("IPCP boot reported success.\n");
+ goto fail;
+ }
+
+ pthread_join(thr, NULL);
+
+ if (reg_destroy_proc(info.pid) < 0) {
+ printf("Failed to destroy ipcp.\n");
+ goto fail;
+ }
+
+ if (reg.n_ipcps != 0) {
+ printf("n_ipcps was not updated.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_wait_ipcp_boot_success(void)
+{
+ pthread_t thr;
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+ struct ipcp_info info = {
+ .name = TEST_IPCP,
+ .pid = TEST_PID,
+ .state = IPCP_BOOT /* set by spawn_ipcp */
+ };
+ struct ipcp_info resp_info = {
+ .name = TEST_IPCP,
+ .pid = TEST_PID,
+ .state = IPCP_OPERATIONAL
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp.\n");
+ goto fail;
+ }
+
+ pthread_create(&thr, NULL, test_ipcp_respond, &resp_info);
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ info.state = IPCP_BOOT;
+
+ if (reg_wait_ipcp_boot(&info, &abstime) < 0) {
+ printf("IPCP boot failed.\n");
+ goto fail;
+ }
+
+ pthread_join(thr, NULL);
+
+ if (info.state != IPCP_OPERATIONAL) {
+ printf("IPCP boot succeeded in non-operational state.\n");
+ goto fail;
+ }
+
+ if (reg_destroy_proc(info.pid) < 0) {
+ printf("Failed to destroy ipcp.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_wait_ipcp_boot(void)
+{
+ int ret = 0;
+
+ ret |= test_wait_ipcp_boot_timeout();
+
+ ret |= test_wait_ipcp_boot_fail();
+
+ ret |= test_wait_ipcp_boot_success();
+
+ return ret;
+}
+
+static int test_wait_proc_timeout(void)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_MS(1);
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ if (reg_wait_proc(TEST_PID, &abstime) != -ETIMEDOUT) {
+ printf("Wait proc did not timeout.\n");
+ goto fail;
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static void * test_proc(void * o)
+{
+ (void) o;
+
+ reg_create_proc((struct proc_info *) o);
+
+ return (void *) 0;
+}
+
+static int test_wait_proc_success(void)
+{
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+ pthread_t thr;
+ struct proc_info info = {
+ .pid = TEST_PID,
+ .prog = TEST_PROG
+ };
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ pthread_create(&thr, NULL, test_proc, &info);
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ if (reg_wait_proc(info.pid, &abstime) < 0) {
+ printf("Waiting for proc failed.\n");
+ goto fail;
+ }
+
+ pthread_join(thr, NULL);
+
+ reg_destroy_proc(info.pid);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return 0;
+ fail:
+ REG_TEST_FAIL();
+ return -1;
+}
+
+static int test_wait_proc(void)
+{
+ int ret = 0;
+
+ ret |= test_wait_proc_timeout();
+
+ ret |= test_wait_proc_success();
+
+ return ret;
+}
+
+
+int reg_test(int argc,
+ char ** argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_reg_init();
+
+ ret |= test_reg_flow();
+
+ ret |= test_reg_ipcp();
+
+ ret |= test_reg_name();
+
+ ret |= test_reg_proc();
+
+ ret |= test_reg_prog();
+
+ ret |= test_reg_spawned();
+
+ ret |= test_bind_proc();
+
+ ret |= test_bind_prog();
+
+ ret |= test_inherit_prog();
+
+ ret |= test_wait_accepting();
+
+ ret |= test_wait_ipcp_boot();
+
+ ret |= test_wait_proc();
+
+ return ret;
+}
diff --git a/src/irmd/registry.c b/src/irmd/registry.c
deleted file mode 100644
index 66cc5af3..00000000
--- a/src/irmd/registry.c
+++ /dev/null
@@ -1,615 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Registry
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 200809L
-#endif
-
-#include "config.h"
-
-#define OUROBOROS_PREFIX "registry"
-
-#include <ouroboros/errno.h>
-#include <ouroboros/logs.h>
-#include <ouroboros/time_utils.h>
-
-#include "registry.h"
-#include "utils.h"
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <signal.h>
-#include <unistd.h>
-#include <limits.h>
-#include <assert.h>
-
-static struct reg_entry * reg_entry_create(void)
-{
- struct reg_entry * e;
-
- e = malloc(sizeof(*e));
- if (e == NULL)
- return NULL;
-
- e->name = NULL;
- e->state = REG_NAME_NULL;
-
- return e;
-}
-
-static int reg_entry_init(struct reg_entry * e,
- char * name)
-{
- pthread_condattr_t cattr;
-
- assert(e);
- assert(name);
-
- list_head_init(&e->next);
- list_head_init(&e->reg_progs);
- list_head_init(&e->reg_pids);
-
- e->name = name;
- e->pol_lb = 0;
-
- if (pthread_condattr_init(&cattr))
- goto fail_cattr;
-
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
- if (pthread_cond_init(&e->state_cond, &cattr))
- goto fail_cond;
-
- if (pthread_mutex_init(&e->state_lock, NULL))
- goto fail_mutex;
-
- pthread_condattr_destroy(&cattr);
-
- e->state = REG_NAME_IDLE;
-
- return 0;
-
- fail_mutex:
- pthread_cond_destroy(&e->state_cond);
- fail_cond:
- pthread_condattr_destroy(&cattr);
- fail_cattr:
- return -1;
-}
-
-static void cancel_reg_entry_destroy(void * o)
-{
- struct reg_entry * e;
- struct list_head * p;
- struct list_head * h;
-
- e = (struct reg_entry *) o;
-
- pthread_mutex_unlock(&e->state_lock);
-
- pthread_cond_destroy(&e->state_cond);
- pthread_mutex_destroy(&e->state_lock);
-
- if (e->name != NULL)
- free(e->name);
-
- list_for_each_safe(p, h, &e->reg_pids) {
- struct pid_el * pe = list_entry(p, struct pid_el, next);
- list_del(&pe->next);
- free(pe);
- }
-
- list_for_each_safe(p, h, &e->reg_progs) {
- struct str_el * a = list_entry(p, struct str_el, next);
- list_del(&a->next);
- free(a->str);
- free(a);
- }
-
- free(e);
-}
-
-static void reg_entry_destroy(struct reg_entry * e)
-{
- if (e == NULL)
- return;
-
- pthread_mutex_lock(&e->state_lock);
-
- if (e->state == REG_NAME_DESTROY) {
- pthread_mutex_unlock(&e->state_lock);
- return;
- }
-
- if (e->state != REG_NAME_FLOW_ACCEPT)
- e->state = REG_NAME_NULL;
- else
- e->state = REG_NAME_DESTROY;
-
- pthread_cond_broadcast(&e->state_cond);
-
- pthread_cleanup_push(cancel_reg_entry_destroy, e);
-
- while (e->state != REG_NAME_NULL)
- pthread_cond_wait(&e->state_cond, &e->state_lock);
-
- pthread_cleanup_pop(true);
-}
-
-static bool reg_entry_has_prog(struct reg_entry * e,
- const char * prog)
-{
- struct list_head * p;
-
- list_for_each(p, &e->reg_progs) {
- struct str_el * e = list_entry(p, struct str_el, next);
- if (!strcmp(e->str, prog))
- return true;
- }
-
- return false;
-}
-
-int reg_entry_add_prog(struct reg_entry * e,
- struct prog_entry * a)
-{
- struct str_el * n;
-
- if (reg_entry_has_prog(e, a->prog)) {
- log_warn("Program %s already accepting flows for %s.",
- a->prog, e->name);
- return 0;
- }
-
- if (!(a->flags & BIND_AUTO)) {
- log_dbg("Program %s cannot be auto-instantiated.", a->prog);
- return 0;
- }
-
- n = malloc(sizeof(*n));
- if (n == NULL)
- return -ENOMEM;
-
- n->str = strdup(a->prog);
- if (n->str == NULL) {
- free(n);
- return -ENOMEM;
- }
-
- list_add(&n->next, &e->reg_progs);
-
- pthread_mutex_lock(&e->state_lock);
-
- if (e->state == REG_NAME_IDLE)
- e->state = REG_NAME_AUTO_ACCEPT;
-
- pthread_mutex_unlock(&e->state_lock);
-
- return 0;
-}
-
-void reg_entry_del_prog(struct reg_entry * e,
- const char * prog)
-{
- struct list_head * p;
- struct list_head * h;
-
- list_for_each_safe(p, h, &e->reg_progs) {
- struct str_el * e = list_entry(p, struct str_el, next);
- if (!strcmp(prog, e->str)) {
- list_del(&e->next);
- free(e->str);
- free(e);
- }
- }
-
- pthread_mutex_lock(&e->state_lock);
-
- if (e->state == REG_NAME_AUTO_ACCEPT && list_is_empty(&e->reg_progs)) {
- e->state = REG_NAME_IDLE;
- pthread_cond_broadcast(&e->state_cond);
- }
-
- pthread_mutex_unlock(&e->state_lock);
-}
-
-char * reg_entry_get_prog(struct reg_entry * e)
-{
- if (!list_is_empty(&e->reg_pids) || list_is_empty(&e->reg_progs))
- return NULL;
-
- return list_first_entry(&e->reg_progs, struct str_el, next)->str;
-}
-
-static bool reg_entry_has_pid(struct reg_entry * e,
- pid_t pid)
-{
- struct list_head * p;
-
- list_for_each(p, &e->reg_progs) {
- struct pid_el * e = list_entry(p, struct pid_el, next);
- if (e->pid == pid)
- return true;
- }
-
- return false;
-}
-
-int reg_entry_add_pid(struct reg_entry * e,
- pid_t pid)
-{
- struct pid_el * i;
-
- assert(e);
-
- if (reg_entry_has_pid(e, pid)) {
- log_dbg("Process already registered with this name.");
- return -EPERM;
- }
-
- pthread_mutex_lock(&e->state_lock);
-
- if (e->state == REG_NAME_NULL) {
- pthread_mutex_unlock(&e->state_lock);
- log_dbg("Tried to add instance in NULL state.");
- return -EPERM;
- }
-
- i = malloc(sizeof(*i));
- if (i == NULL) {
- pthread_mutex_unlock(&e->state_lock);
- return -ENOMEM;
- }
-
- i->pid = pid;
-
- /* load balancing policy assigns queue order for this process. */
- switch(e->pol_lb) {
- case LB_RR: /* Round robin policy. */
- list_add_tail(&i->next, &e->reg_pids);
- break;
- case LB_SPILL: /* Keep accepting flows on the current process */
- list_add(&i->next, &e->reg_pids);
- break;
- default:
- assert(false);
- };
-
- if (e->state == REG_NAME_IDLE ||
- e->state == REG_NAME_AUTO_ACCEPT ||
- e->state == REG_NAME_AUTO_EXEC) {
- e->state = REG_NAME_FLOW_ACCEPT;
- pthread_cond_broadcast(&e->state_cond);
- }
-
- pthread_mutex_unlock(&e->state_lock);
-
- return 0;
-}
-
-void reg_entry_set_policy(struct reg_entry * e,
- enum pol_balance p)
-{
- e->pol_lb = p;
-}
-
-
-static void reg_entry_check_state(struct reg_entry * e)
-{
- assert(e);
-
- if (e->state == REG_NAME_DESTROY) {
- e->state = REG_NAME_NULL;
- pthread_cond_broadcast(&e->state_cond);
- return;
- }
-
- if (list_is_empty(&e->reg_pids)) {
- if (!list_is_empty(&e->reg_progs))
- e->state = REG_NAME_AUTO_ACCEPT;
- else
- e->state = REG_NAME_IDLE;
- } else {
- e->state = REG_NAME_FLOW_ACCEPT;
- }
-
- pthread_cond_broadcast(&e->state_cond);
-}
-
-void reg_entry_del_pid_el(struct reg_entry * e,
- struct pid_el * p)
-{
- assert(e);
- assert(p);
-
- list_del(&p->next);
- free(p);
-
- reg_entry_check_state(e);
-}
-
-void reg_entry_del_pid(struct reg_entry * e,
- pid_t pid)
-{
- struct list_head * p;
- struct list_head * h;
-
- assert(e);
-
- if (e == NULL)
- return;
-
- list_for_each_safe(p, h, &e->reg_pids) {
- struct pid_el * a = list_entry(p, struct pid_el, next);
- if (a->pid == pid) {
- list_del(&a->next);
- free(a);
- }
- }
-
- reg_entry_check_state(e);
-}
-
-pid_t reg_entry_get_pid(struct reg_entry * e)
-{
- if (e == NULL)
- return -1;
-
- if (list_is_empty(&e->reg_pids))
- return -1;
-
- return list_first_entry(&e->reg_pids, struct pid_el, next)->pid;
-}
-
-enum reg_name_state reg_entry_get_state(struct reg_entry * e)
-{
- enum reg_name_state state;
-
- assert(e);
-
- pthread_mutex_lock(&e->state_lock);
-
- state = e->state;
-
- pthread_mutex_unlock(&e->state_lock);
-
- return state;
-}
-
-int reg_entry_set_state(struct reg_entry * e,
- enum reg_name_state state)
-{
- assert(state != REG_NAME_DESTROY);
-
- pthread_mutex_lock(&e->state_lock);
-
- e->state = state;
- pthread_cond_broadcast(&e->state_cond);
-
- pthread_mutex_unlock(&e->state_lock);
-
- return 0;
-}
-
-int reg_entry_leave_state(struct reg_entry * e,
- enum reg_name_state state,
- struct timespec * timeout)
-{
- struct timespec abstime;
- int ret = 0;
-
- assert(e);
- assert(state != REG_NAME_DESTROY);
-
- if (timeout != NULL) {
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- ts_add(&abstime, timeout, &abstime);
- }
-
- pthread_mutex_lock(&e->state_lock);
-
- pthread_cleanup_push((void *)(void *) pthread_mutex_unlock,
- &e->state_lock);
-
- while (e->state == state && ret != -ETIMEDOUT)
- if (timeout)
- ret = -pthread_cond_timedwait(&e->state_cond,
- &e->state_lock,
- &abstime);
- else
- ret = -pthread_cond_wait(&e->state_cond,
- &e->state_lock);
-
- if (e->state == REG_NAME_DESTROY) {
- ret = -1;
- e->state = REG_NAME_NULL;
- pthread_cond_broadcast(&e->state_cond);
- }
-
- pthread_cleanup_pop(true);
-
- return ret;
-}
-
-int reg_entry_wait_state(struct reg_entry * e,
- enum reg_name_state state,
- struct timespec * timeout)
-{
- struct timespec abstime;
- int ret = 0;
-
- assert(e);
- assert(state != REG_NAME_DESTROY);
-
- if (timeout != NULL) {
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- ts_add(&abstime, timeout, &abstime);
- }
-
- pthread_mutex_lock(&e->state_lock);
-
- while (e->state != state &&
- e->state != REG_NAME_DESTROY &&
- ret != -ETIMEDOUT)
- if (timeout)
- ret = -pthread_cond_timedwait(&e->state_cond,
- &e->state_lock,
- &abstime);
- else
- ret = -pthread_cond_wait(&e->state_cond,
- &e->state_lock);
-
- if (e->state == REG_NAME_DESTROY) {
- ret = -1;
- e->state = REG_NAME_NULL;
- pthread_cond_broadcast(&e->state_cond);
- }
-
- pthread_mutex_unlock(&e->state_lock);
-
- return ret;
-}
-
-struct reg_entry * registry_get_entry(struct list_head * registry,
- const char * name)
-{
- struct list_head * p = NULL;
-
- assert(registry);
-
- list_for_each(p, registry) {
- struct reg_entry * e = list_entry(p, struct reg_entry, next);
- if (!strcmp(name, e->name))
- return e;
- }
-
- return NULL;
-}
-
-struct reg_entry * registry_get_entry_by_hash(struct list_head * registry,
- enum hash_algo algo,
- const uint8_t * hash,
- size_t len)
-{
- struct list_head * p = NULL;
- uint8_t * thash;
-
- thash = malloc(len);
- if (thash == NULL)
- return NULL;
-
- assert(registry);
-
- list_for_each(p, registry) {
- struct reg_entry * e = list_entry(p, struct reg_entry, next);
- str_hash(algo, thash, e->name);
- if (memcmp(thash, hash, len) == 0) {
- free(thash);
- return e;
- }
- }
-
- free(thash);
-
- return NULL;
-}
-
-struct reg_entry * registry_add_name(struct list_head * registry,
- const char * name)
-{
- struct reg_entry * e = NULL;
-
- assert(registry);
- assert(name);
-
- if (registry_has_name(registry, name)) {
- log_dbg("Name %s already registered.", name);
- return NULL;
- }
-
- e = reg_entry_create();
- if (e == NULL) {
- log_dbg("Could not create registry entry.");
- return NULL;
- }
-
- if (reg_entry_init(e, strdup(name))) {
- reg_entry_destroy(e);
- log_dbg("Could not initialize registry entry.");
- return NULL;
- }
-
- list_add(&e->next, registry);
-
- return e;
-}
-
-void registry_del_name(struct list_head * registry,
- const char * name)
-{
- struct reg_entry * e = registry_get_entry(registry, name);
- if (e == NULL)
- return;
-
- list_del(&e->next);
- reg_entry_destroy(e);
-
- return;
-}
-
-void registry_del_process(struct list_head * registry,
- pid_t pid)
-{
- struct list_head * p;
-
- assert(registry);
- assert(pid > 0);
-
- list_for_each(p, registry) {
- struct reg_entry * e = list_entry(p, struct reg_entry, next);
- pthread_mutex_lock(&e->state_lock);
- assert(e);
- reg_entry_del_pid(e, pid);
- pthread_mutex_unlock(&e->state_lock);
- }
-
- return;
-}
-
-void registry_destroy(struct list_head * registry)
-{
- struct list_head * p = NULL;
- struct list_head * h = NULL;
-
- assert(registry);
-
- list_for_each_safe(p, h, registry) {
- struct reg_entry * e = list_entry(p, struct reg_entry, next);
- list_del(&e->next);
- reg_entry_set_state(e, REG_NAME_NULL);
- reg_entry_destroy(e);
- }
-}
diff --git a/src/irmd/registry.h b/src/irmd/registry.h
deleted file mode 100644
index bc9aa23b..00000000
--- a/src/irmd/registry.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Registry
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_IRMD_REGISTRY_H
-#define OUROBOROS_IRMD_REGISTRY_H
-
-#include <ouroboros/hash.h>
-#include <ouroboros/ipcp.h>
-#include <ouroboros/list.h>
-#include <ouroboros/irm.h>
-
-#include "proc_table.h"
-#include "prog_table.h"
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <pthread.h>
-#include <string.h>
-#include <sys/types.h>
-
-#define registry_has_name(r, name) \
- (registry_get_entry(r, name) != NULL)
-
-enum reg_name_state {
- REG_NAME_NULL = 0,
- REG_NAME_IDLE,
- REG_NAME_AUTO_ACCEPT,
- REG_NAME_AUTO_EXEC,
- REG_NAME_FLOW_ACCEPT,
- REG_NAME_FLOW_ARRIVED,
- REG_NAME_DESTROY
-};
-
-/* An entry in the registry */
-struct reg_entry {
- struct list_head next;
- char * name;
-
- /* Policies for this name. */
- enum pol_balance pol_lb; /* Load balance incoming flows. */
- /* Programs that can be instantiated by the irmd. */
- struct list_head reg_progs;
- /* Processes that are listening for this name. */
- struct list_head reg_pids;
-
- enum reg_name_state state;
- pthread_cond_t state_cond;
- pthread_mutex_t state_lock;
-};
-
-int reg_entry_add_prog(struct reg_entry * e,
- struct prog_entry * a);
-
-void reg_entry_del_prog(struct reg_entry * e,
- const char * prog);
-
-char * reg_entry_get_prog(struct reg_entry * e);
-
-int reg_entry_add_pid(struct reg_entry * e,
- pid_t pid);
-
-void reg_entry_del_pid(struct reg_entry * e,
- pid_t pid);
-
-void reg_entry_del_pid_el(struct reg_entry * e,
- struct pid_el * a);
-
-pid_t reg_entry_get_pid(struct reg_entry * e);
-
-void reg_entry_set_policy(struct reg_entry * e,
- enum pol_balance p);
-
-enum reg_name_state reg_entry_get_state(struct reg_entry * e);
-
-int reg_entry_set_state(struct reg_entry * e,
- enum reg_name_state state);
-
-int reg_entry_leave_state(struct reg_entry * e,
- enum reg_name_state state,
- struct timespec * timeout);
-
-int reg_entry_wait_state(struct reg_entry * e,
- enum reg_name_state state,
- struct timespec * timeout);
-
-struct reg_entry * registry_add_name(struct list_head * registry,
- const char * name);
-
-void registry_del_name(struct list_head * registry,
- const char * name);
-
-void registry_del_process(struct list_head * registry,
- pid_t pid);
-
-void registry_sanitize_pids(struct list_head * registry);
-
-struct reg_entry * registry_get_entry(struct list_head * registry,
- const char * name);
-
-struct reg_entry * registry_get_entry_by_hash(struct list_head * registry,
- enum hash_algo algo,
- const uint8_t * hash,
- size_t len);
-
-void registry_destroy(struct list_head * registry);
-
-#endif /* OUROBOROS_IRMD_REGISTRY_H */
diff --git a/src/irmd/tests/CMakeLists.txt b/src/irmd/tests/CMakeLists.txt
index 68bd762d..99743052 100644
--- a/src/irmd/tests/CMakeLists.txt
+++ b/src/irmd/tests/CMakeLists.txt
@@ -2,18 +2,22 @@ get_filename_component(tmp ".." ABSOLUTE)
get_filename_component(src_folder "${tmp}" NAME)
create_test_sourcelist(${src_folder}_tests test_suite.c
- # Add new tests here
+ # Add new tests here
)
add_executable(${src_folder}_test EXCLUDE_FROM_ALL ${${src_folder}_tests})
-target_link_libraries(${src_folder}_test ouroboros)
+target_link_libraries(${src_folder}_test ouroboros-common)
add_dependencies(check ${src_folder}_test)
set(tests_to_run ${${src_folder}_tests})
-remove(tests_to_run test_suite.c)
+if(CMAKE_VERSION VERSION_LESS "3.29.0")
+ remove(tests_to_run test_suite.c)
+else ()
+ list(POP_FRONT tests_to_run)
+endif()
foreach(test ${tests_to_run})
get_filename_component(test_name ${test} NAME_WE)
- add_test(${test_name} ${C_TEST_PATH}/${src_folder}_test ${test_name})
+ add_test(irmd/${test_name} ${C_TEST_PATH}/${src_folder}_test ${test_name})
endforeach(test)
diff --git a/src/irmd/utils.c b/src/irmd/utils.c
deleted file mode 100644
index a525014b..00000000
--- a/src/irmd/utils.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * The IPC Resource Manager - Utilities
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define _POSIX_C_SOURCE 200809L
-
-#include <stdlib.h>
-#include <string.h>
-
-void argvfree(char ** argv)
-{
- char ** argv_dup = argv;
- if (argv == NULL)
- return;
-
- while (*argv_dup != NULL)
- free(*(argv_dup++));
-
- free(argv);
-}
-
-char ** argvdup(char ** argv)
-{
- int argc = 0;
- char ** argv_dup = argv;
- int i;
-
- if (argv == NULL)
- return NULL;
-
- while (*(argv_dup++) != NULL)
- argc++;
-
- if (argc != 0) {
- argv_dup = malloc((argc + 1) * sizeof(*argv_dup));
- for (i = 0; i < argc; ++i) {
- argv_dup[i] = strdup(argv[i]);
- if (argv_dup[i] == NULL) {
- argvfree(argv_dup);
- return NULL;
- }
- }
- }
- argv_dup[argc] = NULL;
- return argv_dup;
-}
diff --git a/src/lib/.gitignore b/src/lib/.gitignore
index 8704469b..3ecaf66d 100644
--- a/src/lib/.gitignore
+++ b/src/lib/.gitignore
@@ -1 +1 @@
-*.pb-c.[ch] \ No newline at end of file
+*.pb-c.[ch]
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index c5be9946..a6d7ac98 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -4,13 +4,18 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
-protobuf_generate_c(IRM_PROTO_SRCS IRM_PROTO_HDRS irmd_messages.proto)
-protobuf_generate_c(IPCP_PROTO_SRCS IPCP_PROTO_HDRS ipcpd_messages.proto)
-protobuf_generate_c(QOSSPEC_PROTO_SRCS QOSSPEC_PROTO_HDRS
- qosspec.proto)
-protobuf_generate_c(LAYER_CONFIG_PROTO_SRCS LAYER_CONFIG_PROTO_HDRS
- ipcp_config.proto)
-protobuf_generate_c(CACEP_PROTO_SRCS CACEP_PROTO_HDRS cacep.proto)
+protobuf_generate_c(MODEL_PROTO_SRCS MODEL_PROTO_HDRS
+ pb/model.proto)
+protobuf_generate_c(IPCP_CONFIG_PROTO_SRCS IPCP_CONFIG_PROTO_HDRS
+ pb/ipcp_config.proto)
+protobuf_generate_c(ENROLL_PROTO_SRCS ENROLL_PROTO_HDRS
+ pb/enroll.proto)
+protobuf_generate_c(CEP_PROTO_SRCS CEP_PROTO_HDRS
+ pb/cep.proto)
+protobuf_generate_c(IRM_PROTO_SRCS IRM_PROTO_HDRS
+ pb/irm.proto)
+protobuf_generate_c(IPCP_PROTO_SRCS IPCP_PROTO_HDRS
+ pb/ipcp.proto)
if (NOT APPLE)
find_library(LIBRT_LIBRARIES rt)
@@ -118,6 +123,7 @@ endif ()
if (NOT HAVE_OPENSSL_RNG)
set(OPENSSL_INCLUDE_DIR "")
set(OPENSSL_LIBRARIES "")
+ set(OPENSSL_CRYPTO_LIBRARY "")
endif ()
if (APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
@@ -140,10 +146,10 @@ if (NOT ((CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") OR APPLE OR
endif ()
mark_as_advanced(LIBRT_LIBRARIES LIBPTHREAD_LIBRARIES
- LIBGCRYPT_LIBRARIES OPENSSL_LIBRARIES SYS_RND_INCLUDE_DIR
- LIBGCRYPT_INCLUDE_DIR SYS_RND_HDR)
+ LIBGCRYPT_LIBRARIES OPENSSL_LIBRARIES OPENSSL_CRYPTO_LIBRARY
+ SYS_RND_INCLUDE_DIR LIBGCRYPT_INCLUDE_DIR SYS_RND_HDR)
-set(SHM_BUFFER_SIZE 4096 CACHE STRING
+set(SHM_BUFFER_SIZE 16384 CACHE STRING
"Number of blocks in packet buffer, must be a power of 2")
set(SHM_RBUFF_SIZE 1024 CACHE STRING
"Number of blocks in rbuff buffer, must be a power of 2")
@@ -166,7 +172,7 @@ else ()
set(PTHREAD_COND_CLOCK "CLOCK_REALTIME" CACHE INTERNAL
"Clock to use for condition variable timing")
endif ()
-set(SOCKET_TIMEOUT 1000 CACHE STRING
+set(SOCKET_TIMEOUT 500 CACHE STRING
"Default timeout for responses from IPCPs (ms)")
set(SHM_PREFIX "ouroboros" CACHE STRING
"String to prepend to POSIX shared memory filenames")
@@ -180,16 +186,62 @@ set(SHM_RDRB_NAME "/${SHM_PREFIX}.rdrb" CACHE INTERNAL
"Name for the main POSIX shared memory buffer")
set(SHM_RDRB_BLOCK_SIZE "sysconf(_SC_PAGESIZE)" CACHE STRING
"Packet buffer block size, multiple of pagesize for performance")
-set(SHM_RDRB_MULTI_BLOCK true CACHE BOOL
+set(SHM_RDRB_MULTI_BLOCK TRUE CACHE BOOL
"Packet buffer multiblock packet support")
-set(SHM_RBUFF_LOCKLESS 0 CACHE BOOL
+set(SHM_RBUFF_LOCKLESS FALSE CACHE BOOL
"Enable shared memory lockless rbuff support")
set(QOS_DISABLE_CRC TRUE CACHE BOOL
"Ignores ber setting on all QoS cubes")
+set(DELTA_T_MPL 60 CACHE STRING
+ "Maximum packet lifetime (s)")
+set(DELTA_T_ACK 10 CACHE STRING
+ "Maximum time to acknowledge a packet (s)")
+set(DELTA_T_RTX 120 CACHE STRING
+ "Maximum time to retransmit a packet (s)")
+set(FRCT_REORDER_QUEUE_SIZE 256 CACHE STRING
+ "Size of the reordering queue, must be a power of 2")
+set(FRCT_START_WINDOW 64 CACHE STRING
+ "Start window, must be a power of 2")
+set(FRCT_LINUX_RTT_ESTIMATOR TRUE CACHE BOOL
+ "Use Linux RTT estimator formula instead of the TCP RFC formula")
+set(FRCT_RTO_MDEV_MULTIPLIER 2 CACHE STRING
+ "Multiplier for deviation term in the RTO: RTO = sRTT + (mdev << X)")
+set(FRCT_RTO_INC_FACTOR 0 CACHE STRING
+ "Divisor for RTO increase after timeout: RTO += RTX >> X, 0: Karn/Partridge")
+set(FRCT_RTO_MIN 250 CACHE STRING
+ "Minimum Retransmission Timeout (RTO) for FRCT (us)")
+set(FRCT_TICK_TIME 5000 CACHE STRING
+ "Tick time for FRCT activity (retransmission, acknowledgments) (us)")
+set(RXM_BUFFER_ON_HEAP FALSE CACHE BOOL
+ "Store packets for retransmission on the heap instead of in packet buffer")
+set(RXM_BLOCKING TRUE CACHE BOOL
+ "Use blocking writes for retransmission")
+set(RXM_MIN_RESOLUTION 20 CACHE STRING
+ "Minimum retransmission delay (ns), as a power to 2")
+set(RXM_WHEEL_MULTIPLIER 4 CACHE STRING
+ "Factor for retransmission wheel levels as a power to 2")
+set(RXM_WHEEL_LEVELS 3 CACHE STRING
+ "Number of levels in the retransmission wheel")
+set(RXM_WHEEL_SLOTS_PER_LEVEL 256 CACHE STRING
+ "Number of slots per level in the retransmission wheel, must be a power of 2")
+set(ACK_WHEEL_SLOTS 256 CACHE STRING
+ "Number of slots in the acknowledgment wheel, must be a power of 2")
+set(ACK_WHEEL_RESOLUTION 18 CACHE STRING
+ "Minimum acknowledgment delay (ns), as a power to 2")
+
+if (HAVE_FUSE)
+ set(PROC_FLOW_STATS TRUE CACHE BOOL
+ "Enable flow statistics tracking for application flows")
+ if (PROC_FLOW_STATS)
+ message(STATUS "Application flow statistics enabled")
+ else ()
+ message(STATUS "Application flow statistics disabled")
+ endif ()
+endif ()
set(SOURCE_FILES_DEV
# Add source files here
- cacep.c
+ cep.c
dev.c
)
@@ -201,15 +253,19 @@ set(SOURCE_FILES_COMMON
bitmap.c
btree.c
crc32.c
+ crypt.c
hash.c
list.c
lockfile.c
logs.c
md5.c
notifier.c
+ protobuf.c
qoscube.c
random.c
rib.c
+ serdes-irm.c
+ serdes-oep.c
sha3.c
shm_flow_set.c
shm_rbuff.c
@@ -223,12 +279,23 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
add_library(ouroboros-common SHARED ${SOURCE_FILES_COMMON} ${IRM_PROTO_SRCS}
- ${IPCP_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS} ${QOSSPEC_PROTO_SRCS})
+ ${IPCP_PROTO_SRCS} ${IPCP_CONFIG_PROTO_SRCS} ${MODEL_PROTO_SRCS}
+ ${ENROLL_PROTO_SRCS})
-add_library(ouroboros-dev SHARED ${SOURCE_FILES_DEV} ${CACEP_PROTO_SRCS})
+add_library(ouroboros-dev SHARED ${SOURCE_FILES_DEV} ${CEP_PROTO_SRCS})
add_library(ouroboros-irm SHARED ${SOURCE_FILES_IRM})
+set_target_properties(ouroboros-common PROPERTIES
+ VERSION ${PACKAGE_VERSION}
+ SOVERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR})
+set_target_properties(ouroboros-dev PROPERTIES
+ VERSION ${PACKAGE_VERSION}
+ SOVERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR})
+set_target_properties(ouroboros-irm PROPERTIES
+ VERSION ${PACKAGE_VERSION}
+ SOVERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR})
+
include(AddCompileFlags)
if (CMAKE_BUILD_TYPE MATCHES "Debug*")
add_compile_flags(ouroboros-common -DCONFIG_OUROBOROS_DEBUG)
@@ -237,7 +304,7 @@ if (CMAKE_BUILD_TYPE MATCHES "Debug*")
endif ()
target_link_libraries(ouroboros-common ${LIBRT_LIBRARIES}
- ${LIBPTHREAD_LIBRARIES} ${PROTOBUF_C_LIBRARY} ${OPENSSL_LIBRARIES}
+ ${LIBPTHREAD_LIBRARIES} ${PROTOBUF_C_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}
${LIBGCRYPT_LIBRARIES} ${FUSE_LIBRARIES})
target_link_libraries(ouroboros-dev ouroboros-common)
diff --git a/src/lib/bitmap.c b/src/lib/bitmap.c
index b76960da..b0840c44 100644
--- a/src/lib/bitmap.c
+++ b/src/lib/bitmap.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Bitmap implementation
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/src/lib/btree.c b/src/lib/btree.c
index 86d1299b..1af94b73 100644
--- a/src/lib/btree.c
+++ b/src/lib/btree.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* B-trees
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/src/lib/cacep.c b/src/lib/cep.c
index 9a889530..ba238023 100644
--- a/src/lib/cacep.c
+++ b/src/lib/cep.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
- * The Common Application Connection Establishment Protocol
+ * The Ouroboros Connection Establishment Protocol
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -22,35 +22,35 @@
#define _POSIX_C_SOURCE 199309L
-#include <ouroboros/cacep.h>
+#include <ouroboros/cep.h>
#include <ouroboros/dev.h>
#include <ouroboros/errno.h>
#include <stdlib.h>
#include <string.h>
-#include "cacep.pb-c.h"
-typedef CacepMsg cacep_msg_t;
+#include "cep.pb-c.h"
+typedef CepMsg cep_msg_t;
#define BUF_SIZE 128
static int read_msg(int fd,
struct conn_info * info)
{
- uint8_t buf[BUF_SIZE];
- cacep_msg_t * msg;
- ssize_t len;
+ uint8_t buf[BUF_SIZE];
+ cep_msg_t * msg;
+ ssize_t len;
len = flow_read(fd, buf, BUF_SIZE);
if (len < 0)
- return -1;
+ return (int) len;
- msg = cacep_msg__unpack(NULL, len, buf);
+ msg = cep_msg__unpack(NULL, len, buf);
if (msg == NULL)
return -1;
- if (strlen(msg->comp_name) > CACEP_BUF_STRLEN) {
- cacep_msg__free_unpacked(msg, NULL);
+ if (strlen(msg->comp_name) > OCEP_BUF_STRLEN) {
+ cep_msg__free_unpacked(msg, NULL);
return -1;
}
@@ -61,7 +61,7 @@ static int read_msg(int fd,
info->pref_syntax = msg->pref_syntax;
info->addr = msg->address;
- cacep_msg__free_unpacked(msg, NULL);
+ cep_msg__free_unpacked(msg, NULL);
return 0;
}
@@ -69,9 +69,9 @@ static int read_msg(int fd,
static int send_msg(int fd,
const struct conn_info * info)
{
- cacep_msg_t msg = CACEP_MSG__INIT;
- uint8_t * data = NULL;
- size_t len = 0;
+ cep_msg_t msg = CEP_MSG__INIT;
+ uint8_t * data = NULL;
+ size_t len = 0;
msg.comp_name = (char *) info->comp_name;
msg.protocol = (char *) info->protocol;
@@ -81,7 +81,7 @@ static int send_msg(int fd,
if (msg.pref_syntax < 0)
return -1;
- len = cacep_msg__get_packed_size(&msg);
+ len = cep_msg__get_packed_size(&msg);
if (len == 0)
return -1;
@@ -89,7 +89,7 @@ static int send_msg(int fd,
if (data == NULL)
return -ENOMEM;
- cacep_msg__pack(&msg, data);
+ cep_msg__pack(&msg, data);
if (flow_write(fd, data, len) < 0) {
free(data);
@@ -101,26 +101,20 @@ static int send_msg(int fd,
return 0;
}
-int cacep_snd(int fd,
- const struct conn_info * in)
+int cep_snd(int fd,
+ const struct conn_info * in)
{
if (in == NULL)
return -EINVAL;
- if (send_msg(fd, in))
- return -1;
-
- return 0;
+ return send_msg(fd, in);
}
-int cacep_rcv(int fd,
- struct conn_info * out)
+int cep_rcv(int fd,
+ struct conn_info * out)
{
if (out == NULL)
return -EINVAL;
- if (read_msg(fd, out))
- return -1;
-
- return 0;
+ return read_msg(fd, out);
}
diff --git a/src/lib/config.h.in b/src/lib/config.h.in
index b6e49100..604038b4 100644
--- a/src/lib/config.h.in
+++ b/src/lib/config.h.in
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros library configuration
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -42,6 +42,7 @@
#define SHM_RDRB_BLOCK_SIZE @SHM_RDRB_BLOCK_SIZE@
#define SHM_BUFFER_SIZE @SHM_BUFFER_SIZE@
#define SHM_RBUFF_SIZE @SHM_RBUFF_SIZE@
+#define FLOW_ALLOC_TIMEOUT @FLOW_ALLOC_TIMEOUT@
#if defined(__linux__) || (defined(__MACH__) && !defined(__APPLE__))
/* Avoid a bug in robust mutex implementation of glibc 2.25 */
@@ -55,7 +56,8 @@
#cmakedefine HAVE_FUSE
#ifdef HAVE_FUSE
-#define FUSE_PREFIX "@FUSE_PREFIX@"
+#define FUSE_PREFIX "@FUSE_PREFIX@"
+#cmakedefine PROC_FLOW_STATS
#endif
#define PTHREAD_COND_CLOCK @PTHREAD_COND_CLOCK@
@@ -66,3 +68,28 @@
#define DU_BUFF_HEADSPACE @DU_BUFF_HEADSPACE@
#define DU_BUFF_TAILSPACE @DU_BUFF_TAILSPACE@
+
+/* Default Delta-t parameters */
+#cmakedefine FRCT_LINUX_RTT_ESTIMATOR
+#define DELT_A (@DELTA_T_ACK@) /* ns */
+#define DELT_R (@DELTA_T_RTX@) /* ns */
+
+#define RQ_SIZE (@FRCT_REORDER_QUEUE_SIZE@)
+#define START_WINDOW (@FRCT_START_WINDOW@)
+#define RTO_MIN (@FRCT_RTO_MIN@ * 1000)
+#define RTO_DIV (@FRCT_RTO_INC_FACTOR@)
+#define MDEV_MUL (@FRCT_RTO_MDEV_MULTIPLIER@)
+
+#define TICTIME (@FRCT_TICK_TIME@ * 1000) /* ns */
+
+/* Retransmission tuning */
+#cmakedefine RXM_BUFFER_ON_HEAP
+#cmakedefine RXM_BLOCKING
+
+#define RXMQ_RES (@RXM_MIN_RESOLUTION@) /* 2^N ns */
+#define RXMQ_BUMP (@RXM_WHEEL_MULTIPLIER@)
+#define RXMQ_LVLS (@RXM_WHEEL_LEVELS@)
+#define RXMQ_SLOTS (@RXM_WHEEL_SLOTS_PER_LEVEL@)
+
+#define ACKQ_SLOTS (@ACK_WHEEL_SLOTS@)
+#define ACKQ_RES (@ACK_WHEEL_RESOLUTION@) /* 2^N ns */
diff --git a/src/lib/crc32.c b/src/lib/crc32.c
index 1b8a5bc8..f369ad20 100644
--- a/src/lib/crc32.c
+++ b/src/lib/crc32.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* 32-bit Cyclic Redundancy Check
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/src/lib/crypt.c b/src/lib/crypt.c
index 1fa12bb8..ad679501 100644
--- a/src/lib/crypt.c
+++ b/src/lib/crypt.c
@@ -1,5 +1,5 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Elliptic curve Diffie-Hellman key exchange and
* AES encryption for flows using OpenSSL
@@ -20,9 +20,19 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
+#include <config.h>
+
+#include <ouroboros/crypt.h>
+#include <ouroboros/errno.h>
+
+#include <assert.h>
+#include <string.h>
#ifdef HAVE_OPENSSL
+#include <ouroboros/hash.h>
+#include <ouroboros/random.h>
+
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
@@ -144,8 +154,8 @@ static int __openssl_ecdh_gen_key(void ** kp)
static ssize_t openssl_ecdh_pkp_create(void ** pkp,
uint8_t * pk)
{
- uint8_t * pos;
- ssize_t len;
+ uint8_t * pos;
+ ssize_t len;
assert(pkp != NULL);
assert(*pkp == NULL);
@@ -172,15 +182,14 @@ static void openssl_ecdh_pkp_destroy(void * pkp)
}
static int openssl_ecdh_derive(void * pkp,
- uint8_t * pk,
- size_t len,
+ buffer_t pk,
uint8_t * s)
{
uint8_t * pos;
EVP_PKEY * pub;
- pos = pk; /* d2i_PUBKEY increments the pointer, don't use key ptr! */
- pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) len);
+ pos = pk.data; /* d2i_PUBKEY increments the pointer, don't use key ptr! */
+ pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) pk.len);
if (pub == NULL)
return -ECRYPT;
@@ -202,7 +211,8 @@ static int openssl_ecdh_derive(void * pkp,
* encryption context for each packet.
*/
-static int openssl_encrypt(struct flow * f,
+static int openssl_encrypt(void * ctx,
+ uint8_t * key,
struct shm_du_buff * sdb)
{
uint8_t * out;
@@ -217,6 +227,8 @@ static int openssl_encrypt(struct flow * f,
in = shm_du_buff_head(sdb);
in_sz = shm_du_buff_tail(sdb) - in;
+ assert(in_sz > 0);
+
if (random_buffer(iv, IVSZ) < 0)
goto fail_iv;
@@ -224,28 +236,24 @@ static int openssl_encrypt(struct flow * f,
if (out == NULL)
goto fail_iv;
- EVP_CIPHER_CTX_reset(f->ctx);
+ EVP_CIPHER_CTX_reset(ctx);
- ret = EVP_EncryptInit_ex(f->ctx,
- EVP_aes_256_cbc(),
- NULL,
- f->key,
- iv);
+ ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
if (ret != 1)
goto fail_encrypt_init;
- ret = EVP_EncryptUpdate(f->ctx, out, &tmp_sz, in, in_sz);
+ ret = EVP_EncryptUpdate(ctx, out, &tmp_sz, in, in_sz);
if (ret != 1)
goto fail_encrypt;
out_sz = tmp_sz;
- ret = EVP_EncryptFinal_ex(f->ctx, out + tmp_sz, &tmp_sz);
+ ret = EVP_EncryptFinal_ex(ctx, out + tmp_sz, &tmp_sz);
if (ret != 1)
goto fail_encrypt;
out_sz += tmp_sz;
- EVP_CIPHER_CTX_cleanup(f->ctx);
+ EVP_CIPHER_CTX_cleanup(ctx);
assert(out_sz >= in_sz);
@@ -266,14 +274,15 @@ static int openssl_encrypt(struct flow * f,
fail_tail_alloc:
shm_du_buff_head_release(sdb, IVSZ);
fail_encrypt:
- EVP_CIPHER_CTX_cleanup(f->ctx);
+ EVP_CIPHER_CTX_cleanup(ctx);
fail_encrypt_init:
free(out);
fail_iv:
return -ECRYPT;
}
-static int openssl_decrypt(struct flow * f,
+static int openssl_decrypt(void * ctx,
+ uint8_t * key,
struct shm_du_buff * sdb)
{
uint8_t * in;
@@ -284,35 +293,34 @@ static int openssl_decrypt(struct flow * f,
int in_sz;
int tmp_sz;
+ in_sz = shm_du_buff_len(sdb);
+ if (in_sz < IVSZ)
+ return -ECRYPT;
+
in = shm_du_buff_head_release(sdb, IVSZ);
memcpy(iv, in, IVSZ);
in = shm_du_buff_head(sdb);
-
- in_sz = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
+ in_sz = shm_du_buff_tail(sdb) - in;
out = malloc(in_sz);
if (out == NULL)
goto fail_malloc;
- EVP_CIPHER_CTX_reset(f->ctx);
+ EVP_CIPHER_CTX_reset(ctx);
- ret = EVP_DecryptInit_ex(f->ctx,
- EVP_aes_256_cbc(),
- NULL,
- f->key,
- iv);
+ ret = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
if (ret != 1)
goto fail_decrypt_init;
- ret = EVP_DecryptUpdate(f->ctx, out, &tmp_sz, in, in_sz);
+ ret = EVP_DecryptUpdate(ctx, out, &tmp_sz, in, in_sz);
if (ret != 1)
goto fail_decrypt;
out_sz = tmp_sz;
- ret = EVP_DecryptFinal_ex(f->ctx, out + tmp_sz, &tmp_sz);
+ ret = EVP_DecryptFinal_ex(ctx, out + tmp_sz, &tmp_sz);
if (ret != 1)
goto fail_decrypt;
@@ -329,7 +337,7 @@ static int openssl_decrypt(struct flow * f,
return 0;
fail_decrypt:
- EVP_CIPHER_CTX_cleanup(f->ctx);
+ EVP_CIPHER_CTX_cleanup(ctx);
fail_decrypt_init:
free(out);
fail_malloc:
@@ -353,8 +361,8 @@ static void openssl_crypt_fini(void * ctx)
#endif /* HAVE_OPENSSL */
-static int crypt_dh_pkp_create(void ** pkp,
- uint8_t * pk)
+int crypt_dh_pkp_create(void ** pkp,
+ uint8_t * pk)
{
#ifdef HAVE_OPENSSL
assert(pkp != NULL);
@@ -364,33 +372,31 @@ static int crypt_dh_pkp_create(void ** pkp,
(void) pkp;
(void) pk;
- memset(pk, 0, MSGBUFSZ);
+ *pkp = NULL;
- return -ECRYPT;
+ return 0;
#endif
}
-static void crypt_dh_pkp_destroy(void * pkp)
+void crypt_dh_pkp_destroy(void * pkp)
{
#ifdef HAVE_OPENSSL
openssl_ecdh_pkp_destroy(pkp);
#else
(void) pkp;
- return 0;
+ return;
#endif
}
-static int crypt_dh_derive(void * pkp,
- uint8_t * pk,
- size_t len,
- uint8_t * s)
+int crypt_dh_derive(void * pkp,
+ buffer_t pk,
+ uint8_t * s)
{
#ifdef HAVE_OPENSSL
- return openssl_ecdh_derive(pkp, pk, len, s);
+ return openssl_ecdh_derive(pkp, pk, s);
#else
(void) pkp;
(void) pk;
- (void) len;
memset(s, 0, SYMMKEYSZ);
@@ -398,50 +404,52 @@ static int crypt_dh_derive(void * pkp,
#endif
}
-static int crypt_encrypt(struct flow * f,
- struct shm_du_buff * sdb)
+int crypt_encrypt(struct crypt_info * info,
+ struct shm_du_buff * sdb)
{
+ if (info->flags == 0)
+ return 0;
+
#ifdef HAVE_OPENSSL
- return openssl_encrypt(f, sdb);
+ return openssl_encrypt(info->ctx, info->key, sdb);
#else
- (void) f;
(void) sdb;
return 0;
#endif
}
-static int crypt_decrypt(struct flow * f,
- struct shm_du_buff * sdb)
+int crypt_decrypt(struct crypt_info * info,
+ struct shm_du_buff * sdb)
{
+ if (info->flags == 0)
+ return 0;
+
#ifdef HAVE_OPENSSL
- return openssl_decrypt(f, sdb);
+ return openssl_decrypt(info->ctx, info->key, sdb);
#else
- (void) f;
(void) sdb;
return -ECRYPT;
#endif
}
-static int crypt_init(void ** ctx)
+int crypt_init(struct crypt_info * info)
{
#ifdef HAVE_OPENSSL
- return openssl_crypt_init(ctx);
+ return openssl_crypt_init(&info->ctx);
#else
- assert(ctx != NULL);
- *ctx = NULL;
-
+ info->ctx = NULL;
return 0;
#endif
}
-static void crypt_fini(void * ctx)
+void crypt_fini(struct crypt_info * info)
{
#ifdef HAVE_OPENSSL
- openssl_crypt_fini(ctx);
+ openssl_crypt_fini(info->ctx);
#else
- assert(ctx == NULL);
- (void) ctx;
+ (void) info;
+ assert(info->ctx == NULL);
#endif
}
diff --git a/src/lib/dev.c b/src/lib/dev.c
index 80d7e9ad..92310b9e 100644
--- a/src/lib/dev.c
+++ b/src/lib/dev.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* API for applications
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -28,22 +28,36 @@
#include "config.h"
-#include <ouroboros/hash.h>
-#include <ouroboros/cacep.h>
-#include <ouroboros/errno.h>
+#include <ouroboros/bitmap.h>
+#include <ouroboros/cep.h>
+#include <ouroboros/crypt.h>
#include <ouroboros/dev.h>
+#include <ouroboros/errno.h>
+#include <ouroboros/fccntl.h>
+#include <ouroboros/flow.h>
+#include <ouroboros/fqueue.h>
+#include <ouroboros/hash.h>
+#include <ouroboros/ipcp.h>
#include <ouroboros/ipcp-dev.h>
+#include <ouroboros/list.h>
#include <ouroboros/local-dev.h>
-#include <ouroboros/sockets.h>
-#include <ouroboros/fccntl.h>
-#include <ouroboros/bitmap.h>
+#include <ouroboros/np1_flow.h>
+#include <ouroboros/pthread.h>
#include <ouroboros/random.h>
+#include <ouroboros/serdes-irm.h>
#include <ouroboros/shm_flow_set.h>
#include <ouroboros/shm_rdrbuff.h>
#include <ouroboros/shm_rbuff.h>
+#include <ouroboros/sockets.h>
#include <ouroboros/utils.h>
-#include <ouroboros/fqueue.h>
+#ifdef PROC_FLOW_STATS
+#include <ouroboros/rib.h>
+#endif
+#ifdef HAVE_LIBGCRYPT
+#include <gcrypt.h>
+#endif
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -61,51 +75,34 @@
#define CRCLEN (sizeof(uint32_t))
#define SECMEMSZ 16384
-#define SYMMKEYSZ 32
#define MSGBUFSZ 2048
-struct flow_set {
- size_t idx;
-};
-
-struct fqueue {
- int fqueue[2 * SHM_BUFFER_SIZE]; /* Safe copy from shm. */
- size_t fqsize;
- size_t next;
-};
-
-enum port_state {
- PORT_NULL = 0,
- PORT_INIT,
- PORT_ID_PENDING,
- PORT_ID_ASSIGNED,
- PORT_DESTROY
-};
-
-struct port {
+/* map flow_ids to flow descriptors; track state of the flow */
+struct fmap {
int fd;
-
- enum port_state state;
- pthread_mutex_t state_lock;
- pthread_cond_t state_cond;
+ /* TODO: use actual flow state */
+ enum flow_state state;
};
#define frcti_to_flow(frcti) \
((struct flow *)((uint8_t *) frcti - offsetof(struct flow, frcti)))
struct flow {
+ struct list_head next;
+
+ struct flow_info info;
+
struct shm_rbuff * rx_rb;
struct shm_rbuff * tx_rb;
struct shm_flow_set * set;
- int flow_id;
- int oflags;
- qosspec_t qs;
+
+ uint16_t oflags;
ssize_t part_idx;
- void * ctx;
- uint8_t key[SYMMKEYSZ];
+ struct crypt_info crypt;
- pid_t pid;
+ struct timespec snd_act;
+ struct timespec rcv_act;
bool snd_timesout;
bool rcv_timesout;
@@ -115,143 +112,297 @@ struct flow {
struct frcti * frcti;
};
-struct {
- char * prog;
- pid_t pid;
+struct flow_set {
+ size_t idx;
+ pthread_rwlock_t lock;
+};
+
+struct fqueue {
+ struct flowevent fqueue[SHM_BUFFER_SIZE]; /* Safe copy from shm. */
+ size_t fqsize;
+ size_t next;
+};
+struct {
struct shm_rdrbuff * rdrb;
struct shm_flow_set * fqset;
- struct timerwheel * tw;
-
struct bmp * fds;
struct bmp * fqueues;
struct flow * flows;
- struct port * ports;
+ struct fmap * id_to_fd;
+ struct list_head flow_list;
+
+ pthread_mutex_t mtx;
+ pthread_cond_t cond;
+
+ pthread_t tx;
+ pthread_t rx;
+ size_t n_frcti;
+ fset_t * frct_set;
pthread_rwlock_t lock;
} ai;
-#include "frct.c"
-
-static void port_destroy(struct port * p)
+static void flow_destroy(struct fmap * p)
{
- pthread_mutex_lock(&p->state_lock);
+ pthread_mutex_lock(&ai.mtx);
- if (p->state == PORT_DESTROY) {
- pthread_mutex_unlock(&p->state_lock);
+ if (p->state == FLOW_DESTROY) {
+ pthread_mutex_unlock(&ai.mtx);
return;
}
- if (p->state == PORT_ID_PENDING)
- p->state = PORT_DESTROY;
+ if (p->state == FLOW_ALLOC_PENDING)
+ p->state = FLOW_DESTROY;
else
- p->state = PORT_NULL;
+ p->state = FLOW_NULL;
+
+ pthread_cond_signal(&ai.cond);
- pthread_cond_signal(&p->state_cond);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &ai.mtx);
- while (p->state != PORT_NULL)
- pthread_cond_wait(&p->state_cond, &p->state_lock);
+ while (p->state != FLOW_NULL)
+ pthread_cond_wait(&ai.cond, &ai.mtx);
- p->fd = -1;
- p->state = PORT_INIT;
+ p->fd = -1;
+ p->state = FLOW_INIT;
- pthread_mutex_unlock(&p->state_lock);
+ pthread_cleanup_pop(true);
}
-static void port_set_state(struct port * p,
- enum port_state state)
+static void flow_set_state(struct fmap * p,
+ enum flow_state state)
{
- pthread_mutex_lock(&p->state_lock);
+ pthread_mutex_lock(&ai.mtx);
- if (p->state == PORT_DESTROY) {
- pthread_mutex_unlock(&p->state_lock);
+ if (p->state == FLOW_DESTROY) {
+ pthread_mutex_unlock(&ai.mtx);
return;
}
p->state = state;
- pthread_cond_broadcast(&p->state_cond);
+ pthread_cond_broadcast(&ai.cond);
- pthread_mutex_unlock(&p->state_lock);
+ pthread_mutex_unlock(&ai.mtx);
}
-static enum port_state port_wait_assign(int flow_id)
+static enum flow_state flow_wait_assign(int flow_id)
{
- enum port_state state;
- struct port * p;
+ enum flow_state state;
+ struct fmap * p;
- p = &ai.ports[flow_id];
+ p = &ai.id_to_fd[flow_id];
- pthread_mutex_lock(&p->state_lock);
+ pthread_mutex_lock(&ai.mtx);
- if (p->state == PORT_ID_ASSIGNED) {
- pthread_mutex_unlock(&p->state_lock);
- return PORT_ID_ASSIGNED;
+ if (p->state == FLOW_ALLOCATED) {
+ pthread_mutex_unlock(&ai.mtx);
+ return FLOW_ALLOCATED;
}
- if (p->state == PORT_INIT)
- p->state = PORT_ID_PENDING;
+ if (p->state == FLOW_INIT)
+ p->state = FLOW_ALLOC_PENDING;
- while (p->state == PORT_ID_PENDING)
- pthread_cond_wait(&p->state_cond, &p->state_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &ai.mtx);
- if (p->state == PORT_DESTROY) {
- p->state = PORT_NULL;
- pthread_cond_broadcast(&p->state_cond);
+ while (p->state == FLOW_ALLOC_PENDING)
+ pthread_cond_wait(&ai.cond, &ai.mtx);
+
+ if (p->state == FLOW_DESTROY) {
+ p->state = FLOW_NULL;
+ pthread_cond_broadcast(&ai.cond);
}
state = p->state;
- assert(state != PORT_INIT);
+ pthread_cleanup_pop(true);
- pthread_mutex_unlock(&p->state_lock);
+ assert(state != FLOW_INIT);
return state;
}
-static int proc_announce(char * prog)
+static int proc_announce(const char * prog)
+{
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ int err;
+
+ if (proc_announce__irm_req_ser(&msg, prog) < 0)
+ return -ENOMEM;
+
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
+
+ return irm__irm_result_des(&msg);
+}
+
+/* IRMd will clean up the mess if this fails */
+static void proc_exit(void)
+{
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+
+ if (proc_exit__irm_req_ser(&msg) < 0)
+ return;
+
+ send_recv_msg(&msg);
+}
+
+#include "frct.c"
+
+void * flow_tx(void * o)
+{
+ struct timespec tic = TIMESPEC_INIT_NS(TICTIME);
+
+ (void) o;
+
+ while (true) {
+ timerwheel_move();
+
+ nanosleep(&tic, NULL);
+ }
+
+ return (void *) 0;
+}
+
+static void flow_send_keepalive(struct flow * flow,
+ struct timespec now)
+{
+ struct shm_du_buff * sdb;
+ ssize_t idx;
+ uint8_t * ptr;
+
+ idx = shm_rdrbuff_alloc(ai.rdrb, 0, &ptr, &sdb);
+ if (idx < 0)
+ return;
+
+ pthread_rwlock_wrlock(&ai.lock);
+
+ flow->snd_act = now;
+
+ if (shm_rbuff_write(flow->tx_rb, idx))
+ shm_rdrbuff_remove(ai.rdrb, idx);
+ else
+ shm_flow_set_notify(flow->set, flow->info.id, FLOW_PKT);
+
+ pthread_rwlock_unlock(&ai.lock);
+}
+
+/* Needs rdlock on ai. */
+static void _flow_keepalive(struct flow * flow)
{
- irm_msg_t msg = IRM_MSG__INIT;
- irm_msg_t * recv_msg;
- int ret = -1;
-
- msg.code = IRM_MSG_CODE__IRM_PROC_ANNOUNCE;
- msg.has_pid = true;
- msg.pid = ai.pid;
- msg.prog = prog;
-
- recv_msg = send_recv_irm_msg(&msg);
- if (recv_msg == NULL) {
- return -EIRMD;
+ struct timespec now;
+ struct timespec s_act;
+ struct timespec r_act;
+ int flow_id;
+ time_t timeo;
+ uint32_t acl;
+
+ s_act = flow->snd_act;
+ r_act = flow->rcv_act;
+
+ flow_id = flow->info.id;
+ timeo = flow->info.qs.timeout;
+
+ acl = shm_rbuff_get_acl(flow->rx_rb);
+ if (timeo == 0 || acl & (ACL_FLOWPEER | ACL_FLOWDOWN))
+ return;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ if (ts_diff_ns(&r_act, &now) > (int64_t) timeo * MILLION) {
+ shm_rbuff_set_acl(flow->rx_rb, ACL_FLOWPEER);
+ shm_flow_set_notify(ai.fqset, flow_id, FLOW_PEER);
+ return;
}
- if (!recv_msg->has_result || (ret = recv_msg->result)) {
- irm_msg__free_unpacked(recv_msg, NULL);
- return ret;
+ if (ts_diff_ns(&s_act, &now) > (int64_t) timeo * (MILLION >> 2)) {
+ pthread_rwlock_unlock(&ai.lock);
+
+ flow_send_keepalive(flow, now);
+
+ pthread_rwlock_rdlock(&ai.lock);
}
+}
- irm_msg__free_unpacked(recv_msg, NULL);
+static void handle_keepalives(void)
+{
+ struct list_head * p;
+ struct list_head * h;
- return ret;
+ pthread_rwlock_rdlock(&ai.lock);
+
+ list_for_each_safe(p, h, &ai.flow_list) {
+ struct flow * flow;
+ flow = list_entry(p, struct flow, next);
+ _flow_keepalive(flow);
+ }
+
+ pthread_rwlock_unlock(&ai.lock);
+}
+
+static void __cleanup_fqueue_destroy(void * fq)
+{
+ fqueue_destroy((fqueue_t *) fq);
+}
+
+void * flow_rx(void * o)
+{
+ struct timespec tic = TIMESPEC_INIT_NS(TICTIME);
+ int ret;
+ struct fqueue * fq;
+
+ (void) o;
+
+ fq = fqueue_create();
+
+ pthread_cleanup_push(__cleanup_fqueue_destroy, fq);
+
+ /* fevent will filter all FRCT packets for us */
+ while ((ret = fevent(ai.frct_set, fq, &tic)) != 0) {
+ if (ret == -ETIMEDOUT) {
+ handle_keepalives();
+ continue;
+ }
+
+ while (fqueue_next(fq) >= 0)
+ ; /* no need to act */
+ }
+
+ pthread_cleanup_pop(true);
+
+ return (void *) 0;
}
static void flow_clear(int fd)
{
memset(&ai.flows[fd], 0, sizeof(ai.flows[fd]));
- ai.flows[fd].flow_id = -1;
- ai.flows[fd].pid = -1;
+ ai.flows[fd].info.id = -1;
}
-#include "crypt.c"
-
-static void flow_fini(int fd)
+static void __flow_fini(int fd)
{
assert(fd >= 0 && fd < SYS_MAX_FLOWS);
- if (ai.flows[fd].flow_id != -1) {
- port_destroy(&ai.ports[ai.flows[fd].flow_id]);
+ if (ai.flows[fd].frcti != NULL) {
+ ai.n_frcti--;
+ if (ai.n_frcti == 0) {
+ pthread_cancel(ai.tx);
+ pthread_join(ai.tx, NULL);
+ }
+
+ shm_flow_set_del(ai.fqset, 0, ai.flows[fd].info.id);
+
+ frcti_destroy(ai.flows[fd].frcti);
+ }
+
+ if (ai.flows[fd].info.id != -1) {
+ flow_destroy(&ai.id_to_fd[ai.flows[fd].info.id]);
bmp_release(ai.fds, fd);
}
@@ -267,27 +418,36 @@ static void flow_fini(int fd)
if (ai.flows[fd].set != NULL) {
shm_flow_set_notify(ai.flows[fd].set,
- ai.flows[fd].flow_id,
+ ai.flows[fd].info.id,
FLOW_DEALLOC);
shm_flow_set_close(ai.flows[fd].set);
}
- if (ai.flows[fd].frcti != NULL)
- frcti_destroy(ai.flows[fd].frcti);
+ crypt_fini(&ai.flows[fd].crypt);
- if (ai.flows[fd].ctx != NULL)
- crypt_fini(ai.flows[fd].ctx);
+ list_del(&ai.flows[fd].next);
flow_clear(fd);
}
-static int flow_init(int flow_id,
- pid_t pid,
- qosspec_t qs,
- uint8_t * s)
+static void flow_fini(int fd)
{
- int fd;
- int err = -ENOMEM;
+ pthread_rwlock_wrlock(&ai.lock);
+
+ __flow_fini(fd);
+
+ pthread_rwlock_unlock(&ai.lock);
+}
+
+static int flow_init(struct flow_info * info,
+ buffer_t * sk)
+{
+ struct timespec now;
+ struct flow * flow;
+ int fd;
+ int err = -ENOMEM;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
pthread_rwlock_wrlock(&ai.lock);
@@ -297,46 +457,75 @@ static int flow_init(int flow_id,
goto fail_fds;
}
- ai.flows[fd].rx_rb = shm_rbuff_open(ai.pid, flow_id);
- if (ai.flows[fd].rx_rb == NULL)
+ flow = &ai.flows[fd];
+
+ flow->info = *info;
+
+ flow->rx_rb = shm_rbuff_open(info->n_pid, info->id);
+ if (flow->rx_rb == NULL)
goto fail_rx_rb;
- ai.flows[fd].tx_rb = shm_rbuff_open(pid, flow_id);
- if (ai.flows[fd].tx_rb == NULL)
+ flow->tx_rb = shm_rbuff_open(info->n_1_pid, info->id);
+ if (flow->tx_rb == NULL)
goto fail_tx_rb;
- ai.flows[fd].set = shm_flow_set_open(pid);
- if (ai.flows[fd].set == NULL)
+ flow->set = shm_flow_set_open(info->n_1_pid);
+ if (flow->set == NULL)
goto fail_set;
- ai.flows[fd].flow_id = flow_id;
- ai.flows[fd].oflags = FLOWFDEFAULT;
- ai.flows[fd].pid = pid;
- ai.flows[fd].part_idx = NO_PART;
- ai.flows[fd].qs = qs;
+ flow->oflags = FLOWFDEFAULT;
+ flow->part_idx = NO_PART;
+ flow->snd_act = now;
+ flow->rcv_act = now;
+
+ flow->crypt.flags = info->qs.cypher_s; /* TODO: move cypher_s */
- if (qs.cypher_s > 0) {
- assert(s != NULL);
- if (crypt_init(&ai.flows[fd].ctx) < 0)
- goto fail_ctx;
+ memset(flow->crypt.key, 0, SYMMKEYSZ);
- memcpy(ai.flows[fd].key, s, SYMMKEYSZ);
+ if (flow->crypt.flags > 0 && sk!= NULL && sk->data != NULL)
+ memcpy(flow->crypt.key, sk->data , sk->len);
+
+ if (crypt_init(&flow->crypt) < 0)
+ goto fail_crypt;
+
+ assert(flow->frcti == NULL);
+
+ if (info->qs.in_order != 0) {
+ flow->frcti = frcti_create(fd, DELT_A, DELT_R, info->mpl);
+ if (flow->frcti == NULL)
+ goto fail_frcti;
+
+ if (shm_flow_set_add(ai.fqset, 0, info->id))
+ goto fail_flow_set_add;
+
+ ++ai.n_frcti;
+ if (ai.n_frcti == 1 &&
+ pthread_create(&ai.tx, NULL, flow_tx, NULL) < 0)
+ goto fail_tx_thread;
}
- ai.ports[flow_id].fd = fd;
+ list_add_tail(&flow->next, &ai.flow_list);
+
+ ai.id_to_fd[info->id].fd = fd;
- port_set_state(&ai.ports[flow_id], PORT_ID_ASSIGNED);
+ flow_set_state(&ai.id_to_fd[info->id], FLOW_ALLOCATED);
pthread_rwlock_unlock(&ai.lock);
return fd;
- fail_ctx:
- shm_flow_set_close(ai.flows[fd].set);
+ fail_tx_thread:
+ shm_flow_set_del(ai.fqset, 0, info->id);
+ fail_flow_set_add:
+ frcti_destroy(flow->frcti);
+ fail_frcti:
+ crypt_fini(&flow->crypt);
+ fail_crypt:
+ shm_flow_set_close(flow->set);
fail_set:
- shm_rbuff_close(ai.flows[fd].tx_rb);
+ shm_rbuff_close(flow->tx_rb);
fail_tx_rb:
- shm_rbuff_close(ai.flows[fd].rx_rb);
+ shm_rbuff_close(flow->rx_rb);
fail_rx_rb:
bmp_release(ai.fds, fd);
fail_fds:
@@ -358,101 +547,143 @@ static void init(int argc,
char ** argv,
char ** envp)
{
- const char * prog = argv[0];
- int i;
-
+ char * prog = argv[0];
+ int i;
+#ifdef PROC_FLOW_STATS
+ char procstr[32];
+#endif
(void) argc;
(void) envp;
- assert(ai.prog == NULL);
-
if (check_python(argv[0]))
prog = argv[1];
- ai.pid = getpid();
+ prog = path_strip(prog);
+ if (prog == NULL) {
+ fprintf(stderr, "FATAL: Could not determine program name.\n");
+ goto fail_prog;
+ }
+
+ if (proc_announce(prog)) {
+ fprintf(stderr, "FATAL: Could not announce to IRMd.\n");
+ goto fail_prog;
+ }
+
#ifdef HAVE_LIBGCRYPT
if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) {
- if (!gcry_check_version(GCRYPT_VERSION))
- goto fail_fds;
+ if (!gcry_check_version(GCRYPT_VERSION)) {
+ fprintf(stderr, "FATAL: Could not get gcry version.\n");
+ goto fail_prog;
+ }
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
}
#endif
ai.fds = bmp_create(PROG_MAX_FLOWS - PROG_RES_FDS, PROG_RES_FDS);
- if (ai.fds == NULL)
+ if (ai.fds == NULL) {
+ fprintf(stderr, "FATAL: Could not create fd bitmap.\n");
goto fail_fds;
+ }
ai.fqueues = bmp_create(PROG_MAX_FQUEUES, 0);
- if (ai.fqueues == NULL)
+ if (ai.fqueues == NULL) {
+ fprintf(stderr, "FATAL: Could not create fqueue bitmap.\n");
goto fail_fqueues;
+ }
ai.rdrb = shm_rdrbuff_open();
- if (ai.rdrb == NULL)
+ if (ai.rdrb == NULL) {
+ fprintf(stderr, "FATAL: Could not open packet buffer.\n");
goto fail_rdrb;
+ }
ai.flows = malloc(sizeof(*ai.flows) * PROG_MAX_FLOWS);
- if (ai.flows == NULL)
+ if (ai.flows == NULL) {
+ fprintf(stderr, "FATAL: Could not malloc flows.\n");
goto fail_flows;
+ }
for (i = 0; i < PROG_MAX_FLOWS; ++i)
flow_clear(i);
- ai.ports = malloc(sizeof(*ai.ports) * SYS_MAX_FLOWS);
- if (ai.ports == NULL)
- goto fail_ports;
+ ai.id_to_fd = malloc(sizeof(*ai.id_to_fd) * SYS_MAX_FLOWS);
+ if (ai.id_to_fd == NULL) {
+ fprintf(stderr, "FATAL: Could not malloc id_to_fd.\n");
+ goto fail_id_to_fd;
+ }
- if (prog != NULL) {
- ai.prog = strdup(path_strip((char *) prog));
- if (ai.prog == NULL)
- goto fail_prog;
+ for (i = 0; i < SYS_MAX_FLOWS; ++i)
+ ai.id_to_fd[i].state = FLOW_INIT;
- if (proc_announce((char *) ai.prog))
- goto fail_announce;
+ if (pthread_mutex_init(&ai.mtx, NULL)) {
+ fprintf(stderr, "FATAL: Could not init mutex.\n");
+ goto fail_mtx;
}
- for (i = 0; i < SYS_MAX_FLOWS; ++i) {
- ai.ports[i].state = PORT_INIT;
- if (pthread_mutex_init(&ai.ports[i].state_lock, NULL)) {
- int j;
- for (j = 0; j < i; ++j)
- pthread_mutex_destroy(&ai.ports[j].state_lock);
- goto fail_announce;
- }
- if (pthread_cond_init(&ai.ports[i].state_cond, NULL)) {
- int j;
- for (j = 0; j < i; ++j)
- pthread_cond_destroy(&ai.ports[j].state_cond);
- goto fail_state_cond;
- }
+ if (pthread_cond_init(&ai.cond, NULL) < 0) {
+ fprintf(stderr, "FATAL: Could not init condvar.\n");
+ goto fail_cond;
}
- if (pthread_rwlock_init(&ai.lock, NULL))
- goto fail_lock;
-
- if (rxmwheel_init())
- goto fail_rxmwheel;
+ if (pthread_rwlock_init(&ai.lock, NULL) < 0) {
+ fprintf(stderr, "FATAL: Could not initialize flow lock.\n");
+ goto fail_flow_lock;
+ }
ai.fqset = shm_flow_set_open(getpid());
- if (ai.fqset == NULL)
+ if (ai.fqset == NULL) {
+ fprintf(stderr, "FATAL: Could not open flow set.\n");
goto fail_fqset;
+ }
+
+ ai.frct_set = fset_create();
+ if (ai.frct_set == NULL || ai.frct_set->idx != 0) {
+ fprintf(stderr, "FATAL: Could not create FRCT set.\n");
+ goto fail_frct_set;
+ }
+
+ if (timerwheel_init() < 0) {
+ fprintf(stderr, "FATAL: Could not initialize timerwheel.\n");
+ goto fail_timerwheel;
+ }
+
+#if defined PROC_FLOW_STATS
+ if (strstr(argv[0], "ipcpd") == NULL) {
+ sprintf(procstr, "proc.%d", getpid());
+ if (rib_init(procstr) < 0) {
+ fprintf(stderr, "FATAL: Could not initialize RIB.\n");
+ goto fail_rib_init;
+ }
+ }
+#endif
+ if (pthread_create(&ai.rx, NULL, flow_rx, NULL) < 0) {
+ fprintf(stderr, "FATAL: Could not start monitor thread.\n");
+ goto fail_monitor;
+ }
+
+ list_head_init(&ai.flow_list);
return;
+ fail_monitor:
+#if defined PROC_FLOW_STATS
+ rib_fini();
+ fail_rib_init:
+#endif
+ timerwheel_fini();
+ fail_timerwheel:
+ fset_destroy(ai.frct_set);
+ fail_frct_set:
+ shm_flow_set_close(ai.fqset);
fail_fqset:
- rxmwheel_fini();
- fail_rxmwheel:
pthread_rwlock_destroy(&ai.lock);
- fail_lock:
- for (i = 0; i < SYS_MAX_FLOWS; ++i)
- pthread_cond_destroy(&ai.ports[i].state_cond);
- fail_state_cond:
- for (i = 0; i < SYS_MAX_FLOWS; ++i)
- pthread_mutex_destroy(&ai.ports[i].state_lock);
- fail_announce:
- free(ai.prog);
- fail_prog:
- free(ai.ports);
- fail_ports:
+ fail_flow_lock:
+ pthread_cond_destroy(&ai.cond);
+ fail_cond:
+ pthread_mutex_destroy(&ai.mtx);
+ fail_mtx:
+ free(ai.id_to_fd);
+ fail_id_to_fd:
free(ai.flows);
fail_flows:
shm_rdrbuff_close(ai.rdrb);
@@ -461,54 +692,60 @@ static void init(int argc,
fail_fqueues:
bmp_destroy(ai.fds);
fail_fds:
- fprintf(stderr, "FATAL: ouroboros-dev init failed. "
- "Make sure an IRMd is running.\n\n");
memset(&ai, 0, sizeof(ai));
+ fail_prog:
exit(EXIT_FAILURE);
}
static void fini(void)
{
- int i = 0;
+ int i;
if (ai.fds == NULL)
return;
- rxmwheel_fini();
-
- if (ai.prog != NULL)
- free(ai.prog);
+ pthread_cancel(ai.rx);
+ pthread_join(ai.rx, NULL);
pthread_rwlock_wrlock(&ai.lock);
for (i = 0; i < PROG_MAX_FLOWS; ++i) {
- if (ai.flows[i].flow_id != -1) {
+ if (ai.flows[i].info.id != -1) {
ssize_t idx;
shm_rbuff_set_acl(ai.flows[i].rx_rb, ACL_FLOWDOWN);
while ((idx = shm_rbuff_read(ai.flows[i].rx_rb)) >= 0)
shm_rdrbuff_remove(ai.rdrb, idx);
- flow_fini(i);
+ __flow_fini(i);
}
}
- shm_flow_set_close(ai.fqset);
+ pthread_cond_destroy(&ai.cond);
+ pthread_mutex_destroy(&ai.mtx);
- for (i = 0; i < SYS_MAX_FLOWS; ++i) {
- pthread_mutex_destroy(&ai.ports[i].state_lock);
- pthread_cond_destroy(&ai.ports[i].state_cond);
- }
+ pthread_rwlock_unlock(&ai.lock);
- shm_rdrbuff_close(ai.rdrb);
+#ifdef PROC_FLOW_STATS
+ rib_fini();
+#endif
+ timerwheel_fini();
+
+ fset_destroy(ai.frct_set);
+
+ shm_flow_set_close(ai.fqset);
+
+ pthread_rwlock_destroy(&ai.lock);
free(ai.flows);
- free(ai.ports);
+ free(ai.id_to_fd);
+
+ shm_rdrbuff_close(ai.rdrb);
bmp_destroy(ai.fds);
bmp_destroy(ai.fqueues);
- pthread_rwlock_unlock(&ai.lock);
+ proc_exit();
- pthread_rwlock_destroy(&ai.lock);
+ memset(&ai, 0, sizeof(ai));
}
#if defined(__MACH__) && defined(__APPLE__)
@@ -525,275 +762,241 @@ __attribute__((section(FINI_SECTION))) __typeof__(fini) * __fini = fini;
int flow_accept(qosspec_t * qs,
const struct timespec * timeo)
{
- irm_msg_t msg = IRM_MSG__INIT;
- irm_msg_t * recv_msg;
- int fd;
- void * pkp; /* public key pair */
- uint8_t s[SYMMKEYSZ]; /* secret key for flow */
- uint8_t buf[MSGBUFSZ];
- int err = -EIRMD;
- ssize_t key_len;
+ struct flow_info flow;
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t sk;
+ int fd;
+ int err;
- memset(s, 0, SYMMKEYSZ);
-
- msg.code = IRM_MSG_CODE__IRM_FLOW_ACCEPT;
- msg.has_pid = true;
- msg.pid = ai.pid;
-
- if (timeo != NULL) {
- msg.has_timeo_sec = true;
- msg.has_timeo_nsec = true;
- msg.timeo_sec = timeo->tv_sec;
- msg.timeo_nsec = timeo->tv_nsec;
- }
+#ifdef QOS_DISABLE_CRC
+ if (qs != NULL)
+ qs->ber = 1;
+#endif
+ memset(&flow, 0, sizeof(flow));
- key_len = crypt_dh_pkp_create(&pkp, buf);
- if (key_len < 0) {
- err = -ECRYPT;
- goto fail_crypt_pkp;
- }
+ flow.n_pid = getpid();
+ flow.qs = qs == NULL ? qos_raw : *qs;
- msg.has_pk = true;
- msg.pk.data = buf;
- msg.pk.len = (uint32_t) key_len;
+ if (flow_accept__irm_req_ser(&msg, &flow, timeo))
+ return -ENOMEM;
- pthread_cleanup_push(crypt_dh_pkp_destroy, pkp);
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
- recv_msg = send_recv_irm_msg(&msg);
+ err = flow__irm_result_des(&msg, &flow, &sk);
+ if (err < 0)
+ return err;
- pthread_cleanup_pop(false);
+ fd = flow_init(&flow, &sk);
- if (recv_msg == NULL)
- goto fail_recv;
+ freebuf(sk);
- if (!recv_msg->has_result)
- goto fail_result;
+ if (qs != NULL)
+ *qs = flow.qs;
- if (recv_msg->result != 0) {
- err = recv_msg->result;
- goto fail_result;
- }
+ return fd;
+}
- if (!recv_msg->has_pid || !recv_msg->has_flow_id ||
- recv_msg->qosspec == NULL)
- goto fail_result;
+int flow_alloc(const char * dst,
+ qosspec_t * qs,
+ const struct timespec * timeo)
+{
+ struct flow_info flow;
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t sk; /* symmetric key */
+ int fd;
+ int err;
- if (recv_msg->pk.len != 0 &&
- crypt_dh_derive(pkp, recv_msg->pk.data,
- recv_msg->pk.len, s) < 0) {
- err = -ECRYPT;
- goto fail_result;
- }
+#ifdef QOS_DISABLE_CRC
+ if (qs != NULL)
+ qs->ber = 1;
+#endif
- crypt_dh_pkp_destroy(pkp);
+ memset(&flow, 0, sizeof(flow));
- fd = flow_init(recv_msg->flow_id, recv_msg->pid,
- msg_to_spec(recv_msg->qosspec), s);
+ flow.n_pid = getpid();
+ flow.qs = qs == NULL ? qos_raw : *qs;
- irm_msg__free_unpacked(recv_msg, NULL);
+ if (flow_alloc__irm_req_ser(&msg, &flow, dst, timeo))
+ return -ENOMEM;
- if (fd < 0)
- return fd;
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
- pthread_rwlock_wrlock(&ai.lock);
+ err = flow__irm_result_des(&msg, &flow, &sk);
+ if (err < 0)
+ return err;
- assert(ai.flows[fd].frcti == NULL);
+ fd = flow_init(&flow, &sk);
- if (ai.flows[fd].qs.in_order != 0) {
- ai.flows[fd].frcti = frcti_create(fd);
- if (ai.flows[fd].frcti == NULL) {
- pthread_rwlock_unlock(&ai.lock);
- flow_dealloc(fd);
- return -ENOMEM;
- }
- }
+ freebuf(sk);
if (qs != NULL)
- *qs = ai.flows[fd].qs;
-
- pthread_rwlock_unlock(&ai.lock);
+ *qs = flow.qs;
return fd;
-
- fail_result:
- irm_msg__free_unpacked(recv_msg, NULL);
- fail_recv:
- crypt_dh_pkp_destroy(pkp);
- fail_crypt_pkp:
- return err;
}
-static int __flow_alloc(const char * dst,
- qosspec_t * qs,
- const struct timespec * timeo,
- bool join)
+int flow_join(const char * dst,
+ qosspec_t * qs,
+ const struct timespec * timeo)
{
- irm_msg_t msg = IRM_MSG__INIT;
- qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT;
- irm_msg_t * recv_msg;
- int fd;
- void * pkp = NULL; /* public key pair */
- uint8_t s[SYMMKEYSZ]; /* secret key for flow */
- uint8_t buf[MSGBUFSZ];
- int err = -EIRMD;
-
- memset(s, 0, SYMMKEYSZ);
+ struct flow_info flow;
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ int fd;
+ int err;
#ifdef QOS_DISABLE_CRC
if (qs != NULL)
qs->ber = 1;
#endif
- msg.code = join ? IRM_MSG_CODE__IRM_FLOW_JOIN
- : IRM_MSG_CODE__IRM_FLOW_ALLOC;
- msg.dst = (char *) dst;
- msg.has_pid = true;
- msg.pid = ai.pid;
- qs_msg = spec_to_msg(qs);
- msg.qosspec = &qs_msg;
+ if (qs != NULL && qs->cypher_s > 0)
+ return -ENOTSUP; /* TODO: Encrypted broadcast */
- if (timeo != NULL) {
- msg.has_timeo_sec = true;
- msg.has_timeo_nsec = true;
- msg.timeo_sec = timeo->tv_sec;
- msg.timeo_nsec = timeo->tv_nsec;
- }
+ memset(&flow, 0, sizeof(flow));
- if (!join && qs != NULL && qs->cypher_s != 0) {
- ssize_t key_len;
+ flow.n_pid = getpid();
+ flow.qs = qs == NULL ? qos_raw : *qs;
- key_len = crypt_dh_pkp_create(&pkp, buf);
- if (key_len < 0) {
- err = -ECRYPT;
- goto fail_crypt_pkp;
- }
+ if (flow_alloc__irm_req_ser(&msg, &flow, dst, timeo))
+ return -ENOMEM;
- msg.has_pk = true;
- msg.pk.data = buf;
- msg.pk.len = (uint32_t) key_len;
- }
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
- recv_msg = send_recv_irm_msg(&msg);
- if (recv_msg == NULL)
- goto fail_send;
+ err = flow__irm_result_des(&msg, &flow, NULL);
+ if (err < 0)
+ return err;
- if (!recv_msg->has_result)
- goto fail_result;
+ fd = flow_init(&flow, NULL);
- if (recv_msg->result != 0) {
- err = recv_msg->result;
- goto fail_result;
- }
+ if (qs != NULL)
+ *qs = flow.qs;
- if (!recv_msg->has_pid || !recv_msg->has_flow_id)
- goto fail_result;
+ return fd;
+}
- if (!join && qs != NULL && qs->cypher_s != 0) {
- if (!recv_msg->has_pk || recv_msg->pk.len == 0) {
- err = -ECRYPT;
- goto fail_result;
- }
+#define PKT_BUF_LEN 2048
+int flow_dealloc(int fd)
+{
+ struct flow_info info;
+ uint8_t pkt[PKT_BUF_LEN];
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ struct timespec tic = TIMESPEC_INIT_NS(TICTIME);
+ struct timespec timeo = TIMESPEC_INIT_S(0);
+ struct flow * flow;
+ int err;
- if (crypt_dh_derive(pkp, recv_msg->pk.data,
- recv_msg->pk.len, s) < 0) {
- err = -ECRYPT;
- goto fail_result;
- }
+ if (fd < 0 || fd >= SYS_MAX_FLOWS )
+ return -EINVAL;
+
+ memset(&info, 0, sizeof(flow));
- crypt_dh_pkp_destroy(pkp);
+ flow = &ai.flows[fd];
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ if (flow->info.id < 0) {
+ pthread_rwlock_unlock(&ai.lock);
+ return -ENOTALLOC;
}
- fd = flow_init(recv_msg->flow_id, recv_msg->pid,
- qs == NULL ? qos_raw : *qs, s);
+ flow->oflags = FLOWFDEFAULT | FLOWFRNOPART;
- irm_msg__free_unpacked(recv_msg, NULL);
+ flow->rcv_timesout = true;
+ flow->rcv_timeo = tic;
- if (fd < 0)
- return fd;
+ pthread_rwlock_unlock(&ai.lock);
- pthread_rwlock_wrlock(&ai.lock);
+ flow_read(fd, buf, SOCK_BUF_SIZE);
- assert(ai.flows[fd].frcti == NULL);
+ pthread_rwlock_rdlock(&ai.lock);
- if (ai.flows[fd].qs.in_order != 0) {
- ai.flows[fd].frcti = frcti_create(fd);
- if (ai.flows[fd].frcti == NULL) {
- pthread_rwlock_unlock(&ai.lock);
- flow_dealloc(fd);
- return -ENOMEM;
- }
+ timeo.tv_sec = frcti_dealloc(flow->frcti);
+ while (timeo.tv_sec < 0) { /* keep the flow active for rtx */
+ ssize_t ret;
+
+ pthread_rwlock_unlock(&ai.lock);
+
+ ret = flow_read(fd, pkt, PKT_BUF_LEN);
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ timeo.tv_sec = frcti_dealloc(flow->frcti);
+
+ if (ret == -EFLOWDOWN && timeo.tv_sec < 0)
+ timeo.tv_sec = -timeo.tv_sec;
}
- pthread_rwlock_unlock(&ai.lock);
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &ai.lock);
- return fd;
+ shm_rbuff_fini(flow->tx_rb);
- fail_result:
- irm_msg__free_unpacked(recv_msg, NULL);
- fail_send:
- crypt_dh_pkp_destroy(pkp);
- fail_crypt_pkp:
- return err;
-}
+ pthread_cleanup_pop(true);
-int flow_alloc(const char * dst,
- qosspec_t * qs,
- const struct timespec * timeo)
-{
- return __flow_alloc(dst, qs, timeo, false);
-}
+ info.id = flow->info.id;
+ info.n_pid = getpid();
-int flow_join(const char * dst,
- qosspec_t * qs,
- const struct timespec * timeo)
-{
- if (qs != NULL && qs->cypher_s != 0)
- return -ECRYPT;
+ if (flow_dealloc__irm_req_ser(&msg, &info, &timeo) < 0)
+ return -ENOMEM;
+
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
+
+ err = irm__irm_result_des(&msg);
+
+ flow_fini(fd);
- return __flow_alloc(dst, qs, timeo, true);
+ return err;
}
-int flow_dealloc(int fd)
+int ipcp_flow_dealloc(int fd)
{
- irm_msg_t msg = IRM_MSG__INIT;
- irm_msg_t * recv_msg;
+ struct flow_info info;
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ struct flow * flow;
+ int err;
if (fd < 0 || fd >= SYS_MAX_FLOWS )
return -EINVAL;
- msg.code = IRM_MSG_CODE__IRM_FLOW_DEALLOC;
- msg.has_flow_id = true;
- msg.has_pid = true;
- msg.pid = ai.pid;
+ flow = &ai.flows[fd];
+
+ memset(&info, 0, sizeof(flow));
pthread_rwlock_rdlock(&ai.lock);
- if (ai.flows[fd].flow_id < 0) {
+ if (flow->info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
return -ENOTALLOC;
}
- msg.flow_id = ai.flows[fd].flow_id;
+ info.id = flow->info.id;
+ info.n_1_pid = flow->info.n_1_pid;
pthread_rwlock_unlock(&ai.lock);
- recv_msg = send_recv_irm_msg(&msg);
- if (recv_msg == NULL)
- return -EIRMD;
-
- if (!recv_msg->has_result) {
- irm_msg__free_unpacked(recv_msg, NULL);
- return -EIRMD;
- }
+ if (ipcp_flow_dealloc__irm_req_ser(&msg, &info) < 0)
+ return -ENOMEM;
- irm_msg__free_unpacked(recv_msg, NULL);
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
- pthread_rwlock_wrlock(&ai.lock);
+ err = irm__irm_result_des(&msg);
flow_fini(fd);
- pthread_rwlock_unlock(&ai.lock);
-
- return 0;
+ return err;
}
int fccntl(int fd,
@@ -802,6 +1005,7 @@ int fccntl(int fd,
{
uint32_t * fflags;
uint16_t * cflags;
+ uint16_t csflags;
va_list l;
struct timespec * timeo;
qosspec_t * qs;
@@ -819,7 +1023,7 @@ int fccntl(int fd,
pthread_rwlock_wrlock(&ai.lock);
- if (flow->flow_id < 0) {
+ if (flow->info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
va_end(l);
return -ENOTALLOC;
@@ -858,13 +1062,13 @@ int fccntl(int fd,
goto einval;
if (!flow->rcv_timesout)
goto eperm;
- *timeo = flow->snd_timeo;
+ *timeo = flow->rcv_timeo;
break;
case FLOWGQOSSPEC:
qs = va_arg(l, qosspec_t *);
if (qs == NULL)
goto einval;
- *qs = flow->qs;
+ *qs = flow->info.qs;
break;
case FLOWGRXQLEN:
qlen = va_arg(l, size_t *);
@@ -891,13 +1095,13 @@ int fccntl(int fd,
rx_acl |= ACL_FLOWDOWN;
tx_acl |= ACL_FLOWDOWN;
shm_flow_set_notify(flow->set,
- flow->flow_id,
+ flow->info.id,
FLOW_DOWN);
} else {
rx_acl &= ~ACL_FLOWDOWN;
tx_acl &= ~ACL_FLOWDOWN;
shm_flow_set_notify(flow->set,
- flow->flow_id,
+ flow->info.id,
FLOW_UP);
}
@@ -911,13 +1115,19 @@ int fccntl(int fd,
goto einval;
*fflags = flow->oflags;
break;
+ case FRCTSFLAGS:
+ csflags = (uint16_t) va_arg(l, uint32_t);
+ if (flow->frcti == NULL)
+ goto eperm;
+ frcti_setflags(flow->frcti, csflags);
+ break;
case FRCTGFLAGS:
- cflags = (uint16_t *) va_arg(l, int *);
+ cflags = (uint16_t *) va_arg(l, uint32_t *);
if (cflags == NULL)
goto einval;
if (flow->frcti == NULL)
goto eperm;
- *cflags = frcti_getconf(flow->frcti);
+ *cflags = frcti_getflags(flow->frcti);
break;
default:
pthread_rwlock_unlock(&ai.lock);
@@ -965,6 +1175,60 @@ static int add_crc(struct shm_du_buff * sdb)
return 0;
}
+static int flow_tx_sdb(struct flow * flow,
+ struct shm_du_buff * sdb,
+ bool block,
+ struct timespec * abstime)
+{
+ struct timespec now;
+ ssize_t idx;
+ int ret;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ pthread_rwlock_wrlock(&ai.lock);
+
+ flow->snd_act = now;
+
+ pthread_rwlock_unlock(&ai.lock);
+
+ idx = shm_du_buff_get_idx(sdb);
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ if (shm_du_buff_len(sdb) > 0) {
+ if (frcti_snd(flow->frcti, sdb) < 0)
+ goto enomem;
+
+ if (crypt_encrypt(&flow->crypt, sdb) < 0)
+ goto enomem;
+
+ if (flow->info.qs.ber == 0 && add_crc(sdb) != 0)
+ goto enomem;
+ }
+
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &ai.lock);
+
+ if (!block)
+ ret = shm_rbuff_write(flow->tx_rb, idx);
+ else
+ ret = shm_rbuff_write_b(flow->tx_rb, idx, abstime);
+
+ if (ret < 0)
+ shm_rdrbuff_remove(ai.rdrb, idx);
+ else
+ shm_flow_set_notify(flow->set, flow->info.id, FLOW_PKT);
+
+ pthread_cleanup_pop(true);
+
+ return 0;
+
+enomem:
+ pthread_rwlock_unlock(&ai.lock);
+ shm_rdrbuff_remove(ai.rdrb, idx);
+ return -ENOMEM;
+}
+
ssize_t flow_write(int fd,
const void * buf,
size_t count)
@@ -978,24 +1242,24 @@ ssize_t flow_write(int fd,
struct shm_du_buff * sdb;
uint8_t * ptr;
- if (buf == NULL)
- return 0;
+ if (buf == NULL && count != 0)
+ return -EINVAL;
- if (fd < 0 || fd > PROG_MAX_FLOWS)
+ if (fd < 0 || fd >= PROG_MAX_FLOWS)
return -EBADF;
flow = &ai.flows[fd];
clock_gettime(PTHREAD_COND_CLOCK, &abs);
- pthread_rwlock_rdlock(&ai.lock);
+ pthread_rwlock_wrlock(&ai.lock);
- if (flow->flow_id < 0) {
+ if (flow->info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
return -ENOTALLOC;
}
- if (ai.flows[fd].snd_timesout) {
+ if (flow->snd_timesout) {
ts_add(&abs, &flow->snd_timeo, &abs);
abstime = &abs;
}
@@ -1007,57 +1271,71 @@ ssize_t flow_write(int fd,
if ((flags & FLOWFACCMODE) == FLOWFRDONLY)
return -EPERM;
- /* TODO: partial writes. */
- if (flags & FLOWFWNOBLOCK)
- idx = shm_rdrbuff_alloc(ai.rdrb,
- count,
- &ptr,
- &sdb);
- else /* Blocking. */
- idx = shm_rdrbuff_alloc_b(ai.rdrb,
- count,
- &ptr,
- &sdb,
- abstime);
+ if (flags & FLOWFWNOBLOCK) {
+ if (!frcti_is_window_open(flow->frcti))
+ return -EAGAIN;
+ idx = shm_rdrbuff_alloc(ai.rdrb, count, &ptr, &sdb);
+ } else {
+ ret = frcti_window_wait(flow->frcti, abstime);
+ if (ret < 0)
+ return ret;
+ idx = shm_rdrbuff_alloc_b(ai.rdrb, count, &ptr, &sdb, abstime);
+ }
+
if (idx < 0)
return idx;
- memcpy(ptr, buf, count);
+ if (count > 0)
+ memcpy(ptr, buf, count);
- if (frcti_snd(flow->frcti, sdb) < 0) {
- shm_rdrbuff_remove(ai.rdrb, idx);
- return -ENOMEM;
- }
+ ret = flow_tx_sdb(flow, sdb, !(flags & FLOWFWNOBLOCK), abstime);
- pthread_rwlock_wrlock(&ai.lock);
- if (flow->qs.cypher_s > 0)
- if (crypt_encrypt(flow, sdb) < 0) {
- pthread_rwlock_unlock(&ai.lock);
- shm_rdrbuff_remove(ai.rdrb, idx);
- return -ENOMEM;
- }
- pthread_rwlock_unlock(&ai.lock);
+ return ret < 0 ? (ssize_t) ret : (ssize_t) count;
+}
- if (flow->qs.ber == 0 && add_crc(sdb) != 0) {
- shm_rdrbuff_remove(ai.rdrb, idx);
- return -ENOMEM;
- }
+static bool invalid_pkt(struct flow * flow,
+ struct shm_du_buff * sdb)
+{
+ if (shm_du_buff_len(sdb) == 0)
+ return true;
- pthread_rwlock_rdlock(&ai.lock);
+ if (flow->info.qs.ber == 0 && chk_crc(sdb) != 0)
+ return true;
- if (flags & FLOWFWNOBLOCK)
- ret = shm_rbuff_write(flow->tx_rb, idx);
- else
- ret = shm_rbuff_write_b(flow->tx_rb, idx, abstime);
+ if (crypt_decrypt(&flow->crypt, sdb) < 0)
+ return true;
- if (ret < 0)
- shm_rdrbuff_remove(ai.rdrb, idx);
- else
- shm_flow_set_notify(flow->set, flow->flow_id, FLOW_PKT);
+ return false;
+}
+
+static ssize_t flow_rx_sdb(struct flow * flow,
+ struct shm_du_buff ** sdb,
+ bool block,
+ struct timespec * abstime)
+{
+ ssize_t idx;
+ struct timespec now;
+
+ idx = block ? shm_rbuff_read_b(flow->rx_rb, abstime) :
+ shm_rbuff_read(flow->rx_rb);
+ if (idx < 0)
+ return idx;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ pthread_rwlock_wrlock(&ai.lock);
+
+ flow->rcv_act = now;
pthread_rwlock_unlock(&ai.lock);
- return ret < 0 ? (ssize_t) ret : (ssize_t) count;
+ *sdb = shm_rdrbuff_get(ai.rdrb, idx);
+ if (invalid_pkt(flow, *sdb)) {
+ shm_rdrbuff_remove(ai.rdrb, idx);
+ return -EAGAIN;
+ }
+
+ return idx;
}
ssize_t flow_read(int fd,
@@ -1067,92 +1345,100 @@ ssize_t flow_read(int fd,
ssize_t idx;
ssize_t n;
uint8_t * packet;
- struct shm_rbuff * rb;
struct shm_du_buff * sdb;
struct timespec abs;
+ struct timespec now;
struct timespec * abstime = NULL;
struct flow * flow;
- bool noblock;
+ bool block;
bool partrd;
- if (fd < 0 || fd > PROG_MAX_FLOWS)
+ if (fd < 0 || fd >= PROG_MAX_FLOWS)
return -EBADF;
flow = &ai.flows[fd];
- if (flow->part_idx == DONE_PART) {
- flow->part_idx = NO_PART;
- return 0;
- }
-
- clock_gettime(PTHREAD_COND_CLOCK, &abs);
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
pthread_rwlock_rdlock(&ai.lock);
- if (flow->flow_id < 0) {
+ if (flow->info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
return -ENOTALLOC;
}
- rb = flow->rx_rb;
- noblock = flow->oflags & FLOWFRNOBLOCK;
+ if (flow->part_idx == DONE_PART) {
+ pthread_rwlock_unlock(&ai.lock);
+ flow->part_idx = NO_PART;
+ return 0;
+ }
+
+ block = !(flow->oflags & FLOWFRNOBLOCK);
partrd = !(flow->oflags & FLOWFRNOPART);
- if (ai.flows[fd].rcv_timesout) {
- ts_add(&abs, &flow->rcv_timeo, &abs);
+ if (flow->rcv_timesout) {
+ ts_add(&now, &flow->rcv_timeo, &abs);
abstime = &abs;
}
- pthread_rwlock_unlock(&ai.lock);
-
idx = flow->part_idx;
if (idx < 0) {
- idx = frcti_queued_pdu(flow->frcti);
- if (idx < 0) {
- do {
- idx = noblock ? shm_rbuff_read(rb) :
- shm_rbuff_read_b(rb, abstime);
- if (idx < 0)
+ while ((idx = frcti_queued_pdu(flow->frcti)) < 0) {
+ pthread_rwlock_unlock(&ai.lock);
+
+ idx = flow_rx_sdb(flow, &sdb, block, abstime);
+ if (idx < 0) {
+ if (block && idx != -EAGAIN)
return idx;
+ if (!block)
+ return idx;
+
+ pthread_rwlock_rdlock(&ai.lock);
+ continue;
+ }
- sdb = shm_rdrbuff_get(ai.rdrb, idx);
- if (flow->qs.ber == 0 && chk_crc(sdb) != 0) {
- shm_rdrbuff_remove(ai.rdrb, idx);
- continue;
- }
-
- pthread_rwlock_wrlock(&ai.lock);
- if (flow->qs.cypher_s > 0)
- if (crypt_decrypt(flow, sdb) < 0) {
- pthread_rwlock_unlock(&ai.lock);
- shm_rdrbuff_remove(ai.rdrb,
- idx);
- return -ENOMEM;
- }
- pthread_rwlock_unlock(&ai.lock);
- } while (frcti_rcv(flow->frcti, sdb) != 0);
+ pthread_rwlock_rdlock(&ai.lock);
+
+ frcti_rcv(flow->frcti, sdb);
}
}
- n = shm_rdrbuff_read(&packet, ai.rdrb, idx);
+ sdb = shm_rdrbuff_get(ai.rdrb, idx);
+
+ pthread_rwlock_unlock(&ai.lock);
+
+ packet = shm_du_buff_head(sdb);
+
+ n = shm_du_buff_len(sdb);
assert(n >= 0);
if (n <= (ssize_t) count) {
memcpy(buf, packet, n);
- shm_rdrbuff_remove(ai.rdrb, idx);
+ ipcp_sdb_release(sdb);
+
+ pthread_rwlock_wrlock(&ai.lock);
+
flow->part_idx = (partrd && n == (ssize_t) count) ?
DONE_PART : NO_PART;
+
+ flow->rcv_act = now;
+
+ pthread_rwlock_unlock(&ai.lock);
return n;
} else {
if (partrd) {
memcpy(buf, packet, count);
- sdb = shm_rdrbuff_get(ai.rdrb, idx);
shm_du_buff_head_release(sdb, n);
+ pthread_rwlock_wrlock(&ai.lock);
flow->part_idx = idx;
+
+ flow->rcv_act = now;
+
+ pthread_rwlock_unlock(&ai.lock);
return count;
} else {
- shm_rdrbuff_remove(ai.rdrb, idx);
+ ipcp_sdb_release(sdb);
return -EMSGSIZE;
}
}
@@ -1160,26 +1446,31 @@ ssize_t flow_read(int fd,
/* fqueue functions. */
-struct flow_set * fset_create()
+struct flow_set * fset_create(void)
{
- struct flow_set * set = malloc(sizeof(*set));
+ struct flow_set * set;
+
+ set = malloc(sizeof(*set));
if (set == NULL)
- return NULL;
+ goto fail_malloc;
assert(ai.fqueues);
pthread_rwlock_wrlock(&ai.lock);
set->idx = bmp_allocate(ai.fqueues);
- if (!bmp_is_id_valid(ai.fqueues, set->idx)) {
- pthread_rwlock_unlock(&ai.lock);
- free(set);
- return NULL;
- }
+ if (!bmp_is_id_valid(ai.fqueues, set->idx))
+ goto fail_bmp_alloc;
pthread_rwlock_unlock(&ai.lock);
return set;
+
+ fail_bmp_alloc:
+ pthread_rwlock_unlock(&ai.lock);
+ free(set);
+ fail_malloc:
+ return NULL;
}
void fset_destroy(struct flow_set * set)
@@ -1198,13 +1489,13 @@ void fset_destroy(struct flow_set * set)
free(set);
}
-struct fqueue * fqueue_create()
+struct fqueue * fqueue_create(void)
{
struct fqueue * fq = malloc(sizeof(*fq));
if (fq == NULL)
return NULL;
- memset(fq->fqueue, -1, (SHM_BUFFER_SIZE) * sizeof(*fq->fqueue));
+ memset(fq->fqueue, -1, SHM_BUFFER_SIZE * sizeof(*fq->fqueue));
fq->fqsize = 0;
fq->next = 0;
@@ -1227,41 +1518,57 @@ void fset_zero(struct flow_set * set)
int fset_add(struct flow_set * set,
int fd)
{
- int ret;
- size_t packets;
- size_t i;
+ struct flow * flow;
+ int ret;
- if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS)
+ if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)
return -EINVAL;
- pthread_rwlock_wrlock(&ai.lock);
+ flow = &ai.flows[fd];
- if (ai.flows[fd].flow_id < 0) {
- pthread_rwlock_unlock(&ai.lock);
- return -EINVAL;
+ pthread_rwlock_rdlock(&ai.lock);
+
+ if (flow->info.id < 0) {
+ ret = -EINVAL;
+ goto fail;
}
- ret = shm_flow_set_add(ai.fqset, set->idx, ai.flows[fd].flow_id);
+ if (flow->frcti != NULL)
+ shm_flow_set_del(ai.fqset, 0, ai.flows[fd].info.id);
- packets = shm_rbuff_queued(ai.flows[fd].rx_rb);
- for (i = 0; i < packets; i++)
- shm_flow_set_notify(ai.fqset, ai.flows[fd].flow_id, FLOW_PKT);
+ ret = shm_flow_set_add(ai.fqset, set->idx, ai.flows[fd].info.id);
+ if (ret < 0)
+ goto fail;
+
+ if (shm_rbuff_queued(ai.flows[fd].rx_rb))
+ shm_flow_set_notify(ai.fqset, ai.flows[fd].info.id, FLOW_PKT);
pthread_rwlock_unlock(&ai.lock);
return ret;
+
+ fail:
+ pthread_rwlock_unlock(&ai.lock);
+ return ret;
}
void fset_del(struct flow_set * set,
int fd)
{
- if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS)
+ struct flow * flow;
+
+ if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)
return;
- pthread_rwlock_wrlock(&ai.lock);
+ flow = &ai.flows[fd];
- if (ai.flows[fd].flow_id >= 0)
- shm_flow_set_del(ai.fqset, set->idx, ai.flows[fd].flow_id);
+ pthread_rwlock_rdlock(&ai.lock);
+
+ if (flow->info.id >= 0)
+ shm_flow_set_del(ai.fqset, set->idx, flow->info.id);
+
+ if (flow->frcti != NULL)
+ shm_flow_set_add(ai.fqset, 0, ai.flows[fd].info.id);
pthread_rwlock_unlock(&ai.lock);
}
@@ -1269,28 +1576,86 @@ void fset_del(struct flow_set * set,
bool fset_has(const struct flow_set * set,
int fd)
{
- bool ret = false;
+ bool ret;
- if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS)
+ if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)
return false;
pthread_rwlock_rdlock(&ai.lock);
- if (ai.flows[fd].flow_id < 0) {
+ if (ai.flows[fd].info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
return false;
}
- ret = (shm_flow_set_has(ai.fqset, set->idx, ai.flows[fd].flow_id) == 1);
+ ret = (shm_flow_set_has(ai.fqset, set->idx, ai.flows[fd].info.id) == 1);
pthread_rwlock_unlock(&ai.lock);
return ret;
}
+/* Filter fqueue events for non-data packets */
+static int fqueue_filter(struct fqueue * fq)
+{
+ struct shm_du_buff * sdb;
+ int fd;
+ ssize_t idx;
+ struct frcti * frcti;
+
+ while (fq->next < fq->fqsize) {
+ if (fq->fqueue[fq->next].event != FLOW_PKT)
+ return 1;
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ fd = ai.id_to_fd[fq->fqueue[fq->next].flow_id].fd;
+ if (fd < 0) {
+ ++fq->next;
+ pthread_rwlock_unlock(&ai.lock);
+ continue;
+ }
+
+ frcti = ai.flows[fd].frcti;
+ if (frcti == NULL) {
+ pthread_rwlock_unlock(&ai.lock);
+ return 1;
+ }
+
+ if (__frcti_pdu_ready(frcti) >= 0) {
+ pthread_rwlock_unlock(&ai.lock);
+ return 1;
+ }
+
+ pthread_rwlock_unlock(&ai.lock);
+
+ idx = flow_rx_sdb(&ai.flows[fd], &sdb, false, NULL);
+ if (idx < 0)
+ return 0;
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ sdb = shm_rdrbuff_get(ai.rdrb, idx);
+
+ __frcti_rcv(frcti, sdb);
+
+ if (__frcti_pdu_ready(frcti) >= 0) {
+ pthread_rwlock_unlock(&ai.lock);
+ return 1;
+ }
+
+ pthread_rwlock_unlock(&ai.lock);
+
+ ++fq->next;
+ }
+
+ return 0;
+}
+
int fqueue_next(struct fqueue * fq)
{
- int fd;
+ int fd;
+ struct flowevent * e;
if (fq == NULL)
return -EINVAL;
@@ -1298,11 +1663,16 @@ int fqueue_next(struct fqueue * fq)
if (fq->fqsize == 0 || fq->next == fq->fqsize)
return -EPERM;
+ if (fq->next != 0 && fqueue_filter(fq) == 0)
+ return -EPERM;
+
pthread_rwlock_rdlock(&ai.lock);
- fd = ai.ports[fq->fqueue[fq->next]].fd;
+ e = fq->fqueue + fq->next;
- fq->next += 2;
+ fd = ai.id_to_fd[e->flow_id].fd;
+
+ ++fq->next;
pthread_rwlock_unlock(&ai.lock);
@@ -1317,60 +1687,80 @@ enum fqtype fqueue_type(struct fqueue * fq)
if (fq->fqsize == 0 || fq->next == 0)
return -EPERM;
- return fq->fqueue[fq->next - 1];
+ return fq->fqueue[(fq->next - 1)].event;
}
ssize_t fevent(struct flow_set * set,
struct fqueue * fq,
const struct timespec * timeo)
{
- ssize_t ret;
- struct timespec abstime;
+ ssize_t ret = 0;
+ struct timespec abs;
struct timespec * t = NULL;
if (set == NULL || fq == NULL)
return -EINVAL;
if (fq->fqsize > 0 && fq->next != fq->fqsize)
- return fq->fqsize;
+ return 1;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abs);
if (timeo != NULL) {
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- ts_add(&abstime, timeo, &abstime);
- t = &abstime;
+ ts_add(&abs, timeo, &abs);
+ t = &abs;
}
- ret = shm_flow_set_wait(ai.fqset, set->idx, fq->fqueue, t);
- if (ret == -ETIMEDOUT) {
- fq->fqsize = 0;
- return -ETIMEDOUT;
- }
+ while (ret == 0) {
+ ret = shm_flow_set_wait(ai.fqset, set->idx, fq->fqueue, t);
+ if (ret == -ETIMEDOUT)
+ return -ETIMEDOUT;
- fq->fqsize = ret << 1;
- fq->next = 0;
+ fq->fqsize = ret;
+ fq->next = 0;
+
+ ret = fqueue_filter(fq);
+ }
- assert(ret);
+ assert(ret != 0);
- return ret;
+ return 1;
}
/* ipcp-dev functions. */
-int np1_flow_alloc(pid_t n_pid,
- int flow_id,
- qosspec_t qs)
+int np1_flow_alloc(pid_t n_pid,
+ int flow_id)
{
- qs.cypher_s = 0; /* No encryption ctx for np1 */
- return flow_init(flow_id, n_pid, qs, NULL);
+ struct flow_info flow;
+
+ memset(&flow, 0, sizeof(flow));
+
+ flow.id = flow_id;
+ flow.n_pid = getpid();
+ flow.qs = qos_np1;
+ flow.mpl = 0;
+ flow.n_1_pid = n_pid; /* This "flow" is upside-down! */
+
+ return flow_init(&flow, NULL);
}
-int np1_flow_dealloc(int flow_id)
+int np1_flow_dealloc(int flow_id,
+ time_t timeo)
{
int fd;
+ /*
+ * TODO: Don't pass timeo to the IPCP but wait in IRMd.
+ * This will need async ops, waiting until we bootstrap
+ * the IRMd over ouroboros.
+ */
+
+ sleep(timeo);
+
pthread_rwlock_rdlock(&ai.lock);
- fd = ai.ports[flow_id].fd;
+ fd = ai.id_to_fd[flow_id].fd;
pthread_rwlock_unlock(&ai.lock);
@@ -1381,140 +1771,106 @@ int np1_flow_resp(int flow_id)
{
int fd;
- if (port_wait_assign(flow_id) != PORT_ID_ASSIGNED)
+ if (flow_wait_assign(flow_id) != FLOW_ALLOCATED)
return -1;
pthread_rwlock_rdlock(&ai.lock);
- fd = ai.ports[flow_id].fd;
+ fd = ai.id_to_fd[flow_id].fd;
pthread_rwlock_unlock(&ai.lock);
return fd;
}
-int ipcp_create_r(int result)
+int ipcp_create_r(const struct ipcp_info * info)
{
- irm_msg_t msg = IRM_MSG__INIT;
- irm_msg_t * recv_msg;
- int ret;
-
- msg.code = IRM_MSG_CODE__IPCP_CREATE_R;
- msg.has_pid = true;
- msg.pid = getpid();
- msg.has_result = true;
- msg.result = result;
-
- recv_msg = send_recv_irm_msg(&msg);
- if (recv_msg == NULL)
- return -EIRMD;
-
- if (!recv_msg->has_result) {
- irm_msg__free_unpacked(recv_msg, NULL);
- return -1;
- }
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ int err;
- ret = recv_msg->result;
- irm_msg__free_unpacked(recv_msg, NULL);
+ if (ipcp_create_r__irm_req_ser(&msg,info) < 0)
+ return -ENOMEM;
- return ret;
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
+
+ return irm__irm_result_des(&msg);
}
-int ipcp_flow_req_arr(const uint8_t * dst,
- size_t len,
- qosspec_t qs,
- const void * data,
- size_t dlen)
+int ipcp_flow_req_arr(const buffer_t * dst,
+ qosspec_t qs,
+ time_t mpl,
+ const buffer_t * data)
{
- irm_msg_t msg = IRM_MSG__INIT;
- irm_msg_t * recv_msg;
- qosspec_msg_t qs_msg;
- int fd;
-
- assert(dst != NULL);
-
- msg.code = IRM_MSG_CODE__IPCP_FLOW_REQ_ARR;
- msg.has_pid = true;
- msg.pid = getpid();
- msg.has_hash = true;
- msg.hash.len = len;
- msg.hash.data = (uint8_t *) dst;
- qs_msg = spec_to_msg(&qs);
- msg.qosspec = &qs_msg;
- msg.has_pk = true;
- msg.pk.data = (uint8_t *) data;
- msg.pk.len = dlen;
-
- recv_msg = send_recv_irm_msg(&msg);
- if (recv_msg == NULL)
- return -EIRMD;
-
- if (!recv_msg->has_flow_id || !recv_msg->has_pid) {
- irm_msg__free_unpacked(recv_msg, NULL);
- return -1;
- }
+ struct flow_info flow;
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ int err;
- if (recv_msg->has_result && recv_msg->result) {
- irm_msg__free_unpacked(recv_msg, NULL);
- return -1;
- }
+ memset(&flow, 0, sizeof(flow));
- qs.cypher_s = 0; /* No encryption ctx for np1 */
- fd = flow_init(recv_msg->flow_id, recv_msg->pid, qs, NULL);
+ assert(dst != NULL && dst->len != 0 && dst->data != NULL);
- irm_msg__free_unpacked(recv_msg, NULL);
+ flow.n_1_pid = getpid();
+ flow.qs = qs;
+ flow.mpl = mpl;
- return fd;
+ if (ipcp_flow_req_arr__irm_req_ser(&msg, dst, &flow, data) < 0)
+ return -ENOMEM;
+
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
+
+ err = flow__irm_result_des(&msg, &flow, NULL);
+ if (err < 0)
+ return err;
+
+ /* inverted for np1_flow */
+ flow.n_1_pid = flow.n_pid;
+ flow.n_pid = getpid();
+ flow.mpl = 0;
+
+ return flow_init(&flow, NULL);
}
-int ipcp_flow_alloc_reply(int fd,
- int response,
- const void * data,
- size_t len)
+int ipcp_flow_alloc_reply(int fd,
+ int response,
+ time_t mpl,
+ const buffer_t * data)
{
- irm_msg_t msg = IRM_MSG__INIT;
- irm_msg_t * recv_msg;
- int ret;
+ struct flow_info flow;
+ uint8_t buf[SOCK_BUF_SIZE];
+ buffer_t msg = {buf, SOCK_BUF_SIZE};
+ int err;
assert(fd >= 0 && fd < SYS_MAX_FLOWS);
- msg.code = IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY;
- msg.has_flow_id = true;
- msg.has_pk = true;
- msg.pk.data = (uint8_t *) data;
- msg.pk.len = (uint32_t) len;
-
pthread_rwlock_rdlock(&ai.lock);
- msg.flow_id = ai.flows[fd].flow_id;
+ flow.id = ai.flows[fd].info.id;
pthread_rwlock_unlock(&ai.lock);
- msg.has_response = true;
- msg.response = response;
-
- recv_msg = send_recv_irm_msg(&msg);
- if (recv_msg == NULL)
- return -EIRMD;
+ flow.mpl = mpl;
- if (!recv_msg->has_result) {
- irm_msg__free_unpacked(recv_msg, NULL);
- return -1;
- }
-
- ret = recv_msg->result;
+ if (ipcp_flow_alloc_reply__irm_msg_ser(&msg, &flow, response, data) < 0)
+ return -ENOMEM;
- irm_msg__free_unpacked(recv_msg, NULL);
+ err = send_recv_msg(&msg);
+ if (err < 0)
+ return err;
- return ret;
+ return irm__irm_result_des(&msg);
}
int ipcp_flow_read(int fd,
struct shm_du_buff ** sdb)
{
- struct flow * flow;
- struct shm_rbuff * rb;
- ssize_t idx;
+ struct flow * flow;
+ ssize_t idx = -1;
assert(fd >= 0 && fd < SYS_MAX_FLOWS);
assert(sdb);
@@ -1523,28 +1879,21 @@ int ipcp_flow_read(int fd,
pthread_rwlock_rdlock(&ai.lock);
- assert(flow->flow_id >= 0);
+ assert(flow->info.id >= 0);
- rb = flow->rx_rb;
+ while (frcti_queued_pdu(flow->frcti) < 0) {
+ pthread_rwlock_unlock(&ai.lock);
- pthread_rwlock_unlock(&ai.lock);
+ idx = flow_rx_sdb(flow, sdb, false, NULL);
+ if (idx < 0)
+ return idx;
- if (flow->frcti != NULL) {
- idx = frcti_queued_pdu(flow->frcti);
- if (idx >= 0) {
- *sdb = shm_rdrbuff_get(ai.rdrb, idx);
- return 0;
- }
+ pthread_rwlock_rdlock(&ai.lock);
+
+ frcti_rcv(flow->frcti, *sdb);
}
- do {
- idx = shm_rbuff_read(rb);
- if (idx < 0)
- return idx;
- *sdb = shm_rdrbuff_get(ai.rdrb, idx);
- if (flow->qs.ber == 0 && chk_crc(*sdb) != 0)
- continue;
- } while (frcti_rcv(flow->frcti, *sdb) != 0);
+ pthread_rwlock_unlock(&ai.lock);
return 0;
}
@@ -1552,18 +1901,17 @@ int ipcp_flow_read(int fd,
int ipcp_flow_write(int fd,
struct shm_du_buff * sdb)
{
- struct flow * flow;
- int ret;
- ssize_t idx;
+ struct flow * flow;
+ int ret;
assert(fd >= 0 && fd < SYS_MAX_FLOWS);
assert(sdb);
flow = &ai.flows[fd];
- pthread_rwlock_rdlock(&ai.lock);
+ pthread_rwlock_wrlock(&ai.lock);
- if (flow->flow_id < 0) {
+ if (flow->info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
return -ENOTALLOC;
}
@@ -1573,30 +1921,74 @@ int ipcp_flow_write(int fd,
return -EPERM;
}
- assert(flow->tx_rb);
+ pthread_rwlock_unlock(&ai.lock);
- idx = shm_du_buff_get_idx(sdb);
+ ret = flow_tx_sdb(flow, sdb, true, NULL);
+
+ return ret;
+}
+
+int np1_flow_read(int fd,
+ struct shm_du_buff ** sdb)
+{
+ struct flow * flow;
+ ssize_t idx = -1;
+
+ assert(fd >= 0 && fd < SYS_MAX_FLOWS);
+ assert(sdb);
- if (frcti_snd(flow->frcti, sdb) < 0) {
+ flow = &ai.flows[fd];
+
+ assert(flow->info.id >= 0);
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ idx = shm_rbuff_read(flow->rx_rb);;
+ if (idx < 0) {
pthread_rwlock_unlock(&ai.lock);
- return -ENOMEM;
+ return idx;
}
- if (flow->qs.ber == 0 && add_crc(sdb) != 0) {
+ pthread_rwlock_unlock(&ai.lock);
+
+ *sdb = shm_rdrbuff_get(ai.rdrb, idx);
+
+ return 0;
+}
+
+int np1_flow_write(int fd,
+ struct shm_du_buff * sdb)
+{
+ struct flow * flow;
+ int ret;
+ ssize_t idx;
+
+ assert(fd >= 0 && fd < SYS_MAX_FLOWS);
+ assert(sdb);
+
+ flow = &ai.flows[fd];
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ if (flow->info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
- shm_rdrbuff_remove(ai.rdrb, idx);
- return -ENOMEM;
+ return -ENOTALLOC;
}
- ret = shm_rbuff_write_b(flow->tx_rb, idx, NULL);
- if (ret == 0)
- shm_flow_set_notify(flow->set, flow->flow_id, FLOW_PKT);
- else
- shm_rdrbuff_remove(ai.rdrb, idx);
+ if ((flow->oflags & FLOWFACCMODE) == FLOWFRDONLY) {
+ pthread_rwlock_unlock(&ai.lock);
+ return -EPERM;
+ }
pthread_rwlock_unlock(&ai.lock);
- assert(ret <= 0);
+ idx = shm_du_buff_get_idx(sdb);
+
+ ret = shm_rbuff_write_b(flow->tx_rb, idx, NULL);
+ if (ret < 0)
+ shm_rdrbuff_remove(ai.rdrb, idx);
+ else
+ shm_flow_set_notify(flow->set, flow->info.id, FLOW_PKT);
return ret;
}
@@ -1620,7 +2012,7 @@ int ipcp_flow_fini(int fd)
pthread_rwlock_rdlock(&ai.lock);
- if (ai.flows[fd].flow_id < 0) {
+ if (ai.flows[fd].info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
return -1;
}
@@ -1629,7 +2021,7 @@ int ipcp_flow_fini(int fd)
shm_rbuff_set_acl(ai.flows[fd].tx_rb, ACL_FLOWDOWN);
shm_flow_set_notify(ai.flows[fd].set,
- ai.flows[fd].flow_id,
+ ai.flows[fd].info.id,
FLOW_DEALLOC);
rx_rb = ai.flows[fd].rx_rb;
@@ -1650,15 +2042,30 @@ int ipcp_flow_get_qoscube(int fd,
pthread_rwlock_rdlock(&ai.lock);
- assert(ai.flows[fd].flow_id >= 0);
+ assert(ai.flows[fd].info.id >= 0);
- *cube = qos_spec_to_cube(ai.flows[fd].qs);
+ *cube = qos_spec_to_cube(ai.flows[fd].info.qs);
pthread_rwlock_unlock(&ai.lock);
return 0;
}
+size_t ipcp_flow_queued(int fd)
+{
+ size_t q;
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ assert(ai.flows[fd].info.id >= 0);
+
+ q = shm_rbuff_queued(ai.flows[fd].tx_rb);
+
+ pthread_rwlock_unlock(&ai.lock);
+
+ return q;
+}
+
ssize_t local_flow_read(int fd)
{
ssize_t ret;
@@ -1686,13 +2093,14 @@ int local_flow_write(int fd,
pthread_rwlock_rdlock(&ai.lock);
- if (flow->flow_id < 0) {
+ if (flow->info.id < 0) {
pthread_rwlock_unlock(&ai.lock);
return -ENOTALLOC;
}
+
ret = shm_rbuff_write_b(flow->tx_rb, idx, NULL);
if (ret == 0)
- shm_flow_set_notify(flow->set, flow->flow_id, FLOW_PKT);
+ shm_flow_set_notify(flow->set, flow->info.id, FLOW_PKT);
else
shm_rdrbuff_remove(ai.rdrb, idx);
diff --git a/src/lib/frct.c b/src/lib/frct.c
index e4b858d0..c6fef35c 100644
--- a/src/lib/frct.c
+++ b/src/lib/frct.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Flow and Retransmission Control
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,47 +20,62 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-/* Default Delta-t parameters */
-#define DELT_MPL 60000 /* ms */
-#define DELT_A 0 /* ms */
-#define DELT_R 2000 /* ms */
+#include <ouroboros/endian.h>
-#define RQ_SIZE 64
+#define DELT_RDV (100 * MILLION) /* ns */
+#define MAX_RDV (1 * BILLION) /* ns */
-#define TW_ELEMENTS 6000
-#define TW_RESOLUTION 1 /* ms */
-
-#define FRCT_PCILEN (sizeof(struct frct_pci))
+#define FRCT "frct"
+#define FRCT_PCILEN (sizeof(struct frct_pci))
+#define FRCT_NAME_STRLEN 32
struct frct_cr {
- uint32_t lwe;
- uint32_t rwe;
+ uint32_t lwe; /* Left window edge */
+ uint32_t rwe; /* Right window edge */
- uint8_t cflags;
- uint32_t seqno;
+ uint8_t cflags;
+ uint32_t seqno; /* SEQ to send, or last SEQ Ack'd */
- time_t act; /* s */
- time_t inact; /* s */
+ struct timespec act; /* Last seen activity */
+ time_t inact; /* Inactivity (s) */
};
struct frcti {
- int fd;
-
- time_t mpl;
- time_t a;
- time_t r;
+ int fd;
+
+ time_t mpl;
+ time_t a;
+ time_t r;
+ time_t rdv;
+
+ time_t srtt; /* Smoothed rtt */
+ time_t mdev; /* Deviation */
+ time_t rto; /* Retransmission timeout */
+ uint32_t rttseq;
+ struct timespec t_probe; /* Probe time */
+ bool probe; /* Probe active */
+#ifdef PROC_FLOW_STATS
+ size_t n_rtx; /* Number of rxm packets */
+ size_t n_prb; /* Number of rtt probes */
+ size_t n_rtt; /* Number of estimates */
+ size_t n_dup; /* Duplicates received */
+ size_t n_dak; /* Delayed ACKs received */
+ size_t n_rdv; /* Number of rdv packets */
+ size_t n_out; /* Packets out of window */
+ size_t n_rqo; /* Packets out of rqueue */
+#endif
+ struct frct_cr snd_cr;
+ struct frct_cr rcv_cr;
- time_t srtt_us; /* smoothed rtt */
- time_t mdev_us; /* mdev */
- uint32_t rttseq;
- struct timespec t_probe; /* probe time */
- bool probe; /* probe active */
- struct frct_cr snd_cr;
- struct frct_cr rcv_cr;
+ ssize_t rq[RQ_SIZE];
+ pthread_rwlock_t lock;
- ssize_t rq[RQ_SIZE];
- pthread_rwlock_t lock;
+ bool open; /* Window open/closed */
+ struct timespec t_wnd; /* Window closed time */
+ struct timespec t_rdvs; /* Last rendez-vous sent */
+ pthread_cond_t cond;
+ pthread_mutex_t mtx;
};
enum frct_flags {
@@ -68,28 +83,265 @@ enum frct_flags {
FRCT_DRF = 0x02, /* Data run flag */
FRCT_ACK = 0x04, /* ACK field valid */
FRCT_FC = 0x08, /* FC window valid */
- FRCT_RDVZ = 0x10, /* Rendez-vous */
+ FRCT_RDVS = 0x10, /* Rendez-vous */
FRCT_FFGM = 0x20, /* First Fragment */
FRCT_MFGM = 0x40, /* More fragments */
};
struct frct_pci {
- uint16_t flags;
+ uint8_t flags;
+ uint8_t pad; /* 24 bit window! */
uint16_t window;
uint32_t seqno;
uint32_t ackno;
} __attribute__((packed));
-#include <rxmwheel.c>
+#ifdef PROC_FLOW_STATS
-static struct frcti * frcti_create(int fd)
+static int frct_rib_read(const char * path,
+ char * buf,
+ size_t len)
{
- struct frcti * frcti;
- time_t delta_t;
- ssize_t idx;
struct timespec now;
+ char * entry;
+ struct flow * flow;
+ struct frcti * frcti;
+ int fd;
+
+ (void) len;
+
+ entry = strstr(path, RIB_SEPARATOR);
+ assert(entry);
+ *entry = '\0';
+
+ fd = atoi(path);
+
+ flow = &ai.flows[fd];
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ pthread_rwlock_rdlock(&ai.lock);
+
+ frcti = flow->frcti;
+
+ pthread_rwlock_rdlock(&frcti->lock);
+
+ sprintf(buf,
+ "Maximum packet lifetime (ns): %20ld\n"
+ "Max time to Ack (ns): %20ld\n"
+ "Max time to Retransmit (ns): %20ld\n"
+ "Smoothed rtt (ns): %20ld\n"
+ "RTT standard deviation (ns): %20ld\n"
+ "Retransmit timeout RTO (ns): %20ld\n"
+ "Sender left window edge: %20u\n"
+ "Sender right window edge: %20u\n"
+ "Sender inactive (ns): %20ld\n"
+ "Sender current sequence number: %20u\n"
+ "Receiver left window edge: %20u\n"
+ "Receiver right window edge: %20u\n"
+ "Receiver inactive (ns): %20ld\n"
+ "Receiver last ack: %20u\n"
+ "Number of pkt retransmissions: %20zu\n"
+ "Number of rtt probes: %20zu\n"
+ "Number of rtt estimates: %20zu\n"
+ "Number of duplicates received: %20zu\n"
+ "Number of delayed acks received: %20zu\n"
+ "Number of rendez-vous sent: %20zu\n"
+ "Number of packets out of window: %20zu\n"
+ "Number of packets out of rqueue: %20zu\n",
+ frcti->mpl,
+ frcti->a,
+ frcti->r,
+ frcti->srtt,
+ frcti->mdev,
+ frcti->rto,
+ frcti->snd_cr.lwe,
+ frcti->snd_cr.rwe,
+ ts_diff_ns(&frcti->snd_cr.act, &now),
+ frcti->snd_cr.seqno,
+ frcti->rcv_cr.lwe,
+ frcti->rcv_cr.rwe,
+ ts_diff_ns(&frcti->rcv_cr.act, &now),
+ frcti->rcv_cr.seqno,
+ frcti->n_rtx,
+ frcti->n_prb,
+ frcti->n_rtt,
+ frcti->n_dup,
+ frcti->n_dak,
+ frcti->n_rdv,
+ frcti->n_out,
+ frcti->n_rqo);
+
+ pthread_rwlock_unlock(&flow->frcti->lock);
+
+ pthread_rwlock_unlock(&ai.lock);
+
+ return strlen(buf);
+}
+
+static int frct_rib_readdir(char *** buf)
+{
+ *buf = malloc(sizeof(**buf));
+ if (*buf == NULL)
+ goto fail_malloc;
+
+ (*buf)[0] = strdup("frct");
+ if ((*buf)[0] == NULL)
+ goto fail_strdup;
+
+ return 1;
+
+ fail_strdup:
+ free(*buf);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+static int frct_rib_getattr(const char * path,
+ struct rib_attr * attr)
+{
+ (void) path;
+ (void) attr;
+
+ attr->size = 1189;
+ attr->mtime = 0;
+
+ return 0;
+}
+
+
+static struct rib_ops r_ops = {
+ .read = frct_rib_read,
+ .readdir = frct_rib_readdir,
+ .getattr = frct_rib_getattr
+};
+
+#endif /* PROC_FLOW_STATS */
+
+static bool before(uint32_t seq1,
+ uint32_t seq2)
+{
+ return (int32_t)(seq1 - seq2) < 0;
+}
+
+static bool after(uint32_t seq1,
+ uint32_t seq2)
+{
+ return (int32_t)(seq2 - seq1) < 0;
+}
+
+static void __send_frct_pkt(int fd,
+ uint8_t flags,
+ uint32_t ackno,
+ uint32_t rwe)
+{
+ struct shm_du_buff * sdb;
+ struct frct_pci * pci;
+ ssize_t idx;
+ struct flow * f;
+
+ /* Raw calls needed to bypass frcti. */
+#ifdef RXM_BLOCKING
+ idx = shm_rdrbuff_alloc_b(ai.rdrb, sizeof(*pci), NULL, &sdb, NULL);
+#else
+ idx = shm_rdrbuff_alloc(ai.rdrb, sizeof(*pci), NULL, &sdb);
+#endif
+ if (idx < 0)
+ return;
+
+ pci = (struct frct_pci *) shm_du_buff_head(sdb);
+ memset(pci, 0, sizeof(*pci));
+
+ *((uint32_t *) pci) = hton32(rwe);
+
+ pci->flags = flags;
+ pci->ackno = hton32(ackno);
+
+ f = &ai.flows[fd];
+
+ if (crypt_encrypt(&f->crypt, sdb) < 0)
+ goto fail;
+
+#ifdef RXM_BLOCKING
+ if (shm_rbuff_write_b(f->tx_rb, idx, NULL))
+#else
+ if (shm_rbuff_write(f->tx_rb, idx))
+#endif
+ goto fail;
+
+ shm_flow_set_notify(f->set, f->info.id, FLOW_PKT);
+
+ return;
+
+ fail:
+ ipcp_sdb_release(sdb);
+ return;
+}
+
+static void send_frct_pkt(struct frcti * frcti)
+{
+ struct timespec now;
+ time_t diff;
+ uint32_t ackno;
+ uint32_t rwe;
+ int fd;
+
+ assert(frcti);
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ pthread_rwlock_wrlock(&frcti->lock);
+
+ if (!after(frcti->rcv_cr.lwe, frcti->rcv_cr.seqno)) {
+ pthread_rwlock_unlock(&frcti->lock);
+ return;
+ }
+
+ fd = frcti->fd;
+ ackno = frcti->rcv_cr.lwe;
+ rwe = frcti->rcv_cr.rwe;
+
+ diff = ts_diff_ns(&frcti->rcv_cr.act, &now);
+ if (diff > frcti->a) {
+ pthread_rwlock_unlock(&frcti->lock);
+ return;
+ }
+
+ diff = ts_diff_ns(&frcti->snd_cr.act, &now);
+ if (diff < TICTIME) {
+ pthread_rwlock_unlock(&frcti->lock);
+ return;
+ }
+
+ frcti->rcv_cr.seqno = frcti->rcv_cr.lwe;
+
+ pthread_rwlock_unlock(&frcti->lock);
+
+ __send_frct_pkt(fd, FRCT_ACK | FRCT_FC, ackno, rwe);
+}
+
+static void __send_rdv(int fd)
+{
+ __send_frct_pkt(fd, FRCT_RDVS, 0, 0);
+}
+
+static struct frcti * frcti_create(int fd,
+ time_t a,
+ time_t r,
+ time_t mpl)
+{
+ struct frcti * frcti;
+ ssize_t idx;
+ struct timespec now;
+ pthread_condattr_t cattr;
+#ifdef PROC_FLOW_STATS
+ char frctstr[FRCT_NAME_STRLEN + 1];
+#endif
+ mpl *= BILLION;
+ a *= BILLION;
+ r *= BILLION;
frcti = malloc(sizeof(*frcti));
if (frcti == NULL)
@@ -100,36 +352,79 @@ static struct frcti * frcti_create(int fd)
if (pthread_rwlock_init(&frcti->lock, NULL))
goto fail_lock;
+ if (pthread_mutex_init(&frcti->mtx, NULL))
+ goto fail_mutex;
+
+ if (pthread_condattr_init(&cattr))
+ goto fail_cattr;
+#ifndef __APPLE__
+ pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
+#endif
+ if (pthread_cond_init(&frcti->cond, &cattr))
+ goto fail_cond;
+
+#ifdef PROC_FLOW_STATS
+ sprintf(frctstr, "%d", fd);
+ if (rib_reg(frctstr, &r_ops))
+ goto fail_rib_reg;
+#endif
+ pthread_condattr_destroy(&cattr);
+
for (idx = 0; idx < RQ_SIZE; ++idx)
frcti->rq[idx] = -1;
- clock_gettime(CLOCK_REALTIME_COARSE, &now);
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
- frcti->mpl = DELT_MPL;
- frcti->a = DELT_A;
- frcti->r = DELT_R;
+ frcti->mpl = mpl;
+ frcti->a = a;
+ frcti->r = r;
+ frcti->rdv = DELT_RDV;
frcti->fd = fd;
- delta_t = (frcti->mpl + frcti->a + frcti->r) / 1000;
-
- frcti->snd_cr.inact = 3 * delta_t;
- frcti->snd_cr.act = now.tv_sec - (frcti->snd_cr.inact + 1);
- /* rtt estimator. rto is currently srtt + 2 * mdev */
- frcti->srtt_us = 0; /* updated on first ACK */
- frcti->mdev_us = 100000; /* initial rxm will be after 200 ms */
- frcti->rttseq = 0;
- frcti->probe = false;
- if (ai.flows[fd].qs.loss == 0) {
- frcti->snd_cr.cflags |= FRCTFRTX;
+ frcti->rttseq = 0;
+ frcti->probe = false;
+
+ frcti->srtt = 0; /* Updated on first ACK */
+ frcti->mdev = 10 * MILLION; /* Updated on first ACK */
+ frcti->rto = BILLION; /* Initial rxm will be after 1 s */
+#ifdef PROC_FLOW_STATS
+ frcti->n_rtx = 0;
+ frcti->n_prb = 0;
+ frcti->n_rtt = 0;
+ frcti->n_dup = 0;
+ frcti->n_dak = 0;
+ frcti->n_rdv = 0;
+ frcti->n_out = 0;
+ frcti->n_rqo = 0;
+#endif
+ if (ai.flows[fd].info.qs.loss == 0) {
+ frcti->snd_cr.cflags |= FRCTFRTX | FRCTFLINGER;
frcti->rcv_cr.cflags |= FRCTFRTX;
}
- frcti->rcv_cr.inact = 2 * delta_t;
- frcti->rcv_cr.act = now.tv_sec - (frcti->rcv_cr.inact + 1);
+ frcti->snd_cr.cflags |= FRCTFRESCNTL;
+
+ frcti->snd_cr.rwe = START_WINDOW;
+
+ frcti->snd_cr.inact = (3 * mpl + a + r) / BILLION + 1; /* s */
+ frcti->snd_cr.act.tv_sec = now.tv_sec - (frcti->snd_cr.inact + 1);
+
+ frcti->rcv_cr.inact = (2 * mpl + a + r) / BILLION + 1; /* s */
+ frcti->rcv_cr.act.tv_sec = now.tv_sec - (frcti->rcv_cr.inact + 1);
return frcti;
+#ifdef PROC_FLOW_STATS
+ fail_rib_reg:
+ pthread_cond_destroy(&frcti->cond);
+#endif
+ fail_cond:
+ pthread_condattr_destroy(&cattr);
+ fail_cattr:
+ pthread_mutex_destroy(&frcti->mtx);
+ fail_mutex:
+ pthread_rwlock_destroy(&frcti->lock);
fail_lock:
free(frcti);
fail_malloc:
@@ -138,23 +433,23 @@ static struct frcti * frcti_create(int fd)
static void frcti_destroy(struct frcti * frcti)
{
- /*
- * FIXME: In case of reliable transmission we should
- * make sure everything we sent is acked.
- */
-
- rxmwheel_clear(frcti->fd);
-
+#ifdef PROC_FLOW_STATS
+ char frctstr[FRCT_NAME_STRLEN + 1];
+ sprintf(frctstr, "%d", frcti->fd);
+ rib_unreg(frctstr);
+#endif
+ pthread_cond_destroy(&frcti->cond);
+ pthread_mutex_destroy(&frcti->mtx);
pthread_rwlock_destroy(&frcti->lock);
free(frcti);
}
-static uint16_t frcti_getconf(struct frcti * frcti)
+static uint16_t frcti_getflags(struct frcti * frcti)
{
uint16_t ret;
- assert (frcti);
+ assert(frcti);
pthread_rwlock_rdlock(&frcti->lock);
@@ -165,15 +460,148 @@ static uint16_t frcti_getconf(struct frcti * frcti)
return ret;
}
-#define frcti_queued_pdu(frcti) \
- (frcti == NULL ? -1 : __frcti_queued_pdu(frcti))
+static void frcti_setflags(struct frcti * frcti,
+ uint16_t flags)
+{
+ flags |= FRCTFRTX; /* Should not be set by command */
+
+ assert(frcti);
+
+ pthread_rwlock_wrlock(&frcti->lock);
-#define frcti_snd(frcti, sdb) \
+ frcti->snd_cr.cflags &= FRCTFRTX; /* Zero other flags */
+
+ frcti->snd_cr.cflags &= flags;
+
+ pthread_rwlock_unlock(&frcti->lock);
+}
+
+#define frcti_queued_pdu(frcti) \
+ (frcti == NULL ? idx : __frcti_queued_pdu(frcti))
+
+#define frcti_snd(frcti, sdb) \
(frcti == NULL ? 0 : __frcti_snd(frcti, sdb))
-#define frcti_rcv(frcti, sdb) \
+#define frcti_rcv(frcti, sdb) \
(frcti == NULL ? 0 : __frcti_rcv(frcti, sdb))
+#define frcti_dealloc(frcti) \
+ (frcti == NULL ? 0 : __frcti_dealloc(frcti))
+
+#define frcti_is_window_open(frcti) \
+ (frcti == NULL ? true : __frcti_is_window_open(frcti))
+
+#define frcti_window_wait(frcti, abstime) \
+ (frcti == NULL ? 0 : __frcti_window_wait(frcti, abstime))
+
+
+static bool __frcti_is_window_open(struct frcti * frcti)
+{
+ struct frct_cr * snd_cr = &frcti->snd_cr;
+ bool ret = true;
+
+ pthread_rwlock_rdlock(&frcti->lock);
+
+ if (snd_cr->cflags & FRCTFRESCNTL)
+ ret = before(snd_cr->seqno, snd_cr->rwe);
+
+ if (!ret) {
+ struct timespec now;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ pthread_mutex_lock(&frcti->mtx);
+ if (frcti->open) {
+ frcti->open = false;
+ frcti->t_wnd = now;
+ frcti->t_rdvs = now;
+ } else {
+ time_t diff;
+ diff = ts_diff_ns(&frcti->t_wnd, &now);
+ if (diff > MAX_RDV) {
+ pthread_mutex_unlock(&frcti->mtx);
+ pthread_rwlock_unlock(&frcti->lock);
+ return false;
+ }
+
+ diff = ts_diff_ns(&frcti->t_rdvs, &now);
+ if (diff > frcti->rdv) {
+ frcti->t_rdvs = now;
+ __send_rdv(frcti->fd);
+#ifdef PROC_FLOW_STATS
+ frcti->n_rdv++;
+#endif
+
+ }
+ }
+
+ pthread_mutex_unlock(&frcti->mtx);
+ }
+
+ pthread_rwlock_unlock(&frcti->lock);
+
+ return ret;
+}
+
+static int __frcti_window_wait(struct frcti * frcti,
+ struct timespec * abstime)
+{
+ struct frct_cr * snd_cr = &frcti->snd_cr;
+ int ret = 0;
+
+ pthread_rwlock_rdlock(&frcti->lock);
+
+ if (!(snd_cr->cflags & FRCTFRESCNTL)) {
+ pthread_rwlock_unlock(&frcti->lock);
+ return 0;
+ }
+
+ while (snd_cr->seqno == snd_cr->rwe && ret != -ETIMEDOUT) {
+ struct timespec now;
+ pthread_rwlock_unlock(&frcti->lock);
+ pthread_mutex_lock(&frcti->mtx);
+
+ if (frcti->open) {
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ frcti->t_wnd = now;
+ frcti->t_rdvs = now;
+ frcti->open = false;
+ }
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &frcti->mtx);
+
+ ret = -__timedwait(&frcti->cond, &frcti->mtx, abstime);
+
+ pthread_cleanup_pop(false);
+
+ if (ret == -ETIMEDOUT) {
+ time_t diff;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ diff = ts_diff_ns(&frcti->t_wnd, &now);
+ if (diff > MAX_RDV) {
+ pthread_mutex_unlock(&frcti->mtx);
+ return -ECONNRESET; /* write fails! */
+ }
+
+ diff = ts_diff_ns(&frcti->t_rdvs, &now);
+ if (diff > frcti->rdv) {
+ frcti->t_rdvs = now;
+ __send_rdv(frcti->fd);
+ }
+ }
+
+ pthread_mutex_unlock(&frcti->mtx);
+ pthread_rwlock_rdlock(&frcti->lock);
+ }
+
+ pthread_rwlock_unlock(&frcti->lock);
+
+ return ret;
+}
+
static ssize_t __frcti_queued_pdu(struct frcti * frcti)
{
ssize_t idx;
@@ -184,10 +612,12 @@ static ssize_t __frcti_queued_pdu(struct frcti * frcti)
/* See if we already have the next PDU. */
pthread_rwlock_wrlock(&frcti->lock);
- pos = frcti->rcv_cr.seqno & (RQ_SIZE - 1);
+ pos = frcti->rcv_cr.lwe & (RQ_SIZE - 1);
+
idx = frcti->rq[pos];
if (idx != -1) {
- ++frcti->rcv_cr.seqno;
+ ++frcti->rcv_cr.lwe;
+ ++frcti->rcv_cr.rwe;
frcti->rq[pos] = -1;
}
@@ -196,27 +626,60 @@ static ssize_t __frcti_queued_pdu(struct frcti * frcti)
return idx;
}
-static struct frct_pci * frcti_alloc_head(struct shm_du_buff * sdb)
+static ssize_t __frcti_pdu_ready(struct frcti * frcti)
{
- struct frct_pci * pci;
+ ssize_t idx;
+ size_t pos;
- pci = (struct frct_pci *) shm_du_buff_head_alloc(sdb, FRCT_PCILEN);
- if (pci != NULL)
- memset(pci, 0, sizeof(*pci));
+ assert(frcti);
- return pci;
-}
+ /* See if we already have the next PDU. */
+ pthread_rwlock_rdlock(&frcti->lock);
-static bool before(uint32_t seq1,
- uint32_t seq2)
-{
- return (int32_t)(seq1 - seq2) < 0;
+ pos = frcti->rcv_cr.lwe & (RQ_SIZE - 1);
+ idx = frcti->rq[pos];
+
+ pthread_rwlock_unlock(&frcti->lock);
+
+ return idx;
}
-static bool after(uint32_t seq1,
- uint32_t seq2)
+#include <timerwheel.c>
+
+/*
+ * Send a final ACK for everything that has not been ACK'd.
+ * If the flow should be kept active for retransmission,
+ * the returned time will be negative.
+ */
+static time_t __frcti_dealloc(struct frcti * frcti)
{
- return (int32_t)(seq2 - seq1) < 0;
+ struct timespec now;
+ time_t wait;
+ int ackno;
+ int fd = -1;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ pthread_rwlock_rdlock(&frcti->lock);
+
+ ackno = frcti->rcv_cr.lwe;
+ if (frcti->rcv_cr.lwe != frcti->rcv_cr.seqno)
+ fd = frcti->fd;
+
+ wait = MAX(frcti->rcv_cr.inact - now.tv_sec + frcti->rcv_cr.act.tv_sec,
+ frcti->snd_cr.inact - now.tv_sec + frcti->snd_cr.act.tv_sec);
+ wait = MAX(wait, 0);
+
+ if (frcti->snd_cr.cflags & FRCTFLINGER
+ && before(frcti->snd_cr.lwe, frcti->snd_cr.seqno))
+ wait = -wait;
+
+ pthread_rwlock_unlock(&frcti->lock);
+
+ if (fd != -1)
+ __send_frct_pkt(fd, FRCT_ACK, ackno, 0);
+
+ return wait;
}
static int __frcti_snd(struct frcti * frcti,
@@ -226,22 +689,29 @@ static int __frcti_snd(struct frcti * frcti,
struct timespec now;
struct frct_cr * snd_cr;
struct frct_cr * rcv_cr;
+ uint32_t seqno;
+ bool rtx;
assert(frcti);
+ assert(shm_du_buff_len(sdb) != 0);
snd_cr = &frcti->snd_cr;
rcv_cr = &frcti->rcv_cr;
- rxmwheel_move();
+ timerwheel_move();
- pci = frcti_alloc_head(sdb);
+ pci = (struct frct_pci *) shm_du_buff_head_alloc(sdb, FRCT_PCILEN);
if (pci == NULL)
- return -1;
+ return -ENOMEM;
+
+ memset(pci, 0, sizeof(*pci));
- clock_gettime(CLOCK_REALTIME, &now);
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
pthread_rwlock_wrlock(&frcti->lock);
+ rtx = snd_cr->cflags & FRCTFRTX;
+
pci->flags |= FRCT_DATA;
/* Set DRF if there are no unacknowledged packets. */
@@ -249,145 +719,216 @@ static int __frcti_snd(struct frcti * frcti,
pci->flags |= FRCT_DRF;
/* Choose a new sequence number if sender inactivity expired. */
- if (now.tv_sec - snd_cr->act > snd_cr->inact) {
+ if (now.tv_sec - snd_cr->act.tv_sec > snd_cr->inact) {
/* There are no unacknowledged packets. */
assert(snd_cr->seqno == snd_cr->lwe);
-#ifdef CONFIG_OUROBOROS_DEBUG
- snd_cr->seqno = 0;
-#else
random_buffer(&snd_cr->seqno, sizeof(snd_cr->seqno));
-#endif
- frcti->snd_cr.lwe = snd_cr->seqno - 1;
+ snd_cr->lwe = snd_cr->seqno;
+ snd_cr->rwe = snd_cr->lwe + START_WINDOW;
+ }
+
+ seqno = snd_cr->seqno;
+ pci->seqno = hton32(seqno);
+
+ if (now.tv_sec - rcv_cr->act.tv_sec < rcv_cr->inact) {
+ pci->flags |= FRCT_FC;
+ *((uint32_t *) pci) |= hton32(rcv_cr->rwe & 0x00FFFFFF);
}
- pci->seqno = hton32(snd_cr->seqno);
- if (!(snd_cr->cflags & FRCTFRTX)) {
+ if (!rtx) {
snd_cr->lwe++;
} else {
if (!frcti->probe) {
frcti->rttseq = snd_cr->seqno;
frcti->t_probe = now;
frcti->probe = true;
+#ifdef PROC_FLOW_STATS
+ frcti->n_prb++;
+#endif
}
-
- if (now.tv_sec - rcv_cr->act <= rcv_cr->inact) {
- rxmwheel_add(frcti, snd_cr->seqno, sdb);
- if (rcv_cr->lwe <= rcv_cr->seqno) {
- pci->flags |= FRCT_ACK;
- pci->ackno = hton32(rcv_cr->seqno);
- rcv_cr->lwe = rcv_cr->seqno;
- }
+ if ((now.tv_sec - rcv_cr->act.tv_sec) * BILLION <= frcti->a) {
+ pci->flags |= FRCT_ACK;
+ pci->ackno = hton32(rcv_cr->lwe);
+ rcv_cr->seqno = rcv_cr->lwe;
}
}
snd_cr->seqno++;
- snd_cr->act = now.tv_sec;
+ snd_cr->act = now;
pthread_rwlock_unlock(&frcti->lock);
+ if (rtx)
+ timerwheel_rxm(frcti, seqno, sdb);
+
return 0;
}
static void rtt_estimator(struct frcti * frcti,
- time_t mrtt_us)
+ time_t mrtt)
{
- time_t srtt = frcti->srtt_us;
- time_t mdev = frcti->mdev_us;
-
- if (srtt != 0) {
- srtt -= (srtt >> 3);
- srtt += mrtt_us >> 3; /* rtt = 7/8 rtt + 1/8 new */
- mdev -= (mdev >> 2);
- mdev += ABS(srtt - mrtt_us) >> 2;
+ time_t srtt = frcti->srtt;
+ time_t rttvar = frcti->mdev;
+
+ if (srtt == 0) { /* first measurement */
+ srtt = mrtt;
+ rttvar = mrtt >> 1;
} else {
- srtt = mrtt_us << 3; /* take the measured time to be rtt */
- mdev = mrtt_us >> 1; /* take half mrtt_us as deviation */
+ time_t delta = mrtt - srtt;
+ srtt += (delta >> 3);
+ delta = (ABS(delta) - rttvar) >> 2;
+#ifdef FRCT_LINUX_RTT_ESTIMATOR
+ if (delta < 0)
+ delta >>= 3;
+#endif
+ rttvar += delta;
}
-
- frcti->srtt_us = MAX(1U, srtt);
- frcti->mdev_us = MAX(1U, mdev);
+#ifdef PROC_FLOW_STATS
+ frcti->n_rtt++;
+#endif
+ frcti->srtt = MAX(1000L, srtt);
+ frcti->mdev = MAX(100L, rttvar);
+ frcti->rto = MAX(RTO_MIN, frcti->srtt + (frcti->mdev << MDEV_MUL));
}
-/* Returns 0 when idx contains a packet for the application. */
-static int __frcti_rcv(struct frcti * frcti,
- struct shm_du_buff * sdb)
+/* Always queues the next application packet on the RQ. */
+static void __frcti_rcv(struct frcti * frcti,
+ struct shm_du_buff * sdb)
{
ssize_t idx;
+ size_t pos;
struct frct_pci * pci;
struct timespec now;
- struct frct_cr * snd_cr;
struct frct_cr * rcv_cr;
+ struct frct_cr * snd_cr;
uint32_t seqno;
- int ret = 0;
+ uint32_t ackno;
+ uint32_t rwe;
+ int fd = -1;
assert(frcti);
rcv_cr = &frcti->rcv_cr;
snd_cr = &frcti->snd_cr;
- pci = (struct frct_pci *) shm_du_buff_head_release(sdb, FRCT_PCILEN);
-
- clock_gettime(CLOCK_REALTIME, &now);
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
- pthread_rwlock_wrlock(&frcti->lock);
+ pci = (struct frct_pci *) shm_du_buff_head_release(sdb, FRCT_PCILEN);
idx = shm_du_buff_get_idx(sdb);
-
seqno = ntoh32(pci->seqno);
+ pos = seqno & (RQ_SIZE - 1);
- /* Check if receiver inactivity is true. */
- if (now.tv_sec - rcv_cr->act > rcv_cr->inact) {
- /* Inactive receiver, check for DRF. */
- if (pci->flags & FRCT_DRF) /* New run. */
+ pthread_rwlock_wrlock(&frcti->lock);
+
+ if (now.tv_sec - rcv_cr->act.tv_sec > rcv_cr->inact) {
+ if (pci->flags & FRCT_DRF) { /* New run. */
+ rcv_cr->lwe = seqno;
+ rcv_cr->rwe = seqno + RQ_SIZE;
rcv_cr->seqno = seqno;
- else
+ } else if (pci->flags & FRCT_DATA) {
goto drop_packet;
+ }
}
- if (seqno == rcv_cr->seqno) {
- ++rcv_cr->seqno;
- } else { /* Out of order. */
- if (before(seqno, rcv_cr->seqno))
- goto drop_packet;
+ rcv_cr->act = now;
- if (rcv_cr->cflags & FRCTFRTX) {
- size_t pos = seqno & (RQ_SIZE - 1);
- if ((seqno - rcv_cr->lwe) > RQ_SIZE /* Out of rq. */
- || frcti->rq[pos] != -1) /* Duplicate in rq. */
- goto drop_packet;
- /* Queue. */
- frcti->rq[pos] = idx;
- ret = -EAGAIN;
- } else {
- rcv_cr->seqno = seqno + 1;
- }
+ /* For now, just send an immediate window update. */
+ if (pci->flags & FRCT_RDVS) {
+ fd = frcti->fd;
+ rwe = rcv_cr->rwe;
+ pthread_rwlock_unlock(&frcti->lock);
+
+ __send_frct_pkt(fd, FRCT_FC, 0, rwe);
+
+ shm_rdrbuff_remove(ai.rdrb, idx);
+ return;
}
- if (rcv_cr->cflags & FRCTFRTX && pci->flags & FRCT_ACK) {
- uint32_t ackno = ntoh32(pci->ackno);
- /* Check for duplicate (old) acks. */
- if ((int32_t)(ackno - snd_cr->lwe) >= 0)
- snd_cr->lwe = ackno;
+ if (pci->flags & FRCT_ACK) {
+ ackno = ntoh32(pci->ackno);
+ if (after(ackno, frcti->snd_cr.lwe))
+ frcti->snd_cr.lwe = ackno;
+
if (frcti->probe && after(ackno, frcti->rttseq)) {
- rtt_estimator(frcti, ts_diff_us(&frcti->t_probe, &now));
+#ifdef PROC_FLOW_STATS
+ if (!(pci->flags & FRCT_DATA))
+ frcti->n_dak++;
+#endif
+ rtt_estimator(frcti, ts_diff_ns(&frcti->t_probe, &now));
frcti->probe = false;
}
}
- rcv_cr->act = now.tv_sec;
+ if (pci->flags & FRCT_FC) {
+ uint32_t rwe;
- pthread_rwlock_unlock(&frcti->lock);
+ rwe = ntoh32(*((uint32_t *)pci) & hton32(0x00FFFFFF));
+ rwe |= snd_cr->rwe & 0xFF000000;
+
+ /* Rollover for 24 bit */
+ if (before(rwe, snd_cr->rwe) && snd_cr->rwe - rwe > 0x007FFFFF)
+ rwe += 0x01000000;
+
+ snd_cr->rwe = rwe;
+
+ pthread_mutex_lock(&frcti->mtx);
+ if (!frcti->open) {
+ frcti->open = true;
+ pthread_cond_broadcast(&frcti->cond);
+ }
+ pthread_mutex_unlock(&frcti->mtx);
+ }
if (!(pci->flags & FRCT_DATA))
- shm_rdrbuff_remove(ai.rdrb, idx);
+ goto drop_packet;
- rxmwheel_move();
+ if (before(seqno, rcv_cr->lwe)) {
+ rcv_cr->seqno = seqno; /* Ensures we send a new ACK. */
+#ifdef PROC_FLOW_STATS
+ frcti->n_dup++;
+#endif
+ goto drop_packet;
+ }
- return ret;
+ if (rcv_cr->cflags & FRCTFRTX) {
+
+ if (!before(seqno, rcv_cr->rwe)) { /* Out of window. */
+#ifdef PROC_FLOW_STATS
+ frcti->n_out++;
+#endif
+ goto drop_packet;
+ }
+
+ if (!before(seqno, rcv_cr->lwe + RQ_SIZE)) {
+#ifdef PROC_FLOW_STATS
+ frcti->n_rqo++;
+#endif
+ goto drop_packet; /* Out of rq. */
+ }
+ if (frcti->rq[pos] != -1) {
+#ifdef PROC_FLOW_STATS
+ frcti->n_dup++;
+#endif
+ goto drop_packet; /* Duplicate in rq. */
+ }
+ fd = frcti->fd;
+ } else {
+ rcv_cr->lwe = seqno;
+ }
+
+ frcti->rq[pos] = idx;
+
+ pthread_rwlock_unlock(&frcti->lock);
+
+ if (fd != -1)
+ timerwheel_delayed_ack(fd, frcti);
+
+ return;
drop_packet:
pthread_rwlock_unlock(&frcti->lock);
shm_rdrbuff_remove(ai.rdrb, idx);
- rxmwheel_move();
- return -EAGAIN;
+ send_frct_pkt(frcti);
+ return;
}
diff --git a/src/lib/hash.c b/src/lib/hash.c
index e5f90ee0..b465f894 100644
--- a/src/lib/hash.c
+++ b/src/lib/hash.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Hashing
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This implementation is adapted and redistributed from the RHASH
* project
@@ -29,43 +29,50 @@
#include "config.h"
+#include <ouroboros/endian.h>
#include <ouroboros/hash.h>
-#ifndef HAVE_LIBGCRYPT
+#ifdef HAVE_LIBGCRYPT
+#include <gcrypt.h>
+#else
#include <ouroboros/crc32.h>
#include <ouroboros/md5.h>
#include <ouroboros/sha3.h>
-#else
-#include <gcrypt.h>
#endif
#include <string.h>
#include <assert.h>
#include <stdbool.h>
+#ifdef HAVE_LIBGCRYPT
+int gcry_algo_tbl [] = {
+ /* DIR_HASH policies first */
+ GCRY_MD_SHA3_224,
+ GCRY_MD_SHA3_256,
+ GCRY_MD_SHA3_384,
+ GCRY_MD_SHA3_512,
+ /* Below for internal use only */
+ GCRY_MD_CRC32,
+ GCRY_MD_MD5,
+};
+#else
+int hash_len_tbl [] = {
+ /* DIR_HASH policies first */
+ SHA3_224_HASH_LEN,
+ SHA3_256_HASH_LEN,
+ SHA3_384_HASH_LEN,
+ SHA3_512_HASH_LEN,
+ /* Below for internal use only */
+ CRC32_HASH_LEN,
+ MD5_HASH_LEN
+};
+#endif
+
uint16_t hash_len(enum hash_algo algo)
{
#ifdef HAVE_LIBGCRYPT
- return (uint16_t) gcry_md_get_algo_dlen(algo);
+ return (uint16_t) gcry_md_get_algo_dlen(gcry_algo_tbl[algo]);
#else
- switch (algo) {
- case HASH_CRC32:
- return CRC32_HASH_LEN;
- case HASH_MD5:
- return MD5_HASH_LEN;
- case HASH_SHA3_224:
- return SHA3_224_HASH_LEN;
- case HASH_SHA3_256:
- return SHA3_256_HASH_LEN;
- case HASH_SHA3_384:
- return SHA3_384_HASH_LEN;
- case HASH_SHA3_512:
- return SHA3_512_HASH_LEN;
- default:
- assert(false);
- break;
- }
-
- return 0;
+ return hash_len_tbl[algo];
#endif
}
@@ -75,7 +82,7 @@ void mem_hash(enum hash_algo algo,
size_t len)
{
#ifdef HAVE_LIBGCRYPT
- gcry_md_hash_buffer(algo, dst, buf, len);
+ gcry_md_hash_buffer(gcry_algo_tbl[algo], dst, buf, len);
#else
struct sha3_ctx sha3_ctx;
struct md5_ctx md5_ctx;
@@ -84,6 +91,7 @@ void mem_hash(enum hash_algo algo,
case HASH_CRC32:
memset(dst, 0, CRC32_HASH_LEN);
crc32((uint32_t *) dst, buf, len);
+ *(uint32_t *) dst = htobe32(*(uint32_t *) dst);
break;
case HASH_MD5:
rhash_md5_init(&md5_ctx);
diff --git a/src/lib/ipcp_config.proto b/src/lib/ipcp_config.proto
deleted file mode 100644
index 23c65e94..00000000
--- a/src/lib/ipcp_config.proto
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * Layer configuration message
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-syntax = "proto2";
-
-message layer_info_msg {
- required string layer_name = 1;
- required uint32 dir_hash_algo = 2;
-}
-
-message ipcp_config_msg {
- required layer_info_msg layer_info = 1;
- required int32 ipcp_type = 2;
- // Config for unicast IPCP
- optional uint32 addr_size = 3;
- optional uint32 eid_size = 4;
- optional uint32 max_ttl = 5;
- optional uint32 addr_auth_type = 6;
- optional uint32 routing_type = 7;
- // Config for UDP
- optional uint32 ip_addr = 8;
- optional uint32 dns_addr = 9;
- optional uint32 clt_port = 10;
- optional uint32 srv_port = 11;
- // Config for the Ethernet
- optional string dev = 12;
- // Config for DIX Ethernet
- optional uint32 ethertype = 13;
-}
-
-enum enroll_code {
- ENROLL_REQ = 1;
- ENROLL_BOOT = 2;
- ENROLL_DONE = 4;
-};
-
-message enroll_msg {
- required enroll_code code = 1;
- optional ipcp_config_msg conf = 2;
- optional int64 t_sec = 3;
- optional uint32 t_nsec = 4;
- optional int32 result = 5;
-}; \ No newline at end of file
diff --git a/src/lib/irm.c b/src/lib/irm.c
index 08dffb6c..d25101f3 100644
--- a/src/lib/irm.c
+++ b/src/lib/irm.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* The API to instruct the IRM
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -31,28 +31,37 @@
#include <ouroboros/irm.h>
#include <ouroboros/utils.h>
#include <ouroboros/sockets.h>
+#include <ouroboros/protobuf.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
-pid_t irm_create_ipcp(const char * name,
- enum ipcp_type type)
+int irm_create_ipcp(const char * name,
+ enum ipcp_type type)
{
- irm_msg_t msg = IRM_MSG__INIT;
- irm_msg_t * recv_msg = NULL;
- int ret = -1;
+ irm_msg_t msg = IRM_MSG__INIT;
+ irm_msg_t * recv_msg;
+ int ret;
+ struct ipcp_info info;
- if (name == NULL)
+ if (name == NULL || strlen(name) > IPCP_NAME_SIZE)
return -EINVAL;
- msg.code = IRM_MSG_CODE__IRM_CREATE_IPCP;
- msg.name = (char *) name;
- msg.has_ipcp_type = true;
- msg.ipcp_type = type;
+ memset(&info, 0, sizeof(info));
+
+ info.type = type;
+ strcpy(info.name, name);
+
+ msg.code = IRM_MSG_CODE__IRM_CREATE_IPCP;
+ msg.ipcp_info = ipcp_info_s_to_msg(&info);
+ if (msg.ipcp_info == NULL)
+ return -ENOMEM;
recv_msg = send_recv_irm_msg(&msg);
+ ipcp_info_msg__free_unpacked(msg.ipcp_info, NULL);
+
if (recv_msg == NULL)
return -EIRMD;
@@ -98,11 +107,9 @@ int irm_destroy_ipcp(pid_t pid)
int irm_bootstrap_ipcp(pid_t pid,
const struct ipcp_config * conf)
{
- irm_msg_t msg = IRM_MSG__INIT;
- ipcp_config_msg_t config = IPCP_CONFIG_MSG__INIT;
- layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT;
- irm_msg_t * recv_msg = NULL;
- int ret = -1;
+ irm_msg_t msg = IRM_MSG__INIT;
+ irm_msg_t * recv_msg;
+ int ret;
if (pid == -1 || conf == NULL)
return -EINVAL;
@@ -110,56 +117,10 @@ int irm_bootstrap_ipcp(pid_t pid,
msg.code = IRM_MSG_CODE__IRM_BOOTSTRAP_IPCP;
msg.has_pid = true;
msg.pid = pid;
-
- config.layer_info = &layer_info;
- msg.conf = &config;
- layer_info.layer_name = (char *) conf->layer_info.layer_name;
-
- config.ipcp_type = conf->type;
-
- if (conf->type != IPCP_UDP)
- layer_info.dir_hash_algo = conf->layer_info.dir_hash_algo;
-
- switch (conf->type) {
- case IPCP_UNICAST:
- config.has_addr_size = true;
- config.addr_size = conf->addr_size;
- config.has_eid_size = true;
- config.eid_size = conf->eid_size;
- config.has_max_ttl = true;
- config.max_ttl = conf->max_ttl;
- config.has_addr_auth_type = true;
- config.addr_auth_type = conf->addr_auth_type;
- config.has_routing_type = true;
- config.routing_type = conf->routing_type;
- break;
- case IPCP_UDP:
- config.has_ip_addr = true;
- config.ip_addr = conf->ip_addr;
- config.has_dns_addr = true;
- config.dns_addr = conf->dns_addr;
- config.has_srv_port = true;
- config.srv_port = conf->srv_port;
- config.has_clt_port = true;
- config.clt_port = conf->clt_port;
- break;
- case IPCP_LOCAL:
- case IPCP_BROADCAST:
- case IPCP_RAPTOR:
- break;
- case IPCP_ETH_LLC:
- config.dev = conf->dev;
- break;
- case IPCP_ETH_DIX:
- config.dev = conf->dev;
- config.has_ethertype = true;
- config.ethertype = conf->ethertype;
- break;
- default:
- return -EIPCPTYPE;
- }
+ msg.conf = ipcp_config_s_to_msg(conf);
recv_msg = send_recv_irm_msg(&msg);
+ ipcp_config_msg__free_unpacked(msg.conf, NULL);
if (recv_msg == NULL)
return -EIRMD;
@@ -179,8 +140,7 @@ int irm_connect_ipcp(pid_t pid,
const char * component,
qosspec_t qs)
{
- irm_msg_t msg = IRM_MSG__INIT;
- qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT;
+ irm_msg_t msg = IRM_MSG__INIT;
irm_msg_t * recv_msg;
int ret;
@@ -190,10 +150,11 @@ int irm_connect_ipcp(pid_t pid,
msg.comp = (char *) component;
msg.has_pid = true;
msg.pid = pid;
- qs_msg = spec_to_msg(&qs);
- msg.qosspec = &qs_msg;
+ msg.qosspec = qos_spec_s_to_msg(&qs);
recv_msg = send_recv_irm_msg(&msg);
+ qosspec_msg__free_unpacked(msg.qosspec, NULL);
+
if (recv_msg == NULL)
return -EIRMD;
@@ -237,7 +198,7 @@ int irm_disconnect_ipcp(pid_t pid,
return ret;
}
-ssize_t irm_list_ipcps(struct ipcp_info ** ipcps)
+ssize_t irm_list_ipcps(struct ipcp_list_info ** ipcps)
{
irm_msg_t msg = IRM_MSG__INIT;
irm_msg_t * recv_msg;
@@ -407,50 +368,69 @@ int irm_bind_program(const char * prog,
int argc,
char ** argv)
{
- irm_msg_t msg = IRM_MSG__INIT;
- irm_msg_t * recv_msg = NULL;
- int ret = -1;
- char * full_name;
+ irm_msg_t msg = IRM_MSG__INIT;
+ irm_msg_t * recv_msg;
+ char ** exec;
+ int ret;
+ int i;
if (prog == NULL || name == NULL)
return -EINVAL;
- full_name = strdup(prog);
- if (full_name == NULL)
- return -ENOMEM;
+ exec = malloc((argc + 2) * sizeof(*exec));
+ if (exec== NULL) {
+ ret = -ENOMEM;
+ goto fail_exec;
+ }
- if ((ret = check_prog_path(&full_name)) < 0) {
- free(full_name);
- return ret;
+ exec[0] = strdup(prog);
+ if (exec[0] == NULL) {
+ ret = -ENOMEM;
+ goto fail_exec0;
}
+ ret = check_prog_path(&exec[0]);
+ if (ret < 0)
+ goto fail;
+
+ for (i = 0; i < argc; i++)
+ exec[i + 1] = argv[i];
+
+ exec[argc + 1] = "";
+
msg.code = IRM_MSG_CODE__IRM_BIND_PROGRAM;
msg.name = (char *) name;
- msg.prog = full_name;
- if (argv != NULL) {
- msg.n_args = argc;
- msg.args = (char **) argv;
- }
+ msg.n_exec = argc + 2;
+ msg.exec = exec;
msg.has_opts = true;
msg.opts = opts;
recv_msg = send_recv_irm_msg(&msg);
-
- free(full_name);
-
- if (recv_msg == NULL)
- return -EIRMD;
+ if (recv_msg == NULL) {
+ ret = -EIRMD;
+ goto fail;
+ }
if (!recv_msg->has_result) {
irm_msg__free_unpacked(recv_msg, NULL);
- return -1;
+ ret = -EPERM;
+ goto fail;
}
ret = recv_msg->result;
irm_msg__free_unpacked(recv_msg, NULL);
+ free(exec[0]);
+ free(exec);
+
+ return ret;
+ fail:
+ free(exec[0]);
+ fail_exec0:
+ free(exec);
+ fail_exec:
return ret;
}
diff --git a/src/lib/irmd_messages.proto b/src/lib/irmd_messages.proto
deleted file mode 100644
index 5b23ee9d..00000000
--- a/src/lib/irmd_messages.proto
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * IRMd message
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-syntax = "proto2";
-
-import "ipcp_config.proto";
-import "qosspec.proto";
-
-enum irm_msg_code {
- IRM_CREATE_IPCP = 1;
- IPCP_CREATE_R = 2;
- IRM_DESTROY_IPCP = 3;
- IRM_LIST_IPCPS = 4;
- IRM_BOOTSTRAP_IPCP = 5;
- IRM_ENROLL_IPCP = 6;
- IRM_CONNECT_IPCP = 7;
- IRM_DISCONNECT_IPCP = 8;
- IRM_BIND_PROGRAM = 9;
- IRM_UNBIND_PROGRAM = 10;
- IRM_PROC_ANNOUNCE = 11;
- IRM_BIND_PROCESS = 12;
- IRM_UNBIND_PROCESS = 13;
- IRM_CREATE_NAME = 14;
- IRM_DESTROY_NAME = 15;
- IRM_LIST_NAMES = 16;
- IRM_REG_NAME = 17;
- IRM_UNREG_NAME = 18;
- IRM_FLOW_ALLOC = 19;
- IRM_FLOW_ACCEPT = 20;
- IRM_FLOW_JOIN = 21;
- IRM_FLOW_DEALLOC = 22;
- IPCP_FLOW_REQ_ARR = 23;
- IPCP_FLOW_ALLOC_REPLY = 24;
- IRM_REPLY = 25;
-};
-
-message ipcp_info_msg {
- required uint32 pid = 1;
- required uint32 type = 2;
- required string name = 3;
- required string layer = 4;
-};
-
-message name_info_msg {
- required string name = 1;
- required uint32 pol_lb = 2;
-};
-
-message irm_msg {
- required irm_msg_code code = 1;
- optional string prog = 2;
- optional sint32 pid = 3;
- optional string name = 4;
- optional uint32 ipcp_type = 5;
- optional string layer = 6;
- repeated string args = 7;
- optional sint32 response = 8;
- optional string dst = 9;
- optional bytes hash = 10;
- optional sint32 flow_id = 11;
- optional qosspec_msg qosspec = 12;
- optional ipcp_config_msg conf = 13;
- optional uint32 opts = 14;
- repeated ipcp_info_msg ipcps = 15;
- repeated name_info_msg names = 16;
- optional uint32 timeo_sec = 17;
- optional uint32 timeo_nsec = 18;
- optional string comp = 19;
- optional bytes pk = 20; /* piggyback */
- optional sint32 result = 21;
-};
diff --git a/src/lib/list.c b/src/lib/list.c
index 83950a5c..62b2eb27 100644
--- a/src/lib/list.c
+++ b/src/lib/list.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Simple doubly linked list implementation.
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -62,10 +62,10 @@ void list_add_tail(struct list_head * n,
void list_del(struct list_head * e)
{
del_list(e->prv, e->nxt);
- e->nxt = e->prv = NULL;
+ e->nxt = e->prv = e;
}
-bool list_is_empty(struct list_head * h)
+bool list_is_empty(const struct list_head * h)
{
return h->nxt == h;
}
diff --git a/src/lib/lockfile.c b/src/lib/lockfile.c
index ac3c3062..cf6d3c94 100644
--- a/src/lib/lockfile.c
+++ b/src/lib/lockfile.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Lockfile for Ouroboros
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -36,81 +36,69 @@
#include <sys/stat.h>
#define LF_SIZE (sizeof(pid_t))
+#define LF_PROT (PROT_READ | PROT_WRITE)
struct lockfile {
pid_t * pid;
};
-struct lockfile * lockfile_create() {
- int fd;
- mode_t mask;
- struct lockfile * lf = malloc(sizeof(*lf));
- if (lf == NULL)
- return NULL;
-
- mask = umask(0);
+static struct lockfile * __lockfile_open(int oflag)
+{
+ int fd;
+ struct lockfile * lf;
- fd = shm_open(SHM_LOCKFILE_NAME, O_CREAT | O_EXCL | O_RDWR, 0666);
- if (fd == -1) {
- free(lf);
- return NULL;
- }
+ lf = malloc(sizeof(*lf));
+ if (lf == NULL)
+ goto fail_lockfile;
- umask(mask);
+ fd = shm_open(SHM_LOCKFILE_NAME, oflag, 0666);
+ if (fd == -1)
+ goto fail_shm_open;
- if (ftruncate(fd, LF_SIZE - 1) < 0) {
- free(lf);
- return NULL;
- }
+ if ((oflag & O_CREAT) && ftruncate(fd, LF_SIZE) < 0)
+ goto fail_truncate;
- lf->pid = mmap(NULL,
- LF_SIZE, PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd,
- 0);
+ lf->pid = mmap(NULL, LF_SIZE, LF_PROT, MAP_SHARED, fd, 0);
+ if (lf->pid == MAP_FAILED)
+ goto fail_mmap;
close (fd);
- if (lf->pid == MAP_FAILED) {
- shm_unlink(SHM_LOCKFILE_NAME);
- free(lf);
- return NULL;
- }
-
- *lf->pid = getpid();
-
return lf;
+
+ fail_mmap:
+ shm_unlink(SHM_LOCKFILE_NAME);
+ fail_truncate:
+ close(fd);
+ fail_shm_open:
+ free(lf);
+ fail_lockfile:
+ return NULL;
}
-struct lockfile * lockfile_open() {
- int fd;
- struct lockfile * lf = malloc(sizeof(*lf));
- if (lf == NULL)
- return NULL;
+struct lockfile * lockfile_create(void)
+{
+ struct lockfile * lf;
+ mode_t mask;
- fd = shm_open(SHM_LOCKFILE_NAME, O_RDWR, 0666);
- if (fd < 0) {
- free(lf);
- return NULL;
- }
+ mask = umask(0);
- lf->pid = mmap(NULL,
- LF_SIZE, PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd,
- 0);
+ lf = __lockfile_open(O_CREAT | O_EXCL | O_RDWR);
+ if (lf == NULL)
+ return NULL;
- close(fd);
+ umask(mask);
- if (lf->pid == MAP_FAILED) {
- shm_unlink(SHM_LOCKFILE_NAME);
- free(lf);
- return NULL;
- }
+ *lf->pid = getpid();
return lf;
}
+struct lockfile * lockfile_open(void)
+{
+ return __lockfile_open(O_RDWR);
+}
+
void lockfile_close(struct lockfile * lf)
{
assert(lf);
@@ -127,11 +115,9 @@ void lockfile_destroy(struct lockfile * lf)
if (getpid() != *lf->pid && kill(*lf->pid, 0) == 0)
return;
- munmap(lf->pid, LF_SIZE);
+ lockfile_close(lf);
shm_unlink(SHM_LOCKFILE_NAME);
-
- free(lf);
}
pid_t lockfile_owner(struct lockfile * lf)
diff --git a/src/lib/logs.c b/src/lib/logs.c
index 986b01ec..d90bcd63 100644
--- a/src/lib/logs.c
+++ b/src/lib/logs.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Logging facilities
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/src/lib/md5.c b/src/lib/md5.c
index 4dfa8f66..ad0dd4d7 100644
--- a/src/lib/md5.c
+++ b/src/lib/md5.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* MD5 algorithm
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This implementation is adapted and redistributed from the RHASH
* project
diff --git a/src/lib/notifier.c b/src/lib/notifier.c
index dd211dd3..45745b9a 100644
--- a/src/lib/notifier.c
+++ b/src/lib/notifier.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Notifier event system using callbacks
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -25,8 +25,9 @@
#include <ouroboros/errno.h>
#include <ouroboros/notifier.h>
#include <ouroboros/list.h>
+#include <ouroboros/utils.h>
+#include <ouroboros/pthread.h>
-#include <pthread.h>
#include <stdlib.h>
struct listener {
@@ -75,8 +76,7 @@ void notifier_event(int event,
pthread_rwlock_rdlock(&notifier.lock);
- pthread_cleanup_push((void (*) (void *)) pthread_rwlock_unlock,
- (void *) &notifier.lock)
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &notifier.lock)
list_for_each(p, &notifier.listeners) {
struct listener * l = list_entry(p, struct listener, next);
diff --git a/src/lib/cacep.proto b/src/lib/pb/cep.proto
index 4f4ae9df..d31cf4f7 100644
--- a/src/lib/cacep.proto
+++ b/src/lib/pb/cep.proto
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
- * Message for Connection Information in CACEP
+ * Message for Connection Information in OCEP
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -27,7 +27,7 @@ message fixed_conc_syntax_msg {
repeated uint32 lens = 2;
}
-message cacep_msg {
+message cep_msg {
required string comp_name = 1;
required string protocol = 2;
required int32 pref_version = 3;
@@ -36,4 +36,4 @@ message cacep_msg {
repeated int32 supp_syntax = 6;
optional fixed_conc_syntax_msg syntax_spec = 7;
required uint64 address = 8;
-} \ No newline at end of file
+}
diff --git a/src/lib/pb/enroll.proto b/src/lib/pb/enroll.proto
new file mode 100644
index 00000000..7fe612a8
--- /dev/null
+++ b/src/lib/pb/enroll.proto
@@ -0,0 +1,42 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Enrollment protocol
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+syntax = "proto2";
+import "ipcp_config.proto";
+
+message enroll_req_msg {
+ /* TODO authentication */
+ required bytes id = 1;
+}
+
+message enroll_resp_msg {
+ required bytes id = 1;
+ required int64 t_sec = 2;
+ required int32 t_nsec = 3;
+ required int32 response = 4;
+ optional ipcp_config_msg conf = 5;
+}
+
+message enroll_ack_msg {
+ required bytes id = 1;
+ required int32 result = 2;
+}
diff --git a/src/lib/ipcpd_messages.proto b/src/lib/pb/ipcp.proto
index b0efe9ab..c2c7f48b 100644
--- a/src/lib/ipcpd_messages.proto
+++ b/src/lib/pb/ipcp.proto
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
- * IPCPd message
+ * Messages sent to IPCPds
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -23,7 +23,8 @@
syntax = "proto2";
import "ipcp_config.proto";
-import "qosspec.proto";
+import "model.proto";
+
enum ipcp_msg_code {
IPCP_BOOTSTRAP = 1;
@@ -38,7 +39,7 @@ enum ipcp_msg_code {
IPCP_CONNECT = 10;
IPCP_DISCONNECT = 11;
IPCP_REPLY = 12;
-};
+}
message ipcp_msg {
required ipcp_msg_code code = 1;
@@ -52,5 +53,7 @@ message ipcp_msg {
optional layer_info_msg layer_info = 9;
optional int32 response = 10;
optional string comp = 11;
- optional int32 result = 12;
-};
+ optional uint32 timeo_sec = 12;
+ optional sint32 mpl = 13;
+ optional int32 result = 14;
+}
diff --git a/src/lib/pb/ipcp_config.proto b/src/lib/pb/ipcp_config.proto
new file mode 100644
index 00000000..28528b0c
--- /dev/null
+++ b/src/lib/pb/ipcp_config.proto
@@ -0,0 +1,57 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Layer configuration message
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+syntax = "proto2";
+
+import "model.proto";
+
+message dt_config_msg {
+ required uint32 addr_size = 1;
+ required uint32 eid_size = 2;
+ required uint32 max_ttl = 3;
+ required uint32 routing_type = 4;
+}
+
+message uni_config_msg {
+ required dt_config_msg dt = 1;
+ required uint32 addr_auth_type = 2;
+ required uint32 cong_avoid = 3;
+}
+
+message eth_config_msg {
+ required string dev = 1;
+ required uint32 ethertype = 2;
+}
+
+message udp_config_msg {
+ required uint32 ip_addr = 1;
+ required uint32 port = 2;
+ required uint32 dns_addr = 3; /* set to 0 if unused */
+}
+
+message ipcp_config_msg {
+ required layer_info_msg layer_info = 1;
+ required uint32 ipcp_type = 2;
+ optional uni_config_msg unicast = 3;
+ optional udp_config_msg udp = 4;
+ optional eth_config_msg eth = 5;
+}
diff --git a/src/lib/pb/irm.proto b/src/lib/pb/irm.proto
new file mode 100644
index 00000000..da3bd982
--- /dev/null
+++ b/src/lib/pb/irm.proto
@@ -0,0 +1,97 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Messages sent to IRMd
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+syntax = "proto2";
+
+import "ipcp_config.proto";
+import "model.proto";
+
+enum irm_msg_code {
+ IRM_CREATE_IPCP = 1;
+ IPCP_CREATE_R = 2;
+ IRM_DESTROY_IPCP = 3;
+ IRM_LIST_IPCPS = 4;
+ IRM_BOOTSTRAP_IPCP = 5;
+ IRM_ENROLL_IPCP = 6;
+ IRM_CONNECT_IPCP = 7;
+ IRM_DISCONNECT_IPCP = 8;
+ IRM_BIND_PROGRAM = 9;
+ IRM_UNBIND_PROGRAM = 10;
+ IRM_PROC_ANNOUNCE = 11;
+ IRM_PROC_EXIT = 12;
+ IRM_BIND_PROCESS = 13;
+ IRM_UNBIND_PROCESS = 14;
+ IRM_CREATE_NAME = 15;
+ IRM_DESTROY_NAME = 16;
+ IRM_LIST_NAMES = 17;
+ IRM_REG_NAME = 18;
+ IRM_UNREG_NAME = 19;
+ IRM_FLOW_ALLOC = 20;
+ IRM_FLOW_ACCEPT = 21;
+ IRM_FLOW_JOIN = 22;
+ IRM_FLOW_DEALLOC = 23;
+ IPCP_FLOW_DEALLOC = 24;
+ IPCP_FLOW_REQ_ARR = 25;
+ IPCP_FLOW_ALLOC_REPLY = 26;
+ IRM_REPLY = 27;
+}
+
+message timespec_msg {
+ required uint64 tv_sec = 1;
+ required uint32 tv_nsec = 2;
+}
+
+message ipcp_list_msg {
+ required uint32 pid = 1;
+ required uint32 type = 2;
+ required string name = 3;
+ required string layer = 4;
+ required uint32 hash_algo = 5;
+}
+
+message irm_msg {
+ required irm_msg_code code = 1;
+ optional string prog = 2;
+ optional sint32 pid = 3;
+ optional string name = 4;
+ optional flow_info_msg flow_info = 5;
+ optional ipcp_info_msg ipcp_info = 6;
+ optional string layer = 7;
+ repeated string exec = 8;
+ optional sint32 response = 9;
+ optional string dst = 10;
+ optional bytes hash = 11;
+ optional sint32 flow_id = 12;
+ optional qosspec_msg qosspec = 13;
+ optional ipcp_config_msg conf = 14;
+ optional uint32 opts = 15;
+ repeated ipcp_list_msg ipcps = 16;
+ repeated name_info_msg names = 17;
+ optional timespec_msg timeo = 18;
+ optional sint32 mpl = 20;
+ optional string comp = 21;
+ optional bytes pk = 22; /* piggyback */
+ optional bytes symmkey = 23;
+ optional uint32 timeo_sec = 24;
+ optional uint32 timeo_nsec = 25;
+ optional sint32 result = 26;
+}
diff --git a/src/lib/pb/model.proto b/src/lib/pb/model.proto
new file mode 100644
index 00000000..f1e401f9
--- /dev/null
+++ b/src/lib/pb/model.proto
@@ -0,0 +1,61 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Model description messages
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+syntax = "proto2";
+
+message qosspec_msg {
+ required uint32 delay = 1; /* In ms. */
+ required uint64 bandwidth = 2; /* In bits/s. */
+ required uint32 availability = 3; /* Class of 9s. */
+ required uint32 loss = 4; /* Packet loss. */
+ required uint32 ber = 5; /* Bit error rate, ppb. */
+ required uint32 in_order = 6; /* In-order delivery. */
+ required uint32 max_gap = 7; /* In ms. */
+ required uint32 cypher_s = 8; /* Crypto strength in bits. */
+ required uint32 timeout = 9; /* Timeout in ms. */
+}
+
+message flow_info_msg {
+ required uint32 id = 1;
+ required uint32 n_pid = 2;
+ required uint32 n_1_pid = 3;
+ required uint32 mpl = 4;
+ required uint32 state = 5;
+ required qosspec_msg qos = 6;
+}
+
+message name_info_msg {
+ required string name = 1;
+ required uint32 pol_lb = 2;
+}
+
+message layer_info_msg {
+ required string name = 1;
+ required uint32 dir_hash_algo = 2;
+}
+
+message ipcp_info_msg {
+ required uint32 type = 1;
+ required string name = 2;
+ required uint32 pid = 3;
+ required uint32 state = 4;
+}
diff --git a/src/lib/protobuf.c b/src/lib/protobuf.c
new file mode 100644
index 00000000..b586168c
--- /dev/null
+++ b/src/lib/protobuf.c
@@ -0,0 +1,605 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Protobuf syntax conversion
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _DEFAULT_SOURCE
+
+#include <ouroboros/protobuf.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+timespec_msg_t * timespec_s_to_msg(const struct timespec * s)
+{
+ timespec_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ timespec_msg__init(msg);
+
+ msg->tv_sec = s->tv_sec;
+ msg->tv_nsec = s->tv_nsec;
+
+ return msg;
+
+ fail_malloc:
+ return NULL;
+}
+
+struct timespec timespec_msg_to_s(timespec_msg_t * msg)
+{
+ struct timespec s;
+
+ assert(msg != NULL);
+
+ s.tv_sec = msg->tv_sec;
+ s.tv_nsec = msg->tv_nsec;
+
+ return s;
+}
+
+flow_info_msg_t * flow_info_s_to_msg(const struct flow_info * s)
+{
+ flow_info_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ flow_info_msg__init(msg);
+
+ msg->id = s->id;
+ msg->n_pid = s->n_pid;
+ msg->n_1_pid = s->n_1_pid;
+ msg->mpl = s->mpl;
+ msg->state = s->state;
+ msg->qos = qos_spec_s_to_msg(&s->qs);
+ if (msg->qos == NULL)
+ goto fail_msg;
+
+ return msg;
+
+ fail_msg:
+ flow_info_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct flow_info flow_info_msg_to_s(const flow_info_msg_t * msg)
+{
+ struct flow_info s;
+
+ assert(msg != NULL);
+
+ s.id = msg->id;
+ s.n_pid = msg->n_pid;
+ s.n_1_pid = msg->n_1_pid;
+ s.mpl = msg->mpl;
+ s.state = msg->state;
+ s.qs = qos_spec_msg_to_s(msg->qos);
+
+ return s;
+}
+
+layer_info_msg_t * layer_info_s_to_msg(const struct layer_info * s)
+{
+ layer_info_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ layer_info_msg__init(msg);
+
+ msg->name = strdup(s->name);
+ if (msg->name == NULL)
+ goto fail_msg;
+
+ msg->dir_hash_algo = s->dir_hash_algo;
+
+ return msg;
+
+ fail_msg:
+ layer_info_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct layer_info layer_info_msg_to_s(const layer_info_msg_t * msg)
+{
+ struct layer_info s;
+
+ assert(msg != NULL);
+ assert(strlen(msg->name) <= LAYER_NAME_SIZE);
+
+ s.dir_hash_algo = msg->dir_hash_algo;
+ strcpy(s.name, msg->name);
+
+ return s;
+}
+
+ipcp_info_msg_t * ipcp_info_s_to_msg(const struct ipcp_info * s)
+{
+ ipcp_info_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ ipcp_info_msg__init(msg);
+
+ msg->name = strdup(s->name);
+ if (msg->name == NULL)
+ goto fail_msg;
+
+ msg->type = s->type;
+ msg->pid = s->pid;
+ msg->state = s->state;
+
+ return msg;
+ fail_msg:
+ ipcp_info_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct ipcp_info ipcp_info_msg_to_s(const ipcp_info_msg_t * msg)
+{
+ struct ipcp_info s;
+
+ assert(msg != NULL);
+ assert(msg->name != NULL);
+ assert(strlen(msg->name) <= NAME_SIZE);
+
+ strcpy(s.name, msg->name);
+ s.type = msg->type;
+ s.pid = msg->pid;
+ s.state = msg->state;
+
+ return s;
+}
+
+dt_config_msg_t * dt_config_s_to_msg(const struct dt_config * s)
+{
+ dt_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+
+ dt_config_msg__init(msg);
+
+ msg->addr_size = s->addr_size;
+ msg->eid_size = s->eid_size;
+ msg->max_ttl = s->max_ttl;
+ msg->routing_type = s->routing_type;
+
+ return msg;
+}
+
+struct dt_config dt_config_msg_to_s(const dt_config_msg_t * msg)
+{
+ struct dt_config s;
+
+ assert(msg != NULL);
+
+ s.addr_size = msg->addr_size;
+ s.eid_size = msg->eid_size;
+ s.max_ttl = msg->max_ttl;
+ s.routing_type = msg->routing_type;
+
+ return s;
+}
+
+uni_config_msg_t * uni_config_s_to_msg(const struct uni_config * s)
+{
+ uni_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ uni_config_msg__init(msg);
+
+ msg->dt = dt_config_s_to_msg(&s->dt);
+ if (msg->dt == NULL)
+ goto fail_msg;
+
+ msg->addr_auth_type = s->addr_auth_type;
+ msg->cong_avoid = s->cong_avoid;
+
+ return msg;
+
+ fail_msg:
+ uni_config_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct uni_config uni_config_msg_to_s(const uni_config_msg_t * msg)
+{
+ struct uni_config s;
+
+ s.dt = dt_config_msg_to_s(msg->dt);
+
+ s.addr_auth_type = msg->addr_auth_type;
+ s.cong_avoid = msg->cong_avoid;
+
+ return s;
+}
+
+udp_config_msg_t * udp_config_s_to_msg(const struct udp_config * s)
+{
+ udp_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+
+ udp_config_msg__init(msg);
+
+ msg->ip_addr = s->ip_addr;
+ msg->dns_addr = s->dns_addr;
+ msg->port = s->port;
+
+ return msg;
+}
+
+struct udp_config udp_config_msg_to_s(const udp_config_msg_t * msg)
+{
+ struct udp_config s;
+
+ assert(msg != NULL);
+
+ s.ip_addr = msg->ip_addr;
+ s.dns_addr = msg->dns_addr;
+ s.port = msg->port;
+
+ return s;
+}
+
+eth_config_msg_t * eth_config_s_to_msg(const struct eth_config * s)
+{
+ eth_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ eth_config_msg__init(msg);
+
+ msg->dev = strdup(s->dev);
+ if (msg->dev == NULL)
+ goto fail_msg;
+
+ msg->ethertype = s->ethertype;
+
+ return msg;
+
+ fail_msg:
+ eth_config_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct eth_config eth_config_msg_to_s(const eth_config_msg_t * msg)
+{
+ struct eth_config s;
+
+ assert(msg != NULL);
+ assert(strlen(msg->dev) <= DEV_NAME_SIZE);
+
+ strcpy(s.dev, msg->dev);
+ s.ethertype = msg->ethertype;
+
+ return s;
+}
+
+
+ipcp_config_msg_t * ipcp_config_s_to_msg(const struct ipcp_config * s)
+{
+ ipcp_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ ipcp_config_msg__init(msg);
+
+ switch (s->type) {
+ case IPCP_LOCAL:
+ break;
+ case IPCP_UNICAST:
+ msg->unicast = uni_config_s_to_msg(&s->unicast);
+ if (msg->unicast == NULL)
+ goto fail_msg;
+ break;
+ case IPCP_BROADCAST:
+ break;
+ case IPCP_ETH_LLC:
+ /* FALLTHRU */
+ case IPCP_ETH_DIX:
+ msg->eth = eth_config_s_to_msg(&s->eth);
+ if (msg->eth == NULL)
+ goto fail_msg;
+ break;
+ case IPCP_UDP:
+ msg->udp = udp_config_s_to_msg(&s->udp);
+ if (msg->udp == NULL)
+ goto fail_msg;
+ break;
+ default:
+ /* No checks here */
+ break;
+ }
+
+ msg->ipcp_type = s->type;
+
+ msg->layer_info = layer_info_s_to_msg(&s->layer_info);
+ if (msg->layer_info == NULL)
+ goto fail_msg;
+
+ return msg;
+
+ fail_msg:
+ ipcp_config_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct ipcp_config ipcp_config_msg_to_s(const ipcp_config_msg_t * msg)
+{
+ struct ipcp_config s;
+
+ assert(msg != NULL);
+
+ s.type = msg->ipcp_type;
+
+ s.layer_info = layer_info_msg_to_s(msg->layer_info);
+
+ switch(msg->ipcp_type) {
+ case IPCP_LOCAL:
+ break;
+ case IPCP_UNICAST:
+ s.unicast = uni_config_msg_to_s(msg->unicast);
+ break;
+ case IPCP_ETH_LLC:
+ /* FALLTHRU */
+ case IPCP_ETH_DIX:
+ s.eth = eth_config_msg_to_s(msg->eth);
+ break;
+ case IPCP_UDP:
+ s.udp = udp_config_msg_to_s(msg->udp);
+ break;
+ case IPCP_BROADCAST:
+ break;
+ default:
+ /* No checks here */
+ break;
+ }
+
+ return s;
+}
+
+qosspec_msg_t * qos_spec_s_to_msg(const struct qos_spec * s)
+{
+ qosspec_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+
+ qosspec_msg__init(msg);
+
+ msg->delay = s->delay;
+ msg->bandwidth = s->bandwidth;
+ msg->availability = s->availability;
+ msg->loss = s->loss;
+ msg->ber = s->ber;
+ msg->in_order = s->in_order;
+ msg->max_gap = s->max_gap;
+ msg->cypher_s = s->cypher_s;
+ msg->timeout = s->timeout;
+
+ return msg;
+}
+
+struct qos_spec qos_spec_msg_to_s(const qosspec_msg_t * msg)
+{
+ struct qos_spec s;
+
+ assert(msg != NULL);
+
+ s.delay = msg->delay;
+ s.bandwidth = msg->bandwidth;
+ s.availability = msg->availability;
+ s.loss = msg->loss;
+ s.ber = msg->ber;
+ s.in_order = msg->in_order;
+ s.max_gap = msg->max_gap;
+ s.cypher_s = msg->cypher_s;
+ s.timeout = msg->timeout;
+
+ return s;
+}
+
+enroll_req_msg_t * enroll_req_s_to_msg(const struct enroll_req * s)
+{
+ enroll_req_msg_t * msg;
+ uint8_t * id;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_msg;
+
+ id = malloc(ENROLL_ID_LEN);
+ if (id == NULL)
+ goto fail_id;
+
+ memcpy(id, s->id, ENROLL_ID_LEN);
+
+ enroll_req_msg__init(msg);
+
+ msg->id.len = ENROLL_ID_LEN;
+ msg->id.data = id;
+
+ return msg;
+
+ fail_id:
+ free(msg);
+ fail_msg:
+ return NULL;
+}
+
+struct enroll_req enroll_req_msg_to_s(const enroll_req_msg_t * msg)
+{
+ struct enroll_req s;
+
+ assert(msg != NULL);
+
+ memcpy(s.id, msg->id.data, ENROLL_ID_LEN);
+
+ return s;
+}
+
+enroll_resp_msg_t * enroll_resp_s_to_msg(const struct enroll_resp * s)
+{
+ enroll_resp_msg_t * msg;
+ uint8_t * id;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_msg;
+
+ id = malloc(ENROLL_ID_LEN);
+ if (id == NULL)
+ goto fail_id;
+
+ memcpy(id, s->id, ENROLL_ID_LEN);
+
+ enroll_resp_msg__init(msg);
+
+ msg->id.len = ENROLL_ID_LEN;
+ msg->id.data = id;
+
+ msg->t_sec = s->t.tv_sec;
+ msg->t_nsec = s->t.tv_nsec;
+ msg->response = s->response;
+ if (msg->response < 0)
+ return msg;
+
+ msg->conf = ipcp_config_s_to_msg(&s->conf);
+ if (msg->conf == NULL)
+ goto fail_id;
+
+ return msg;
+
+ fail_id:
+ enroll_resp_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return NULL;
+}
+
+struct enroll_resp enroll_resp_msg_to_s(const enroll_resp_msg_t * msg)
+{
+ struct enroll_resp s;
+
+ assert (msg != NULL);
+
+ s.response = msg->response;
+ if (s.response >= 0)
+ s.conf = ipcp_config_msg_to_s(msg->conf);
+
+ s.t.tv_sec = msg->t_sec;
+ s.t.tv_nsec = msg->t_nsec;
+
+ memcpy(s.id, msg->id.data, ENROLL_ID_LEN);
+
+ return s;
+}
+
+enroll_ack_msg_t * enroll_ack_s_to_msg(const struct enroll_ack * s)
+{
+ enroll_ack_msg_t * msg;
+ uint8_t * id;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_msg;
+
+ id = malloc(ENROLL_ID_LEN);
+ if (id == NULL)
+ goto fail_id;
+
+ memcpy(id, s->id, ENROLL_ID_LEN);
+
+ enroll_ack_msg__init(msg);
+
+ msg->id.len = ENROLL_ID_LEN;
+ msg->id.data = id;
+
+ msg->result = s->result;
+
+ return msg;
+
+ fail_id:
+ enroll_ack_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return NULL;
+}
+
+struct enroll_ack enroll_ack_msg_to_s(const enroll_ack_msg_t * msg)
+{
+ struct enroll_ack s;
+
+ assert(msg != NULL);
+
+ memcpy(s.id, msg->id.data, ENROLL_ID_LEN);
+
+ s.result = msg->result;
+
+ return s;
+}
diff --git a/src/lib/qoscube.c b/src/lib/qoscube.c
index 3e6f884d..267b3a87 100644
--- a/src/lib/qoscube.c
+++ b/src/lib/qoscube.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Quality of Service cube
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/src/lib/qosspec.proto b/src/lib/qosspec.proto
deleted file mode 100644
index 5d8abb79..00000000
--- a/src/lib/qosspec.proto
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * QoS specification message
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-syntax = "proto2";
-
-message qosspec_msg {
- required uint32 delay = 1; /* In ms */
- required uint64 bandwidth = 2; /* In bits/s */
- required uint32 availability = 3; /* Class of 9s */
- required uint32 loss = 4; /* Packet loss */
- required uint32 ber = 5; /* Bit error rate, ppb */
- required uint32 in_order = 6; /* In-order delivery */
- required uint32 max_gap = 7; /* In ms */
- required uint32 cypher_s = 8; /* Crypto strength in bits */
-};
diff --git a/src/lib/random.c b/src/lib/random.c
index b2cdabbc..09e0b844 100644
--- a/src/lib/random.c
+++ b/src/lib/random.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Pseudo random generator
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
diff --git a/src/lib/rib.c b/src/lib/rib.c
index 684c5dcd..97a20f47 100644
--- a/src/lib/rib.c
+++ b/src/lib/rib.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* RIB export using FUSE
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -43,15 +43,14 @@
#define __USE_XOPEN
#elif defined (__FreeBSD__)
#define __XSI_VISIBLE 500
-#endif
+#endif /* __linux__ */
+#include <sys/stat.h>
#include <fuse.h>
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
#endif
-#define RT "/"
-
struct reg_comp {
struct list_head next;
@@ -106,8 +105,7 @@ static int rib_read(const char * path,
strcpy(comp, path + 1);
- c = strstr(comp, "/");
-
+ c = strstr(comp, RIB_SEPARATOR);
if (c != NULL)
*c = '\0';
@@ -119,7 +117,7 @@ static int rib_read(const char * path,
list_for_each(p, &rib.reg_comps) {
struct reg_comp * r = list_entry(p, struct reg_comp, next);
if (strcmp(comp, r->path) == 0) {
- int ret = r->ops->read(c + 1, buf, size);
+ int ret = r->ops->read(path + 1, buf, size);
pthread_rwlock_unlock(&rib.lock);
return ret;
}
@@ -141,12 +139,16 @@ static int rib_readdir(const char * path,
(void) offset;
(void) info;
+ /* Fix ls calling readdir in an infinite loop on raspbian. */
+ if (info != NULL && info->nonseekable != 0)
+ return -ENOENT;
+
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
pthread_rwlock_rdlock(&rib.lock);
- if (strcmp(path, RT) == 0) {
+ if (strcmp(path, RIB_SEPARATOR) == 0) {
list_for_each(p, &rib.reg_comps) {
struct reg_comp * c;
c = list_entry(p, struct reg_comp, next);
@@ -185,24 +187,35 @@ static size_t __getattr(const char * path,
struct list_head * p;
char comp[RIB_PATH_LEN + 1];
char * c;
+ struct rib_attr attr;
if (strlen(path) > RIB_PATH_LEN)
return -1;
strcpy(comp, path + 1);
- c = strstr(comp, "/");
-
+ c = strstr(comp, RIB_SEPARATOR);
if (c != NULL)
*c = '\0';
+ memset(&attr, 0, sizeof(attr));
+
pthread_rwlock_rdlock(&rib.lock);
list_for_each(p, &rib.reg_comps) {
struct reg_comp * r = list_entry(p, struct reg_comp, next);
if (strcmp(comp, r->path) == 0) {
- size_t ret = r->ops->getattr(c + 1, st);
+ size_t ret = r->ops->getattr(path + 1, &attr);
pthread_rwlock_unlock(&rib.lock);
+ st->st_mode = S_IFREG | 0644;
+ st->st_blocks = 1;
+ st->st_nlink = 1;
+ st->st_uid = getuid();
+ st->st_gid = getgid();
+ st->st_size = attr.size;
+ st->st_atime = attr.mtime;
+ st->st_mtime = attr.mtime;
+ st->st_ctime = attr.mtime;
return ret;
}
}
@@ -220,7 +233,7 @@ static int rib_getattr(const char * path,
memset(st, 0, sizeof(*st));
- if (strcmp(path, RT) == 0)
+ if (strcmp(path, RIB_SEPARATOR) == 0)
goto finish_dir;
pthread_rwlock_rdlock(&rib.lock);
@@ -246,6 +259,8 @@ static int rib_getattr(const char * path,
st->st_uid = getuid();
st->st_gid = getgid();
st->st_mtime = now.tv_sec;
+ st->st_atime = now.tv_sec;
+ st->st_ctime = now.tv_sec;
return 0;
}
@@ -266,7 +281,6 @@ static void * fuse_thr(void * o)
}
#endif /* HAVE_FUSE */
-
int rib_init(const char * mountpt)
{
#ifdef HAVE_FUSE
@@ -280,8 +294,11 @@ int rib_init(const char * mountpt)
NULL};
struct fuse_args args = FUSE_ARGS_INIT(3, argv);
+ if (access("/dev/fuse", R_OK))
+ goto fail;
+
if (stat(FUSE_PREFIX, &st) == -1)
- return -1;
+ goto fail;
sprintf(rib.mnt, FUSE_PREFIX "/%s", mountpt);
@@ -289,13 +306,13 @@ int rib_init(const char * mountpt)
switch(errno) {
case ENOENT:
if (mkdir(rib.mnt, 0777))
- return -1;
+ goto fail_mnt;
break;
case ENOTCONN:
fuse_unmount(rib.mnt, rib.ch);
break;
default:
- return -1;
+ goto fail_mnt;
}
fuse_opt_parse(&args, NULL, NULL, NULL);
@@ -329,6 +346,9 @@ int rib_init(const char * mountpt)
fail_mount:
fuse_opt_free_args(&args);
rmdir(rib.mnt);
+ fail_mnt:
+ memset(rib.mnt, 0, sizeof(rib.mnt));
+ fail:
return -1;
#else
(void) mountpt;
@@ -342,6 +362,9 @@ void rib_fini(void)
struct list_head * p;
struct list_head * h;
+ if (strlen(rib.mnt) == 0)
+ return;
+
fuse_exit(rib.fuse);
fuse_unmount(rib.mnt, rib.ch);
@@ -363,6 +386,18 @@ void rib_fini(void)
pthread_rwlock_unlock(&rib.lock);
pthread_rwlock_destroy(&rib.lock);
+
+ memset(rib.mnt, 0, sizeof(rib.mnt));
+#endif
+}
+
+void rib_cleanup(const char * mnt)
+{
+#ifdef HAVE_FUSE
+ fuse_unmount(mnt, NULL);
+ rmdir(mnt);
+#else
+ (void) mnt;
#endif
}
@@ -373,6 +408,9 @@ int rib_reg(const char * path,
struct reg_comp * rc;
struct list_head * p;
+ if (strlen(rib.mnt) == 0)
+ return 0;
+
pthread_rwlock_wrlock(&rib.lock);
list_for_each(p, &rib.reg_comps) {
@@ -417,6 +455,9 @@ void rib_unreg(const char * path)
struct list_head * p;
struct list_head * h;
+ if (strlen(rib.mnt) == 0)
+ return;
+
pthread_rwlock_wrlock(&rib.lock);
list_for_each_safe(p, h, &rib.reg_comps) {
diff --git a/src/lib/rxmwheel.c b/src/lib/rxmwheel.c
deleted file mode 100644
index ce7ef8e4..00000000
--- a/src/lib/rxmwheel.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2020
- *
- * Timerwheel
- *
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#include <ouroboros/list.h>
-
-#define RXMQ_S 16 /* defines #slots */
-#define RXMQ_M 24 /* defines max delay */
-#define RXMQ_R (RXMQ_M - RXMQ_S) /* defines resolution */
-#define RXMQ_SLOTS (1 << RXMQ_S)
-#define RXMQ_MAX (1 << RXMQ_M) /* ms */
-
-/* Small inacurracy to avoid slow division by MILLION. */
-#define ts_to_ms(ts) (ts.tv_sec * 1000 + (ts.tv_nsec >> 20))
-#define ts_to_us(ts) (ts.tv_sec * MILLION + (ts.tv_nsec >> 10))
-#define ts_to_slot(ts) ((ts_to_us(ts) >> RXMQ_R) & (RXMQ_SLOTS - 1))
-
-struct rxm {
- struct list_head next;
- uint32_t seqno;
- struct shm_du_buff * sdb;
- uint8_t * head;
- uint8_t * tail;
- time_t t0; /* Time when original was sent (s). */
- size_t mul; /* RTO multiplier. */
- struct frcti * frcti;
-};
-
-struct {
- struct list_head wheel[RXMQ_SLOTS];
-
- size_t prv; /* Last processed slot. */
- pthread_mutex_t lock;
-} rw;
-
-static void rxmwheel_fini(void)
-{
- size_t i;
- struct list_head * p;
- struct list_head * h;
-
- for (i = 0; i < RXMQ_SLOTS; ++i) {
- list_for_each_safe(p, h, &rw.wheel[i]) {
- struct rxm * rxm = list_entry(p, struct rxm, next);
- list_del(&rxm->next);
- free(rxm);
- }
- }
-}
-
-static int rxmwheel_init(void)
-{
- struct timespec now;
- size_t i;
-
- if (pthread_mutex_init(&rw.lock, NULL))
- return -1;
-
- clock_gettime(PTHREAD_COND_CLOCK, &now);
-
- /* Mark the previous timeslot as the last one processed. */
- rw.prv = (ts_to_slot(now) - 1) & (RXMQ_SLOTS - 1);
-
- for (i = 0; i < RXMQ_SLOTS; ++i)
- list_head_init(&rw.wheel[i]);
-
- return 0;
-}
-
-static void rxmwheel_clear(int fd)
-{
- size_t i;
-
- /* FIXME: Add list element to avoid looping over full rxmwheel. */
- pthread_mutex_lock(&rw.lock);
-
- for (i = 0; i < RXMQ_SLOTS; ++i) {
- struct list_head * p;
- struct list_head * h;
-
- list_for_each_safe(p, h, &rw.wheel[i]) {
- struct rxm * r = list_entry(p, struct rxm, next);
- if (r->frcti->fd == fd) {
- list_del(&r->next);
- shm_du_buff_ack(r->sdb);
- ipcp_sdb_release(r->sdb);
- free(r);
- }
- }
- }
-
- pthread_mutex_unlock(&rw.lock);
-}
-
-static void check_probe(struct frcti * frcti,
- uint32_t seqno)
-{
- /* disable rtt probe if this packet */
-
- /* TODO: This should be locked, but lock reversal! */
-
- if (frcti->probe && ((frcti->rttseq + 1) == seqno)) {
- /* Backoff to avoid never updating rtt */
- frcti->srtt_us <<= 1;
- frcti->probe = false;
- }
-}
-
-#define rto(frcti) (frcti->srtt_us + (frcti->mdev_us << 1))
-/* Return fd on r-timer expiry. */
-static int rxmwheel_move(void)
-{
- struct timespec now;
- struct list_head * p;
- struct list_head * h;
- size_t slot;
- size_t i;
-
- clock_gettime(PTHREAD_COND_CLOCK, &now);
-
- slot = ts_to_slot(now);
-
- pthread_mutex_lock(&rw.lock);
-
- for (i = rw.prv; (ssize_t) (i - slot) <= 0; ++i) {
- list_for_each_safe(p, h, &rw.wheel[i]) {
- struct rxm * r;
- struct frct_cr * snd_cr;
- struct frct_cr * rcv_cr;
- size_t rslot;
- time_t newtime;
- ssize_t idx;
- struct shm_du_buff * sdb;
- uint8_t * head;
- struct flow * f;
-
- r = list_entry(p, struct rxm, next);
- list_del(&r->next);
-
- snd_cr = &r->frcti->snd_cr;
- rcv_cr = &r->frcti->rcv_cr;
- /* Has been ack'd, remove. */
- if ((int) (r->seqno - snd_cr->lwe) <= 0) {
- shm_du_buff_ack(r->sdb);
- ipcp_sdb_release(r->sdb);
- free(r);
- continue;
- }
-
- /* Disable using this seqno as rto probe. */
- check_probe(r->frcti, r->seqno);
-
- /* Check for r-timer expiry. */
- if (ts_to_ms(now) - r->t0 > r->frcti->r) {
- int fd = r->frcti->fd;
- pthread_mutex_unlock(&rw.lock);
- shm_du_buff_ack(r->sdb);
- ipcp_sdb_release(r->sdb);
- free(r);
- return fd;
- }
-
- /* Copy the payload, safe rtx in other layers. */
- if (ipcp_sdb_reserve(&sdb, r->tail - r->head)) {
- /* FIXME: reschedule send? */
- int fd = r->frcti->fd;
- pthread_mutex_unlock(&rw.lock);
- shm_du_buff_ack(r->sdb);
- ipcp_sdb_release(r->sdb);
- free(r);
- return fd;
- }
-
- idx = shm_du_buff_get_idx(sdb);
-
- head = shm_du_buff_head(sdb);
- memcpy(head, r->head, r->tail - r->head);
-
- /* Release the old copy. */
- shm_du_buff_ack(r->sdb);
- ipcp_sdb_release(r->sdb);
-
- /* Update ackno and make sure DRF is not set. */
- ((struct frct_pci *) head)->ackno = ntoh32(rcv_cr->lwe);
- ((struct frct_pci *) head)->flags &= ~FRCT_DRF;
-
- f = &ai.flows[r->frcti->fd];
-
- /* Retransmit the copy. */
- if (shm_rbuff_write(f->tx_rb, idx)) {
- ipcp_sdb_release(sdb);
- free(r);
- /* FIXME: reschedule send? */
- continue;
- }
-
- shm_flow_set_notify(f->set, f->flow_id, FLOW_PKT);
-
- /* Reschedule. */
- shm_du_buff_wait_ack(sdb);
-
- r->head = head;
- r->tail = shm_du_buff_tail(sdb);
- r->sdb = sdb;
-
- newtime = ts_to_us(now) + rto(f->frcti);
- rslot = (newtime >> RXMQ_R) & (RXMQ_SLOTS - 1);
-
- list_add_tail(&r->next, &rw.wheel[rslot]);
- }
- }
-
- rw.prv = slot;
-
- pthread_mutex_unlock(&rw.lock);
-
- return 0;
-}
-
-static int rxmwheel_add(struct frcti * frcti,
- uint32_t seqno,
- struct shm_du_buff * sdb)
-{
- struct timespec now;
- struct rxm * r;
- size_t slot;
-
- r = malloc(sizeof(*r));
- if (r == NULL)
- return -ENOMEM;
-
- clock_gettime(PTHREAD_COND_CLOCK, &now);
-
- pthread_mutex_lock(&rw.lock);
-
- r->t0 = ts_to_us(now);
- r->mul = 0;
- r->seqno = seqno;
- r->sdb = sdb;
- r->head = shm_du_buff_head(sdb);
- r->tail = shm_du_buff_tail(sdb);
- r->frcti = frcti;
-
- slot = ((r->t0 + rto(frcti)) >> RXMQ_R) & (RXMQ_SLOTS - 1);
-
- list_add_tail(&r->next, &rw.wheel[slot]);
-
- pthread_mutex_unlock(&rw.lock);
-
- shm_du_buff_wait_ack(sdb);
-
- return 0;
-}
diff --git a/src/lib/serdes-irm.c b/src/lib/serdes-irm.c
new file mode 100644
index 00000000..c4ba3053
--- /dev/null
+++ b/src/lib/serdes-irm.c
@@ -0,0 +1,478 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros IRM Protocol - serialization/deserialization
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#include "config.h"
+
+#include <ouroboros/errno.h>
+#include <ouroboros/serdes-irm.h>
+#include <ouroboros/protobuf.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+int flow_accept__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const struct timespec * timeo)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = IRM_MSG_CODE__IRM_FLOW_ACCEPT;
+ msg->flow_info = flow_info_s_to_msg(flow);
+ if (msg->flow_info == NULL)
+ goto fail_msg;
+
+ msg->timeo = timeo == NULL ? NULL : timespec_s_to_msg(timeo);
+ if (timeo != NULL && msg->timeo == NULL)
+ goto fail_msg;
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+static int __flow_alloc_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const char * dst,
+ const struct timespec * timeo,
+ int msg_code)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = msg_code;
+ msg->flow_info = flow_info_s_to_msg(flow);
+ if (msg->flow_info == NULL)
+ goto fail_msg;
+
+ msg->dst = strdup(dst);
+ if (msg->dst == NULL)
+ goto fail_msg;
+
+ msg->timeo = timeo == NULL ? NULL : timespec_s_to_msg(timeo);
+ if (timeo != NULL && msg->timeo == NULL)
+ goto fail_msg;
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+int flow_alloc__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const char * dst,
+ const struct timespec * timeo)
+{
+ return __flow_alloc_ser(buf, flow, dst, timeo,
+ IRM_MSG_CODE__IRM_FLOW_ALLOC);
+}
+
+int flow_join__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const char * dst,
+ const struct timespec * timeo)
+{
+ return __flow_alloc_ser(buf, flow, dst, timeo,
+ IRM_MSG_CODE__IRM_FLOW_JOIN);
+}
+
+int flow__irm_result_des(buffer_t * buf,
+ struct flow_info * flow,
+ buffer_t * sk)
+{
+ irm_msg_t * msg;
+ int err;
+
+ if (sk != NULL)
+ sk->data = NULL;
+
+ msg = irm_msg__unpack(NULL, buf->len, buf->data);
+ if (msg == NULL) {
+ err = -EIRMD;
+ goto fail_msg;
+ }
+
+ if (!msg->has_result) {
+ err = -EIRMD;
+ goto fail;
+ }
+
+ if (msg->result < 0) {
+ err = msg->result;
+ goto fail;
+ }
+
+ if (msg->flow_info == NULL) {
+ err = -EBADF;
+ goto fail;
+ }
+
+ *flow = flow_info_msg_to_s(msg->flow_info);
+
+ if (flow->qs.cypher_s > 0 && sk != NULL) {
+ if (msg->symmkey.data == NULL || msg->symmkey.len == 0) {
+ err = -ECRYPT;
+ goto fail;
+ }
+
+ sk->len = msg->symmkey.len;
+ sk->data = msg->symmkey.data;
+
+ msg->symmkey.data = NULL;
+ msg->symmkey.len = 0;
+ }
+
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return err;
+}
+
+int flow_dealloc__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ const struct timespec * timeo)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = IRM_MSG_CODE__IRM_FLOW_DEALLOC;
+ msg->flow_info = flow_info_s_to_msg(flow);
+ if (msg->flow_info == NULL)
+ goto fail_msg;
+
+ msg->timeo = timespec_s_to_msg(timeo);
+ if (msg->timeo == NULL)
+ goto fail_msg;
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+int ipcp_flow_dealloc__irm_req_ser(buffer_t * buf,
+ const struct flow_info * flow)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = IRM_MSG_CODE__IPCP_FLOW_DEALLOC;
+ msg->flow_info = flow_info_s_to_msg(flow);
+ if (msg->flow_info == NULL)
+ goto fail_msg;
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+
+int ipcp_create_r__irm_req_ser(buffer_t * buf,
+ const struct ipcp_info * ipcp)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = IRM_MSG_CODE__IPCP_CREATE_R;
+ msg->ipcp_info = ipcp_info_s_to_msg(ipcp);
+ if (msg->ipcp_info == NULL)
+ goto fail_msg;
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+int proc_announce__irm_req_ser(buffer_t * buf,
+ const char * prog)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = IRM_MSG_CODE__IRM_PROC_ANNOUNCE;
+ msg->has_pid = true;
+ msg->pid = getpid();
+ msg->prog = strdup(prog);
+ if (msg->prog == NULL)
+ goto fail_msg;
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+int proc_exit__irm_req_ser(buffer_t * buf)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = IRM_MSG_CODE__IRM_PROC_EXIT;
+ msg->has_pid = true;
+ msg->pid = getpid();
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+int ipcp_flow_req_arr__irm_req_ser(buffer_t * buf,
+ const buffer_t * dst,
+ const struct flow_info * flow,
+ const buffer_t * data)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = IRM_MSG_CODE__IPCP_FLOW_REQ_ARR;
+ msg->flow_info = flow_info_s_to_msg(flow);
+ if (msg->flow_info == NULL)
+ goto fail_msg;
+
+ msg->has_hash = true;
+ msg->hash.len = dst->len;
+ msg->hash.data = dst->data;
+ msg->has_pk = true;
+ msg->pk.len = data->len;
+ msg->pk.data = data->data;
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+
+ /* Don't free * dst or data! */
+ msg->hash.len = 0;
+ msg->hash.data = NULL;
+ msg->pk.len = 0;
+ msg->pk.data = NULL;
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+int ipcp_flow_alloc_reply__irm_msg_ser(buffer_t * buf,
+ const struct flow_info * flow,
+ int response,
+ const buffer_t * data)
+{
+ irm_msg_t * msg;
+ size_t len;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ irm_msg__init(msg);
+
+ msg->code = IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY;
+ msg->flow_info = flow_info_s_to_msg(flow);
+ if (msg->flow_info == NULL)
+ goto fail_msg;
+
+ msg->has_pk = true;
+ msg->pk.len = data->len;
+ msg->pk.data = data->data;
+ msg->has_response = true;
+ msg->response = response;
+
+ len = irm_msg__get_packed_size(msg);
+ if (len == 0 || len > buf->len)
+ goto fail_msg;
+
+ buf->len = len;
+
+ irm_msg__pack(msg, buf->data);
+
+ /* Don't free * data! */
+ msg->pk.len = 0;
+ msg->pk.data = NULL;
+
+ irm_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail_msg:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+int irm__irm_result_des(buffer_t * buf)
+{
+ irm_msg_t * msg;
+ int err;
+
+ msg = irm_msg__unpack(NULL, buf->len, buf->data);
+ if (msg == NULL) {
+ err = -EIRMD;
+ goto fail_msg;
+ }
+
+ if (!msg->has_result) {
+ err = -EIRMD;
+ goto fail;
+ }
+
+ err = msg->result;
+ fail:
+ irm_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return err;
+}
diff --git a/src/lib/serdes-oep.c b/src/lib/serdes-oep.c
new file mode 100644
index 00000000..8a836b3b
--- /dev/null
+++ b/src/lib/serdes-oep.c
@@ -0,0 +1,161 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros Enrollment Protocol - serialization/deserialization
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#define _POSIX_C_SOURCE 200112L
+
+#include <ouroboros/protobuf.h>
+#include <ouroboros/serdes-oep.h>
+
+ssize_t enroll_req_ser(const struct enroll_req * req,
+ buffer_t buf)
+{
+ enroll_req_msg_t * msg;
+ ssize_t sz;
+
+ msg = enroll_req_s_to_msg(req);
+ if (msg == NULL)
+ goto fail_msg;
+
+ sz = enroll_req_msg__get_packed_size(msg);
+ if (sz < 0 || (size_t) sz > buf.len)
+ goto fail_pack;
+
+ enroll_req_msg__pack(msg, buf.data);
+
+ enroll_req_msg__free_unpacked(msg, NULL);
+
+ return sz;
+
+ fail_pack:
+ enroll_req_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return -1;
+}
+
+int enroll_req_des(struct enroll_req * req,
+ const buffer_t buf)
+{
+ enroll_req_msg_t * msg;
+
+ msg = enroll_req_msg__unpack(NULL, buf.len, buf.data);
+ if (msg == NULL)
+ goto fail_unpack;
+
+ if (msg->id.len != ENROLL_ID_LEN)
+ goto fail_id;
+
+ *req = enroll_req_msg_to_s(msg);
+
+ enroll_req_msg__free_unpacked(msg, NULL);
+
+ return 0;
+
+ fail_id:
+ enroll_req_msg__free_unpacked(msg, NULL);
+ fail_unpack:
+ return -1;
+}
+
+ssize_t enroll_resp_ser(const struct enroll_resp * resp,
+ buffer_t buf)
+{
+ enroll_resp_msg_t * msg;
+ ssize_t sz;
+
+ msg = enroll_resp_s_to_msg(resp);
+ if (msg == NULL)
+ goto fail_msg;
+
+ sz = enroll_resp_msg__get_packed_size(msg);
+ if (sz < 0 || (size_t) sz > buf.len)
+ goto fail_pack;
+
+ enroll_resp_msg__pack(msg, buf.data);
+
+ enroll_resp_msg__free_unpacked(msg, NULL);
+
+ return sz;
+
+ fail_pack:
+ enroll_resp_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return -1;
+}
+
+int enroll_resp_des(struct enroll_resp * resp,
+ const buffer_t buf)
+{
+ enroll_resp_msg_t * msg;
+
+ msg = enroll_resp_msg__unpack(NULL, buf.len, buf.data);
+ if (msg == NULL)
+ return -1;
+
+ *resp = enroll_resp_msg_to_s(msg);
+
+ enroll_resp_msg__free_unpacked(msg, NULL);
+
+ return 0;
+}
+
+ssize_t enroll_ack_ser(const struct enroll_ack * ack,
+ buffer_t buf)
+{
+ enroll_ack_msg_t * msg;
+ ssize_t sz;
+
+ msg = enroll_ack_s_to_msg(ack);
+ if (msg == NULL)
+ goto fail_msg;
+
+ sz = enroll_ack_msg__get_packed_size(msg);
+ if (sz < 0 || (size_t) sz > buf.len)
+ goto fail_pack;
+
+ enroll_ack_msg__pack(msg, buf.data);
+
+ enroll_ack_msg__free_unpacked(msg, NULL);
+
+ return sz;
+
+ fail_pack:
+ enroll_ack_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return -1;
+
+}
+
+int enroll_ack_des(struct enroll_ack * ack,
+ const buffer_t buf)
+{
+ enroll_ack_msg_t * msg;
+
+ msg = enroll_ack_msg__unpack(NULL, buf.len, buf.data);
+ if (msg == NULL)
+ return -1;
+
+ *ack = enroll_ack_msg_to_s(msg);
+
+ enroll_ack_msg__free_unpacked(msg, NULL);
+
+ return 0;
+}
diff --git a/src/lib/sha3.c b/src/lib/sha3.c
index 7bdafcb5..b9d6b07f 100644
--- a/src/lib/sha3.c
+++ b/src/lib/sha3.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* SHA3 algorithm
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This implementation is adapted and redistributed from the RHASH
* project
@@ -52,8 +52,7 @@
#include <assert.h>
#include <string.h>
-#define IS_ALIGNED_64(p) (0 == (7 & ((const uint8_t *) (p) \
- - (const uint8_t *) 0)))
+#define IS_ALIGNED_64(p) (0 == (7 & ((uintptr_t) (p))))
#define I64(x) x##LL
#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n))))
diff --git a/src/lib/shm_flow_set.c b/src/lib/shm_flow_set.c
index 0f701b63..39913fd1 100644
--- a/src/lib/shm_flow_set.c
+++ b/src/lib/shm_flow_set.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Management of flow_sets for fqueue
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -24,21 +24,21 @@
#include "config.h"
+#include <ouroboros/errno.h>
#include <ouroboros/lockfile.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/pthread.h>
#include <ouroboros/shm_flow_set.h>
-#include <ouroboros/errno.h>
+#include <ouroboros/time.h>
-#include <pthread.h>
-#include <sys/mman.h>
+#include <assert.h>
#include <fcntl.h>
+#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <unistd.h>
-#include <signal.h>
+#include <sys/mman.h>
#include <sys/stat.h>
-#include <string.h>
-#include <assert.h>
/*
* pthread_cond_timedwait has a WONTFIX bug as of glibc 2.25 where it
@@ -52,39 +52,35 @@
#endif
#define FN_MAX_CHARS 255
+#define FS_PROT (PROT_READ | PROT_WRITE)
-#define QUEUESIZE ((SHM_BUFFER_SIZE) * sizeof(struct portevent))
+#define QUEUESIZE ((SHM_BUFFER_SIZE) * sizeof(struct flowevent))
-#define SHM_FLOW_SET_FILE_SIZE (SYS_MAX_FLOWS * sizeof(ssize_t) \
- + PROG_MAX_FQUEUES * sizeof(size_t) \
- + PROG_MAX_FQUEUES * sizeof(pthread_cond_t) \
- + PROG_MAX_FQUEUES * QUEUESIZE \
- + sizeof(pthread_mutex_t))
+#define SHM_FSET_FILE_SIZE (SYS_MAX_FLOWS * sizeof(ssize_t) \
+ + PROG_MAX_FQUEUES * sizeof(size_t) \
+ + PROG_MAX_FQUEUES * sizeof(pthread_cond_t) \
+ + PROG_MAX_FQUEUES * QUEUESIZE \
+ + sizeof(pthread_mutex_t))
#define fqueue_ptr(fs, idx) (fs->fqueues + (SHM_BUFFER_SIZE) * idx)
-struct portevent {
- int flow_id;
- int event;
-};
-
struct shm_flow_set {
ssize_t * mtable;
size_t * heads;
pthread_cond_t * conds;
- struct portevent * fqueues;
+ struct flowevent * fqueues;
pthread_mutex_t * lock;
pid_t pid;
};
static struct shm_flow_set * flow_set_create(pid_t pid,
- int flags)
+ int oflags)
{
struct shm_flow_set * set;
ssize_t * shm_base;
char fn[FN_MAX_CHARS];
- int shm_fd;
+ int fd;
sprintf(fn, SHM_FLOW_SET_PREFIX "%d", pid);
@@ -92,39 +88,33 @@ static struct shm_flow_set * flow_set_create(pid_t pid,
if (set == NULL)
goto fail_malloc;
- shm_fd = shm_open(fn, flags, 0666);
- if (shm_fd == -1)
+ fd = shm_open(fn, oflags, 0666);
+ if (fd == -1)
goto fail_shm_open;
- if (ftruncate(shm_fd, SHM_FLOW_SET_FILE_SIZE - 1) < 0) {
- close(shm_fd);
- goto fail_shm_open;
- }
-
- shm_base = mmap(NULL,
- SHM_FLOW_SET_FILE_SIZE,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- shm_fd,
- 0);
-
- close(shm_fd);
+ if ((oflags & O_CREAT) && ftruncate(fd, SHM_FSET_FILE_SIZE) < 0)
+ goto fail_truncate;
+ shm_base = mmap(NULL, SHM_FSET_FILE_SIZE, FS_PROT, MAP_SHARED, fd, 0);
if (shm_base == MAP_FAILED)
goto fail_mmap;
+ close(fd);
+
set->mtable = shm_base;
set->heads = (size_t *) (set->mtable + SYS_MAX_FLOWS);
set->conds = (pthread_cond_t *)(set->heads + PROG_MAX_FQUEUES);
- set->fqueues = (struct portevent *) (set->conds + PROG_MAX_FQUEUES);
+ set->fqueues = (struct flowevent *) (set->conds + PROG_MAX_FQUEUES);
set->lock = (pthread_mutex_t *)
(set->fqueues + PROG_MAX_FQUEUES * (SHM_BUFFER_SIZE));
return set;
fail_mmap:
- if (flags & O_CREAT)
+ if (oflags & O_CREAT)
shm_unlink(fn);
+ fail_truncate:
+ close(fd);
fail_shm_open:
free(set);
fail_malloc:
@@ -206,7 +196,7 @@ struct shm_flow_set * shm_flow_set_open(pid_t pid)
void shm_flow_set_destroy(struct shm_flow_set * set)
{
- char fn[25];
+ char fn[FN_MAX_CHARS];
assert(set);
@@ -221,7 +211,7 @@ void shm_flow_set_close(struct shm_flow_set * set)
{
assert(set);
- munmap(set->mtable, SHM_FLOW_SET_FILE_SIZE);
+ munmap(set->mtable, SHM_FSET_FILE_SIZE);
free(set);
}
@@ -307,6 +297,8 @@ void shm_flow_set_notify(struct shm_flow_set * set,
int flow_id,
int event)
{
+ struct flowevent * e;
+
assert(set);
assert(!(flow_id < 0) && flow_id < SYS_MAX_FLOWS);
@@ -317,10 +309,13 @@ void shm_flow_set_notify(struct shm_flow_set * set,
return;
}
- (fqueue_ptr(set, set->mtable[flow_id]) +
- (set->heads[set->mtable[flow_id]]))->flow_id = flow_id;
- (fqueue_ptr(set, set->mtable[flow_id]) +
- (set->heads[set->mtable[flow_id]])++)->event = event;
+ e = fqueue_ptr(set, set->mtable[flow_id]) +
+ set->heads[set->mtable[flow_id]];
+
+ e->flow_id = flow_id;
+ e->event = event;
+
+ ++set->heads[set->mtable[flow_id]];
pthread_cond_signal(&set->conds[set->mtable[flow_id]]);
@@ -330,7 +325,7 @@ void shm_flow_set_notify(struct shm_flow_set * set,
ssize_t shm_flow_set_wait(const struct shm_flow_set * set,
size_t idx,
- int * fqueue,
+ struct flowevent * fqueue,
const struct timespec * abstime)
{
ssize_t ret = 0;
@@ -346,22 +341,14 @@ ssize_t shm_flow_set_wait(const struct shm_flow_set * set,
pthread_mutex_consistent(set->lock);
#endif
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) set->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, set->lock);
while (set->heads[idx] == 0 && ret != -ETIMEDOUT) {
- if (abstime != NULL) {
- ret = -pthread_cond_timedwait(set->conds + idx,
- set->lock,
- abstime);
+ ret = -__timedwait(set->conds + idx, set->lock, abstime);
#ifdef HAVE_CANCEL_BUG
- if (ret == -ETIMEDOUT)
- pthread_testcancel();
+ if (ret == -ETIMEDOUT)
+ pthread_testcancel();
#endif
- } else {
- ret = -pthread_cond_wait(set->conds + idx,
- set->lock);
- }
#ifdef HAVE_ROBUST_MUTEX
if (ret == -EOWNERDEAD)
pthread_mutex_consistent(set->lock);
@@ -371,7 +358,7 @@ ssize_t shm_flow_set_wait(const struct shm_flow_set * set,
if (ret != -ETIMEDOUT) {
memcpy(fqueue,
fqueue_ptr(set, idx),
- set->heads[idx] * sizeof(struct portevent));
+ set->heads[idx] * sizeof(*fqueue));
ret = set->heads[idx];
set->heads[idx] = 0;
}
diff --git a/src/lib/shm_rbuff.c b/src/lib/shm_rbuff.c
index 0a07e799..22cff41c 100644
--- a/src/lib/shm_rbuff.c
+++ b/src/lib/shm_rbuff.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ring buffer implementations for incoming packets
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -26,22 +26,22 @@
#include <ouroboros/shm_rbuff.h>
#include <ouroboros/lockfile.h>
-#include <ouroboros/time_utils.h>
#include <ouroboros/errno.h>
#include <ouroboros/fccntl.h>
+#include <ouroboros/pthread.h>
+#include <ouroboros/time.h>
-#include <pthread.h>
-#include <sys/mman.h>
+#include <assert.h>
#include <fcntl.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include <stdint.h>
#include <unistd.h>
-#include <signal.h>
+#include <sys/mman.h>
#include <sys/stat.h>
-#include <assert.h>
-#include <stdbool.h>
#define FN_MAX_CHARS 255
@@ -69,20 +69,11 @@ struct shm_rbuff {
int flow_id; /* flow_id of the flow */
};
-void shm_rbuff_close(struct shm_rbuff * rb)
-{
- assert(rb);
-
- munmap(rb->shm_base, SHM_RB_FILE_SIZE);
-
- free(rb);
-}
-
#define MM_FLAGS (PROT_READ | PROT_WRITE)
-struct shm_rbuff * rbuff_create(pid_t pid,
- int flow_id,
- int flags)
+static struct shm_rbuff * rbuff_create(pid_t pid,
+ int flow_id,
+ int flags)
{
struct shm_rbuff * rb;
int fd;
@@ -99,7 +90,7 @@ struct shm_rbuff * rbuff_create(pid_t pid,
if (fd == -1)
goto fail_open;
- if ((flags & O_CREAT) && ftruncate(fd, SHM_RB_FILE_SIZE - 1) < 0)
+ if ((flags & O_CREAT) && ftruncate(fd, SHM_RB_FILE_SIZE) < 0)
goto fail_truncate;
shm_base = mmap(NULL, SHM_RB_FILE_SIZE, MM_FLAGS, MAP_SHARED, fd, 0);
@@ -130,6 +121,13 @@ struct shm_rbuff * rbuff_create(pid_t pid,
return NULL;
}
+static void rbuff_destroy(struct shm_rbuff * rb)
+{
+ munmap(rb->shm_base, SHM_RB_FILE_SIZE);
+
+ free(rb);
+}
+
struct shm_rbuff * shm_rbuff_create(pid_t pid,
int flow_id)
{
@@ -174,7 +172,7 @@ struct shm_rbuff * shm_rbuff_create(pid_t pid,
*rb->head = 0;
*rb->tail = 0;
- rb->pid = pid;
+ rb->pid = pid;
rb->flow_id = flow_id;
pthread_mutexattr_destroy(&mattr);
@@ -202,6 +200,13 @@ struct shm_rbuff * shm_rbuff_open(pid_t pid,
return rbuff_create(pid, flow_id, O_RDWR);
}
+void shm_rbuff_close(struct shm_rbuff * rb)
+{
+ assert(rb);
+
+ rbuff_destroy(rb);
+}
+
#if (defined(SHM_RBUFF_LOCKLESS) && \
(defined(__GNUC__) || defined (__clang__)))
#include "shm_rbuff_ll.c"
diff --git a/src/lib/shm_rbuff_ll.c b/src/lib/shm_rbuff_ll.c
index 7c2a7d60..46a5314e 100644
--- a/src/lib/shm_rbuff_ll.c
+++ b/src/lib/shm_rbuff_ll.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Lockless ring buffer for incoming packets
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -31,6 +31,11 @@ void shm_rbuff_destroy(struct shm_rbuff * rb)
sprintf(fn, SHM_RBUFF_PREFIX "%d.%d", rb->pid, rb->flow_id);
+ __sync_bool_compare_and_swap(rb->acl, *rb->acl, ACL_FLOWDOWN);
+
+ pthread_cond_broadcast(rb->del);
+ pthread_cond_broadcast(rb->add);
+
shm_rbuff_close(rb);
shm_unlink(fn);
@@ -100,16 +105,10 @@ int shm_rbuff_write_b(struct shm_rbuff * rb,
goto err;
}
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) rb->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock);
while (!shm_rbuff_free(rb) && ret != -ETIMEDOUT) {
- if (abstime != NULL)
- ret = -pthread_cond_timedwait(rb->add,
- rb->lock,
- abstime);
- else
- ret = -pthread_cond_wait(rb->add, rb->lock);
+ ret = -__timedwait(rb->add, rb->lock, abstime);
#ifdef HAVE_ROBUST_MUTEX
if (ret == -EOWNERDEAD)
pthread_mutex_consistent(rb->lock);
@@ -139,9 +138,15 @@ ssize_t shm_rbuff_read(struct shm_rbuff * rb)
assert(rb);
- if (shm_rbuff_empty(rb))
- return __sync_fetch_and_add(rb->acl, 0) & ACL_FLOWDOWN ?
- -EFLOWDOWN : -EAGAIN;
+ if (shm_rbuff_empty(rb)) {
+ if (_sync_fetch_and_add(rb->acl, 0) & ACL_FLOWDOWN)
+ return -EFLOWDOWN;
+
+ if (_sync_fetch_and_add(rb->acl, 0) & ACL_FLOWPEER)
+ return -EFLOWPEER;
+
+ return -EAGAIN;
+ }
ntail = RB_TAIL;
@@ -174,16 +179,10 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff * rb,
if (pthread_mutex_lock(rb->lock) == EOWNERDEAD)
pthread_mutex_consistent(rb->lock);
#endif
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) rb->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock);
while (shm_rbuff_empty(rb) && (idx != -ETIMEDOUT)) {
- if (abstime != NULL)
- idx = -pthread_cond_timedwait(rb->add,
- rb->lock,
- abstime);
- else
- idx = -pthread_cond_wait(rb->add, rb->lock);
+ idx = -__timedwait(rb->add, rb->lock, abstime);
#ifdef HAVE_ROBUST_MUTEX
if (idx == -EOWNERDEAD)
pthread_mutex_consistent(rb->lock);
@@ -230,8 +229,7 @@ void shm_rbuff_fini(struct shm_rbuff * rb)
pthread_mutex_consistent(rb->lock);
#endif
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) rb->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock);
while (!shm_rbuff_empty(rb))
#ifndef HAVE_ROBUST_MUTEX
diff --git a/src/lib/shm_rbuff_pthr.c b/src/lib/shm_rbuff_pthr.c
index 00ffd583..b543fb07 100644
--- a/src/lib/shm_rbuff_pthr.c
+++ b/src/lib/shm_rbuff_pthr.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ring buffer for incoming packets
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -24,12 +24,15 @@ void shm_rbuff_destroy(struct shm_rbuff * rb)
{
char fn[FN_MAX_CHARS];
- assert(rb);
+ assert(rb != NULL);
#ifdef CONFIG_OUROBOROS_DEBUG
pthread_mutex_lock(rb->lock);
- assert(shm_rbuff_empty(rb));
+ *rb->acl = *rb->acl & ACL_FLOWDOWN;
+
+ pthread_cond_broadcast(rb->del);
+ pthread_cond_broadcast(rb->add);
pthread_mutex_unlock(rb->lock);
#endif
@@ -45,7 +48,7 @@ int shm_rbuff_write(struct shm_rbuff * rb,
{
int ret = 0;
- assert(rb);
+ assert(rb != NULL);
assert(idx < SHM_BUFFER_SIZE);
#ifndef HAVE_ROBUST_MUTEX
@@ -88,7 +91,7 @@ int shm_rbuff_write_b(struct shm_rbuff * rb,
{
int ret = 0;
- assert(rb);
+ assert(rb != NULL);
assert(idx < SHM_BUFFER_SIZE);
#ifndef HAVE_ROBUST_MUTEX
@@ -106,16 +109,12 @@ int shm_rbuff_write_b(struct shm_rbuff * rb,
goto err;
}
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) rb->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock);
- while (!shm_rbuff_free(rb) && ret != -ETIMEDOUT) {
- if (abstime != NULL)
- ret = -pthread_cond_timedwait(rb->del,
- rb->lock,
- abstime);
- else
- ret = -pthread_cond_wait(rb->del, rb->lock);
+ while (!shm_rbuff_free(rb)
+ && ret != -ETIMEDOUT
+ && !(*rb->acl & ACL_FLOWDOWN)) {
+ ret = -__timedwait(rb->del, rb->lock, abstime);
#ifdef HAVE_ROBUST_MUTEX
if (ret == -EOWNERDEAD)
pthread_mutex_consistent(rb->lock);
@@ -137,11 +136,24 @@ int shm_rbuff_write_b(struct shm_rbuff * rb,
return ret;
}
+static int check_rb_acl(struct shm_rbuff * rb)
+{
+ assert(rb != NULL);
+
+ if (*rb->acl & ACL_FLOWDOWN)
+ return -EFLOWDOWN;
+
+ if (*rb->acl & ACL_FLOWPEER)
+ return -EFLOWPEER;
+
+ return -EAGAIN;
+}
+
ssize_t shm_rbuff_read(struct shm_rbuff * rb)
{
ssize_t ret = 0;
- assert(rb);
+ assert(rb != NULL);
#ifndef HAVE_ROBUST_MUTEX
pthread_mutex_lock(rb->lock);
@@ -151,7 +163,7 @@ ssize_t shm_rbuff_read(struct shm_rbuff * rb)
#endif
if (shm_rbuff_empty(rb)) {
- ret = *rb->acl & ACL_FLOWDOWN ? -EFLOWDOWN : -EAGAIN;
+ ret = check_rb_acl(rb);
pthread_mutex_unlock(rb->lock);
return ret;
}
@@ -170,7 +182,7 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff * rb,
{
ssize_t idx = -1;
- assert(rb);
+ assert(rb != NULL);
#ifndef HAVE_ROBUST_MUTEX
pthread_mutex_lock(rb->lock);
@@ -184,37 +196,37 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff * rb,
return -EFLOWDOWN;
}
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) rb->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock);
- while (shm_rbuff_empty(rb) && (idx != -ETIMEDOUT)) {
- if (abstime != NULL)
- idx = -pthread_cond_timedwait(rb->add,
- rb->lock,
- abstime);
- else
- idx = -pthread_cond_wait(rb->add, rb->lock);
+ while (shm_rbuff_empty(rb) &&
+ idx != -ETIMEDOUT &&
+ check_rb_acl(rb) == -EAGAIN) {
+ idx = -__timedwait(rb->add, rb->lock, abstime);
#ifdef HAVE_ROBUST_MUTEX
if (idx == -EOWNERDEAD)
pthread_mutex_consistent(rb->lock);
#endif
}
- if (idx != -ETIMEDOUT) {
+ if (!shm_rbuff_empty(rb)) {
idx = *tail_el_ptr(rb);
*rb->tail = (*rb->tail + 1) & ((SHM_RBUFF_SIZE) - 1);
pthread_cond_broadcast(rb->del);
+ } else if (idx != -ETIMEDOUT) {
+ idx = check_rb_acl(rb);
}
pthread_cleanup_pop(true);
+ assert(idx != -EAGAIN);
+
return idx;
}
void shm_rbuff_set_acl(struct shm_rbuff * rb,
uint32_t flags)
{
- assert(rb);
+ assert(rb != NULL);
#ifndef HAVE_ROBUST_MUTEX
pthread_mutex_lock(rb->lock);
@@ -224,6 +236,9 @@ void shm_rbuff_set_acl(struct shm_rbuff * rb,
#endif
*rb->acl = (size_t) flags;
+ pthread_cond_broadcast(rb->del);
+ pthread_cond_broadcast(rb->add);
+
pthread_mutex_unlock(rb->lock);
}
@@ -231,7 +246,7 @@ uint32_t shm_rbuff_get_acl(struct shm_rbuff * rb)
{
uint32_t flags;
- assert(rb);
+ assert(rb != NULL);
#ifndef HAVE_ROBUST_MUTEX
pthread_mutex_lock(rb->lock);
@@ -248,7 +263,7 @@ uint32_t shm_rbuff_get_acl(struct shm_rbuff * rb)
void shm_rbuff_fini(struct shm_rbuff * rb)
{
- assert(rb);
+ assert(rb != NULL);
#ifndef HAVE_ROBUST_MUTEX
pthread_mutex_lock(rb->lock);
@@ -256,8 +271,7 @@ void shm_rbuff_fini(struct shm_rbuff * rb)
if (pthread_mutex_lock(rb->lock) == EOWNERDEAD)
pthread_mutex_consistent(rb->lock);
#endif
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) rb->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock);
while (!shm_rbuff_empty(rb))
#ifndef HAVE_ROBUST_MUTEX
@@ -273,7 +287,7 @@ size_t shm_rbuff_queued(struct shm_rbuff * rb)
{
size_t ret;
- assert(rb);
+ assert(rb != NULL);
#ifndef HAVE_ROBUST_MUTEX
pthread_mutex_lock(rb->lock);
diff --git a/src/lib/shm_rdrbuff.c b/src/lib/shm_rdrbuff.c
index 9a003e21..7ad1bd2e 100644
--- a/src/lib/shm_rdrbuff.c
+++ b/src/lib/shm_rdrbuff.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Random Deletion Ring Buffer for Data Units
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -25,21 +25,19 @@
#include "config.h"
#include <ouroboros/errno.h>
+#include <ouroboros/pthread.h>
#include <ouroboros/shm_rdrbuff.h>
-#include <ouroboros/shm_du_buff.h>
-#include <ouroboros/time_utils.h>
-#include <pthread.h>
-#include <sys/mman.h>
+#include <assert.h>
#include <fcntl.h>
-#include <unistd.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include <signal.h>
+#include <unistd.h>
+#include <sys/mman.h>
#include <sys/stat.h>
-#include <stdbool.h>
-#include <assert.h>
#define SHM_BLOCKS_SIZE ((SHM_BUFFER_SIZE) * SHM_RDRB_BLOCK_SIZE)
#define SHM_FILE_SIZE (SHM_BLOCKS_SIZE + 2 * sizeof(size_t) \
@@ -101,12 +99,14 @@ static void garbage_collect(struct shm_rdrbuff * rdrb)
pthread_cond_broadcast(rdrb->healthy);
}
+#ifdef HAVE_ROBUST_MUTEX
static void sanitize(struct shm_rdrbuff * rdrb)
{
--get_head_ptr(rdrb)->refs;
garbage_collect(rdrb);
pthread_mutex_consistent(rdrb->lock);
}
+#endif
static char * rdrb_filename(void)
{
@@ -171,7 +171,7 @@ static struct shm_rdrbuff * rdrb_create(int flags)
if (fd == -1)
goto fail_open;
- if ((flags & O_CREAT) && ftruncate(fd, SHM_FILE_SIZE - 1) < 0)
+ if ((flags & O_CREAT) && ftruncate(fd, SHM_FILE_SIZE) < 0)
goto fail_truncate;
shm_base = mmap(NULL, SHM_FILE_SIZE, MM_FLAGS, MAP_SHARED, fd, 0);
@@ -203,7 +203,7 @@ static struct shm_rdrbuff * rdrb_create(int flags)
return NULL;
}
-struct shm_rdrbuff * shm_rdrbuff_create()
+struct shm_rdrbuff * shm_rdrbuff_create(void)
{
struct shm_rdrbuff * rdrb;
mode_t mask;
@@ -261,7 +261,7 @@ struct shm_rdrbuff * shm_rdrbuff_create()
return NULL;
}
-struct shm_rdrbuff * shm_rdrbuff_open()
+struct shm_rdrbuff * shm_rdrbuff_open(void)
{
return rdrb_create(O_RDWR);
}
@@ -390,8 +390,7 @@ ssize_t shm_rdrbuff_alloc_b(struct shm_rdrbuff * rdrb,
if (pthread_mutex_lock(rdrb->lock) == EOWNERDEAD)
sanitize(rdrb);
#endif
- pthread_cleanup_push((void (*) (void *)) pthread_mutex_unlock,
- (void *) rdrb->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, rdrb->lock);
#ifdef SHM_RDRB_MULTI_BLOCK
if (blocks + *rdrb->head > (SHM_BUFFER_SIZE))
@@ -401,13 +400,7 @@ ssize_t shm_rdrbuff_alloc_b(struct shm_rdrbuff * rdrb,
#else
while (!shm_rdrb_free(rdrb, 1) && ret != ETIMEDOUT) {
#endif
- if (abstime != NULL)
- ret = pthread_cond_timedwait(rdrb->healthy,
- rdrb->lock,
- abstime);
- else
- ret = pthread_cond_wait(rdrb->healthy, rdrb->lock);
-
+ ret = __timedwait(rdrb->healthy, rdrb->lock, abstime);
#ifdef SHM_RDRB_MULTI_BLOCK
if (blocks + *rdrb->head > (SHM_BUFFER_SIZE))
padblocks = (SHM_BUFFER_SIZE) - *rdrb->head;
@@ -495,7 +488,7 @@ int shm_rdrbuff_remove(struct shm_rdrbuff * rdrb,
if (pthread_mutex_lock(rdrb->lock) == EOWNERDEAD)
sanitize(rdrb);
#endif
- assert(!shm_rdrb_empty(rdrb));
+ /* assert(!shm_rdrb_empty(rdrb)); */
sdb = idx_to_du_buff_ptr(rdrb, idx);
@@ -531,6 +524,13 @@ uint8_t * shm_du_buff_tail(struct shm_du_buff * sdb)
return (uint8_t *) (sdb + 1) + sdb->du_tail;
}
+size_t shm_du_buff_len(struct shm_du_buff * sdb)
+{
+ assert(sdb);
+
+ return sdb->du_tail - sdb->du_head;
+}
+
uint8_t * shm_du_buff_head_alloc(struct shm_du_buff * sdb,
size_t size)
{
@@ -577,7 +577,7 @@ uint8_t * shm_du_buff_head_release(struct shm_du_buff * sdb,
}
uint8_t * shm_du_buff_tail_release(struct shm_du_buff * sdb,
- size_t size)
+ size_t size)
{
assert(sdb);
assert(!(size > sdb->du_tail - sdb->du_head));
diff --git a/src/lib/sockets.c b/src/lib/sockets.c
index f25ee2ce..13219db0 100644
--- a/src/lib/sockets.c
+++ b/src/lib/sockets.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* The sockets layer to communicate between daemons
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -21,6 +21,7 @@
*/
#include <ouroboros/errno.h>
+#include <ouroboros/pthread.h>
#include <ouroboros/sockets.h>
#include <ouroboros/utils.h>
@@ -29,9 +30,7 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include <pthread.h>
#include <stdbool.h>
-#include <sys/time.h>
/* Apple doesn't support SEQPACKET. */
#ifdef __APPLE__
@@ -40,6 +39,11 @@
#define SOCK_TYPE SOCK_SEQPACKET
#endif
+void __cleanup_close_ptr(void * fd)
+{
+ close(*(int *) fd);
+}
+
int client_socket_open(char * file_name)
{
int sockfd;
@@ -52,8 +56,7 @@ int client_socket_open(char * file_name)
serv_addr.sun_family = AF_UNIX;
sprintf(serv_addr.sun_path, "%s", file_name);
- if (connect(sockfd,
- (struct sockaddr *) &serv_addr,
+ if (connect(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr))) {
close(sockfd);
return -1;
@@ -95,17 +98,11 @@ int server_socket_open(char * file_name)
return sockfd;
}
-static void close_ptr(void * o)
-{
- close(*(int *) o);
-}
-
irm_msg_t * send_recv_irm_msg(irm_msg_t * msg)
{
- int sockfd;
- uint8_t buf[SOCK_BUF_SIZE];
- ssize_t len;
- irm_msg_t * recv_msg = NULL;
+ int sockfd;
+ uint8_t buf[SOCK_BUF_SIZE];
+ ssize_t len;
sockfd = client_socket_open(IRM_SOCK_PATH);
if (sockfd < 0)
@@ -117,19 +114,44 @@ irm_msg_t * send_recv_irm_msg(irm_msg_t * msg)
return NULL;
}
- pthread_cleanup_push(close_ptr, &sockfd);
-
irm_msg__pack(msg, buf);
- if (write(sockfd, buf, len) != -1)
+ pthread_cleanup_push(__cleanup_close_ptr, &sockfd);
+
+ len = write(sockfd, buf, len);
+ if (len >= 0)
len = read(sockfd, buf, SOCK_BUF_SIZE);
- if (len > 0)
- recv_msg = irm_msg__unpack(NULL, len, buf);
+ pthread_cleanup_pop(true);
+
+ if (len < 0)
+ goto fail;
+
+ return irm_msg__unpack(NULL, len, buf);
+ fail:
+ return NULL;
+}
+
+int send_recv_msg(buffer_t * msg)
+{
+ int sockfd;
+ ssize_t len = 0;
+
+ sockfd = client_socket_open(IRM_SOCK_PATH);
+ if (sockfd < 0)
+ return -1;
+
+ pthread_cleanup_push(__cleanup_close_ptr, &sockfd);
+
+ len = write(sockfd, msg->data, msg->len);
+ if (len >= 0)
+ len = read(sockfd, msg->data, SOCK_BUF_SIZE);
pthread_cleanup_pop(true);
- return recv_msg;
+ msg->len = (size_t) len;
+
+ return len < 0 ? -1 : 0;
}
char * ipcp_sock_path(pid_t pid)
@@ -165,40 +187,3 @@ char * ipcp_sock_path(pid_t pid)
return full_name;
}
-
-qosspec_msg_t spec_to_msg(const qosspec_t * qs)
-{
- qosspec_t spec;
- qosspec_msg_t msg = QOSSPEC_MSG__INIT;
-
- spec = (qs == NULL ? qos_raw : *qs);
-
- msg.delay = spec.delay;
- msg.bandwidth = spec.bandwidth;
- msg.availability = spec.availability;
- msg.loss = spec.loss;
- msg.ber = spec.ber;
- msg.in_order = spec.in_order;
- msg.max_gap = spec.max_gap;
- msg.cypher_s = spec.cypher_s;
-
- return msg;
-}
-
-qosspec_t msg_to_spec(const qosspec_msg_t * msg)
-{
- qosspec_t spec;
-
- assert(msg);
-
- spec.delay = msg->delay;
- spec.bandwidth = msg->bandwidth;
- spec.availability = msg->availability;
- spec.loss = msg->loss;
- spec.ber = msg->ber;
- spec.in_order = msg->in_order;
- spec.max_gap = msg->max_gap;
- spec.cypher_s = msg->cypher_s;
-
- return spec;
-}
diff --git a/src/lib/tests/CMakeLists.txt b/src/lib/tests/CMakeLists.txt
index 9e23b0ee..dc90671b 100644
--- a/src/lib/tests/CMakeLists.txt
+++ b/src/lib/tests/CMakeLists.txt
@@ -6,10 +6,11 @@ create_test_sourcelist(${PARENT_DIR}_tests test_suite.c
bitmap_test.c
btree_test.c
crc32_test.c
+ hash_test.c
md5_test.c
sha3_test.c
shm_rbuff_test.c
- time_utils_test.c
+ time_test.c
)
add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests})
@@ -19,7 +20,11 @@ target_link_libraries(${PARENT_DIR}_test ouroboros-common)
add_dependencies(check ${PARENT_DIR}_test)
set(tests_to_run ${${PARENT_DIR}_tests})
-remove(tests_to_run test_suite.c)
+if(CMAKE_VERSION VERSION_LESS "3.29.0")
+ remove(tests_to_run test_suite.c)
+else ()
+ list(POP_FRONT tests_to_run)
+endif()
foreach (test ${tests_to_run})
get_filename_component(test_name ${test} NAME_WE)
diff --git a/src/lib/tests/bitmap_test.c b/src/lib/tests/bitmap_test.c
index fdacdce8..4dbd6653 100644
--- a/src/lib/tests/bitmap_test.c
+++ b/src/lib/tests/bitmap_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the bitmap
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -27,7 +27,8 @@
#define BITMAP_SIZE 200
-int bitmap_test(int argc, char ** argv)
+int bitmap_test(int argc,
+ char ** argv)
{
struct bmp * bmp;
ssize_t bits = BITMAP_SIZE;
@@ -60,27 +61,23 @@ int bitmap_test(int argc, char ** argv)
if (!bmp_is_id_valid(bmp, id)) {
if (i < BITMAP_SIZE + offset) {
printf("Failed valid ID %d (%zd).\n", i, id);
- bmp_destroy(bmp);
- return -1;
+ goto fail;
}
if (id >= offset && id < bits + offset) {
printf("Valid ID %zd returned invalid.\n", id);
- bmp_destroy(bmp);
- return -1;
+ goto fail;
}
continue;
}
if (!bmp_is_id_used(bmp, id)) {
printf("ID not marked in use.\n");
- bmp_destroy(bmp);
- return -1;
+ goto fail;
}
if (id != i) {
printf("Wrong ID returned.\n");
- bmp_destroy(bmp);
- return -1;
+ goto fail;
}
}
@@ -89,20 +86,24 @@ int bitmap_test(int argc, char ** argv)
if (bmp_release(bmp, r)) {
printf("Failed to release ID.\n");
- return -1;
+ goto fail;
}
id = bmp_allocate(bmp);
if (!bmp_is_id_valid(bmp, id))
continue;
+
if (id != r) {
printf("Wrong prev ID returned.\n");
- bmp_destroy(bmp);
- return -1;
+ goto fail;
}
}
bmp_destroy(bmp);
return 0;
+
+ fail:
+ bmp_destroy(bmp);
+ return -1;
}
diff --git a/src/lib/tests/btree_test.c b/src/lib/tests/btree_test.c
index 00b3cde1..8bd30370 100644
--- a/src/lib/tests/btree_test.c
+++ b/src/lib/tests/btree_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the B-tree implementation
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/lib/tests/crc32_test.c b/src/lib/tests/crc32_test.c
index 35f8a1cd..a26c8220 100644
--- a/src/lib/tests/crc32_test.c
+++ b/src/lib/tests/crc32_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the CRC32 function
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/lib/tests/hash_test.c b/src/lib/tests/hash_test.c
new file mode 100644
index 00000000..970d9185
--- /dev/null
+++ b/src/lib/tests/hash_test.c
@@ -0,0 +1,202 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Test of the hashing functions
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include <ouroboros/hash.h>
+#include <ouroboros/test.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Test vectors calculated at
+ * https://www.lammertbies.nl/comm/info/crc-calculation.html
+ */
+
+struct vec_entry {
+ char * in;
+ char * out;
+};
+
+static int test_crc32(void)
+{
+ int ret = 0;
+
+ struct vec_entry vec [] = {
+ { "0", "f4dbdf21" },
+ { "123456789", "cbf43926" },
+ { "987654321", "015f0201" },
+ { NULL, NULL }
+ };
+
+ struct vec_entry * cur = vec;
+
+ TEST_START();
+
+ while (cur->in != NULL) {
+ uint8_t crc[4];
+ char res[9];
+
+ str_hash(HASH_CRC32, crc, cur->in);
+
+ sprintf(res, HASH_FMT32, HASH_VAL32(crc));
+ if (strcmp(res, cur->out) != 0) {
+ printf("Hash failed %s != %s.\n", res, cur->out);
+ ret |= -1;
+ }
+
+ ++cur;
+ }
+
+ TEST_END(ret);
+
+ return ret;
+}
+
+static int test_md5(void)
+{
+ int ret = 0;
+
+ struct vec_entry vec [] = {{
+ "abc",
+ "900150983cd24fb0d6963f7d28e17f72"
+ }, {
+ "The quick brown fox jumps over the lazy dog",
+ "9e107d9d372bb6826bd81d3542a419d6"
+ }, {
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "8215ef0796a20bcaaae116d3876c664a"
+ }, {
+ NULL,
+ NULL
+ }};
+
+ struct vec_entry * cur = vec;
+
+ TEST_START();
+
+
+ while (cur->in != NULL) {
+ uint8_t md5[16];
+ char res[33];
+
+ str_hash(HASH_MD5, md5, cur->in);
+
+ sprintf(res, HASH_FMT128, HASH_VAL128(md5));
+ if (strcmp(res, cur->out) != 0) {
+ printf("Hash failed %s != %s.\n", res, cur->out);
+ ret |= -1;
+ }
+
+ ++cur;
+ }
+
+ TEST_END(ret);
+
+ return ret;
+}
+
+static int test_sha3(void)
+{
+ int ret = 0;
+
+ uint8_t sha3[64];
+ char res[129];
+
+ char * in = "abc";
+
+ char * out =
+ "e642824c3f8cf24ad09234ee7d3c766f"
+ "c9a3a5168d0c94ad73b46fdf";
+
+ TEST_START();
+
+ str_hash(HASH_SHA3_224, sha3, in);
+
+ sprintf(res, HASH_FMT224, HASH_VAL224(sha3));
+ if (strcmp(res, out) != 0) {
+ printf("SHA3-224 failed %s != %s", res, out);
+ ret |= -1;
+ }
+
+ out =
+ "3a985da74fe225b2045c172d6bd390bd"
+ "855f086e3e9d525b46bfe24511431532";
+
+ str_hash(HASH_SHA3_256, sha3, in);
+
+ sprintf(res, HASH_FMT256, HASH_VAL256(sha3));
+ if (strcmp(res, out) != 0) {
+ printf("SHA3-256 failed %s != %s.\n", res, out);
+ ret |= -1;
+ }
+
+ out =
+ "ec01498288516fc926459f58e2c6ad8d"
+ "f9b473cb0fc08c2596da7cf0e49be4b2"
+ "98d88cea927ac7f539f1edf228376d25";
+
+ str_hash(HASH_SHA3_384, sha3, in);
+
+ sprintf(res, HASH_FMT384, HASH_VAL384(sha3));
+ if (strcmp(res, out) != 0) {
+ printf("SHA3-384failed %s != %s.'n", res, out);
+ ret |= -1;
+ }
+
+ out =
+ "b751850b1a57168a5693cd924b6b096e"
+ "08f621827444f70d884f5d0240d2712e"
+ "10e116e9192af3c91a7ec57647e39340"
+ "57340b4cf408d5a56592f8274eec53f0";
+
+ str_hash(HASH_SHA3_512, sha3, in);
+
+ sprintf(res, HASH_FMT512, HASH_VAL512(sha3));
+ if (strcmp(res, out) != 0) {
+ printf("SHA3-512 failed %s != %s.\n", res, out);
+ ret |= -1;
+ }
+
+ TEST_END(ret);
+
+ return ret;
+}
+
+int hash_test(int argc,
+ char ** argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_crc32();
+
+ ret |= test_md5();
+
+ ret |= test_sha3();
+
+ return ret;
+}
diff --git a/src/lib/tests/md5_test.c b/src/lib/tests/md5_test.c
index 00497ae7..28e8f42f 100644
--- a/src/lib/tests/md5_test.c
+++ b/src/lib/tests/md5_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the MD5 function
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/lib/tests/sha3_test.c b/src/lib/tests/sha3_test.c
index 945402ee..82b4ef0d 100644
--- a/src/lib/tests/sha3_test.c
+++ b/src/lib/tests/sha3_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the SHA3 function
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/lib/tests/shm_rbuff_test.c b/src/lib/tests/shm_rbuff_test.c
index 1d16a09d..e36c3229 100644
--- a/src/lib/tests/shm_rbuff_test.c
+++ b/src/lib/tests/shm_rbuff_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the shm_rbuff
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/lib/tests/time_utils_test.c b/src/lib/tests/time_test.c
index c384d272..65f896bb 100644
--- a/src/lib/tests/time_utils_test.c
+++ b/src/lib/tests/time_test.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Test of the time utilities
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,7 +22,7 @@
#define _POSIX_C_SOURCE 200809L
-#include <ouroboros/time_utils.h>
+#include <ouroboros/time.h>
#include <stdio.h>
@@ -66,8 +66,8 @@ static int tv_check(struct timeval * v,
return v->tv_sec == sec && v->tv_usec == usec;
}
-int time_utils_test(int argc,
- char ** argv)
+int time_test(int argc,
+ char ** argv)
{
struct timespec s0;
struct timespec s1;
diff --git a/src/lib/timerwheel.c b/src/lib/timerwheel.c
new file mode 100644
index 00000000..96f4ac47
--- /dev/null
+++ b/src/lib/timerwheel.c
@@ -0,0 +1,414 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Timerwheel
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include <ouroboros/list.h>
+
+/* Overflow limits range to about 6 hours. */
+#define ts_to_ns(ts) (ts.tv_sec * BILLION + ts.tv_nsec)
+#define ts_to_rxm_slot(ts) (ts_to_ns(ts) >> RXMQ_RES)
+#define ts_to_ack_slot(ts) (ts_to_ns(ts) >> ACKQ_RES)
+
+struct rxm {
+ struct list_head next;
+ uint32_t seqno;
+#ifndef RXM_BUFFER_ON_HEAP
+ struct shm_du_buff * sdb;
+#endif
+ struct frct_pci * pkt;
+ size_t len;
+ time_t t0; /* Time when original was sent (us). */
+ struct frcti * frcti;
+ int fd;
+ int flow_id; /* Prevent rtx when fd reused. */
+};
+
+struct ack {
+ struct list_head next;
+ struct frcti * frcti;
+ int fd;
+ int flow_id;
+};
+
+struct {
+ /*
+ * At a 1 ms min resolution, every level bumps the
+ * resolution by a factor of 16.
+ */
+ struct list_head rxms[RXMQ_LVLS][RXMQ_SLOTS];
+
+ struct list_head acks[ACKQ_SLOTS];
+ bool map[ACKQ_SLOTS][PROG_MAX_FLOWS];
+
+ size_t prv_rxm[RXMQ_LVLS]; /* Last processed rxm slots. */
+ size_t prv_ack; /* Last processed ack slot. */
+ pthread_mutex_t lock;
+} rw;
+
+static void timerwheel_fini(void)
+{
+ size_t i;
+ size_t j;
+ struct list_head * p;
+ struct list_head * h;
+
+ pthread_mutex_lock(&rw.lock);
+
+ for (i = 0; i < RXMQ_LVLS; ++i) {
+ for (j = 0; j < RXMQ_SLOTS; j++) {
+ list_for_each_safe(p, h, &rw.rxms[i][j]) {
+ struct rxm * rxm;
+ rxm = list_entry(p, struct rxm, next);
+ list_del(&rxm->next);
+#ifdef RXM_BUFFER_ON_HEAP
+ free(rxm->pkt);
+#else
+ shm_du_buff_ack(rxm->sdb);
+ ipcp_sdb_release(rxm->sdb);
+#endif
+ free(rxm);
+ }
+ }
+ }
+
+ for (i = 0; i < ACKQ_SLOTS; ++i) {
+ list_for_each_safe(p, h, &rw.acks[i]) {
+ struct ack * a = list_entry(p, struct ack, next);
+ list_del(&a->next);
+ free(a);
+ }
+ }
+
+ pthread_mutex_unlock(&rw.lock);
+
+ pthread_mutex_destroy(&rw.lock);
+}
+
+static int timerwheel_init(void)
+{
+ struct timespec now;
+ size_t i;
+ size_t j;
+
+ if (pthread_mutex_init(&rw.lock, NULL))
+ return -1;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ for (i = 0; i < RXMQ_LVLS; ++i) {
+ rw.prv_rxm[i] = (ts_to_rxm_slot(now) - 1);
+ rw.prv_rxm[i] >>= (RXMQ_BUMP * i);
+ rw.prv_rxm[i] &= (RXMQ_SLOTS - 1);
+ for (j = 0; j < RXMQ_SLOTS; ++j)
+ list_head_init(&rw.rxms[i][j]);
+ }
+
+ rw.prv_ack = (ts_to_ack_slot(now) - 1) & (ACKQ_SLOTS - 1);
+ for (i = 0; i < ACKQ_SLOTS; ++i)
+ list_head_init(&rw.acks[i]);
+
+ return 0;
+}
+
+static void timerwheel_move(void)
+{
+ struct timespec now;
+ struct list_head * p;
+ struct list_head * h;
+ size_t rxm_slot;
+ size_t ack_slot;
+ size_t i;
+ size_t j;
+
+ pthread_mutex_lock(&rw.lock);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &rw.lock);
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ rxm_slot = ts_to_rxm_slot(now);
+
+ for (i = 0; i < RXMQ_LVLS; ++i) {
+ size_t j_max_slot = rxm_slot & (RXMQ_SLOTS - 1);
+ j = rw.prv_rxm[i];
+ if (j_max_slot < j)
+ j_max_slot += RXMQ_SLOTS;
+ while (j++ < j_max_slot) {
+ list_for_each_safe(p, h,
+ &rw.rxms[i][j & (RXMQ_SLOTS - 1)]) {
+ struct rxm * r;
+ struct frct_cr * snd_cr;
+ struct frct_cr * rcv_cr;
+ size_t slot;
+ size_t rslot;
+ ssize_t idx;
+ struct shm_du_buff * sdb;
+ struct frct_pci * pci;
+ struct flow * f;
+ uint32_t snd_lwe;
+ uint32_t rcv_lwe;
+ size_t lvl = 0;
+
+ r = list_entry(p, struct rxm, next);
+
+ list_del(&r->next);
+
+ snd_cr = &r->frcti->snd_cr;
+ rcv_cr = &r->frcti->rcv_cr;
+ f = &ai.flows[r->fd];
+#ifndef RXM_BUFFER_ON_HEAP
+ shm_du_buff_ack(r->sdb);
+#endif
+ if (f->frcti == NULL
+ || f->info.id != r->flow_id)
+ goto cleanup;
+
+ pthread_rwlock_rdlock(&r->frcti->lock);
+
+ snd_lwe = snd_cr->lwe;
+ rcv_lwe = rcv_cr->lwe;
+
+ pthread_rwlock_unlock(&r->frcti->lock);
+
+ /* Has been ack'd, remove. */
+ if (before(r->seqno, snd_lwe))
+ goto cleanup;
+
+ /* Check for r-timer expiry. */
+ if (ts_to_ns(now) - r->t0 > r->frcti->r)
+ goto flow_down;
+
+ pthread_rwlock_wrlock(&r->frcti->lock);
+
+ if (r->seqno == r->frcti->rttseq) {
+ r->frcti->rto +=
+ r->frcti->rto >> RTO_DIV;
+ r->frcti->probe = false;
+ }
+#ifdef PROC_FLOW_STATS
+ r->frcti->n_rtx++;
+#endif
+ rslot = r->frcti->rto >> RXMQ_RES;
+
+ pthread_rwlock_unlock(&r->frcti->lock);
+
+ /* Schedule at least in the next time slot. */
+ slot = ts_to_ns(now) >> RXMQ_RES;
+
+ while (rslot >= RXMQ_SLOTS) {
+ ++lvl;
+ rslot >>= RXMQ_BUMP;
+ slot >>= RXMQ_BUMP;
+ }
+
+ if (lvl >= RXMQ_LVLS) /* Can't reschedule */
+ goto flow_down;
+
+ rslot = (rslot + slot + 1) & (RXMQ_SLOTS - 1);
+#ifdef RXM_BLOCKING
+ if (ipcp_sdb_reserve(&sdb, r->len) < 0)
+#else
+ if (shm_rdrbuff_alloc(ai.rdrb, r->len, NULL,
+ &sdb) < 0)
+#endif
+ goto reschedule; /* rdrbuff full */
+
+ pci = (struct frct_pci *) shm_du_buff_head(sdb);
+ memcpy(pci, r->pkt, r->len);
+#ifndef RXM_BUFFER_ON_HEAP
+ ipcp_sdb_release(r->sdb);
+ r->sdb = sdb;
+ r->pkt = pci;
+ shm_du_buff_wait_ack(sdb);
+#endif
+ idx = shm_du_buff_get_idx(sdb);
+
+ /* Retransmit the copy. */
+ pci->ackno = hton32(rcv_lwe);
+#ifdef RXM_BLOCKING
+ if (shm_rbuff_write_b(f->tx_rb, idx, NULL) < 0)
+#else
+ if (shm_rbuff_write(f->tx_rb, idx) < 0)
+#endif
+ goto flow_down;
+ shm_flow_set_notify(f->set, f->info.id,
+ FLOW_PKT);
+ reschedule:
+ list_add(&r->next, &rw.rxms[lvl][rslot]);
+ continue;
+
+ flow_down:
+ shm_rbuff_set_acl(f->tx_rb, ACL_FLOWDOWN);
+ shm_rbuff_set_acl(f->rx_rb, ACL_FLOWDOWN);
+ cleanup:
+#ifdef RXM_BUFFER_ON_HEAP
+ free(r->pkt);
+#else
+ ipcp_sdb_release(r->sdb);
+#endif
+ free(r);
+ }
+ }
+ rw.prv_rxm[i] = rxm_slot & (RXMQ_SLOTS - 1);
+ /* Move up a level in the wheel. */
+ rxm_slot >>= RXMQ_BUMP;
+ }
+
+ ack_slot = ts_to_ack_slot(now) & (ACKQ_SLOTS - 1) ;
+
+ j = rw.prv_ack;
+
+ if (ack_slot < j)
+ ack_slot += ACKQ_SLOTS;
+
+ while (j++ < ack_slot) {
+ list_for_each_safe(p, h, &rw.acks[j & (ACKQ_SLOTS - 1)]) {
+ struct ack * a;
+ struct flow * f;
+
+ a = list_entry(p, struct ack, next);
+
+ list_del(&a->next);
+
+ f = &ai.flows[a->fd];
+
+ rw.map[j & (ACKQ_SLOTS - 1)][a->fd] = false;
+
+ if (f->info.id == a->flow_id && f->frcti != NULL)
+ send_frct_pkt(a->frcti);
+
+ free(a);
+ }
+ }
+
+ rw.prv_ack = ack_slot & (ACKQ_SLOTS - 1);
+
+ pthread_cleanup_pop(true);
+}
+
+static int timerwheel_rxm(struct frcti * frcti,
+ uint32_t seqno,
+ struct shm_du_buff * sdb)
+{
+ struct timespec now;
+ struct rxm * r;
+ size_t slot;
+ size_t lvl = 0;
+ time_t rto_slot;
+
+ r = malloc(sizeof(*r));
+ if (r == NULL)
+ return -ENOMEM;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ r->t0 = ts_to_ns(now);
+ r->seqno = seqno;
+ r->frcti = frcti;
+ r->len = shm_du_buff_len(sdb);
+#ifdef RXM_BUFFER_ON_HEAP
+ r->pkt = malloc(r->len);
+ if (r->pkt == NULL) {
+ free(r);
+ return -ENOMEM;
+ }
+ memcpy(r->pkt, shm_du_buff_head(sdb), r->len);
+#else
+ r->sdb = sdb;
+ r->pkt = (struct frct_pci *) shm_du_buff_head(sdb);
+#endif
+ pthread_rwlock_rdlock(&r->frcti->lock);
+
+ rto_slot = frcti->rto >> RXMQ_RES;
+ slot = r->t0 >> RXMQ_RES;
+
+ r->fd = frcti->fd;
+ r->flow_id = ai.flows[r->fd].info.id;
+
+ pthread_rwlock_unlock(&r->frcti->lock);
+
+ while (rto_slot >= RXMQ_SLOTS) {
+ ++lvl;
+ rto_slot >>= RXMQ_BUMP;
+ slot >>= RXMQ_BUMP;
+ }
+
+ if (lvl >= RXMQ_LVLS) { /* Out of timerwheel range. */
+#ifdef RXM_BUFFER_ON_HEAP
+ free(r->pkt);
+#endif
+ free(r);
+ return -EPERM;
+ }
+
+ slot = (slot + rto_slot + 1) & (RXMQ_SLOTS - 1);
+
+ pthread_mutex_lock(&rw.lock);
+
+ list_add_tail(&r->next, &rw.rxms[lvl][slot]);
+#ifndef RXM_BUFFER_ON_HEAP
+ shm_du_buff_wait_ack(sdb);
+#endif
+ pthread_mutex_unlock(&rw.lock);
+
+ return 0;
+}
+
+static int timerwheel_delayed_ack(int fd,
+ struct frcti * frcti)
+{
+ struct timespec now;
+ struct ack * a;
+ size_t slot;
+
+ a = malloc(sizeof(*a));
+ if (a == NULL)
+ return -ENOMEM;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
+
+ pthread_rwlock_rdlock(&frcti->lock);
+
+ slot = (((ts_to_ns(now) + (TICTIME << 1)) >> ACKQ_RES) + 1)
+ & (ACKQ_SLOTS - 1);
+
+ pthread_rwlock_unlock(&frcti->lock);
+
+ a->fd = fd;
+ a->frcti = frcti;
+ a->flow_id = ai.flows[fd].info.id;
+
+ pthread_mutex_lock(&rw.lock);
+
+ if (rw.map[slot][fd]) {
+ pthread_mutex_unlock(&rw.lock);
+ free(a);
+ return 0;
+ }
+
+ rw.map[slot][fd] = true;
+
+ list_add_tail(&a->next, &rw.acks[slot]);
+
+ pthread_mutex_unlock(&rw.lock);
+
+ return 0;
+}
diff --git a/src/lib/tpm.c b/src/lib/tpm.c
index ff0a22df..0ef1fda8 100644
--- a/src/lib/tpm.c
+++ b/src/lib/tpm.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Threadpool management
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -26,12 +26,12 @@
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/time.h>
#include <ouroboros/tpm.h>
+#include <assert.h>
#include <pthread.h>
#include <stdlib.h>
-#include <assert.h>
#define TPM_TIMEOUT 1000
@@ -117,8 +117,7 @@ static void tpm_kill(struct tpm * tpm)
static void * tpmgr(void * o)
{
struct timespec dl;
- struct timespec to = {(TPM_TIMEOUT / 1000),
- (TPM_TIMEOUT % 1000) * MILLION};
+ struct timespec to = TIMESPEC_INIT_MS(TPM_TIMEOUT);
struct tpm * tpm = (struct tpm *) o;
while (true) {
@@ -239,12 +238,12 @@ void tpm_stop(struct tpm * tpm)
tpm->state = TPM_NULL;
pthread_mutex_unlock(&tpm->lock);
+
+ pthread_join(tpm->mgr, NULL);
}
void tpm_destroy(struct tpm * tpm)
{
- pthread_join(tpm->mgr, NULL);
-
pthread_mutex_destroy(&tpm->lock);
pthread_cond_destroy(&tpm->cond);
diff --git a/src/lib/utils.c b/src/lib/utils.c
index e3024283..fdbcd9d9 100644
--- a/src/lib/utils.c
+++ b/src/lib/utils.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Handy utilities
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -20,6 +20,10 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
+#define _POSIX_C_SOURCE 200809L
+
+#include <ouroboros/utils.h>
+
#include <stdlib.h>
#include <string.h>
@@ -35,14 +39,14 @@ int n_digits(unsigned i)
return n;
}
-char * path_strip(char * src)
+char * path_strip(const char * src)
{
- char * dst = NULL;
+ char * dst;
if (src == NULL)
return NULL;
- dst = src + strlen(src);
+ dst = (char *) src + strlen(src);
while (dst > src && *dst != '/')
--dst;
@@ -52,3 +56,58 @@ char * path_strip(char * src)
return dst;
}
+
+size_t argvlen(const char ** argv)
+{
+ size_t argc = 0;
+
+ if (argv == NULL)
+ return 0;
+
+ while (*argv++ != NULL)
+ argc++;
+
+ return argc;
+}
+
+void argvfree(char ** argv)
+{
+ char ** argv_dup;
+
+ if (argv == NULL)
+ return;
+
+ argv_dup = argv;
+ while (*argv_dup != NULL)
+ free(*(argv_dup++));
+
+ free(argv);
+}
+
+char ** argvdup(char ** argv)
+{
+ int argc = 0;
+ char ** argv_dup = argv;
+ int i;
+
+ if (argv == NULL)
+ return NULL;
+
+ while (*(argv_dup++) != NULL)
+ argc++;
+
+ argv_dup = malloc((argc + 1) * sizeof(*argv_dup));
+ if (argv_dup == NULL)
+ return NULL;
+
+ for (i = 0; i < argc; ++i) {
+ argv_dup[i] = strdup(argv[i]);
+ if (argv_dup[i] == NULL) {
+ argvfree(argv_dup);
+ return NULL;
+ }
+ }
+
+ argv_dup[argc] = NULL;
+ return argv_dup;
+}
diff --git a/src/tools/irm/irm.c b/src/tools/irm/irm.c
index 2388bfd9..ba0f4713 100644
--- a/src/tools/irm/irm.c
+++ b/src/tools/irm/irm.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* A tool to instruct the IRM daemon
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -49,7 +49,7 @@
static void usage(void)
{
printf("Usage: irm [OPERATION]\n\n"
- "where OPERATION = {ipcp bind unbind name}\n");
+ "where OPERATION in { ipcp bind unbind name }\n");
}
static int do_help(int argc,
diff --git a/src/tools/irm/irm_bind.c b/src/tools/irm/irm_bind.c
index 2715b48e..2e8b14ef 100644
--- a/src/tools/irm/irm_bind.c
+++ b/src/tools/irm/irm_bind.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Bind names in the processing system
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -47,7 +47,7 @@ static void usage(void)
{
printf("Usage: irm bind [OPERATION]\n"
"\n"
- "where OPERATION = {program process ipcp help}\n");
+ "where OPERATION in {program process ipcp help}\n");
}
static int do_help(int argc,
diff --git a/src/tools/irm/irm_bind_ipcp.c b/src/tools/irm/irm_bind_ipcp.c
index 4f3f11b2..7d5dd636 100644
--- a/src/tools/irm/irm_bind_ipcp.c
+++ b/src/tools/irm/irm_bind_ipcp.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Bind IPCP Instance to a name
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -55,11 +55,11 @@ static void usage(void)
int do_bind_ipcp(int argc,
char ** argv)
{
- char * ipcp = NULL;
- char * name = NULL;
- struct ipcp_info * ipcps;
- ssize_t len;
- ssize_t i;
+ char * ipcp = NULL;
+ char * name = NULL;
+ struct ipcp_list_info * ipcps;
+ ssize_t len;
+ ssize_t i;
while (argc > 0) {
if (matches(*argv, "name") == 0) {
diff --git a/src/tools/irm/irm_bind_process.c b/src/tools/irm/irm_bind_process.c
index a45942b0..fffd5fe9 100644
--- a/src/tools/irm/irm_bind_process.c
+++ b/src/tools/irm/irm_bind_process.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Bind a process to a name
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/irm/irm_bind_program.c b/src/tools/irm/irm_bind_program.c
index 7c62f6a1..8a0dc33c 100644
--- a/src/tools/irm/irm_bind_program.c
+++ b/src/tools/irm/irm_bind_program.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Bind programs to a name
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/irm/irm_ipcp.c b/src/tools/irm/irm_ipcp.c
index 12e79c29..63e617d9 100644
--- a/src/tools/irm/irm_ipcp.c
+++ b/src/tools/irm/irm_ipcp.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* A tool to instruct the IRM daemon
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -44,10 +44,11 @@
static void usage(void)
{
printf("Usage: irm ipcp [OPERATION]\n\n"
- "where OPERATION = {create destroy\n"
- " bootstrap enroll\n"
- " connect disconnect\n"
- " list help}\n");
+ "where OPERATION in {create destroy\n"
+ " bootstrap enroll\n"
+ " connect disconnect\n"
+ " list\n"
+ " help}\n");
}
static int do_help(int argc, char **argv)
diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c
index 84b6759a..b8e5c54d 100644
--- a/src/tools/irm/irm_ipcp_bootstrap.c
+++ b/src/tools/irm/irm_ipcp_bootstrap.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Bootstrap IPC Processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -50,13 +50,12 @@
#include <sys/socket.h>
#endif
-#define UNICAST "unicast"
+#define UNICAST "unicast"
#define BROADCAST "broadcast"
#define UDP "udp"
#define ETH_LLC "eth-llc"
#define ETH_DIX "eth-dix"
#define LOCAL "local"
-#define RAPTOR "raptor"
#define MD5 "MD5"
#define SHA3_224 "SHA3_224"
@@ -65,20 +64,22 @@
#define SHA3_512 "SHA3_512"
#define DEFAULT_ADDR_SIZE 4
-#define DEFAULT_EID_SIZE 2
+#define DEFAULT_EID_SIZE 8
#define DEFAULT_DDNS 0
#define DEFAULT_TTL 60
#define DEFAULT_ADDR_AUTH ADDR_AUTH_FLAT_RANDOM
#define DEFAULT_ROUTING ROUTING_LINK_STATE
+#define DEFAULT_CONG_AVOID CA_MB_ECN
#define DEFAULT_HASH_ALGO DIR_HASH_SHA3_256
#define DEFAULT_ETHERTYPE 0xA000
-#define DEFAULT_CLIENT_PORT 0x0000 /* random port */
-#define DEFAULT_SERVER_PORT 0x0D6B /* 3435 */
+#define DEFAULT_UDP_PORT 0x0D6B /* 3435 */
#define FLAT_RANDOM_ADDR_AUTH "flat"
#define LINK_STATE_ROUTING "link_state"
#define LINK_STATE_LFA_ROUTING "lfa"
#define LINK_STATE_ECM_ROUTING "ecmp"
+#define NONE_CA "none"
+#define MB_ECN_CA "mb-ecn"
static void usage(void)
{
@@ -87,80 +88,77 @@ static void usage(void)
" name <ipcp name>\n"
" layer <layer name>\n"
" [type [TYPE]]\n"
- "where TYPE = {" UNICAST " " BROADCAST " " LOCAL " "
- UDP " " ETH_LLC " " ETH_DIX " " RAPTOR "},\n\n"
+ "where TYPE in {" UNICAST " " BROADCAST " " LOCAL " "
+ UDP " " ETH_LLC " " ETH_DIX "},\n\n"
"if TYPE == " UNICAST "\n"
" [addr <address size> (default: %d)]\n"
" [eid <eid size> (default: %d)]\n"
" [ttl (max time-to-live value, default: %d)]\n"
" [addr_auth <ADDRESS_POLICY> (default: %s)]\n"
" [routing <ROUTING_POLICY> (default: %s)]\n"
+ " [congestion <CONG_POLICY> (default: %s)]\n"
" [hash [ALGORITHM] (default: %s)]\n"
" [autobind]\n"
- "where ADDRESS_POLICY = {"FLAT_RANDOM_ADDR_AUTH"}\n"
- " ROUTING_POLICY = {"LINK_STATE_ROUTING " "
+ "where ADDRESS_POLICY in {" FLAT_RANDOM_ADDR_AUTH "}\n"
+ " ROUTING_POLICY in {" LINK_STATE_ROUTING " "
LINK_STATE_LFA_ROUTING " " LINK_STATE_ECM_ROUTING "}\n"
- " ALGORITHM = {" SHA3_224 " " SHA3_256 " "
+ " CONG_POLICY in {" NONE_CA " " MB_ECN_CA "}\n"
+ " ALGORITHM in {" SHA3_224 " " SHA3_256 " "
SHA3_384 " " SHA3_512 "}\n\n"
"if TYPE == " UDP "\n"
" ip <IP address in dotted notation>\n"
- " [cport <client port> (default: random)]\n"
- " [sport <server port> (default: %d)]\n"
+ " [port <UDP port> (default: %d)]\n"
" [dns <DDNS IP address in dotted notation>"
" (default: none)]\n\n"
"if TYPE == " ETH_LLC "\n"
" dev <interface name>\n"
" [hash [ALGORITHM] (default: %s)]\n"
- "where ALGORITHM = {" SHA3_224 " " SHA3_256 " "
+ "where ALGORITHM in {" SHA3_224 " " SHA3_256 " "
SHA3_384 " " SHA3_512 "}\n\n"
"if TYPE == " ETH_DIX "\n"
" dev <interface name>\n"
" [ethertype <ethertype> (default: 0x%4X)]\n"
" [hash [ALGORITHM] (default: %s)]\n"
- "where ALGORITHM = {" SHA3_224 " " SHA3_256 " "
+ "where ALGORITHM in {" SHA3_224 " " SHA3_256 " "
SHA3_384 " " SHA3_512 "}\n\n"
"if TYPE == " LOCAL "\n"
" [hash [ALGORITHM] (default: %s)]\n"
- "where ALGORITHM = {" SHA3_224 " " SHA3_256 " "
- SHA3_384 " " SHA3_512 "}\n\n"
- "if TYPE == " RAPTOR "\n"
- " [hash [ALGORITHM] (default: %s)]\n"
- "where ALGORITHM = {" SHA3_224 " " SHA3_256 " "
+ "where ALGORITHM in {" SHA3_224 " " SHA3_256 " "
SHA3_384 " " SHA3_512 "}\n\n"
"if TYPE == " BROADCAST "\n"
" [autobind]\n\n",
DEFAULT_ADDR_SIZE, DEFAULT_EID_SIZE, DEFAULT_TTL,
- FLAT_RANDOM_ADDR_AUTH, LINK_STATE_ROUTING,
- SHA3_256, DEFAULT_SERVER_PORT, SHA3_256, 0xA000, SHA3_256,
- SHA3_256, SHA3_256);
+ FLAT_RANDOM_ADDR_AUTH, LINK_STATE_ROUTING, MB_ECN_CA,
+ SHA3_256, DEFAULT_UDP_PORT, SHA3_256, 0xA000, SHA3_256,
+ SHA3_256);
}
int do_bootstrap_ipcp(int argc,
char ** argv)
{
- char * ipcp = NULL;
- pid_t pid = -1;
- struct ipcp_config conf;
- uint8_t addr_size = DEFAULT_ADDR_SIZE;
- uint8_t eid_size = DEFAULT_EID_SIZE;
- uint8_t max_ttl = DEFAULT_TTL;
- enum pol_addr_auth addr_auth_type = DEFAULT_ADDR_AUTH;
- enum pol_routing routing_type = DEFAULT_ROUTING;
- enum pol_dir_hash hash_algo = DEFAULT_HASH_ALGO;
- uint32_t ip_addr = 0;
- uint32_t dns_addr = DEFAULT_DDNS;
- char * ipcp_type = NULL;
- enum ipcp_type type = IPCP_INVALID;
- char * layer = NULL;
- char * dev = NULL;
- uint16_t ethertype = DEFAULT_ETHERTYPE;
- struct ipcp_info * ipcps;
- ssize_t len = 0;
- int i = 0;
- bool autobind = false;
- int cargs;
- int cport = DEFAULT_CLIENT_PORT;
- int sport = DEFAULT_SERVER_PORT;
+ char * ipcp = NULL;
+ pid_t pid = -1;
+ struct ipcp_config conf;
+ uint8_t addr_size = DEFAULT_ADDR_SIZE;
+ uint8_t eid_size = DEFAULT_EID_SIZE;
+ uint8_t max_ttl = DEFAULT_TTL;
+ enum pol_addr_auth addr_auth_type = DEFAULT_ADDR_AUTH;
+ enum pol_routing routing_type = DEFAULT_ROUTING;
+ enum pol_dir_hash hash_algo = DEFAULT_HASH_ALGO;
+ enum pol_cong_avoid cong_avoid = DEFAULT_CONG_AVOID;
+ uint32_t ip_addr = 0;
+ uint32_t dns_addr = DEFAULT_DDNS;
+ char * ipcp_type = NULL;
+ enum ipcp_type type = IPCP_INVALID;
+ char * layer = NULL;
+ char * dev = NULL;
+ uint16_t ethertype = DEFAULT_ETHERTYPE;
+ struct ipcp_list_info * ipcps;
+ ssize_t len = 0;
+ int i = 0;
+ bool autobind = false;
+ int cargs;
+ int port = DEFAULT_UDP_PORT;
while (argc > 0) {
cargs = 2;
@@ -195,7 +193,7 @@ int do_bootstrap_ipcp(int argc,
ethertype = strtol(*(argv + 1), NULL, 0);
else
ethertype = strtol(*(argv + 1), NULL, 16);
- if (ethertype < 0x0600 || ethertype == 0xFFFF) {
+ if (ethertype < 0x0600 || ethertype >= 0xFFFF) {
printf("Invalid Ethertype: \"%s\".\n"
"Recommended range: 0xA000-0xEFFF.\n",
*(argv + 1));
@@ -207,10 +205,8 @@ int do_bootstrap_ipcp(int argc,
eid_size = atoi(*(argv + 1));
} else if (matches(*argv, "ttl") == 0) {
max_ttl = atoi(*(argv + 1));
- } else if (matches(*argv, "cport") == 0) {
- cport = atoi(*(argv + 1));
- } else if (matches(*argv, "sport") == 0) {
- sport = atoi(*(argv + 1));
+ } else if (matches(*argv, "port") == 0) {
+ port = atoi(*(argv + 1));
} else if (matches(*argv, "autobind") == 0) {
autobind = true;
cargs = 1;
@@ -230,6 +226,14 @@ int do_bootstrap_ipcp(int argc,
routing_type = ROUTING_LINK_STATE_ECMP;
else
goto unknown_param;
+ } else if (matches(*argv, "congestion") == 0) {
+ if (strcmp(NONE_CA, *(argv + 1)) == 0)
+ cong_avoid = CA_NONE;
+ else if (strcmp(MB_ECN_CA,
+ *(argv + 1)) == 0)
+ cong_avoid = CA_MB_ECN;
+ else
+ goto unknown_param;
} else {
printf("Unknown option: \"%s\".\n", *argv);
return -1;
@@ -265,8 +269,6 @@ int do_bootstrap_ipcp(int argc,
type = IPCP_ETH_DIX;
else if (strcmp(ipcp_type, LOCAL) == 0)
type = IPCP_LOCAL;
- else if (strcmp(ipcp_type, RAPTOR) == 0)
- type = IPCP_RAPTOR;
else goto fail_usage;
}
@@ -290,6 +292,7 @@ int do_bootstrap_ipcp(int argc,
printf("Types do not match.\n\n");
goto fail;
}
+
conf.type = ipcps[i].type;
if (autobind && (conf.type != IPCP_UNICAST &&
@@ -300,46 +303,45 @@ int do_bootstrap_ipcp(int argc,
}
if (strlen(layer) > LAYER_NAME_SIZE) {
- printf("Layer name too big.\n\n");
+ printf("Layer name too long.\n\n");
goto fail_usage;
}
- strcpy(conf.layer_info.layer_name, layer);
- if (conf.type != IPCP_UDP)
- conf.layer_info.dir_hash_algo = hash_algo;
+ strcpy(conf.layer_info.name, layer);
+ conf.layer_info.dir_hash_algo = hash_algo;
switch (conf.type) {
case IPCP_UNICAST:
- conf.addr_size = addr_size;
- conf.eid_size = eid_size;
- conf.max_ttl = max_ttl;
- conf.addr_auth_type = addr_auth_type;
- conf.routing_type = routing_type;
+ conf.unicast.dt.addr_size = addr_size;
+ conf.unicast.dt.eid_size = eid_size;
+ conf.unicast.dt.max_ttl = max_ttl;
+ conf.unicast.dt.routing_type = routing_type;
+ conf.unicast.addr_auth_type = addr_auth_type;
+ conf.unicast.cong_avoid = cong_avoid;
break;
case IPCP_UDP:
if (ip_addr == 0)
goto fail_usage;
- conf.ip_addr = ip_addr;
- conf.dns_addr = dns_addr;
- conf.clt_port = cport;
- conf.srv_port = sport;
+ conf.udp.ip_addr = ip_addr;
+ conf.udp.dns_addr = dns_addr;
+ conf.udp.port = port;
break;
+ case IPCP_ETH_DIX:
+ conf.eth.ethertype = ethertype;
+ /* FALLTHRU */
case IPCP_ETH_LLC:
if (dev == NULL)
goto fail_usage;
- conf.dev = dev;
- break;
- case IPCP_ETH_DIX:
- if (dev == NULL)
+ if (strlen(dev) > DEV_NAME_SIZE) {
+ printf("Device name too long.\n\n");
goto fail_usage;
- conf.dev = dev;
- conf.ethertype = ethertype;
+ }
+
+ strcpy(conf.eth.dev, dev);
break;
case IPCP_BROADCAST:
/* FALLTHRU */
case IPCP_LOCAL:
- /* FALLTHRU */
- case IPCP_RAPTOR:
break;
default:
assert(false);
diff --git a/src/tools/irm/irm_ipcp_connect.c b/src/tools/irm/irm_ipcp_connect.c
index 12541b2c..68e13bd0 100644
--- a/src/tools/irm/irm_ipcp_connect.c
+++ b/src/tools/irm/irm_ipcp_connect.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Connect components of unicast or broadcast IPC processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -55,25 +55,25 @@ static void usage(void)
" name <ipcp name>\n"
" dst <name of destination IPCP>\n"
" [component [COMPONENT]]\n"
- "where COMPONENT = {" DT " " MGMT "}\n\n"
+ "where COMPONENT in {" DT " " MGMT "}\n\n"
"if COMPONENT == " DT "\n"
" [qos [QOS]\n"
- "where QOS = {raw, best, voice, video, data}\n\n");
+ "where QOS in {raw, best, voice, video, data}\n");
}
int do_connect_ipcp(int argc,
char ** argv)
{
- char * ipcp = NULL;
- char * dst = NULL;
- char * comp = "*";
- char * component = NULL;
- char * qos = NULL;
- struct ipcp_info * ipcps;
- ssize_t len = 0;
- pid_t pid = -1;
- ssize_t i;
- qosspec_t qs = qos_raw;
+ char * ipcp = NULL;
+ char * dst = NULL;
+ char * comp = "*";
+ char * component = NULL;
+ char * qos = NULL;
+ struct ipcp_list_info * ipcps;
+ ssize_t len = 0;
+ pid_t pid = -1;
+ ssize_t i;
+ qosspec_t qs = qos_raw;
while (argc > 0) {
if (matches(*argv, "name") == 0) {
diff --git a/src/tools/irm/irm_ipcp_create.c b/src/tools/irm/irm_ipcp_create.c
index ae2c2289..35d33782 100644
--- a/src/tools/irm/irm_ipcp_create.c
+++ b/src/tools/irm/irm_ipcp_create.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Create IPC Processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -44,30 +44,29 @@
#include "irm_ops.h"
#include "irm_utils.h"
-#define UNICAST "unicast"
+#define UNICAST "unicast"
#define BROADCAST "broadcast"
#define UDP "udp"
#define ETH_LLC "eth-llc"
#define ETH_DIX "eth-dix"
#define LOCAL "local"
-#define RAPTOR "raptor"
static void usage(void)
{
printf("Usage: irm ipcp create\n"
" name <ipcp name>\n"
" type [TYPE]\n\n"
- "where TYPE = {" UNICAST " " BROADCAST " " LOCAL " "
- UDP " " ETH_LLC " " RAPTOR "}\n");
+ "where TYPE in {" UNICAST " " BROADCAST " " LOCAL " "
+ UDP " " ETH_LLC " " ETH_DIX "}\n");
}
int do_create_ipcp(int argc,
char ** argv)
{
- char * ipcp_type = NULL;
- char * ipcp_name = NULL;
- enum ipcp_type type = 0;
- pid_t pid;
+ char * ipcp_type = NULL;
+ char * ipcp_name = NULL;
+ enum ipcp_type type = 0;
+ pid_t pid;
while (argc > 0) {
if (matches(*argv, "type") == 0) {
@@ -101,15 +100,14 @@ int do_create_ipcp(int argc,
type = IPCP_ETH_LLC;
else if (strcmp(ipcp_type, ETH_DIX) == 0)
type = IPCP_ETH_DIX;
- else if (strcmp(ipcp_type, RAPTOR) == 0)
- type = IPCP_RAPTOR;
else {
+ printf("IPCP type \"%s\" is unknown.\n", ipcp_type);
usage();
return -1;
}
pid = irm_create_ipcp(ipcp_name, type);
- if (pid <= 0)
+ if (pid < 0)
return -1;
return 0;
diff --git a/src/tools/irm/irm_ipcp_destroy.c b/src/tools/irm/irm_ipcp_destroy.c
index be03df00..1a5e564e 100644
--- a/src/tools/irm/irm_ipcp_destroy.c
+++ b/src/tools/irm/irm_ipcp_destroy.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Destroy IPC Processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -55,10 +55,10 @@ static void usage(void)
int do_destroy_ipcp(int argc,
char ** argv)
{
- char * ipcp = NULL;
- struct ipcp_info * ipcps;
- ssize_t len;
- int i;
+ char * ipcp = NULL;
+ struct ipcp_list_info * ipcps;
+ ssize_t len;
+ int i;
while (argc > 0) {
if (matches(*argv, "name") == 0) {
diff --git a/src/tools/irm/irm_ipcp_disconnect.c b/src/tools/irm/irm_ipcp_disconnect.c
index d92d56eb..7ce724e1 100644
--- a/src/tools/irm/irm_ipcp_disconnect.c
+++ b/src/tools/irm/irm_ipcp_disconnect.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Connect components of unicast or broadcast IPC processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -54,20 +54,20 @@ static void usage(void)
" name <ipcp name>\n"
" dst <name of destination IPCP>\n"
" [component [COMPONENT]]\n\n"
- "where COMPONENT = {" DT " " MGMT "}\n");
+ "where COMPONENT in {" DT " " MGMT "}\n");
}
int do_disconnect_ipcp(int argc,
char ** argv)
{
- char * ipcp = NULL;
- char * dst = NULL;
- char * comp = "*";
- char * component = NULL;
- struct ipcp_info * ipcps;
- ssize_t len = 0;
- pid_t pid = -1;
- ssize_t i;
+ char * ipcp = NULL;
+ char * dst = NULL;
+ char * comp = "*";
+ char * component = NULL;
+ struct ipcp_list_info * ipcps;
+ ssize_t len = 0;
+ pid_t pid = -1;
+ ssize_t i;
while (argc > 0) {
if (matches(*argv, "name") == 0) {
diff --git a/src/tools/irm/irm_ipcp_enroll.c b/src/tools/irm/irm_ipcp_enroll.c
index ebb1da43..86a22a71 100644
--- a/src/tools/irm/irm_ipcp_enroll.c
+++ b/src/tools/irm/irm_ipcp_enroll.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Enroll IPC Processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -57,15 +57,15 @@ static void usage(void)
" [dst <destination to enroll with>]\n"
" [type [TYPE], default = " UNICAST "]\n"
" [autobind]\n"
- "where TYPE = {" UNICAST " " BROADCAST "}\n");
+ "where TYPE in {" UNICAST " " BROADCAST "}\n");
}
static int get_layer_name(const char * ipcp,
char * layer_name)
{
- struct ipcp_info * ipcps;
- size_t len;
- size_t i;
+ struct ipcp_list_info * ipcps;
+ ssize_t len;
+ ssize_t i;
len = irm_list_ipcps(&ipcps);
for (i = 0; i < len; i++)
@@ -83,17 +83,17 @@ static int get_layer_name(const char * ipcp,
int do_enroll_ipcp(int argc,
char ** argv)
{
- char * ipcp = NULL;
- char * layer = NULL;
- char * dst = NULL;
- struct ipcp_info * ipcps;
- pid_t pid = -1;
- ssize_t len = 0;
- int i = 0;
- bool autobind = false;
- int cargs;
- char * ipcp_type = UNICAST;
- enum ipcp_type type = IPCP_INVALID;
+ char * ipcp = NULL;
+ char * layer = NULL;
+ char * dst = NULL;
+ struct ipcp_list_info * ipcps;
+ pid_t pid = -1;
+ ssize_t len = 0;
+ int i = 0;
+ bool autobind = false;
+ int cargs;
+ char * ipcp_type = UNICAST;
+ enum ipcp_type type = IPCP_INVALID;
while (argc > 0) {
cargs = 2;
@@ -146,40 +146,39 @@ int do_enroll_ipcp(int argc,
}
for (i = 0; i < len; i++) {
+ char enr_layer[LAYER_NAME_SIZE];
if (ipcps[i].type != type)
continue;
- if (wildcard_match(ipcps[i].name, ipcp) == 0) {
- char enr_layer[LAYER_NAME_SIZE];
+ if (wildcard_match(ipcps[i].name, ipcp) != 0)
+ continue;
- pid = ipcps[i].pid;
+ pid = ipcps[i].pid;
+
+ if (irm_enroll_ipcp(pid, dst)) {
+ printf("Failed to enroll IPCP.\n");
+ goto fail;
+ }
+
+ if (get_layer_name(ipcps[i].name, enr_layer)) {
+ printf("Could not get layer name.\n");
+ goto fail;
+ }
- if (irm_enroll_ipcp(pid, dst)) {
- printf("Failed to enroll IPCP.\n");
- goto fail;
- }
-
- if (get_layer_name(ipcps[i].name, enr_layer)) {
- printf("Could not get layer name.\n");
- goto fail;
- }
-
- if (layer != NULL && strcmp(enr_layer, layer)) {
- printf("Enrollment destination does not "
- "match requested layer.\n");
- goto fail;
- }
-
- if (autobind && irm_bind_process(pid, ipcp)) {
- printf("Failed to bind %d to %s.\n", pid, ipcp);
- goto fail;
- }
-
- if (autobind && irm_bind_process(pid, enr_layer)) {
- printf("Failed to bind %d to %s.\n",
- pid, enr_layer);
- goto fail;
- }
+ if (layer != NULL && strcmp(enr_layer, layer)) {
+ printf("Enrollment destination does not "
+ "match requested layer.\n");
+ goto fail;
+ }
+
+ if (autobind && irm_bind_process(pid, ipcp)) {
+ printf("Failed to bind %d to %s.\n", pid, ipcp);
+ goto fail;
+ }
+
+ if (autobind && irm_bind_process(pid, enr_layer)) {
+ printf("Failed to bind %d to %s.\n", pid, enr_layer);
+ goto fail;
}
}
diff --git a/src/tools/irm/irm_ipcp_list.c b/src/tools/irm/irm_ipcp_list.c
index 3b8612ed..dfa3099f 100644
--- a/src/tools/irm/irm_ipcp_list.c
+++ b/src/tools/irm/irm_ipcp_list.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* List IPC Processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -46,12 +46,12 @@
#include <stdlib.h>
#include <string.h>
-#define UNICAST "unicast"
-#define UDP "udp"
-#define ETH_LLC "eth-llc"
-#define ETH_DIX "eth-dix"
-#define LOCAL "local"
-#define RAPTOR "raptor"
+#define UNICAST "unicast"
+#define BROADCAST "broadcast"
+#define UDP "udp"
+#define ETH_LLC "eth-llc"
+#define ETH_DIX "eth-dix"
+#define LOCAL "local"
static void usage(void)
{
@@ -60,7 +60,7 @@ static void usage(void)
" [layer <layer_name>]\n\n"
" [type [TYPE]]\n\n"
"where TYPE = {" UNICAST " " LOCAL " "
- UDP " " ETH_LLC " " ETH_DIX " " RAPTOR "}\n");
+ UDP " " ETH_LLC " " ETH_DIX "}\n");
}
static char * str_type(enum ipcp_type type)
@@ -68,14 +68,14 @@ static char * str_type(enum ipcp_type type)
switch(type) {
case IPCP_UNICAST:
return UNICAST;
+ case IPCP_BROADCAST:
+ return BROADCAST;
case IPCP_ETH_LLC:
return ETH_LLC;
case IPCP_ETH_DIX:
return ETH_DIX;
case IPCP_UDP:
return UDP;
- case IPCP_RAPTOR:
- return RAPTOR;
case IPCP_LOCAL:
return LOCAL;
default:
@@ -86,12 +86,12 @@ static char * str_type(enum ipcp_type type)
int do_list_ipcp(int argc,
char ** argv)
{
- char * ipcp_type = NULL;
- char * ipcp_name = NULL;
- enum ipcp_type type = -1;
- struct ipcp_info * ipcps;
- ssize_t len;
- ssize_t i;
+ char * ipcp_type = NULL;
+ char * ipcp_name = NULL;
+ enum ipcp_type type = -1;
+ struct ipcp_list_info * ipcps;
+ ssize_t len;
+ ssize_t i;
while (argc > 0) {
if (matches(*argv, "type") == 0) {
@@ -111,6 +111,8 @@ int do_list_ipcp(int argc,
if (ipcp_type != NULL) {
if (strcmp(ipcp_type, UNICAST) == 0)
type = IPCP_UNICAST;
+ else if (strcmp(ipcp_type, BROADCAST) == 0)
+ type = IPCP_BROADCAST;
else if (strcmp(ipcp_type, UDP) == 0)
type = IPCP_UDP;
else if (strcmp(ipcp_type, LOCAL) == 0)
@@ -119,8 +121,6 @@ int do_list_ipcp(int argc,
type = IPCP_ETH_LLC;
else if (strcmp(ipcp_type, ETH_DIX) == 0)
type = IPCP_ETH_DIX;
- else if (strcmp(ipcp_type, RAPTOR) == 0)
- type = IPCP_RAPTOR;
else {
usage();
return -1;
diff --git a/src/tools/irm/irm_name.c b/src/tools/irm/irm_name.c
index 3a615b00..d60b6c78 100644
--- a/src/tools/irm/irm_name.c
+++ b/src/tools/irm/irm_name.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* A tool to instruct the IRM daemon
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -44,9 +44,10 @@
static void usage(void)
{
printf("Usage: irm name [OPERATION]\n\n"
- "where OPERATION = {create destroy\n"
- " register unregister\n"
- " list help}\n");
+ "where OPERATION in {create destroy\n"
+ " register unregister\n"
+ " list\n"
+ " help}\n");
}
static int do_help(int argc, char **argv)
diff --git a/src/tools/irm/irm_name_create.c b/src/tools/irm/irm_name_create.c
index 9b7e6a36..a0079cad 100644
--- a/src/tools/irm/irm_name_create.c
+++ b/src/tools/irm/irm_name_create.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Create IPC Processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -52,7 +52,7 @@ static void usage(void)
printf("Usage: irm name create\n"
" <name>\n"
" lb [LB_POLICY], default: %s\n\n"
- "where LB_POLICY = {" RR " " SPILL "}\n", RR);
+ "where LB_POLICY in {" RR " " SPILL "}\n", RR);
}
int do_create_name(int argc,
diff --git a/src/tools/irm/irm_name_destroy.c b/src/tools/irm/irm_name_destroy.c
index 70f801b2..d4bd6c82 100644
--- a/src/tools/irm/irm_name_destroy.c
+++ b/src/tools/irm/irm_name_destroy.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Create IPC Processes
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/irm/irm_name_list.c b/src/tools/irm/irm_name_list.c
index 2e4c3194..a807008c 100644
--- a/src/tools/irm/irm_name_list.c
+++ b/src/tools/irm/irm_name_list.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* List names
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/irm/irm_name_reg.c b/src/tools/irm/irm_name_reg.c
index 52bf911b..061ed8be 100644
--- a/src/tools/irm/irm_name_reg.c
+++ b/src/tools/irm/irm_name_reg.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Register names with IPCPs
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -64,17 +64,17 @@ static void usage(void)
int do_reg_name(int argc,
char ** argv)
{
- char * name = NULL;
- char * layers[MAX_LAYERS];
- size_t layers_len = 0;
- char * ipcp[MAX_IPCPS];
- size_t ipcp_len = 0;
- struct ipcp_info * ipcps;
- ssize_t ipcps_len;
- struct name_info * names;
- ssize_t names_len;
- bool name_create = true;
- ssize_t i;
+ char * name = NULL;
+ char * layers[MAX_LAYERS];
+ size_t layers_len = 0;
+ char * ipcp[MAX_IPCPS];
+ size_t ipcp_len = 0;
+ struct ipcp_list_info * ipcps;
+ ssize_t ipcps_len;
+ struct name_info * names;
+ ssize_t names_len;
+ bool name_create = true;
+ ssize_t i;
name = *(argv++);
--argc;
diff --git a/src/tools/irm/irm_name_unreg.c b/src/tools/irm/irm_name_unreg.c
index 48253143..6e579f04 100644
--- a/src/tools/irm/irm_name_unreg.c
+++ b/src/tools/irm/irm_name_unreg.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Unregister names from IPCPs
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -63,14 +63,14 @@ static void usage(void)
int do_unreg_name(int argc,
char ** argv)
{
- char * name = NULL;
- char * layers[MAX_LAYERS];
- size_t layers_len = 0;
- char * ipcp[MAX_IPCPS];
- size_t ipcp_len = 0;
- struct ipcp_info * ipcps;
- ssize_t len;
- size_t i;
+ char * name = NULL;
+ char * layers[MAX_LAYERS];
+ size_t layers_len = 0;
+ char * ipcp[MAX_IPCPS];
+ size_t ipcp_len = 0;
+ struct ipcp_list_info * ipcps;
+ ssize_t len;
+ size_t i;
name = *(argv++);
--argc;
diff --git a/src/tools/irm/irm_ops.h b/src/tools/irm/irm_ops.h
index 7c1b1a8f..e04ffc02 100644
--- a/src/tools/irm/irm_ops.h
+++ b/src/tools/irm/irm_ops.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Functions of the IRM tool that are one level deep
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/irm/irm_unbind.c b/src/tools/irm/irm_unbind.c
index 05838235..d6594d01 100644
--- a/src/tools/irm/irm_unbind.c
+++ b/src/tools/irm/irm_unbind.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Unbind names in the processing system
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -47,7 +47,7 @@ static void usage(void)
{
printf("Usage: irm unbind [OPERATION]\n"
"\n"
- "where OPERATION = {program process ipcp help}\n");
+ "where OPERATION in {program process ipcp help}\n");
}
static int do_help(int argc,
diff --git a/src/tools/irm/irm_unbind_ipcp.c b/src/tools/irm/irm_unbind_ipcp.c
index d121b2dc..53a2d16c 100644
--- a/src/tools/irm/irm_unbind_ipcp.c
+++ b/src/tools/irm/irm_unbind_ipcp.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Unbind name from IPCP Instance
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -57,11 +57,11 @@ static void usage(void)
int do_unbind_ipcp(int argc,
char ** argv)
{
- char * ipcp = NULL;
- char * name = NULL;
- struct ipcp_info * ipcps;
- ssize_t len;
- ssize_t i;
+ char * ipcp = NULL;
+ char * name = NULL;
+ struct ipcp_list_info * ipcps;
+ ssize_t len;
+ ssize_t i;
while (argc > 0) {
if (matches(*argv, "name") == 0) {
diff --git a/src/tools/irm/irm_unbind_process.c b/src/tools/irm/irm_unbind_process.c
index d5b96141..264ed538 100644
--- a/src/tools/irm/irm_unbind_process.c
+++ b/src/tools/irm/irm_unbind_process.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Unbind process names
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/irm/irm_unbind_program.c b/src/tools/irm/irm_unbind_program.c
index 382c5d8a..0c751e80 100644
--- a/src/tools/irm/irm_unbind_program.c
+++ b/src/tools/irm/irm_unbind_program.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Unbind programs
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/irm/irm_utils.c b/src/tools/irm/irm_utils.c
index 0620e374..9694d647 100644
--- a/src/tools/irm/irm_utils.c
+++ b/src/tools/irm/irm_utils.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Handy helper functions for the IRM tool
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -109,7 +109,7 @@ int wildcard_match(const char * pattern,
return 0;
/* General case, use recursion. */
- while ((c = *string) != '\0') {
+ while (*string != '\0') {
if (!wildcard_match(pattern, string))
return 0;
++string;
diff --git a/src/tools/irm/irm_utils.h b/src/tools/irm/irm_utils.h
index 925a9da6..27a0b941 100644
--- a/src/tools/irm/irm_utils.h
+++ b/src/tools/irm/irm_utils.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Handy helper functions for the IRM tool
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/obc/obc.c b/src/tools/obc/obc.c
index 256cb84e..462cbea9 100644
--- a/src/tools/obc/obc.c
+++ b/src/tools/obc/obc.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* A simple broadcast application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/ocbr/ocbr.c b/src/tools/ocbr/ocbr.c
index e2a23c4a..775bcaac 100644
--- a/src/tools/ocbr/ocbr.c
+++ b/src/tools/ocbr/ocbr.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* CBR traffic generator
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -76,6 +76,7 @@ static void usage(void)
" -s, --size packet size (B, max %ld B)\n"
" -r, --rate Rate (b/s)\n"
" --sleep Sleep in between sending packets\n"
+ " --spin Spin CPU between sending packets\n"
"\n\n"
" --help Display this help text and exit\n",
BUF_SIZE);
@@ -87,7 +88,7 @@ int main(int argc, char ** argv)
int size = 1000; /* 1000 byte packets */
long rate = 1000000; /* 1 Mb/s */
bool flood = false;
- bool sleep = false;
+ bool sleep = true;
int ret = 0;
char * rem = NULL;
char * s_apn = NULL;
@@ -138,6 +139,8 @@ int main(int argc, char ** argv)
flood = true;
} else if (strcmp(*argv, "--sleep") == 0) {
sleep = true;
+ } else if (strcmp(*argv, "--spin") == 0) {
+ sleep = false;
} else {
usage();
return 0;
@@ -152,17 +155,22 @@ int main(int argc, char ** argv)
if (s_apn == NULL) {
printf("No server specified.\n");
usage();
- return 0;
+ return 1;
}
if (size > BUF_SIZE) {
printf("Maximum size: %ld.\n", BUF_SIZE);
- return 0;
+ return 1;
}
if (size < 0) {
printf("Size overflow.\n");
- return 0;
+ return 1;
+ }
+
+ if (rate <= 0) {
+ printf("Invalid rate.\n");
+ return 1;
}
ret = client_main(s_apn, duration, size, rate, flood, sleep);
diff --git a/src/tools/ocbr/ocbr_client.c b/src/tools/ocbr/ocbr_client.c
index 6120e1fd..ba7b41f4 100644
--- a/src/tools/ocbr/ocbr_client.c
+++ b/src/tools/ocbr/ocbr_client.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* A simple CBR generator
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/ocbr/ocbr_server.c b/src/tools/ocbr/ocbr_server.c
index 583f226c..a4bbadd4 100644
--- a/src/tools/ocbr/ocbr_server.c
+++ b/src/tools/ocbr/ocbr_server.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* A simple CBR generator
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -83,6 +83,7 @@ static void handle_flow(int fd)
struct timespec now;
struct timespec alive;
struct timespec intv = {server_settings.interval, 0};
+ struct timespec tic = {0, 100 * MILLION};
struct timespec iv_start;
struct timespec iv_end;
@@ -99,7 +100,8 @@ static void handle_flow(int fd)
alive = iv_start;
ts_add(&iv_start, &intv, &iv_end);
- fccntl(fd, FLOWSFLAGS, FLOWFRNOBLOCK | FLOWFRDWR | FLOWFRNOPART);
+ fccntl(fd, FLOWSFLAGS, FLOWFRDWR | FLOWFRNOPART);
+ fccntl(fd, FLOWSRCVTIMEO, &tic);
while (!stop) {
clock_gettime(CLOCK_REALTIME, &now);
@@ -140,6 +142,11 @@ static void handle_flow(int fd)
flow_dealloc(fd);
}
+static void __cleanup_mutex_unlock(void * mutex)
+{
+ pthread_mutex_unlock((pthread_mutex_t *) mutex);
+}
+
static void * worker(void * o)
{
int cli_fd;
@@ -148,8 +155,7 @@ static void * worker(void * o)
while (true) {
pthread_mutex_lock(&fds_lock);
- pthread_cleanup_push((void(*)(void *)) pthread_mutex_unlock,
- (void *) &fds_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &fds_lock);
while (fds[fds_index] == -1)
pthread_cond_wait(&fds_signal, &fds_lock);
@@ -182,8 +188,7 @@ static void * listener(void * o)
while (true) {
pthread_mutex_lock(&fds_lock);
- pthread_cleanup_push((void(*)(void *)) pthread_mutex_unlock,
- (void *) &fds_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &fds_lock);
while (fds_count == THREADS_SIZE) {
printf("Can't accept any more flows, waiting.\n");
diff --git a/src/tools/oecho/oecho.c b/src/tools/oecho/oecho.c
index a44b8b76..d5d03027 100644
--- a/src/tools/oecho/oecho.c
+++ b/src/tools/oecho/oecho.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* A simple echo application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/operf/operf.c b/src/tools/operf/operf.c
index ed07323c..10896bd5 100644
--- a/src/tools/operf/operf.c
+++ b/src/tools/operf/operf.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros perf application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/operf/operf_client.c b/src/tools/operf/operf_client.c
index 004a8965..63f98299 100644
--- a/src/tools/operf/operf_client.c
+++ b/src/tools/operf/operf_client.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros ping application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/operf/operf_server.c b/src/tools/operf/operf_server.c
index f3ca8b19..d11f3486 100644
--- a/src/tools/operf/operf_server.c
+++ b/src/tools/operf/operf_server.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros perf application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/oping/oping.c b/src/tools/oping/oping.c
index ca685292..ed3529e5 100644
--- a/src/tools/oping/oping.c
+++ b/src/tools/oping/oping.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros ping application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -60,14 +60,31 @@
#include <errno.h>
#include <float.h>
-#define OPING_BUF_SIZE 1500
-
-#define ECHO_REQUEST 0
-#define ECHO_REPLY 1
-
+#define OPING_BUF_SIZE 1500
+#define ECHO_REQUEST 0
+#define ECHO_REPLY 1
#define OPING_MAX_FLOWS 256
-struct c {
+#define USAGE_STRING \
+"Usage: oping [OPTION]...\n" \
+"\n" \
+"Checks liveness between a client and a server\n" \
+"and reports the Round Trip Time (RTT)\n" \
+"\n" \
+" -l, --listen Run in server mode\n" \
+"\n" \
+" -c, --count Number of packets\n" \
+" -d, --duration Duration of the test (default 1s)\n" \
+" -i, --interval Interval (default 1000ms)\n" \
+" -n, --server-name Name of the oping server\n" \
+" -q, --qos QoS (raw, raw_crypt, best, video, voice, data)\n" \
+" -s, --size Payload size (B, default 64)\n" \
+" -Q, --quiet Only print final statistics\n" \
+" -D, --timeofday Print time of day before each line\n" \
+"\n" \
+" --help Display this help text and exit\n" \
+
+struct {
char * s_apn;
int interval;
uint32_t count;
@@ -90,12 +107,14 @@ struct c {
pthread_t writer_pt;
} client;
-struct s {
+struct {
struct timespec times[OPING_MAX_FLOWS];
fset_t * flows;
fqueue_t * fq;
pthread_mutex_t lock;
+ bool quiet;
+
pthread_t cleaner_pt;
pthread_t accept_pt;
pthread_t server_pt;
@@ -114,22 +133,7 @@ struct oping_msg {
static void usage(void)
{
- printf("Usage: oping [OPTION]...\n"
- "Checks liveness between a client and a server\n"
- "and reports the Round Trip Time (RTT)\n\n"
- " -l, --listen Run in server mode\n"
- "\n"
- " -c, --count Number of packets\n"
- " -d, --duration Duration of the test (default 1s)\n"
- " -i, --interval Interval (default 1000ms)\n"
- " -n, --server-name Name of the oping server\n"
- " -q, --qos QoS (raw, best, video, voice, data)"
- "\n"
- " -s, --size Payload size (B, default 64)\n"
- " -Q, --quiet Only print final statistics\n"
- " -D, --timeofday Print time of day before each line"
- "\n"
- " --help Display this help text and exit\n");
+ printf(USAGE_STRING);
}
/* Times are in ms. */
@@ -170,32 +174,39 @@ int main(int argc,
client.timestamp = false;
client.qs = qos_raw;
client.quiet = false;
+ server.quiet = false;
while (argc > 0) {
- if (strcmp(*argv, "-i") == 0 ||
- strcmp(*argv, "--interval") == 0) {
+ if ((strcmp(*argv, "-i") == 0 ||
+ strcmp(*argv, "--interval") == 0) &&
+ argc > 1) {
client.interval = strtol(*(++argv), &rem, 10);
client.interval *= time_mul(rem);
--argc;
- } else if (strcmp(*argv, "-n") == 0 ||
- strcmp(*argv, "--server-name") == 0) {
+ } else if ((strcmp(*argv, "-n") == 0 ||
+ strcmp(*argv, "--server-name") == 0) &&
+ argc > 1) {
client.s_apn = *(++argv);
--argc;
- } else if (strcmp(*argv, "-c") == 0 ||
- strcmp(*argv, "--count") == 0) {
+ } else if ((strcmp(*argv, "-c") == 0 ||
+ strcmp(*argv, "--count") == 0) &&
+ argc > 1) {
client.count = strtol(*(++argv), &rem, 10);
--argc;
- } else if (strcmp(*argv, "-d") == 0 ||
- strcmp(*argv, "--duration") == 0) {
+ } else if ((strcmp(*argv, "-d") == 0 ||
+ strcmp(*argv, "--duration") == 0) &&
+ argc > 1) {
duration = strtol(*(++argv), &rem, 10);
duration *= time_mul(rem);
--argc;
- } else if (strcmp(*argv, "-s") == 0 ||
- strcmp(*argv, "--size") == 0) {
+ } else if ((strcmp(*argv, "-s") == 0 ||
+ strcmp(*argv, "--size") == 0) &&
+ argc > 1) {
client.size = strtol(*(++argv), &rem, 10);
--argc;
- } else if (strcmp(*argv, "-q") == 0 ||
- strcmp(*argv, "--qos") == 0) {
+ } else if ((strcmp(*argv, "-q") == 0 ||
+ strcmp(*argv, "--qos") == 0) &&
+ argc > 1) {
qos = *(++argv);
--argc;
} else if (strcmp(*argv, "-l") == 0 ||
@@ -207,7 +218,7 @@ int main(int argc,
} else if (strcmp(*argv, "-Q") == 0 ||
strcmp(*argv, "--quiet") == 0) {
client.quiet = true;
-
+ server.quiet = true;
} else {
goto fail;
}
diff --git a/src/tools/oping/oping_client.c b/src/tools/oping/oping_client.c
index d0255b7c..7b03c83d 100644
--- a/src/tools/oping/oping_client.c
+++ b/src/tools/oping/oping_client.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros ping application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -163,7 +163,7 @@ void * writer(void * o)
printf("Pinging %s with %d bytes of data (%u packets):\n\n",
client.s_apn, client.size, client.count);
- pthread_cleanup_push((void (*) (void *)) free, buf);
+ pthread_cleanup_push(free, buf);
while (!stop && client.sent < client.count) {
nanosleep(&wait, NULL);
@@ -177,9 +177,7 @@ void * writer(void * o)
if (flow_write(*fdp, buf, client.size) < 0) {
printf("Failed to send packet.\n");
- flow_dealloc(*fdp);
- free(buf);
- return (void *) -1;
+ stop = true;
}
}
@@ -234,7 +232,7 @@ static int client_main(void)
fd = flow_alloc(client.s_apn, &client.qs, NULL);
if (fd < 0) {
- printf("Failed to allocate flow.\n");
+ printf("Failed to allocate flow: %d.\n", fd);
client_fini();
return -1;
}
diff --git a/src/tools/oping/oping_server.c b/src/tools/oping/oping_server.c
index 5cc347cb..6f76869c 100644
--- a/src/tools/oping/oping_server.c
+++ b/src/tools/oping/oping_server.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros ping application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -61,16 +61,21 @@ void * cleaner_thread(void * o)
while (true) {
clock_gettime(CLOCK_REALTIME, &now);
- pthread_mutex_lock(&server.lock);
+
for (i = 0; i < OPING_MAX_FLOWS; ++i)
- if (fset_has(server.flows, i) &&
- ts_diff_ms(&server.times[i], &now) > deadline_ms) {
- printf("Flow %d timed out.\n", i);
- fset_del(server.flows, i);
- flow_dealloc(i);
+ if (fset_has(server.flows, i)) {
+ time_t diff;
+
+ pthread_mutex_lock(&server.lock);
+ diff = ts_diff_ms(&server.times[i], &now);
+ pthread_mutex_unlock(&server.lock);
+
+ if (diff > deadline_ms) {
+ printf("Flow %d timed out.\n", i);
+ fset_del(server.flows, i);
+ flow_dealloc(i);
+ }
}
-
- pthread_mutex_unlock(&server.lock);
sleep(1);
}
}
@@ -100,7 +105,8 @@ void * server_thread(void *o)
continue;
}
- printf("Received %d bytes on fd %d.\n", msg_len, fd);
+ if (!server.quiet)
+ printf("Received %d bytes on fd %d.\n", msg_len, fd);
clock_gettime(CLOCK_REALTIME, &now);
@@ -139,8 +145,9 @@ void * accept_thread(void * o)
clock_gettime(CLOCK_REALTIME, &now);
- pthread_mutex_lock(&server.lock);
fset_add(server.flows, fd);
+
+ pthread_mutex_lock(&server.lock);
server.times[fd] = now;
pthread_mutex_unlock(&server.lock);
diff --git a/src/tools/ovpn/ovpn.c b/src/tools/ovpn/ovpn.c
index 02501d52..5333ff40 100644
--- a/src/tools/ovpn/ovpn.c
+++ b/src/tools/ovpn/ovpn.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros VPN
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/src/tools/time_utils.h b/src/tools/time_utils.h
index 48d694c1..c17282dc 100644
--- a/src/tools/time_utils.h
+++ b/src/tools/time_utils.h
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Time utilities
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions