summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/woodpecker/01-build.yaml111
-rw-r--r--CMakeLists.txt59
-rw-r--r--appveyor.yml34
-rw-r--r--cmake/FindProtobufC.cmake2
-rw-r--r--doc/man/ouroboros.843
-rw-r--r--include/ouroboros/crypt.h92
-rw-r--r--include/ouroboros/endian.h2
-rw-r--r--include/ouroboros/errno.h7
-rw-r--r--include/ouroboros/flow.h4
-rw-r--r--include/ouroboros/hash.h7
-rw-r--r--include/ouroboros/ipcp-dev.h10
-rw-r--r--include/ouroboros/ipcp.h251
-rw-r--r--include/ouroboros/irm.h3
-rw-r--r--include/ouroboros/logs.h8
-rw-r--r--include/ouroboros/name.h10
-rw-r--r--include/ouroboros/np1_flow.h4
-rw-r--r--include/ouroboros/protobuf.h51
-rw-r--r--include/ouroboros/qos.h67
-rw-r--r--include/ouroboros/rib.h2
-rw-r--r--include/ouroboros/serdes-oep.h9
-rw-r--r--include/ouroboros/sockets.h.in12
-rw-r--r--include/ouroboros/test.h23
-rw-r--r--include/ouroboros/time.h20
-rw-r--r--include/ouroboros/tpm.h6
-rw-r--r--include/ouroboros/utils.h26
-rw-r--r--irmd.conf.in33
-rw-r--r--ouroboros-dev.pc.in4
-rw-r--r--ouroboros-irm.pc.in4
-rw-r--r--src/ipcpd/CMakeLists.txt2
-rw-r--r--src/ipcpd/broadcast/main.c29
-rw-r--r--src/ipcpd/common/connmgr.c29
-rw-r--r--src/ipcpd/common/enroll.c34
-rw-r--r--src/ipcpd/config.h.in9
-rw-r--r--src/ipcpd/eth/CMakeLists.txt12
-rw-r--r--src/ipcpd/eth/eth.c394
-rw-r--r--src/ipcpd/ipcp.c622
-rw-r--r--src/ipcpd/ipcp.h54
-rw-r--r--src/ipcpd/local/CMakeLists.txt4
-rw-r--r--src/ipcpd/local/main.c8
-rw-r--r--src/ipcpd/shim-data.c34
-rw-r--r--src/ipcpd/shim-data.h19
-rw-r--r--src/ipcpd/udp/CMakeLists.txt36
-rw-r--r--src/ipcpd/udp/udp.c (renamed from src/ipcpd/udp/main.c)345
-rw-r--r--src/ipcpd/udp/udp4.c42
-rw-r--r--src/ipcpd/udp/udp6.c42
-rw-r--r--src/ipcpd/unicast/CMakeLists.txt17
-rw-r--r--src/ipcpd/unicast/addr-auth.h8
-rw-r--r--src/ipcpd/unicast/addr-auth/flat.c28
-rw-r--r--src/ipcpd/unicast/ca.c1
-rw-r--r--src/ipcpd/unicast/connmgr.c4
-rw-r--r--src/ipcpd/unicast/dir.c51
-rw-r--r--src/ipcpd/unicast/dir.h9
-rw-r--r--src/ipcpd/unicast/dir/dht.c4917
-rw-r--r--src/ipcpd/unicast/dir/dht.h17
-rw-r--r--src/ipcpd/unicast/dir/dht.proto41
-rw-r--r--src/ipcpd/unicast/dir/ops.h18
-rw-r--r--src/ipcpd/unicast/dir/tests/CMakeLists.txt6
-rw-r--r--src/ipcpd/unicast/dir/tests/dht_test.c1921
-rw-r--r--src/ipcpd/unicast/dt.c119
-rw-r--r--src/ipcpd/unicast/dt.h6
-rw-r--r--src/ipcpd/unicast/fa.c76
-rw-r--r--src/ipcpd/unicast/main.c96
-rw-r--r--src/ipcpd/unicast/pff/tests/CMakeLists.txt6
-rw-r--r--src/ipcpd/unicast/routing.c30
-rw-r--r--src/ipcpd/unicast/routing.h7
-rw-r--r--src/ipcpd/unicast/routing/graph.c156
-rw-r--r--src/ipcpd/unicast/routing/link-state.c540
-rw-r--r--src/ipcpd/unicast/routing/link-state.h7
-rw-r--r--src/ipcpd/unicast/routing/ops.h7
-rw-r--r--src/ipcpd/unicast/routing/tests/CMakeLists.txt6
-rw-r--r--src/irmd/CMakeLists.txt33
-rw-r--r--src/irmd/config.h.in57
-rw-r--r--src/irmd/configfile.c332
-rw-r--r--src/irmd/ipcp.c39
-rw-r--r--src/irmd/irmd.h2
-rw-r--r--src/irmd/main.c978
-rw-r--r--src/irmd/oap.c288
-rw-r--r--src/irmd/oap.h94
-rw-r--r--src/irmd/reg/flow.h12
-rw-r--r--src/irmd/reg/ipcp.c8
-rw-r--r--src/irmd/reg/name.c74
-rw-r--r--src/irmd/reg/name.h28
-rw-r--r--src/irmd/reg/proc.h4
-rw-r--r--src/irmd/reg/reg.c289
-rw-r--r--src/irmd/reg/reg.h24
-rw-r--r--src/irmd/reg/tests/CMakeLists.txt6
-rw-r--r--src/irmd/reg/tests/flow_test.c40
-rw-r--r--src/irmd/reg/tests/ipcp_test.c9
-rw-r--r--src/irmd/reg/tests/name_test.c94
-rw-r--r--src/irmd/reg/tests/proc_test.c25
-rw-r--r--src/irmd/reg/tests/prog_test.c22
-rw-r--r--src/irmd/reg/tests/reg_test.c495
-rw-r--r--src/irmd/tests/CMakeLists.txt10
-rw-r--r--src/irmd/tests/irm_test.c33
-rw-r--r--src/irmd/tests/oap_test.c285
-rw-r--r--src/lib/CMakeLists.txt20
-rw-r--r--src/lib/config.h.in33
-rw-r--r--src/lib/crypt.c589
-rw-r--r--src/lib/crypt/openssl.c788
-rw-r--r--src/lib/crypt/openssl.h112
-rw-r--r--src/lib/dev.c131
-rw-r--r--src/lib/frct.c26
-rw-r--r--src/lib/irm.c26
-rw-r--r--src/lib/notifier.c18
-rw-r--r--src/lib/pb/enroll.proto1
-rw-r--r--src/lib/pb/ipcp_config.proto54
-rw-r--r--src/lib/pb/irm.proto25
-rw-r--r--src/lib/pb/model.proto11
-rw-r--r--src/lib/protobuf.c348
-rw-r--r--src/lib/random.c20
-rw-r--r--src/lib/serdes-irm.c7
-rw-r--r--src/lib/sockets.c22
-rw-r--r--src/lib/tests/CMakeLists.txt13
-rw-r--r--src/lib/tests/auth_test.c643
-rw-r--r--src/lib/tests/crypt_test.c258
-rw-r--r--src/lib/tests/sockets_test.c98
-rw-r--r--src/lib/tests/time_test.c543
-rw-r--r--src/lib/tests/tpm_test.c104
-rw-r--r--src/lib/tpm.c197
-rw-r--r--src/lib/utils.c22
-rw-r--r--src/tools/irm/CMakeLists.txt7
-rw-r--r--src/tools/irm/irm_ipcp_bootstrap.c345
-rw-r--r--src/tools/irm/irm_ipcp_create.c11
-rw-r--r--src/tools/irm/irm_ipcp_list.c17
-rw-r--r--src/tools/irm/irm_name_create.c113
-rw-r--r--src/tools/irm/irm_name_reg.c37
-rw-r--r--src/tools/ocbr/ocbr_client.c6
-rw-r--r--src/tools/ocbr/ocbr_server.c6
-rw-r--r--src/tools/operf/operf_client.c6
-rw-r--r--src/tools/operf/operf_server.c2
-rw-r--r--src/tools/oping/oping.c4
-rw-r--r--src/tools/oping/oping_client.c4
-rw-r--r--src/tools/oping/oping_server.c15
-rw-r--r--src/tools/ovpn/ovpn.c5
-rw-r--r--src/tools/time_utils.h10
135 files changed, 13709 insertions, 4982 deletions
diff --git a/.ci/woodpecker/01-build.yaml b/.ci/woodpecker/01-build.yaml
new file mode 100644
index 00000000..f8109c94
--- /dev/null
+++ b/.ci/woodpecker/01-build.yaml
@@ -0,0 +1,111 @@
+matrix:
+ IMAGE:
+ - dstaesse/debian:o7s
+ - dstaesse/ubuntu:o7s
+ FLAGS:
+ - ''
+ - -m32
+ COMPILER:
+ - clang
+ - gcc
+ BUILD_TYPE:
+ - Debug
+ - Release
+ DISABLE_FUSE:
+ - TRUE
+ - FALSE
+ DISABLE_OPENSSL:
+ - TRUE
+ - FALSE
+ DISABLE_LIBGCRYPT:
+ - TRUE
+ - FALSE
+ SANITIZER:
+ - DebugASan
+ - DebugUSan
+ - DebugLSan
+
+steps:
+ - name: build
+ image: ${IMAGE}
+ pull: true
+ when:
+ branch: [testing, be]
+ event: [push, pull_request]
+ commands:
+ - apt-get update -y
+ - apt-get install bash clang -y
+ - apt-get install git protobuf-c-compiler cmake -y
+ - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
+ - apt-get install libprotobuf-c-dev -y || true
+ - mkdir build
+ - cd build
+ - CC=${COMPILER} cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DDISABLE_FUSE=${DISABLE_FUSE} \
+ -DDISABLE_OPENSSL=${DISABLE_OPENSSL} -DDISABLE_LIBGCRYPT=${DISABLE_LIBGCRYPT}
+ - make CFLAGS="${FLAGS}" -s -j2
+ - env CTEST_OUTPUT_ON_FAILURE=1 make CFLAGS="${FLAGS}" -s check
+ - cd ..
+ - rm -rf build
+
+ - name: sanitizers
+ image: ${IMAGE}
+ pull: true
+ when:
+ branch: [testing, be]
+ event: [push, pull_request]
+ commands:
+ - apt-get update -y
+ - apt-get install bash clang -y
+ - apt-get install git protobuf-c-compiler cmake -y
+ - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
+ - apt-get install libprotobuf-c-dev -y || true
+ - mkdir build
+ - cd build
+ - CC=${COMPILER} cmake .. -DCMAKE_BUILD_TYPE=${SANITIZER} -DDISABLE_FUSE=${DISABLE_FUSE} \
+ -DDISABLE_OPENSSL=${DISABLE_OPENSSL} -DDISABLE_LIBGCRYPT=${DISABLE_LIBGCRYPT} \
+ - make -s -j2
+ - env CTEST_OUTPUT_ON_FAILURE=1 make -s check
+ - cd ..
+ - rm -rf build
+
+ - name: build (manual)
+ image: ${IMAGE}
+ pull: true
+ when:
+ event: manual
+ commands:
+ - apt-get update -y
+ - apt-get install bash clang -y
+ - apt-get install git protobuf-c-compiler cmake -y
+ - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
+ - apt-get install libprotobuf-c-dev -y || true
+ - mkdir build
+ - cd build
+ - CC=${COMPILER} cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DDISABLE_FUSE=${DISABLE_FUSE} \
+ -DDISABLE_OPENSSL=${DISABLE_OPENSSL} -DDISABLE_LIBGCRYPT=${DISABLE_LIBGCRYPT}
+ - make CFLAGS="${FLAGS}" -s -j2
+ - env CTEST_OUTPUT_ON_FAILURE=1 make CFLAGS="${FLAGS}" -s check
+ - cd ..
+ - rm -rf build
+
+ - name: sanitizers (manual)
+ image: ${IMAGE}
+ pull: true
+ when:
+ event: manual
+ commands:
+ - apt-get update -y
+ - apt-get install bash clang -y
+ - apt-get install git protobuf-c-compiler cmake -y
+ - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
+ - apt-get install libprotobuf-c-dev -y || true
+ - mkdir build
+ - cd build
+ - CC=${COMPILER} cmake .. -DCMAKE_BUILD_TYPE=${SANITIZER} -DDISABLE_FUSE=${DISABLE_FUSE} \
+ -DDISABLE_OPENSSL=${DISABLE_OPENSSL} -DDISABLE_LIBGCRYPT=${DISABLE_LIBGCRYPT} \
+ - make -s -j2
+ - env CTEST_OUTPUT_ON_FAILURE=1 make -s check
+ - cd ..
+ - rm -rf build
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c298b981..1ffa5bf4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8.12.2...3.28.1)
+cmake_minimum_required(VERSION 2.8.12.2...4.0.3.0)
cmake_policy(VERSION ${CMAKE_VERSION})
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
@@ -9,7 +9,7 @@ include(GNUInstallDirs)
set(PACKAGE_VERSION_MAJOR 0)
set(PACKAGE_VERSION_MINOR 21)
-set(PACKAGE_VERSION_PATCH 3)
+set(PACKAGE_VERSION_PATCH 4)
set(PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
set(PACKAGE_DESCRIPTION "The Ouroboros prototype")
@@ -35,6 +35,7 @@ endif ()
if (APPLE)
set(CMAKE_MACOSX_RPATH 1)
+ include_directories("/usr/local/include/")
endif()
if (CMAKE_INSTALL_PREFIX STREQUAL "/usr")
@@ -130,18 +131,40 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ouroboros-irm.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# modified from https://github.com/ximion/limba
-pkg_check_modules(SYSTEMD "systemd")
-if (SYSTEMD_FOUND)
- if ("${SYSTEMD_UNITDIR}" STREQUAL "")
- execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
- --variable=systemdsystemunitdir systemd
- OUTPUT_VARIABLE SYSTEMD_UNITDIR)
- string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_UNITDIR
- "${SYSTEMD_UNITDIR}"
- )
- endif ()
- if (NOT ${SYSTEMD_UNITDIR} STREQUAL "")
- message(STATUS "Installing systemd service in: ${SYSTEMD_UNITDIR}")
+set(SYSTEMD_INSTALL_FILES "DETECT" CACHE STRING
+ "Install systemd .service files (NO (never), DETECT (use pkg-config - default),\
+ FORCE (always - see SYSTEMD_UNITDIR_OVERRIDE))")
+set(SYSTEMD_UNITDIR_OVERRIDE "" CACHE PATH
+ "Path to install systemd files. When SYSTEMD_INSTALL_FILES == DETECT, this\
+ can be empty to automatically determine the path. Cannot be empty when FORCE.")
+
+if (SYSTEMD_INSTALL_FILES STREQUAL "DETECT" OR SYSTEMD_INSTALL_FILES STREQUAL "FORCE")
+ if (SYSTEMD_INSTALL_FILES STREQUAL "DETECT")
+ pkg_check_modules(SYSTEMD "systemd")
+ if (SYSTEMD_FOUND)
+ if ("${SYSTEMD_UNITDIR_OVERRIDE}" STREQUAL "")
+ execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
+ --variable=systemdsystemunitdir systemd
+ OUTPUT_VARIABLE SYSTEMD_UNITDIR_INTERNAL)
+ string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_UNITDIR_INTERNAL
+ "${SYSTEMD_UNITDIR_INTERNAL}"
+ )
+ else ()
+ set(SYSTEMD_UNITDIR_INTERNAL "${SYSTEMD_UNITDIR_OVERRIDE}")
+ endif ()
+ else ()
+ set(SYSTEMD_UNITDIR_INTERNAL "")
+ endif ()
+ elseif (SYSTEMD_INSTALL_FILES STREQUAL "FORCE")
+ if ("${SYSTEMD_UNITDIR_OVERRIDE}" STREQUAL "")
+ message(FATAL_ERROR "Systemd installation required by user, but no path\
+ provided with SYSTEMD_UNITDIR_OVERRIDE.")
+ else ()
+ set(SYSTEMD_UNITDIR_INTERNAL "${SYSTEMD_UNITDIR_OVERRIDE}")
+ endif ()
+ endif()
+ if (NOT ${SYSTEMD_UNITDIR_INTERNAL} STREQUAL "")
+ message(STATUS "Systemd service installation enabled to: ${SYSTEMD_UNITDIR_INTERNAL}")
if (LIBTOML_LIBRARIES AND NOT DISABLE_CONFIGFILE)
set (CONFIGURE_STRING "--config ${OUROBOROS_CONFIG_DIR}${OUROBOROS_CONFIG_FILE}")
else ()
@@ -150,9 +173,11 @@ if (SYSTEMD_FOUND)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ouroboros.service.in"
"${CMAKE_CURRENT_BINARY_DIR}/ouroboros.service" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ouroboros.service"
- DESTINATION "${SYSTEMD_UNITDIR}")
+ DESTINATION "${SYSTEMD_UNITDIR_INTERNAL}")
endif ()
-endif ()
+else ()
+ message(STATUS "Systemd service installation disabled by user")
+endif()
enable_testing()
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
@@ -162,6 +187,8 @@ if (NOT (PROTOBUF_C_INCLUDE_DIRS AND PROTOBUF_C_LIBRARY
AND PROTOBUF_PROTOC_C_EXECUTABLE))
message(FATAL_ERROR "Protobuf C compiler required but not found. "
"Please install Google Protocol Buffers.")
+else ()
+ message(STATUS "Found protobuf C compiler in ${PROTOBUF_PROTOC_C_EXECUTABLE}")
endif ()
include_directories(${PROTOBUF_C_INCLUDE_DIRS})
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index bf1d8076..00000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-image:
- - Ubuntu2004
- - Ubuntu2204
-
-platform:
- - x64
- - x86
-
-configuration:
- - Release
- - Debug
-
-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
-
-before_build:
- - mkdir -p build
- - cd build
- - cmake -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
-
-build_script:
- - make
-
-test_script:
- - env CTEST_OUTPUT_ON_FAILURE=1 make check
diff --git a/cmake/FindProtobufC.cmake b/cmake/FindProtobufC.cmake
index ff532a46..ff892b5b 100644
--- a/cmake/FindProtobufC.cmake
+++ b/cmake/FindProtobufC.cmake
@@ -62,7 +62,7 @@ mark_as_advanced(PROTOBUF_C_INCLUDE_DIR)
# Find the protoc-c Executable
find_program(PROTOBUF_PROTOC_C_EXECUTABLE
- NAMES protoc-c
+ NAMES protoc protoc-c
DOC "The Google Protocol Buffers C Compiler"
)
mark_as_advanced(PROTOBUF_PROTOC_C_EXECUTABLE)
diff --git a/doc/man/ouroboros.8 b/doc/man/ouroboros.8
index df328fcc..5d3d9475 100644
--- a/doc/man/ouroboros.8
+++ b/doc/man/ouroboros.8
@@ -127,7 +127,9 @@ creates an IPCP process of type \fItype\fR in the system with name
.PP
\fBeth-dix\fR - create an IPCP that attaches to Ethernet using DIX frames.
.PP
-\fBudp\fR - create an IPCP that attaches to a UDP socket.
+\fBudp4\fR - create an IPCP that attaches to a UDP/IPv4 socket.
+.PP
+\fBudp6\fR - create an IPCP that attaches to a UDP/IPv6 socket.
.PP
\fBunicast\fR - create a unicast IPCP that uses lower level layers.
.PP
@@ -190,17 +192,17 @@ default: SHA3_256.
.RE
.PP
-\fBudp\fR
+\fBudp4\fR
.RS 4
.PP
-ip \fIip\fR specifies the local IP address to bind to
+ip \fIip\fR specifies the local IPv4 address to bind to
.PP
[dns \fIdns\fR] specifies an optional DDNS server that will be used for
the directory.
.PP
[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
+receiving ouroboros traffic. This must be the same for the entire UDP4
+layer. Parallel UDP4 layers should use different ports. This UDP port
needs to be forwarded if the server is behind a NAT and wants to
receive incoming requests.
.br
@@ -208,6 +210,22 @@ default: 3435
.RE
.PP
+\fBudp6\fR
+.RS 4
+.PP
+ip \fIip\fR specifies the local IPv6 address to bind to
+.PP
+[dns \fIdns\fR] specifies an optional DDNS server that will be used for
+the directory.
+.PP
+[port \fIport\fR] specifies a UDP port that is used for sending and
+receiving ouroboros traffic. This must be the same for the entire UDP6
+layer. Parallel UDP6 layers should use different ports.
+.br
+default: 3435
+.RE
+
+.PP
\fBunicast\fR
.RS 4
.PP
@@ -370,12 +388,23 @@ not accept future flow allocation requests for \fIname\fR.
.SH IRM NAME COMMANDS
.PP
-\fBirm name create \fIname\fR \fIlb\fR policy
+\fBirm name create \fIname\fR lb \fIpolicy\fR
+[sencpath \fI/path/to/server/enc.cfg\fR]
+[scrtpath \fI/path/to/server/crt.pem\fR]
+[skeypath \fI/path/to/server/key.pem\fR]
+
+[cencpath \fI/path/to/client/enc.cfg\fR]
+[ccrtpath \fI/path/to/client/crt.pem\fR]
+[ckeypath \fI/path/to/client/key.pem\fR]
.RS 4
-Create a name \fIname\fR with a load-balancing policy
+Create a name \fIname\fR with a load-balancing policy and security credentials
.br
\fIpolicy\fR: round-robin, spillover
.br
+\fI/path/to/enc.cfg\fR: The path to the server and client encryption configuration.
+\fI/path/to/pem\fR: The path to the server and client certificates and
+private keys, in pem format.
+.br
.RE
.PP
diff --git a/include/ouroboros/crypt.h b/include/ouroboros/crypt.h
index 28fe63b2..2d7cda6d 100644
--- a/include/ouroboros/crypt.h
+++ b/include/ouroboros/crypt.h
@@ -26,31 +26,89 @@
#include <ouroboros/shm_du_buff.h>
#include <ouroboros/utils.h>
+#define IVSZ 16
#define SYMMKEYSZ 32
+#define MSGBUFSZ 2048
-struct crypt_info {
- uint16_t flags;
- void * ctx;
- uint8_t key[SYMMKEYSZ];
-};
+struct auth_ctx;
+struct crypt_ctx;
-int crypt_dh_pkp_create(void ** pkp,
- uint8_t * pk);
+struct crypt_ctx * crypt_create_ctx(const uint8_t * key);
-void crypt_dh_pkp_destroy(void * pkp);
+void crypt_destroy_ctx(struct crypt_ctx * ctx);
-int crypt_dh_derive(void * pkp,
- buffer_t pk,
- uint8_t * s);
+int crypt_dh_pkp_create(void ** pkp,
+ uint8_t * pk);
-int crypt_encrypt(struct crypt_info * info,
- struct shm_du_buff * sdb);
+void crypt_dh_pkp_destroy(void * pkp);
-int crypt_decrypt(struct crypt_info * info,
- struct shm_du_buff * sdb);
+int crypt_dh_derive(void * pkp,
+ buffer_t pk,
+ uint8_t * s);
-int crypt_init(struct crypt_info * info);
+int crypt_encrypt(struct crypt_ctx * ctx,
+ buffer_t in,
+ buffer_t * out);
-void crypt_fini(struct crypt_info * info);
+int crypt_decrypt(struct crypt_ctx * ctx,
+ buffer_t in,
+ buffer_t * out);
+
+int crypt_load_crt_file(const char * path,
+ void ** crt);
+
+int crypt_load_crt_str(const char * str,
+ void ** crt);
+
+int crypt_load_crt_der(buffer_t buf,
+ void ** crt);
+
+int crypt_get_pubkey_crt(void * crt,
+ void ** pk);
+
+void crypt_free_crt(void * crt);
+
+int crypt_load_privkey_file(const char * path,
+ void ** key);
+
+int crypt_load_privkey_str(const char * str,
+ void ** key);
+
+int crypt_load_pubkey_str(const char * str,
+ void ** key);
+
+int crypt_cmp_key(const void * key1,
+ const void * key2);
+
+void crypt_free_key(void * key);
+
+int crypt_crt_str(const void * crt,
+ char * buf);
+
+int crypt_crt_der(const void * crt,
+ buffer_t * buf);
+
+int crypt_check_crt_name(void * crt,
+ const char * name);
+
+struct auth_ctx * auth_create_ctx(void);
+
+void auth_destroy_ctx(struct auth_ctx * ctx);
+
+int auth_add_crt_to_store(struct auth_ctx * ctx,
+ void * crt);
+
+void auth_destroy_ctx(struct auth_ctx * ctx);
+
+int auth_verify_crt(struct auth_ctx * ctx,
+ void * crt);
+
+int auth_sign(void * pkp,
+ buffer_t msg,
+ buffer_t * sig);
+
+int auth_verify_sig(void * pk,
+ buffer_t msg,
+ buffer_t sig);
#endif /* OUROBOROS_LIB_CRYPT_H */
diff --git a/include/ouroboros/endian.h b/include/ouroboros/endian.h
index addb2ed3..6c3493d9 100644
--- a/include/ouroboros/endian.h
+++ b/include/ouroboros/endian.h
@@ -66,8 +66,8 @@
#endif
#define hton64(x) htobe64(x)
-#define hton32(x) htobe32(x)
#define ntoh64(x) betoh64(x)
+#define hton32(x) htobe32(x)
#define ntoh32(x) betoh32(x)
#define hton16(x) htobe16(x)
#define ntoh16(x) betoh16(x)
diff --git a/include/ouroboros/errno.h b/include/ouroboros/errno.h
index 25e776df..6b808241 100644
--- a/include/ouroboros/errno.h
+++ b/include/ouroboros/errno.h
@@ -32,7 +32,10 @@
#define EIPCPSTATE 1004 /* Target in wrong state */
#define EFLOWDOWN 1005 /* Flow is down */
#define EFLOWPEER 1006 /* Flow is down (peer timed out) */
-#define ECRYPT 1007 /* Encryption error */
-#define ENAME 1008 /* Naming error */
+#define ENAME 1007 /* Naming error */
+#define ECRYPT 1008 /* Encryption error */
+#ifndef EAUTH /* Exists on BSD */
+#define EAUTH 1009 /* Authentication error */
+#endif
#endif /* OUROBOROS_ERRNO_H */
diff --git a/include/ouroboros/flow.h b/include/ouroboros/flow.h
index e6bf8886..77b7737e 100644
--- a/include/ouroboros/flow.h
+++ b/include/ouroboros/flow.h
@@ -27,14 +27,14 @@
#include <sys/types.h>
- enum flow_state { /* DO NOT CHANGE ORDER! */
+ 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_DESTROY, /* TODO: REMOVE! */
FLOW_NULL
};
diff --git a/include/ouroboros/hash.h b/include/ouroboros/hash.h
index 6b0087ce..c44c2c8a 100644
--- a/include/ouroboros/hash.h
+++ b/include/ouroboros/hash.h
@@ -42,7 +42,8 @@ enum hash_algo {
#define HASH_FMT32 "%02x%02x%02x%02x"
#define HASH_VAL32(hash) \
- (hash)[0], (hash)[1], (hash)[2], (hash)[3]
+ ((uint8_t *) hash)[0], ((uint8_t *) hash)[1], \
+ ((uint8_t *) hash)[2], ((uint8_t *) hash)[3]
#define HASH_FMT64 HASH_FMT32 HASH_FMT32
#define HASH_VAL64(hash64) \
@@ -52,6 +53,10 @@ enum hash_algo {
#define HASH_VAL128(hash128) \
HASH_VAL64(hash128), HASH_VAL64(hash128 + 8)
+#define HASH_FMT192 HASH_FMT128 HASH_FMT64
+#define HASH_VAL192(hash192) \
+ HASH_VAL128(hash192), HASH_VAL64(hash192 + 16)
+
#define HASH_FMT224 HASH_FMT128 HASH_FMT64 HASH_FMT32
#define HASH_VAL224(hash224) \
HASH_VAL128(hash224), HASH_VAL64(hash224 + 16), \
diff --git a/include/ouroboros/ipcp-dev.h b/include/ouroboros/ipcp-dev.h
index 378d724a..35e07414 100644
--- a/include/ouroboros/ipcp-dev.h
+++ b/include/ouroboros/ipcp-dev.h
@@ -28,12 +28,12 @@
#include <ouroboros/shm_rdrbuff.h>
#include <ouroboros/utils.h>
-int ipcp_create_r(const struct ipcp_info * info);
+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_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,
diff --git a/include/ouroboros/ipcp.h b/include/ouroboros/ipcp.h
index 42c4dfa4..c397f250 100644
--- a/include/ouroboros/ipcp.h
+++ b/include/ouroboros/ipcp.h
@@ -26,20 +26,22 @@
#include <stdint.h>
#include <unistd.h>
#include <stdbool.h>
+#include <netinet/in.h>
#include <sys/types.h>
#define IPCP_NAME_SIZE 255
#define LAYER_NAME_SIZE 255
#define DEV_NAME_SIZE 255
+/* TODO: Move state to ipcpd/ipcp.h, requires small change to reg/ipcp.c */
enum ipcp_state {
- IPCP_INIT = 0,
+ IPCP_NULL = 0,
+ IPCP_INIT,
IPCP_BOOT,
- IPCP_OPERATIONAL,
IPCP_BOOTSTRAPPED,
IPCP_ENROLLED,
- IPCP_SHUTDOWN,
- IPCP_NULL
+ IPCP_OPERATIONAL,
+ IPCP_SHUTDOWN
};
enum ipcp_type { /* IRMd uses order to select an IPCP for flow allocation. */
@@ -48,7 +50,8 @@ enum ipcp_type { /* IRMd uses order to select an IPCP for flow allocation. */
IPCP_BROADCAST,
IPCP_ETH_LLC,
IPCP_ETH_DIX,
- IPCP_UDP,
+ IPCP_UDP4,
+ IPCP_UDP6,
IPCP_INVALID
};
@@ -56,7 +59,7 @@ struct ipcp_info {
enum ipcp_type type;
pid_t pid;
char name[IPCP_NAME_SIZE + 1];
- enum ipcp_state state;
+ enum ipcp_state state; /* TODO: remove. */
};
/* Unicast IPCP components. */
@@ -69,13 +72,50 @@ enum pol_addr_auth {
ADDR_AUTH_INVALID
};
+enum pol_link_state {
+ LS_SIMPLE = 0,
+ LS_LFA,
+ LS_ECMP,
+ LS_INVALID
+};
+
+struct ls_config {
+ enum pol_link_state pol; /* Link state policy */
+ time_t t_recalc; /* Time to recalculate PFF (s) */
+ time_t t_update; /* Time between updates (s) */
+ time_t t_timeo; /* Link timeout (s) */
+};
+
+static const struct ls_config default_ls_config = {
+ .pol = LS_SIMPLE,
+ .t_recalc = 4,
+ .t_update = 15,
+ .t_timeo = 60
+};
+
enum pol_routing {
ROUTING_LINK_STATE = 0,
- ROUTING_LINK_STATE_LFA,
- ROUTING_LINK_STATE_ECMP,
ROUTING_INVALID
};
+struct routing_config {
+ enum pol_routing pol; /* Routing policy */
+ union {
+ struct ls_config ls; /* Link state config */
+ /* struct pv_config pv */ /* Path vector config */
+ };
+};
+
+static const struct routing_config default_routing_config = {
+ .pol = ROUTING_LINK_STATE,
+ .ls = {
+ .pol = LS_SIMPLE,
+ .t_recalc = 4,
+ .t_update = 15,
+ .t_timeo = 60
+ }
+};
+
enum pol_cong_avoid {
CA_NONE = 0,
CA_MB_ECN,
@@ -83,41 +123,158 @@ enum pol_cong_avoid {
};
struct dt_config {
- uint8_t addr_size;
- uint8_t eid_size;
- uint8_t max_ttl;
- enum pol_routing routing_type;
+ struct {
+ uint8_t addr_size;
+ uint8_t eid_size;
+ uint8_t max_ttl;
+ };
+ struct routing_config routing; /* Routing policy */
+};
+
+static const struct dt_config default_dt_config = {
+ .addr_size = 4,
+ .eid_size = 8,
+ .max_ttl = 60,
+ .routing = {
+ .pol = ROUTING_LINK_STATE,
+ .ls = {
+ .pol = LS_SIMPLE,
+ .t_recalc = 4,
+ .t_update = 15,
+ .t_timeo = 60
+ }
+ }
+};
+
+enum pol_dir {
+ DIR_DHT = 0,
+ DIR_INVALID
+};
+
+enum pol_dir_hash {
+ DIR_HASH_SHA3_224,
+ DIR_HASH_SHA3_256,
+ DIR_HASH_SHA3_384,
+ DIR_HASH_SHA3_512,
+ DIR_HASH_INVALID
+};
+
+enum dir_dht_config_limits {
+ DHT_ALPHA_MIN = 1,
+ DHT_K_MIN = 1,
+ DHT_T_EXPIRE_MIN = 10,
+ DHT_T_REFRESH_MIN = 3,
+ DHT_T_REPLICATE_MIN = 3,
+
+ DHT_ALPHA_MAX = 10,
+ DHT_K_MAX = 20,
+ DHT_T_EXPIRE_MAX = 86400,
+ DHT_T_REFRESH_MAX = 3600,
+ DHT_T_REPLICATE_MAX = 3600,
+};
+
+struct dir_dht_config {
+ struct {
+ uint32_t alpha; /* Parallel search factor */
+ uint32_t k; /* Replication factor */
+ uint32_t t_expire; /* Expire time (s) */
+ uint32_t t_refresh; /* Refresh time (s) */
+ uint32_t t_replicate; /* Replication time (s) */
+ } params;
+ uint64_t peer; /* Initial peer address */
+};
+
+static const struct dir_dht_config default_dht_config = {
+ .params = {
+ .alpha = 3, /* Proven optimal value */
+ .k = 8, /* MDHT value */
+ .t_expire = 86400, /* Expire after 1 day */
+ .t_refresh = 900, /* MDHT value. */
+ .t_replicate = 900 /* MDHT value. */
+ }
+};
+
+/* TODO: Move hash algorithm in directory config */
+struct dir_config {
+ enum pol_dir pol;
+ union {
+ struct dir_dht_config dht;
+ };
+};
+
+static const struct dir_config default_dir_config = {
+ .pol = DIR_DHT,
+ .dht = {
+ .params = {
+ .alpha = 3,
+ .k = 8,
+ .t_expire = 86400,
+ .t_refresh = 900,
+ .t_replicate = 900
+ }
+ }
};
/* IPCP configuration */
struct uni_config {
struct dt_config dt;
+ struct dir_config dir;
enum pol_addr_auth addr_auth_type;
enum pol_cong_avoid cong_avoid;
};
+static const struct uni_config default_uni_config = {
+ .dt = {
+ .addr_size = 4,
+ .eid_size = 8,
+ .max_ttl = 60,
+ .routing = {
+ .pol = ROUTING_LINK_STATE,
+ .ls = {
+ .pol = LS_SIMPLE,
+ .t_recalc = 4,
+ .t_update = 15,
+ .t_timeo = 60
+ }
+ }
+ },
+ .dir = {
+ .pol = DIR_DHT,
+ .dht = {
+ .params = {
+ .alpha = 3,
+ .k = 8,
+ .t_expire = 86400,
+ .t_refresh = 900,
+ .t_replicate = 900
+ }
+ }
+ },
+ .addr_auth_type = ADDR_AUTH_FLAT_RANDOM,
+ .cong_avoid = CA_MB_ECN
+};
+
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;
+struct udp4_config {
+ struct in_addr ip_addr;
+ struct in_addr dns_addr;
+ uint16_t port;
};
-/* Layers */
-enum pol_dir_hash {
- DIR_HASH_SHA3_224,
- DIR_HASH_SHA3_256,
- DIR_HASH_SHA3_384,
- DIR_HASH_SHA3_512,
- DIR_HASH_INVALID
+struct udp6_config {
+ struct in6_addr ip_addr;
+ struct in6_addr dns_addr;
+ uint16_t port;
};
+/* Layers */
struct layer_info {
char name[LAYER_NAME_SIZE + 1];
+ /* TODO: Move this to directory info ? */
enum pol_dir_hash dir_hash_algo;
};
@@ -127,9 +284,10 @@ struct ipcp_config {
enum ipcp_type type;
union {
- struct uni_config unicast;
- struct udp_config udp;
- struct eth_config eth;
+ struct uni_config unicast;
+ struct udp4_config udp4;
+ struct udp6_config udp6;
+ struct eth_config eth;
};
};
@@ -158,9 +316,16 @@ static const struct ipcp_config eth_llc_default_conf = {
}
};
-static const struct ipcp_config udp_default_conf = {
- .type = IPCP_UDP,
- .udp = {
+static const struct ipcp_config udp4_default_conf = {
+ .type = IPCP_UDP4,
+ .udp4 = {
+ .port = 3435
+ }
+};
+
+static const struct ipcp_config udp6_default_conf = {
+ .type = IPCP_UDP6,
+ .udp6 = {
.port = 3435
}
};
@@ -172,10 +337,30 @@ static const struct ipcp_config uni_default_conf = {
},
.unicast = {
.dt = {
- .addr_size = 4,
- .eid_size = 8,
- .max_ttl = 60,
- .routing_type = ROUTING_LINK_STATE
+ .addr_size = 4,
+ .eid_size = 8,
+ .max_ttl = 60,
+ .routing = {
+ .pol = ROUTING_LINK_STATE,
+ .ls = {
+ .pol = LS_SIMPLE,
+ .t_recalc = 4,
+ .t_update = 15,
+ .t_timeo = 60
+ }
+ }
+ },
+ .dir = {
+ .pol = DIR_DHT,
+ .dht = {
+ .params = {
+ .alpha = 3,
+ .k = 8,
+ .t_expire = 86400,
+ .t_refresh = 900,
+ .t_replicate = 900
+ }
+ }
},
.addr_auth_type = ADDR_AUTH_FLAT_RANDOM,
.cong_avoid = CA_MB_ECN
diff --git a/include/ouroboros/irm.h b/include/ouroboros/irm.h
index 0105f88e..70a21ed7 100644
--- a/include/ouroboros/irm.h
+++ b/include/ouroboros/irm.h
@@ -76,8 +76,7 @@ int irm_bind_process(pid_t pid,
int irm_unbind_process(pid_t pid,
const char * name);
-int irm_create_name(const char * name,
- enum pol_balance pol);
+int irm_create_name(struct name_info * info);
int irm_destroy_name(const char * name);
diff --git a/include/ouroboros/logs.h b/include/ouroboros/logs.h
index db49ae32..f1c401fa 100644
--- a/include/ouroboros/logs.h
+++ b/include/ouroboros/logs.h
@@ -37,12 +37,14 @@
#define CLR_RED "\x1b[31m"
#define CLR_GREEN "\x1b[32m"
#define CLR_YELLOW "\x1b[33m"
+#define CLR_BLUE "\x1b[34m"
#define CLR_RESET "\x1b[0m"
#define DEBUG_CODE "DB"
#define ERROR_CODE "EE"
#define WARN_CODE "WW"
#define INFO_CODE "II"
+#define PROTO_CODE "PP"
extern bool log_syslog;
@@ -98,9 +100,15 @@ void log_fini(void);
#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__)
+#define log_proto(...) __olog(CLR_BLUE, PROTO_CODE, LOG_DEBUG, __VA_ARGS__)
+#define log_proto_id(id, fmt, ...) \
+ __olog_id(CLR_BLUE, INFO_CODE, LOG_INFO, id, fmt, ## __VA_ARGS__)
+
#else
#define log_dbg(...) do { } while (0)
#define log_dbg_id(...) do { } while (0)
+#define log_proto(...) do { } while (0)
+#define log_proto_id(...) do { } while (0)
#endif
#endif /* OUROBOROS_LIB_LOGS_H */
diff --git a/include/ouroboros/name.h b/include/ouroboros/name.h
index 9d77a90b..14fdd504 100644
--- a/include/ouroboros/name.h
+++ b/include/ouroboros/name.h
@@ -24,6 +24,7 @@
#define OUROBOROS_NAME_H
#define NAME_SIZE 255
+#define NAME_PATH_SIZE (NAME_SIZE + 256)
#define BIND_AUTO 0x01
enum pol_balance {
@@ -32,9 +33,18 @@ enum pol_balance {
LB_INVALID
};
+struct name_sec_paths {
+ char enc[NAME_PATH_SIZE + 1]; /* path to crypt for this name */
+ char key[NAME_PATH_SIZE + 1]; /* path to key for this name */
+ char crt[NAME_PATH_SIZE + 1]; /* path to crt for this name */
+};
+
struct name_info {
char name[NAME_SIZE + 1];
enum pol_balance pol_lb;
+
+ struct name_sec_paths s; /* server */
+ struct name_sec_paths c; /* client */
};
#endif /* OUROBOROS_NAME_H */
diff --git a/include/ouroboros/np1_flow.h b/include/ouroboros/np1_flow.h
index 31720eea..4110ab6a 100644
--- a/include/ouroboros/np1_flow.h
+++ b/include/ouroboros/np1_flow.h
@@ -30,7 +30,8 @@
int np1_flow_alloc(pid_t n_pid,
int flow_id);
-int np1_flow_resp(int flow_id);
+int np1_flow_resp(int flow_id,
+ int resp);
int np1_flow_dealloc(int flow_id,
time_t timeo);
@@ -43,7 +44,6 @@ static const qosspec_t qos_np1 = {
.ber = UINT32_MAX,
.in_order = 0,
.max_gap = UINT32_MAX,
- .cypher_s = 0,
.timeout = 0
};
diff --git a/include/ouroboros/protobuf.h b/include/ouroboros/protobuf.h
index 9d38afb1..780d58dc 100644
--- a/include/ouroboros/protobuf.h
+++ b/include/ouroboros/protobuf.h
@@ -31,31 +31,36 @@
#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;
+typedef IpcpConfigMsg ipcp_config_msg_t;
+typedef LsConfigMsg ls_config_msg_t;
+typedef RoutingConfigMsg routing_config_msg_t;
+typedef DtConfigMsg dt_config_msg_t;
+typedef DirConfigMsg dir_config_msg_t;
+typedef DirDhtConfigMsg dir_dht_config_msg_t;
+typedef EthConfigMsg eth_config_msg_t;
+typedef Udp4ConfigMsg udp4_config_msg_t;
+typedef Udp6ConfigMsg udp6_config_msg_t;
+typedef UniConfigMsg uni_config_msg_t;
#include "ipcp.pb-c.h"
-typedef IpcpMsg ipcp_msg_t;
+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;
+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;
+typedef FlowInfoMsg flow_info_msg_t;
+typedef NameInfoMsg name_info_msg_t;
+typedef LayerInfoMsg layer_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;
+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);
@@ -66,6 +71,10 @@ 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);
+name_info_msg_t * name_info_s_to_msg(const struct name_info * s);
+
+struct name_info name_info_msg_to_s(const name_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);
@@ -86,9 +95,13 @@ 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);
+udp4_config_msg_t * udp4_config_s_to_msg(const struct udp4_config * s);
+
+struct udp4_config udp4_config_msg_to_s(const udp4_config_msg_t * msg);
+
+udp6_config_msg_t * udp6_config_s_to_msg(const struct udp6_config * s);
-struct udp_config udp_config_msg_to_s(const udp_config_msg_t * msg);
+struct udp6_config udp6_config_msg_to_s(const udp6_config_msg_t * msg);
ipcp_config_msg_t * ipcp_config_s_to_msg(const struct ipcp_config * s);
diff --git a/include/ouroboros/qos.h b/include/ouroboros/qos.h
index a45e8135..2be31305 100644
--- a/include/ouroboros/qos.h
+++ b/include/ouroboros/qos.h
@@ -36,7 +36,6 @@ typedef struct qos_spec {
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;
@@ -48,7 +47,6 @@ static const qosspec_t qos_raw = {
.ber = 1,
.in_order = 0,
.max_gap = UINT32_MAX,
- .cypher_s = 0,
.timeout = DEFAULT_PEER_TIMEOUT
};
@@ -60,19 +58,6 @@ static const qosspec_t qos_raw_no_errors = {
.ber = 0,
.in_order = 0,
.max_gap = UINT32_MAX,
- .cypher_s = 0,
- .timeout = DEFAULT_PEER_TIMEOUT
-};
-
-static const qosspec_t qos_raw_crypt = {
- .delay = UINT32_MAX,
- .bandwidth = 0,
- .availability = 0,
- .loss = 1,
- .ber = 0,
- .in_order = 0,
- .max_gap = UINT32_MAX,
- .cypher_s = 256,
.timeout = DEFAULT_PEER_TIMEOUT
};
@@ -84,19 +69,6 @@ static const qosspec_t qos_best_effort = {
.ber = 0,
.in_order = 1,
.max_gap = UINT32_MAX,
- .cypher_s = 0,
- .timeout = DEFAULT_PEER_TIMEOUT
-};
-
-static const qosspec_t qos_best_effort_crypt = {
- .delay = UINT32_MAX,
- .bandwidth = 0,
- .availability = 0,
- .loss = 1,
- .ber = 0,
- .in_order = 1,
- .max_gap = UINT32_MAX,
- .cypher_s = 256,
.timeout = DEFAULT_PEER_TIMEOUT
};
@@ -108,19 +80,6 @@ static const qosspec_t qos_video = {
.ber = 0,
.in_order = 1,
.max_gap = 100,
- .cypher_s = 0,
- .timeout = DEFAULT_PEER_TIMEOUT
-};
-
-static const qosspec_t qos_video_crypt = {
- .delay = 100,
- .bandwidth = UINT64_MAX,
- .availability = 3,
- .loss = 1,
- .ber = 0,
- .in_order = 1,
- .max_gap = 100,
- .cypher_s = 256,
.timeout = DEFAULT_PEER_TIMEOUT
};
@@ -132,19 +91,6 @@ static const qosspec_t qos_voice = {
.ber = 0,
.in_order = 1,
.max_gap = 50,
- .cypher_s = 0,
- .timeout = DEFAULT_PEER_TIMEOUT
-};
-
-static const qosspec_t qos_voice_crypt = {
- .delay = 50,
- .bandwidth = 100000,
- .availability = 5,
- .loss = 1,
- .ber = 0,
- .in_order = 1,
- .max_gap = 50,
- .cypher_s = 256,
.timeout = DEFAULT_PEER_TIMEOUT
};
@@ -156,19 +102,6 @@ static const qosspec_t qos_data = {
.ber = 0,
.in_order = 1,
.max_gap = 2000,
- .cypher_s = 0,
- .timeout = DEFAULT_PEER_TIMEOUT
-};
-
-static const qosspec_t qos_data_crypt = {
- .delay = 1000,
- .bandwidth = 0,
- .availability = 0,
- .loss = 0,
- .ber = 0,
- .in_order = 1,
- .max_gap = 2000,
- .cypher_s = 256,
.timeout = DEFAULT_PEER_TIMEOUT
};
diff --git a/include/ouroboros/rib.h b/include/ouroboros/rib.h
index 6aabe8f7..cdc5a9d5 100644
--- a/include/ouroboros/rib.h
+++ b/include/ouroboros/rib.h
@@ -25,6 +25,8 @@
#define RIB_PATH_LEN 300
#define RIB_SEPARATOR "/"
+#define RIB_TM_STRLEN 26
+#define RIB_TM_FORMAT "%F %T (UTC)"
#include <sys/types.h>
diff --git a/include/ouroboros/serdes-oep.h b/include/ouroboros/serdes-oep.h
index 69ba71a4..af4446c1 100644
--- a/include/ouroboros/serdes-oep.h
+++ b/include/ouroboros/serdes-oep.h
@@ -33,7 +33,6 @@
#define ENROLL_ID_LEN 8
struct enroll_req {
- /* TODO: Authentication */
uint8_t id[ENROLL_ID_LEN];
};
@@ -67,4 +66,12 @@ ssize_t enroll_ack_ser(const struct enroll_ack * ack,
int enroll_ack_des(struct enroll_ack * ack,
const buffer_t buf);
+#ifdef DEBUG_PROTO_OEP
+void debug_enroll_req(const struct enroll_req * req);
+
+void debug_enroll_resp(const struct enroll_resp * resp);
+
+void debug_enroll_ack(const struct enroll_ack * ack);
+#endif /* DEBUG_PROTO_OEP */
+
#endif /* OUROBOROS_LIB_SERDES_OEP_H*/
diff --git a/include/ouroboros/sockets.h.in b/include/ouroboros/sockets.h.in
index 095674a9..1a6974ac 100644
--- a/include/ouroboros/sockets.h.in
+++ b/include/ouroboros/sockets.h.in
@@ -27,16 +27,20 @@
#include <sys/types.h>
-#define SOCK_PATH "/var/run/ouroboros/"
+#ifndef OUROBOROS_TEST
+ #define SOCK_PATH "/var/run/ouroboros/"
+#else
+ #define SOCK_PATH "/tmp/"
+#endif
#define SOCK_PATH_SUFFIX ".sock"
#define IRM_SOCK_PATH SOCK_PATH "irm" SOCK_PATH_SUFFIX
-#define IPCP_SOCK_PATH_PREFIX SOCK_PATH "ipcp"
+#define IPCP_SOCK_PATH_PREFIX SOCK_PATH "ipcp."
#define SOCK_BUF_SIZE @SOCK_BUF_SIZE@
-/* Returns the full socket path of an IPCP */
-char * ipcp_sock_path(pid_t pid);
+char * sock_path(pid_t pid,
+ const char * path);
int server_socket_open(char * file_name);
diff --git a/include/ouroboros/test.h b/include/ouroboros/test.h
index 096e145c..bccf9ccd 100644
--- a/include/ouroboros/test.h
+++ b/include/ouroboros/test.h
@@ -28,6 +28,11 @@
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
+#include <sys/types.h>
+
+#define TEST_RC_SUCCESS 0
+#define TEST_RC_SKIP 1
+#define TEST_RC_FAIL -1
#define TEST_START() \
do { \
@@ -36,13 +41,19 @@
} while (0)
#define TEST_SUCCESS() \
do { \
- printf("%s succeeded.\n", __func__); \
+ printf("\x1b[32m%s succeeded.\x1b[0m\n", __func__); \
+ fflush(stdout); \
+ } while (0)
+
+#define TEST_SKIPPED() \
+ do { \
+ printf("\x1b[33m%s skipped.\x1b[0m\n", __func__); \
fflush(stdout); \
} while (0)
#define TEST_FAIL() \
do { \
- printf("%s failed.\n", __func__); \
+ printf("\x1b[31m%s failed.\x1b[0m\n", __func__); \
fflush(stdout); \
} while (0)
@@ -57,7 +68,7 @@ static int __attribute__((unused)) test_assert_fail(int(* testfunc)(void))
pid = fork();
if (pid == -1) {
printf("Failed to fork: %s.\n", strerror(errno));
- return -1;
+ return TEST_RC_FAIL;
}
if (pid == 0)
@@ -66,17 +77,17 @@ static int __attribute__((unused)) test_assert_fail(int(* testfunc)(void))
waitpid(pid, &wstatus, 0);
#ifdef CONFIG_OUROBOROS_DEBUG
if (WIFSIGNALED(wstatus) && (wstatus == 134 || wstatus == 6))
- return 0;
+ return TEST_RC_SUCCESS;
printf("Process did not abort, status: %d.\n", wstatus);
#else
if (WIFEXITED(wstatus) && wstatus == 0)
- return 0;
+ return TEST_RC_SUCCESS;
printf("Process did not exit, status: %d.\n", wstatus);
#endif
- return -1;
+ return TEST_RC_FAIL;
}
#endif /* OUROBOROS_LIB_TEST_H */
diff --git a/include/ouroboros/time.h b/include/ouroboros/time.h
index b274c35b..3bd6a257 100644
--- a/include/ouroboros/time.h
+++ b/include/ouroboros/time.h
@@ -31,34 +31,38 @@
#undef BILLION
#endif
-#define MILLION 1000000L
-#define BILLION 1000000000L
+#define MILLION 1000000LL
+#define BILLION 1000000000LL
#include <time.h>
#include <sys/time.h>
+#include <sys/types.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 TS_TO_UINT64(ts) \
+ ((uint64_t)(ts).tv_sec * BILLION + (uint64_t)(ts).tv_nsec)
+
#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 \
+#define ts_diff_ns(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * BILLION \
+ ((tx)->tv_nsec - (t0)->tv_nsec))
-#define ts_diff_us(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * MILLION \
+#define ts_diff_us(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * MILLION \
+ ((tx)->tv_nsec - (t0)->tv_nsec) / 1000L)
-#define ts_diff_ms(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * 1000L \
+#define ts_diff_ms(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * 1000L \
+ ((tx)->tv_nsec - (t0)->tv_nsec) / MILLION)
/* functions for timevals are the same */
-#define tv_diff_us(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * MILLION \
+#define tv_diff_us(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * MILLION \
+ + ((tx)->tv_usec - (t0)->tv_usec))
+#define tv_diff_ms(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * 1000L \
+ ((tx)->tv_usec - (t0)->tv_usec) / 1000L)
-#define tv_diff_ms(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * 1000L \
- + ((tx)->tv_usec - (t0)->tv_usec) / MILLION)
/* functions for timespecs */
diff --git a/include/ouroboros/tpm.h b/include/ouroboros/tpm.h
index 445f9306..3fb49b88 100644
--- a/include/ouroboros/tpm.h
+++ b/include/ouroboros/tpm.h
@@ -38,8 +38,10 @@ int tpm_start(struct tpm * tpm);
void tpm_stop(struct tpm * tpm);
-void tpm_dec(struct tpm * tpm);
+void tpm_begin_work(struct tpm * tpm);
-void tpm_inc(struct tpm * tpm);
+void tpm_wait_work(struct tpm * tpm);
+
+void tpm_end_work(struct tpm * tpm);
#endif /* OUROBOROS_LIB_TPM_H */
diff --git a/include/ouroboros/utils.h b/include/ouroboros/utils.h
index 93fbf402..b93b345d 100644
--- a/include/ouroboros/utils.h
+++ b/include/ouroboros/utils.h
@@ -24,20 +24,26 @@
#define OUROBOROS_LIB_UTILS_H
#include <stdint.h>
-#include <unistd.h>
+#include <stdlib.h>
#include <string.h>
+#include <unistd.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);
+#define BUF_INIT { 0, NULL }
+#define BUF_IS_EMPTY(buf) ((buf)->data == NULL && (buf)->len == 0)
typedef struct {
- uint8_t * data;
size_t len;
+ uint8_t * data;
} buffer_t;
+int bufcmp(const buffer_t * a,
+ const buffer_t * b);
+
/*
* Returns the number of characters a uint would
* need when represented as a string
@@ -57,11 +63,17 @@ void argvfree(char ** argv);
/* destroy a ** */
#define freepp(type, ptr, len) \
do { \
- if (len == 0) \
- break; \
- while (len > 0) \
- free(((type **) ptr)[--len]); \
+ while (len-- > 0) \
+ free(((type **) ptr)[len]); \
+ free(ptr); \
+ } while (0)
+
+/* destroys an array of buffers */
+#define freebufs(ptr, len) \
+ do { \
+ while ((len)-- > 0) \
+ freebuf((ptr)[len]); \
free(ptr); \
- } while (0);
+ } while (0)
#endif /* OUROBOROS_LIB_UTILS_H */
diff --git a/irmd.conf.in b/irmd.conf.in
index 4fb01c93..83ab19b5 100644
--- a/irmd.conf.in
+++ b/irmd.conf.in
@@ -56,6 +56,17 @@ prog=["@INSTALL_DIR@/ocbr"] # Defaults to [].
[name.ovpn]
prog=["@INSTALL_DIR@/ovpn"] # Defaults to [].
+[name."oping.secure"]
+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).
+# server_enc_file=/path/to/enc.cfg Default: @OUROBOROS_SRV_CRT_DIR@/<name>/enc.cfg
+# server_crt_file=/path/to/crt.pem Default: @OUROBOROS_SRV_CRT_DIR@/<name>/crt.pem
+# server_key_file=/path/to/key.pem Default: @OUROBOROS_SRV_CRT_DIR@/<name>/key.pem
+# client_enc_file=/path/to/enc.cfg Default: @OUROBOROS_CLI_CRT_DIR@/<name>/enc.cfg
+# client_crt_file=/path/to/crt.pem Default: @OUROBOROS_CLI_CRT_DIR@/<name>/crt.pem
+# client_key_file=/path/to/key.pem Default: @OUROBOROS_CLI_CRT_DIR@/<name>/key.pem
+
[local.local1]
bootstrap="local1" # Defaults to not set.
# BOOTSTRAP CONFIGURATION
@@ -77,16 +88,23 @@ dev="lo"
# hash="SHA3_224" # Defaults to SHA3_256.
reg=["lan1"]
-[udp.udp1]
+[udp4.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.
+[udp6.udp2]
+bootstrap="udp2" # Defaults to not set.
+ # BOOTSTRAP CONFIGURATION
+ip="::1"
+# port=9000 # Defaults to 3435.
+# dns="::1" # Requires a DDNS server. Disables DDNS support if not set.
+
[broadcast.bc1]
bootstrap="broadcast" # Defaults to not set.
-autobind=true # Defaults to false.
+# autobind=true # Defaults to false.
[broadcast.bc2]
enrol="bc1"
@@ -96,13 +114,22 @@ enrol="bc1"
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).
+# ls_t_recalc=4 # Forwarding Function update interval (s) (Default 4).
+# ls_t_update=15 # Link State Advertisement update interval (s) (Default 15).
+# ls_t_timeo=60 # Link Timeout (s) (Default 60).
# congestion="none" # Defaults to mb-ecn (options: none, mb-ecn).
+# directory=DHT # Defaults to DHT (options: DHT)
+# hash="SHA3_224" # Defaults to SHA3_256.
+# dht_alpha=3 # DHT parallel search factor (Default 3, optimal)
+# dht_k=8 # DHT replication factor (Default: 8, same as Mainline DHT)
+# dht_t_expiry=3600 # DHT entry expiry time (s) (Default: 86400 s)
+# dht_t_refresh=900 # DHT contact refresh interval (s) (Default: 900 s)
+# dht_t_replicate=900 # DHT replication interval (s) (Default: 900 s)
# NAMES KNOWN
reg=["oping"] # Defaults to [].
diff --git a/ouroboros-dev.pc.in b/ouroboros-dev.pc.in
index 8895a76b..b92c2741 100644
--- a/ouroboros-dev.pc.in
+++ b/ouroboros-dev.pc.in
@@ -1,7 +1,7 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
-libdir=${exec_prefix}/usr/lib
-includedir=${prefix}/usr/include
+libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: ouroboros-dev
Description: Development library for Ouroboros
diff --git a/ouroboros-irm.pc.in b/ouroboros-irm.pc.in
index 5e5841c2..6acfe6d6 100644
--- a/ouroboros-irm.pc.in
+++ b/ouroboros-irm.pc.in
@@ -1,7 +1,7 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
-libdir=${exec_prefix}/usr/lib
-includedir=${prefix}/usr/include
+libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: ouroboros-irm
Description: Management library for Ouroboros
diff --git a/src/ipcpd/CMakeLists.txt b/src/ipcpd/CMakeLists.txt
index 54294f11..b3b049e3 100644
--- a/src/ipcpd/CMakeLists.txt
+++ b/src/ipcpd/CMakeLists.txt
@@ -16,8 +16,6 @@ set(IPCP_SCHED_THR_MUL 2 CACHE STRING
"Number of scheduler threads per QoS cube")
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")
diff --git a/src/ipcpd/broadcast/main.c b/src/ipcpd/broadcast/main.c
index f51fc629..ebdb182c 100644
--- a/src/ipcpd/broadcast/main.c
+++ b/src/ipcpd/broadcast/main.c
@@ -52,13 +52,8 @@
#include <assert.h>
#include <inttypes.h>
-struct ipcp ipcpi;
-
-static int initialize_components(const struct ipcp_config * conf)
+static int initialize_components(void)
{
- 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() < 0) {
@@ -107,6 +102,7 @@ static void stop_components(void)
static int broadcast_ipcp_enroll(const char * dst,
struct layer_info * info)
{
+ struct ipcp_config * conf;
struct conn conn;
uint8_t id[ENROLL_ID_LEN];
@@ -128,7 +124,10 @@ static int broadcast_ipcp_enroll(const char * dst,
goto fail_enroll_boot;
}
- if (initialize_components(enroll_get_conf()) < 0) {
+ conf = enroll_get_conf();
+ *info = conf->layer_info;
+
+ if (initialize_components() < 0) {
log_err_id(id, "Failed to initialize components.");
goto fail_enroll_boot;
}
@@ -146,9 +145,6 @@ static int broadcast_ipcp_enroll(const char * dst,
log_info_id(id, "Enrolled with %s.", dst);
- info->dir_hash_algo = (enum pol_dir_hash) ipcpi.dir_hash_algo;
- strcpy(info->name, ipcpi.layer_name);
-
return 0;
fail_start_comp:
@@ -159,16 +155,15 @@ static int broadcast_ipcp_enroll(const char * dst,
return -1;
}
-static int broadcast_ipcp_bootstrap(const struct ipcp_config * conf)
+static int broadcast_ipcp_bootstrap(struct ipcp_config * conf)
{
assert(conf);
assert(conf->type == THIS_TYPE);
- ((struct ipcp_config *) conf)->layer_info.dir_hash_algo =
- DIR_HASH_SHA3_256;
+ assert(conf->layer_info.dir_hash_algo == DIR_HASH_SHA3_256);
enroll_bootstrap(conf);
- if (initialize_components(conf)) {
+ if (initialize_components()) {
log_err("Failed to init IPCP components.");
goto fail_init;
}
@@ -192,12 +187,12 @@ static int name_check(const uint8_t * dst)
size_t len;
int ret;
- len = hash_len(ipcpi.dir_hash_algo);
+ len = ipcp_dir_hash_len();
buf = malloc(len);
if (buf == NULL)
return -ENOMEM;
- str_hash(ipcpi.dir_hash_algo, buf, ipcpi.layer_name);
+ str_hash(HASH_SHA3_256, buf, ipcp_get_name());
ret = memcmp(buf, dst, len);
@@ -212,7 +207,7 @@ static int broadcast_ipcp_join(int fd,
{
struct conn conn;
time_t mpl = IPCP_BROADCAST_MPL;
- buffer_t data = {NULL, 0};
+ buffer_t data = BUF_INIT;
(void) qs;
diff --git a/src/ipcpd/common/connmgr.c b/src/ipcpd/common/connmgr.c
index 4b5fd420..1bb8c932 100644
--- a/src/ipcpd/common/connmgr.c
+++ b/src/ipcpd/common/connmgr.c
@@ -38,12 +38,6 @@
#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;
@@ -61,7 +55,6 @@ struct comp {
struct {
struct comp comps[COMPID_MAX];
- enum connmgr_state state;
pthread_t acceptor;
} connmgr;
@@ -179,6 +172,8 @@ static void * flow_acceptor(void * o)
continue;
}
+ fccntl(fd, FLOWSRCVTIMEO, NULL);
+
err = add_comp_conn(id, fd, qs, &rcv_info);
if (err < 0) {
log_err("Failed to add new connection: %d.", err);
@@ -226,8 +221,6 @@ static void handle_event(void * self,
int connmgr_init(void)
{
- connmgr.state = CONNMGR_INIT;
-
if (notifier_reg(handle_event, NULL)) {
log_err("Failed to register notifier.");
return -1;
@@ -240,13 +233,10 @@ 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);
+
+ notifier_unreg(handle_event);
}
int connmgr_start(void)
@@ -256,15 +246,13 @@ int connmgr_start(void)
return -1;
}
- connmgr.state = CONNMGR_RUNNING;
-
return 0;
}
void connmgr_stop(void)
{
- if (connmgr.state == CONNMGR_RUNNING)
- pthread_cancel(connmgr.acceptor);
+ pthread_cancel(connmgr.acceptor);
+ pthread_join(connmgr.acceptor, NULL);
}
int connmgr_comp_init(enum comp_id id,
@@ -487,9 +475,6 @@ int connmgr_alloc(enum comp_id id,
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);
@@ -513,7 +498,7 @@ int connmgr_dealloc(enum comp_id id,
case COMPID_DT:
notifier_event(NOTIFY_DT_CONN_DEL, conn);
break;
-#if defined(BUILD_IPCP_UNICAST) && defined(IPCP_CONN_WAIT_DIR)
+#if defined(BUILD_IPCP_UNICAST)
case COMPID_MGMT:
notifier_event(NOTIFY_MGMT_CONN_DEL, conn);
break;
diff --git a/src/ipcpd/common/enroll.c b/src/ipcpd/common/enroll.c
index 5e35ce37..8e5384a5 100644
--- a/src/ipcpd/common/enroll.c
+++ b/src/ipcpd/common/enroll.c
@@ -43,20 +43,19 @@
#include <string.h>
#include <pthread.h>
+#ifdef __APPLE__
+#define llabs labs
+#endif
+
#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;
@@ -107,8 +106,6 @@ static void * enroll_handle(void * o)
log_info_id(req.id, "Handling incoming enrollment.");
- /* TODO: authentication, timezone handling (UTC). */
-
ack.result = -100;
clock_gettime(CLOCK_REALTIME, &resp.t);
@@ -227,12 +224,14 @@ int enroll_boot(struct conn * conn,
return -1;
}
- if (resp.conf.type != ipcpi.type) {
+ if (resp.conf.type != ipcp_get_type()) {
log_err_id(id, "Wrong type in enrollment response %d (%d).",
- resp.conf.type, ipcpi.type);
+ resp.conf.type, ipcp_get_type());
return -1;
}
+ enroll.conf = resp.conf;
+
clock_gettime(CLOCK_REALTIME, &rtt);
delta_t = ts_diff_ms(&t0, &rtt);
@@ -240,11 +239,9 @@ int enroll_boot(struct conn * conn,
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)
+ if (llabs(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;
}
@@ -307,16 +304,11 @@ int enroll_init(void)
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);
}
@@ -325,13 +317,11 @@ 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);
+ pthread_cancel(enroll.listener);
+ pthread_join(enroll.listener, NULL);
}
diff --git a/src/ipcpd/config.h.in b/src/ipcpd/config.h.in
index fe4f5fd2..d2af6440 100644
--- a/src/ipcpd/config.h.in
+++ b/src/ipcpd/config.h.in
@@ -41,8 +41,6 @@
#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@
@@ -53,9 +51,14 @@
#define IPCP_UNICAST_MPL @IPCP_UNICAST_MPL@
#define CONNMGR_RCV_TIMEOUT @CONNMGR_RCV_TIMEOUT@
-#cmakedefine IPCP_CONN_WAIT_DIR
#cmakedefine DISABLE_CORE_LOCK
#cmakedefine IPCP_FLOW_STATS
+#cmakedefine IPCP_DEBUG_LOCAL
+#ifdef CONFIG_OUROBOROS_DEBUG
+#cmakedefine DEBUG_PROTO_DHT
+#cmakedefine DEBUG_PROTO_OEP
+#cmakedefine DEBUG_PROTO_LS
+#endif
/* udp */
#cmakedefine HAVE_DDNS
diff --git a/src/ipcpd/eth/CMakeLists.txt b/src/ipcpd/eth/CMakeLists.txt
index d57e1848..44299a59 100644
--- a/src/ipcpd/eth/CMakeLists.txt
+++ b/src/ipcpd/eth/CMakeLists.txt
@@ -85,18 +85,18 @@ 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(IPCP_ETH_MPL 100 CACHE STRING
+ "Default maximum packet lifetime for the Ethernet IPCPs, in ms")
set(ETH_LLC_SOURCES
# Add source files here
- ${CMAKE_CURRENT_SOURCE_DIR}/llc.c
- )
+ llc.c
+ )
set(ETH_DIX_SOURCES
# Add source files here
- ${CMAKE_CURRENT_SOURCE_DIR}/dix.c
- )
+ dix.c
+ )
set(IPCP_ETH_LLC_TARGET ipcpd-eth-llc CACHE INTERNAL "")
set(IPCP_ETH_DIX_TARGET ipcpd-eth-dix CACHE INTERNAL "")
diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c
index ea6e0f1c..0b6a91fb 100644
--- a/src/ipcpd/eth/eth.c
+++ b/src/ipcpd/eth/eth.c
@@ -88,31 +88,31 @@
#include <sys/mman.h>
#if defined(HAVE_NETMAP)
-#define NETMAP_WITH_LIBS
-#include <net/netmap_user.h>
+ #define NETMAP_WITH_LIBS
+ #include <net/netmap_user.h>
#elif defined(HAVE_BPF)
-#define BPF_DEV_MAX 256
-#define BPF_BLEN sysconf(_SC_PAGESIZE)
-#include <net/bpf.h>
+ #define BPF_DEV_MAX 256
+ #define BPF_BLEN sysconf(_SC_PAGESIZE)
+ #include <net/bpf.h>
#endif
-#ifdef __linux__
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_VAL(a) \
+ (uint8_t)(a)[0], (uint8_t)(a)[1], (uint8_t)(a)[2], \
+ (uint8_t)(a)[3], (uint8_t)(a)[4], (uint8_t)(a)[5]
+
+
#ifndef ETH_MAX_MTU /* In if_ether.h as of Linux 4.10. */
-#define ETH_MAX_MTU 0xFFFFU
+ #define ETH_MAX_MTU 0xFFFFU
#endif /* ETH_MAX_MTU */
#ifdef BUILD_ETH_DIX
-#define ETH_MTU eth_data.mtu
-#define ETH_MTU_MAX ETH_MAX_MTU
+ #define ETH_MTU eth_data.mtu
+ #define ETH_MTU_MAX ETH_MAX_MTU
#else
-#define ETH_MTU eth_data.mtu
-#define ETH_MTU_MAX 1500
+ #define ETH_MTU eth_data.mtu
+ #define ETH_MTU_MAX 1500
#endif /* BUILD_ETH_DIX */
-#else /* __linux__ */
-#define ETH_MTU 1500
-#define ETH_MTU_MAX ETH_MTU
-#endif /* __linux__ */
-#define MAC_SIZE 6
#define ETH_TYPE_LENGTH_SIZE sizeof(uint16_t)
#define ETH_HEADER_SIZE (2 * MAC_SIZE + ETH_TYPE_LENGTH_SIZE)
@@ -145,8 +145,6 @@
#define NAME_QUERY_REQ 2
#define NAME_QUERY_REPLY 3
-struct ipcp ipcpi;
-
struct mgmt_msg {
#if defined(BUILD_ETH_DIX)
uint16_t seid;
@@ -165,13 +163,12 @@ struct mgmt_msg {
uint32_t max_gap;
uint32_t delay;
uint32_t timeout;
- uint16_t cypher_s;
+ int32_t response;
uint8_t in_order;
#if defined (BUILD_ETH_DIX)
uint8_t code;
uint8_t availability;
#endif
- int8_t response;
} __attribute__((packed));
struct eth_frame {
@@ -209,8 +206,9 @@ struct mgmt_frame {
struct {
struct shim_data * shim_data;
-#ifdef __linux__
+
int mtu;
+#ifdef __linux__
int if_idx;
#endif
#if defined(HAVE_NETMAP)
@@ -491,7 +489,6 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr,
msg->ber = hton32(qs.ber);
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());
@@ -539,7 +536,7 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
msg->ssap = ssap;
msg->dsap = dsap;
#endif
- msg->response = response;
+ msg->response = hton32(response);
if (data->len > 0)
memcpy(msg + 1, data->data, data->len);
@@ -694,11 +691,11 @@ static int eth_ipcp_name_query_req(const uint8_t * hash,
static int eth_ipcp_name_query_reply(const uint8_t * hash,
uint8_t * r_addr)
{
- uint64_t address = 0;
+ struct addr addr;
- memcpy(&address, r_addr, MAC_SIZE);
+ memcpy(&addr.mac, r_addr, MAC_SIZE);
- shim_data_dir_add_entry(eth_data.shim_data, hash, address);
+ shim_data_dir_add_entry(eth_data.shim_data, hash, addr);
shim_data_dir_query_respond(eth_data.shim_data, hash);
@@ -729,7 +726,6 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
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);
data.data = (uint8_t *) buf + msg_len;
@@ -762,7 +758,7 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
msg->ssap,
msg->dsap,
#endif
- msg->response,
+ ntoh32(msg->response),
&data);
break;
case NAME_QUERY_REQ:
@@ -1217,106 +1213,123 @@ static int open_bpf_device(void)
}
#endif
-static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
-{
- int idx;
- struct ifreq ifr;
-#if defined(HAVE_NETMAP)
- char ifn[IFNAMSIZ];
-#elif defined(HAVE_BPF)
- int enable = 1;
- int disable = 0;
- int blen;
-#endif /* HAVE_NETMAP */
-
#if defined(__FreeBSD__) || defined(__APPLE__)
+static int ifr_hwaddr_from_ifaddrs(struct ifreq * ifr)
+{
struct ifaddrs * ifaddr;
struct ifaddrs * ifa;
-#elif defined(__linux__)
- int skfd;
-#endif
-#ifndef SHM_RDRB_MULTI_BLOCK
- size_t maxsz;
-#endif
-#if defined(HAVE_RAW_SOCKETS)
- #if defined(IPCP_ETH_QDISC_BYPASS)
- int qdisc_bypass = 1;
- #endif /* ENABLE_QDISC_BYPASS */
- int flags;
-#endif
- assert(conf);
- assert(conf->type == THIS_TYPE);
-
- ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo;
- strcpy(ipcpi.layer_name, conf->layer_info.name);
-
- 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->eth.dev);
-
-#ifdef BUILD_ETH_DIX
- if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) {
- log_err("Invalid Ethertype: %d.", conf->eth.ethertype);
- return -1;
- }
- eth_data.ethertype = htons(conf->eth.ethertype);
-#endif
+ int idx;
-#if defined(__FreeBSD__) || defined(__APPLE__)
if (getifaddrs(&ifaddr) < 0) {
log_err("Could not get interfaces.");
- return -1;
+ goto fail_ifaddrs;
}
for (ifa = ifaddr, idx = 0; ifa != NULL; ifa = ifa->ifa_next, ++idx) {
- if (strcmp(ifa->ifa_name, conf->eth.dev))
- continue;
- log_dbg("Interface %s found.", conf->eth.dev);
-
- #if defined(HAVE_NETMAP) || defined(HAVE_BPF)
- memcpy(eth_data.hw_addr,
- LLADDR((struct sockaddr_dl *) (ifa)->ifa_addr),
- MAC_SIZE);
- #elif defined (HAVE_RAW_SOCKETS)
- memcpy(&ifr.ifr_addr, ifa->ifa_addr, sizeof(*ifa->ifa_addr));
- #endif
- break;
+ if (strcmp(ifa->ifa_name, ifr->ifr_name) == 0)
+ break;
}
- freeifaddrs(ifaddr);
-
if (ifa == NULL) {
log_err("Interface not found.");
- return -1;
+ goto fail_ifa;
+ }
+
+ memcpy(&ifr->ifr_addr, ifa->ifa_addr, sizeof(*ifa->ifa_addr));
+
+ log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name,
+ MAC_VAL(ifr->ifr_addr.sa_data));
+
+ freeifaddrs(ifaddr);
+
+ return 0;
+ fail_ifa:
+ freeifaddrs(ifaddr);
+ fail_ifaddrs:
+ return -1;
+
+}
+#elif defined(__linux__)
+static int ifr_hwaddr_from_socket(struct ifreq * ifr)
+{
+ int skfd;
+
+ skfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (skfd < 0) {
+ log_err("Failed to open socket.");
+ goto fail_socket;
+ }
+
+ if (ioctl(skfd, SIOCGIFHWADDR, ifr)) {
+ log_err("Failed to get hwaddr.");
+ goto fail_ifr;
}
+ log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name,
+ MAC_VAL(ifr->ifr_hwaddr.sa_data));
+
+ close(skfd);
+
+ return 0;
+
+ fail_ifr:
+ close(skfd);
+ fail_socket:
+ return -1;
+}
+#endif
+
+static int eth_ifr_hwaddr(struct ifreq * ifr)
+{
+#if defined(__FreeBSD__) || defined(__APPLE__)
+ return ifr_hwaddr_from_ifaddrs(ifr);
#elif defined(__linux__)
+ return ifr_hwaddr_from_socket(ifr);
+#else
+ return -1;
+#endif
+}
+
+static int eth_ifr_mtu(struct ifreq * ifr)
+{
+ int skfd;
+
skfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (skfd < 0) {
log_err("Failed to open socket.");
- return -1;
+ goto fail_socket;
}
- if (ioctl(skfd, SIOCGIFMTU, &ifr)) {
+ if (ioctl(skfd, SIOCGIFMTU, ifr) < 0) {
log_err("Failed to get MTU.");
- close(skfd);
+ goto fail_mtu;
+ }
+ close(skfd);
+
+ return 0;
+
+ fail_mtu:
+ close(skfd);
+ fail_socket:
+ return -1;
+}
+
+static int eth_set_mtu(struct ifreq * ifr)
+{
+ if (eth_ifr_mtu(ifr) < 0) {
+ log_err("Failed to get interface MTU.");
return -1;
}
- log_dbg("Device MTU is %d.", ifr.ifr_mtu);
+ log_dbg("Device MTU is %d.", ifr->ifr_mtu);
- eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr.ifr_mtu);
- if (memcmp(conf->eth.dev, "lo", 2) == 0 &&
+ eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr->ifr_mtu);
+ if (memcmp(ifr->ifr_name, "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;
}
-
#ifndef SHM_RDRB_MULTI_BLOCK
maxsz = SHM_RDRB_BLOCK_SIZE - 5 * sizeof(size_t) -
(DU_BUFF_HEADSPACE + DU_BUFF_TAILSPACE);
@@ -1327,30 +1340,18 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
#endif
log_dbg("Layer MTU is %d.", eth_data.mtu);
- if (ioctl(skfd, SIOCGIFHWADDR, &ifr)) {
- log_err("Failed to get hwaddr.");
- close(skfd);
- return -1;
- }
-
- close(skfd);
-
- idx = if_nametoindex(conf->eth.dev);
- if (idx == 0) {
- log_err("Failed to retrieve interface index.");
- return -1;
- }
- eth_data.if_idx = idx;
-#endif /* __FreeBSD__ */
-
+ return 0;
+}
#if defined(HAVE_NETMAP)
+static int eth_init_nmd(struct ifreq * ifr)
+{
strcpy(ifn, "netmap:");
- strcat(ifn, conf->eth.dev);
+ strcat(ifn, ifr->ifr_name);
eth_data.nmd = nm_open(ifn, NULL, 0, NULL);
if (eth_data.nmd == NULL) {
log_err("Failed to open netmap device.");
- return -1;
+ goto fail_nmd;
}
memset(&eth_data.poll_in, 0, sizeof(eth_data.poll_in));
@@ -1362,11 +1363,22 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
eth_data.poll_out.events = POLLOUT;
log_info("Using netmap device.");
-#elif defined(HAVE_BPF) /* !HAVE_NETMAP */
+
+ return 0;
+ fail_nmd:
+ return -1;
+}
+#elif defined (HAVE_BPF)
+static int eth_init_bpf(struct ifreq * ifr)
+{
+ int enable = 1;
+ int disable = 0;
+ int blen;
+
eth_data.bpf = open_bpf_device();
if (eth_data.bpf < 0) {
log_err("Failed to open bpf device.");
- return -1;
+ goto fail_bpf;
}
ioctl(eth_data.bpf, BIOCGBLEN, &blen);
@@ -1376,7 +1388,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
goto fail_device;
}
- if (ioctl(eth_data.bpf, BIOCSETIF, &ifr) < 0) {
+ if (ioctl(eth_data.bpf, BIOCSETIF, ifr) < 0) {
log_err("Failed to set interface.");
goto fail_device;
}
@@ -1397,22 +1409,39 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
}
log_info("Using Berkeley Packet Filter.");
+
+ return 0;
+
+ fail_device:
+ close(eth_data.bpf);
+ fail_bpf:
+ return -1;
+}
#elif defined(HAVE_RAW_SOCKETS)
+static int eth_init_raw_socket(struct ifreq * ifr)
+{
+ int idx;
+ int flags;
+#if defined(IPCP_ETH_QDISC_BYPASS)
+ int qdisc_bypass = 1;
+#endif /* ENABLE_QDISC_BYPASS */
+
+ idx = if_nametoindex(ifr->ifr_name);
+ if (idx == 0) {
+ log_err("Failed to retrieve interface index.");
+ return -1;
+ }
memset(&(eth_data.device), 0, sizeof(eth_data.device));
eth_data.device.sll_ifindex = idx;
eth_data.device.sll_family = AF_PACKET;
- memcpy(eth_data.device.sll_addr, ifr.ifr_hwaddr.sa_data, MAC_SIZE);
+ memcpy(eth_data.device.sll_addr, ifr->ifr_hwaddr.sa_data, MAC_SIZE);
eth_data.device.sll_halen = MAC_SIZE;
eth_data.device.sll_protocol = htons(ETH_P_ALL);
-
- #if defined (BUILD_ETH_DIX)
+#if defined (BUILD_ETH_DIX)
eth_data.s_fd = socket(AF_PACKET, SOCK_RAW, eth_data.ethertype);
- #elif defined (BUILD_ETH_LLC)
+#elif defined (BUILD_ETH_LLC)
eth_data.s_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_802_2));
- #endif
-
- log_info("Using raw socket device.");
-
+#endif
if (eth_data.s_fd < 0) {
log_err("Failed to create socket.");
goto fail_socket;
@@ -1429,28 +1458,96 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
goto fail_device;
}
- #if defined(IPCP_ETH_QDISC_BYPASS)
+#if defined(IPCP_ETH_QDISC_BYPASS)
if (setsockopt(eth_data.s_fd, SOL_PACKET, PACKET_QDISC_BYPASS,
&qdisc_bypass, sizeof(qdisc_bypass))) {
log_info("Qdisc bypass not supported.");
}
- #endif
+#endif
if (bind(eth_data.s_fd, (struct sockaddr *) &eth_data.device,
sizeof(eth_data.device)) < 0) {
log_err("Failed to bind socket to interface.");
goto fail_device;
}
+#ifdef __linux__
+ eth_data.if_idx = idx;
+#endif
+ log_info("Using raw socket device.");
+
+ return 0;
+ fail_device:
+ close(eth_data.s_fd);
+ fail_socket:
+ return -1;
+}
+#endif
+
+static int eth_ipcp_bootstrap(struct ipcp_config * conf)
+{
+ struct ifreq ifr;
+ int i;
+#if defined(HAVE_NETMAP)
+ char ifn[IFNAMSIZ];
+#endif /* HAVE_NETMAP */
+
+#ifndef SHM_RDRB_MULTI_BLOCK
+ size_t maxsz;
+#endif
+ assert(conf);
+ assert(conf->type == THIS_TYPE);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, conf->eth.dev);
+
+ if (strlen(conf->eth.dev) >= IFNAMSIZ) {
+ log_err("Invalid device name: %s.", conf->eth.dev);
+ return -1;
+ }
+#ifdef BUILD_ETH_DIX
+ if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) {
+ log_err("Invalid Ethertype: %d.", conf->eth.ethertype);
+ return -1;
+ }
+ eth_data.ethertype = htons(conf->eth.ethertype);
+#endif
+ if (eth_set_mtu(&ifr) < 0) {
+ log_err("Failed to set MTU.");
+ return -1;
+ }
+
+ if (eth_ifr_hwaddr(&ifr) < 0) {
+ log_err("Failed to get hardware addr.");
+ return -1;
+ }
+#if defined(HAVE_NETMAP) || defined(HAVE_BPF)
+ memcpy(eth_data.hw_addr, LLADDR((struct sockaddr_dl *) &ifr.ifr_addr),
+ MAC_SIZE);
+#endif
+#if defined(HAVE_NETMAP)
+ if (eth_init_nmd(&ifr) < 0) {
+ log_err("Failed to initialize netmap device.");
+ return -1;
+ }
+#elif defined(HAVE_BPF) /* !HAVE_NETMAP */
+ if (eth_init_bpf(&ifr) < 0) {
+ log_err("Failed to initialize BPF device.");
+ return -1;
+ }
+#elif defined(HAVE_RAW_SOCKETS)
+ if (eth_init_raw_socket(&ifr) < 0) {
+ log_err("Failed to initialize raw socket device.");
+ return -1;
+ }
#endif /* HAVE_NETMAP */
#if defined(__linux__)
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;
+ goto fail_monitor;
}
#endif
-
if (pthread_create(&eth_data.mgmt_handler, NULL,
eth_ipcp_mgmt_handler, NULL)) {
log_err("Failed to create mgmt handler thread: %s.",
@@ -1458,8 +1555,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
goto fail_mgmt_handler;
}
- for (idx = 0; idx < IPCP_ETH_RD_THR; ++idx) {
- if (pthread_create(&eth_data.packet_reader[idx], NULL,
+ for (i = 0; i < IPCP_ETH_RD_THR; i++) {
+ if (pthread_create(&eth_data.packet_reader[i], NULL,
eth_ipcp_packet_reader, NULL)) {
log_err("Failed to create packet reader thread: %s",
strerror(errno));
@@ -1467,8 +1564,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
}
}
- for (idx = 0; idx < IPCP_ETH_WR_THR; ++idx) {
- if (pthread_create(&eth_data.packet_writer[idx], NULL,
+ for (i = 0; i < IPCP_ETH_WR_THR; i++) {
+ if (pthread_create(&eth_data.packet_writer[i], NULL,
eth_ipcp_packet_writer, NULL)) {
log_err("Failed to create packet writer thread: %s",
strerror(errno));
@@ -1486,15 +1583,15 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
return 0;
fail_packet_writer:
- while (idx > 0) {
- pthread_cancel(eth_data.packet_writer[--idx]);
- pthread_join(eth_data.packet_writer[idx], NULL);
+ while (i-- > 0) {
+ pthread_cancel(eth_data.packet_writer[i]);
+ pthread_join(eth_data.packet_writer[i], NULL);
}
- idx = IPCP_ETH_RD_THR;
+ i = IPCP_ETH_RD_THR;
fail_packet_reader:
- while (idx > 0) {
- pthread_cancel(eth_data.packet_reader[--idx]);
- pthread_join(eth_data.packet_reader[idx], NULL);
+ while (i-- > 0) {
+ pthread_cancel(eth_data.packet_reader[i]);
+ pthread_join(eth_data.packet_reader[i], NULL);
}
pthread_cancel(eth_data.mgmt_handler);
pthread_join(eth_data.mgmt_handler, NULL);
@@ -1503,8 +1600,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
pthread_cancel(eth_data.if_monitor);
pthread_join(eth_data.if_monitor, NULL);
#endif
-#if defined(__linux__) || !defined(HAVE_NETMAP)
- fail_device:
+#if defined(__linux__)
+ fail_monitor:
#endif
#if defined(HAVE_NETMAP)
nm_close(eth_data.nmd);
@@ -1513,7 +1610,6 @@ 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;
}
@@ -1599,7 +1695,7 @@ static int eth_ipcp_flow_alloc(int fd,
uint8_t ssap = 0;
#endif
uint8_t r_addr[MAC_SIZE];
- uint64_t addr = 0;
+ struct addr addr;
assert(hash);
@@ -1608,10 +1704,12 @@ static int eth_ipcp_flow_alloc(int fd,
HASH_VAL32(hash));
return -1;
}
+
addr = shim_data_dir_get_addr(eth_data.shim_data, hash);
+ memcpy(r_addr, &addr.mac, MAC_SIZE);
- pthread_rwlock_wrlock(&eth_data.flows_lock);
#ifdef BUILD_ETH_LLC
+ pthread_rwlock_wrlock(&eth_data.flows_lock);
ssap = bmp_allocate(eth_data.saps);
if (!bmp_is_id_valid(eth_data.saps, ssap)) {
pthread_rwlock_unlock(&eth_data.flows_lock);
@@ -1621,10 +1719,8 @@ static int eth_ipcp_flow_alloc(int fd,
eth_data.fd_to_ef[fd].sap = ssap;
eth_data.ef_to_fd[ssap] = fd;
-#endif
pthread_rwlock_unlock(&eth_data.flows_lock);
-
- memcpy(r_addr, &addr, MAC_SIZE);
+#endif
if (eth_ipcp_alloc(r_addr,
#if defined(BUILD_ETH_DIX)
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c
index 966c4920..774bfda4 100644
--- a/src/ipcpd/ipcp.c
+++ b/src/ipcpd/ipcp.c
@@ -64,13 +64,73 @@
#endif
#endif
-char * info[LAYER_NAME_SIZE + 1] = {
- "_state",
- "_type",
- "_layer",
- NULL
+#ifndef CLOCK_REALTIME_COARSE
+#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
+#endif
+
+static char * ipcp_type_str[] = {
+ "local",
+ "unicast",
+ "broadcast",
+ "eth-llc",
+ "eth-dix",
+ "udp4",
+ "udp6"
};
+static char * dir_hash_str[] = {
+ "SHA3-224",
+ "SHA3-256",
+ "SHA3-384",
+ "SHA3-512",
+ "CRC32",
+ "MD5"
+};
+
+static char * ipcp_state_str[] = {
+ "null",
+ "init",
+ "boot",
+ "bootstrapped",
+ "enrolled",
+ "operational",
+ "shutdown"
+};
+
+struct {
+ pid_t irmd_pid;
+ char * name;
+
+ enum ipcp_type type;
+ char layer_name[LAYER_NAME_SIZE + 1];
+
+ uint64_t dt_addr;
+
+ enum hash_algo dir_hash_algo;
+
+ struct ipcp_ops * ops;
+ int irmd_fd;
+
+ enum ipcp_state state;
+ pthread_cond_t state_cond;
+ pthread_mutex_t state_mtx;
+
+ int sockfd;
+ char * sock_path;
+
+ struct list_head cmds;
+ pthread_cond_t cmd_cond;
+ pthread_mutex_t cmd_lock;
+
+ int alloc_id;
+ pthread_cond_t alloc_cond;
+ pthread_mutex_t alloc_lock;
+
+ struct tpm * tpm;
+
+ pthread_t acceptor;
+} ipcpd;
+
struct cmd {
struct list_head next;
@@ -79,9 +139,29 @@ struct cmd {
int fd;
};
+enum ipcp_type ipcp_get_type(void)
+{
+ return ipcpd.type;
+}
+
+const char * ipcp_get_name(void)
+{
+ return ipcpd.name;
+}
+
+void ipcp_set_dir_hash_algo(enum hash_algo algo)
+{
+ ipcpd.dir_hash_algo = algo;
+}
+
+size_t ipcp_dir_hash_len(void)
+{
+ return hash_len(ipcpd.dir_hash_algo);
+}
+
uint8_t * ipcp_hash_dup(const uint8_t * hash)
{
- uint8_t * dup = malloc(hash_len(ipcpi.dir_hash_algo));
+ uint8_t * dup = malloc(hash_len(ipcpd.dir_hash_algo));
if (dup == NULL)
return NULL;
@@ -105,6 +185,13 @@ void ipcp_hash_str(char * buf,
buf[2 * i] = '\0';
}
+static const char * info[] = {
+ "_state",
+ "_type",
+ "_layer",
+ NULL
+};
+
static int ipcp_rib_read(const char * path,
char * buf,
size_t len)
@@ -132,18 +219,20 @@ static int ipcp_rib_read(const char * path,
}
if (strcmp(entry, info[1]) == 0) { /* _type */
- if (ipcpi.type == IPCP_LOCAL)
+ if (ipcpd.type == IPCP_LOCAL)
strcpy(buf, "local\n");
- else if (ipcpi.type == IPCP_UNICAST)
+ else if (ipcpd.type == IPCP_UNICAST)
strcpy(buf, "unicast\n");
- else if (ipcpi.type == IPCP_BROADCAST)
+ else if (ipcpd.type == IPCP_BROADCAST)
strcpy(buf, "broadcast\n");
- else if (ipcpi.type == IPCP_ETH_LLC)
+ else if (ipcpd.type == IPCP_ETH_LLC)
strcpy(buf, "eth-llc\n");
- else if (ipcpi.type == IPCP_ETH_DIX)
+ else if (ipcpd.type == IPCP_ETH_DIX)
strcpy(buf, "eth-dix\n");
- else if (ipcpi.type == IPCP_UDP)
- strcpy(buf, "udp\n");
+ else if (ipcpd.type == IPCP_UDP4)
+ strcpy(buf, "udp4\n");
+ else if (ipcpd.type == IPCP_UDP6)
+ strcpy(buf, "udp6\n");
else
strcpy(buf, "bug\n");
}
@@ -153,7 +242,7 @@ static int ipcp_rib_read(const char * path,
if (ipcp_get_state() < IPCP_OPERATIONAL)
strcpy(buf, "(null)");
else
- strcpy(buf, ipcpi.layer_name);
+ strcpy(buf, ipcpd.layer_name);
buf[strlen(buf)] = '\n';
}
@@ -165,12 +254,11 @@ static int ipcp_rib_readdir(char *** buf)
{
int i = 0;
- while (info[i] != NULL)
- i++;
+ while (info[i++] != NULL);
*buf = malloc(sizeof(**buf) * i);
if (*buf == NULL)
- goto fail;
+ goto fail_entries;
i = 0;
@@ -183,12 +271,11 @@ static int ipcp_rib_readdir(char *** buf)
return i;
fail_dup:
- while (i > 0)
- free((*buf)[--i]);
- fail:
+ while (i-- > 0)
+ free((*buf)[i]);
free(*buf);
-
- return -1;
+ fail_entries:
+ return -ENOMEM;
}
static int ipcp_rib_getattr(const char * path,
@@ -218,10 +305,10 @@ static void * acceptloop(void * o)
(void) o;
while (ipcp_get_state() != IPCP_SHUTDOWN &&
- ipcp_get_state() != IPCP_NULL) {
+ ipcp_get_state() != IPCP_INIT) {
struct cmd * cmd;
- csockfd = accept(ipcpi.sockfd, 0, 0);
+ csockfd = accept(ipcpd.sockfd, 0, 0);
if (csockfd < 0)
continue;
@@ -249,13 +336,13 @@ static void * acceptloop(void * o)
cmd->fd = csockfd;
- pthread_mutex_lock(&ipcpi.cmd_lock);
+ pthread_mutex_lock(&ipcpd.cmd_lock);
- list_add(&cmd->next, &ipcpi.cmds);
+ list_add(&cmd->next, &ipcpd.cmds);
- pthread_cond_signal(&ipcpi.cmd_cond);
+ pthread_cond_signal(&ipcpd.cmd_cond);
- pthread_mutex_unlock(&ipcpi.cmd_lock);
+ pthread_mutex_unlock(&ipcpd.cmd_lock);
}
return (void *) 0;
@@ -276,34 +363,34 @@ int ipcp_wait_flow_req_arr(const uint8_t * dst,
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- pthread_mutex_lock(&ipcpi.alloc_lock);
+ pthread_mutex_lock(&ipcpd.alloc_lock);
- while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
+ while (ipcpd.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
+ pthread_cond_timedwait(&ipcpd.alloc_cond,
+ &ipcpd.alloc_lock,
&abstime);
}
if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ pthread_mutex_unlock(&ipcpd.alloc_lock);
log_err("Won't allocate over non-operational IPCP.");
return -EIPCPSTATE;
}
- assert(ipcpi.alloc_id == -1);
+ assert(ipcpd.alloc_id == -1);
fd = ipcp_flow_req_arr(&hash, qs, mpl, data);
if (fd < 0) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ pthread_mutex_unlock(&ipcpd.alloc_lock);
log_err("Failed to get fd for flow.");
return fd;
}
- ipcpi.alloc_id = fd;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
+ ipcpd.alloc_id = fd;
+ pthread_cond_broadcast(&ipcpd.alloc_cond);
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ pthread_mutex_unlock(&ipcpd.alloc_lock);
return fd;
@@ -311,31 +398,31 @@ int ipcp_wait_flow_req_arr(const uint8_t * dst,
int ipcp_wait_flow_resp(const int fd)
{
- struct timespec ts = TIMESPEC_INIT_MS(ALLOC_TIMEOUT);
- struct timespec abstime;
+ struct timespec ts = TIMESPEC_INIT_MS(ALLOC_TIMEOUT);
+ struct timespec abstime;
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- pthread_mutex_lock(&ipcpi.alloc_lock);
+ pthread_mutex_lock(&ipcpd.alloc_lock);
- while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
+ while (ipcpd.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
+ pthread_cond_timedwait(&ipcpd.alloc_cond,
+ &ipcpd.alloc_lock,
&abstime);
}
if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ pthread_mutex_unlock(&ipcpd.alloc_lock);
return -1;
}
- assert(ipcpi.alloc_id == fd);
+ assert(ipcpd.alloc_id == fd);
- ipcpi.alloc_id = -1;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
+ ipcpd.alloc_id = -1;
+ pthread_cond_broadcast(&ipcpd.alloc_cond);
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ pthread_mutex_unlock(&ipcpd.alloc_lock);
return 0;
}
@@ -349,30 +436,58 @@ static void free_msg(void * o)
static void do_bootstrap(ipcp_config_msg_t * conf_msg,
ipcp_msg_t * ret_msg)
{
- struct ipcp_config conf;
+ struct ipcp_config conf;
+ struct layer_info * info;
log_info("Bootstrapping...");
- if (ipcpi.ops->ipcp_bootstrap == NULL) {
- log_err("Bootstrap unsupported.");
+ if (ipcpd.ops->ipcp_bootstrap == NULL) {
+ log_err("Failed to Bootstrap: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
- if (ipcp_get_state() != IPCP_INIT) {
- log_err("IPCP in wrong state.");
+ if (ipcp_get_state() != IPCP_BOOT) {
+
+ log_err("Failed to bootstrap: IPCP in state <%s>, need <%s>.",
+ ipcp_state_str[ipcp_get_state()],
+ ipcp_state_str[IPCP_BOOT]);
ret_msg->result = -EIPCPSTATE;
- goto finish;
+ return;
}
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);
+ switch(conf.type) { /* FIXED algorithms */
+ case IPCP_UDP4:
+ /* FALLTHRU */
+ case IPCP_UDP6:
+ conf.layer_info.dir_hash_algo = (enum pol_dir_hash) HASH_MD5;
+ break;
+ case IPCP_BROADCAST:
+ conf.layer_info.dir_hash_algo = DIR_HASH_SHA3_256;
+ break;
+ default:
+ break;
+ }
+
+ ret_msg->result = ipcpd.ops->ipcp_bootstrap(&conf);
+ if (ret_msg->result < 0) {
+ log_err("Failed to bootstrap IPCP.");
+ return;
}
- finish:
- log_info("Finished bootstrapping: %d.", ret_msg->result);
+
+ info = &conf.layer_info;
+
+ strcpy(ipcpd.layer_name, info->name);
+ ipcpd.dir_hash_algo = (enum hash_algo) info->dir_hash_algo;
+ ret_msg->layer_info = layer_info_s_to_msg(info);
+ ipcp_set_state(IPCP_OPERATIONAL);
+
+ log_info("Finished bootstrapping in %s.", info->name);
+ log_info(" type: %s", ipcp_type_str[ipcpd.type]);
+ log_info(" hash: %s [%zd bytes]",
+ dir_hash_str[ipcpd.dir_hash_algo],
+ ipcp_dir_hash_len());
}
static void do_enroll(const char * dst,
@@ -382,25 +497,36 @@ static void do_enroll(const char * dst,
log_info("Enrolling with %s...", dst);
- if (ipcpi.ops->ipcp_enroll == NULL) {
- log_err("Enroll unsupported.");
+ if (ipcpd.ops->ipcp_enroll == NULL) {
+ log_err("Failed to enroll: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
- if (ipcp_get_state() != IPCP_INIT) {
- log_err("IPCP in wrong state.");
+ if (ipcp_get_state() != IPCP_BOOT) {
+ log_err("Failed to enroll: IPCP in state <%s>, need <%s>.",
+ ipcp_state_str[ipcp_get_state()],
+ ipcp_state_str[IPCP_BOOT]);
ret_msg->result = -EIPCPSTATE;
- goto finish;
+ return;
}
- 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);
+ ret_msg->result = ipcpd.ops->ipcp_enroll(dst, &info);
+ if (ret_msg->result < 0) {
+ log_err("Failed to bootstrap IPCP.");
+ return;
}
- finish:
- log_info("Finished enrolling with %s: %d.", dst, ret_msg->result);
+
+ strcpy(ipcpd.layer_name, info.name);
+ ipcpd.dir_hash_algo = (enum hash_algo) info.dir_hash_algo;
+ ret_msg->layer_info = layer_info_s_to_msg(&info);
+ ipcp_set_state(IPCP_OPERATIONAL);
+
+ log_info("Finished enrolling with %s in layer %s.", dst, info.name);
+ log_info(" type: %s", ipcp_type_str[ipcpd.type]);
+ log_info(" hash: %s [%zd bytes]",
+ dir_hash_str[ipcpd.dir_hash_algo],
+ ipcp_dir_hash_len());
}
static void do_connect(const char * dst,
@@ -410,15 +536,15 @@ static void do_connect(const char * dst,
{
log_info("Connecting %s to %s...", comp, dst);
- if (ipcpi.ops->ipcp_connect == NULL) {
- log_err("Connect unsupported.");
+ if (ipcpd.ops->ipcp_connect == NULL) {
+ log_err("Failed to connect: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
- ret_msg->result = ipcpi.ops->ipcp_connect(dst, comp, qs);
- finish:
- log_info("Finished connecting: %d.", ret_msg->result);
+ ret_msg->result = ipcpd.ops->ipcp_connect(dst, comp, qs);
+
+ log_info("Finished connecting.");
}
static void do_disconnect(const char * dst,
@@ -427,17 +553,15 @@ static void do_disconnect(const char * dst,
{
log_info("Disconnecting %s from %s...", comp, dst);
- if (ipcpi.ops->ipcp_disconnect == NULL) {
- log_err("Disconnect unsupported.");
+ if (ipcpd.ops->ipcp_disconnect == NULL) {
+ log_err("Failed to disconnect: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
- ret_msg->result = ipcpi.ops->ipcp_disconnect(dst, comp);
+ ret_msg->result = ipcpd.ops->ipcp_disconnect(dst, comp);
- finish:
- log_info("Finished disconnecting %s from %s: %d.",
- comp, dst, ret_msg->result);
+ log_info("Finished disconnecting %s from %s.", comp, dst);
}
static void do_reg(const uint8_t * hash,
@@ -446,16 +570,15 @@ static void do_reg(const uint8_t * hash,
log_info("Registering " HASH_FMT32 "...", HASH_VAL32(hash));
- if (ipcpi.ops->ipcp_reg == NULL) {
- log_err("Registration unsupported.");
+ if (ipcpd.ops->ipcp_reg == NULL) {
+ log_err("Failed to register: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
- ret_msg->result = ipcpi.ops->ipcp_reg(hash);
- finish:
- log_info("Finished registering " HASH_FMT32 " : %d.",
- HASH_VAL32(hash), ret_msg->result);
+ ret_msg->result = ipcpd.ops->ipcp_reg(hash);
+
+ log_info("Finished registering " HASH_FMT32 ".", HASH_VAL32(hash));
}
static void do_unreg(const uint8_t * hash,
@@ -463,16 +586,15 @@ static void do_unreg(const uint8_t * hash,
{
log_info("Unregistering " HASH_FMT32 "...", HASH_VAL32(hash));
- if (ipcpi.ops->ipcp_unreg == NULL) {
- log_err("Unregistration unsupported.");
+ if (ipcpd.ops->ipcp_unreg == NULL) {
+ log_err("Failed to unregister: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
- ret_msg->result = ipcpi.ops->ipcp_unreg(hash);
- finish:
- log_info("Finished unregistering " HASH_FMT32 ": %d.",
- HASH_VAL32(hash), ret_msg->result);
+ ret_msg->result = ipcpd.ops->ipcp_unreg(hash);
+
+ log_info("Finished unregistering " HASH_FMT32 ".", HASH_VAL32(hash));
}
static void do_query(const uint8_t * hash,
@@ -480,19 +602,21 @@ static void do_query(const uint8_t * hash,
{
/* TODO: Log this operation when IRMd has internal caches. */
- if (ipcpi.ops->ipcp_query == NULL) {
- log_err("Directory query unsupported.");
+ if (ipcpd.ops->ipcp_query == NULL) {
+ log_err("Failed to query: operation unsupported.");
ret_msg->result = -ENOTSUP;
return;
}
if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
+ log_dbg("Failed to query: IPCP in state <%s>, need <%s>.",
+ ipcp_state_str[ipcp_get_state()],
+ ipcp_state_str[IPCP_OPERATIONAL]);
ret_msg->result = -EIPCPSTATE;
return;
}
- ret_msg->result = ipcpi.ops->ipcp_query(hash);
+ ret_msg->result = ipcpd.ops->ipcp_query(hash);
}
static void do_flow_alloc(pid_t pid,
@@ -507,16 +631,18 @@ static void do_flow_alloc(pid_t pid,
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.");
+ if (ipcpd.ops->ipcp_flow_alloc == NULL) {
+ log_err("Flow allocation failed: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
+ log_err("Failed to enroll: IPCP in state <%s>, need <%s>.",
+ ipcp_state_str[ipcp_get_state()],
+ ipcp_state_str[IPCP_OPERATIONAL]);
ret_msg->result = -EIPCPSTATE;
- goto finish;
+ return;
}
fd = np1_flow_alloc(pid, flow_id);
@@ -524,13 +650,13 @@ static void do_flow_alloc(pid_t pid,
log_err("Failed allocating n + 1 fd on flow_id %d: %d",
flow_id, fd);
ret_msg->result = -EFLOWDOWN;
- goto finish;
+ return;
}
- 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);
+ ret_msg->result = ipcpd.ops->ipcp_flow_alloc(fd, dst, qs, data);
+
+ log_info("Finished allocating flow %d to " HASH_FMT32 ".",
+ flow_id, HASH_VAL32(dst));
}
@@ -544,27 +670,29 @@ static void do_flow_join(pid_t pid,
log_info("Joining layer " HASH_FMT32 ".", HASH_VAL32(dst));
- if (ipcpi.ops->ipcp_flow_join == NULL) {
- log_err("Broadcast unsupported.");
+ if (ipcpd.ops->ipcp_flow_join == NULL) {
+ log_err("Failed to join: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
+ log_err("Failed to join: IPCP in state <%s>, need <%s>.",
+ ipcp_state_str[ipcp_get_state()],
+ ipcp_state_str[IPCP_OPERATIONAL]);
ret_msg->result = -EIPCPSTATE;
- goto finish;
+ return;
}
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;
+ return;
}
- ret_msg->result = ipcpi.ops->ipcp_flow_join(fd, dst, qs);
- finish:
+ ret_msg->result = ipcpd.ops->ipcp_flow_join(fd, dst, qs);
+
log_info("Finished joining layer " HASH_FMT32 ".", HASH_VAL32(dst));
}
@@ -577,30 +705,33 @@ static void do_flow_alloc_resp(int resp,
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.");
+ if (ipcpd.ops->ipcp_flow_alloc_resp == NULL) {
+ log_err("Failed to respond on flow %d: operation unsupported.",
+ flow_id);
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
+ log_err("Failed to respond to flow %d:"
+ "IPCP in state <%s>, need <%s>.",
+ flow_id,
+ ipcp_state_str[ipcp_get_state()],
+ ipcp_state_str[IPCP_OPERATIONAL]);
ret_msg->result = -EIPCPSTATE;
- goto finish;
+ return;
}
- 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;
- }
+ fd = np1_flow_resp(flow_id, resp);
+ if (fd < 0) {
+ log_warn("Flow_id %d is not known.", flow_id);
+ ret_msg->result = -1;
+ return;
}
- ret_msg->result = ipcpi.ops->ipcp_flow_alloc_resp(fd, resp, data);
- finish:
- log_info("Finished responding to allocation request: %d",
+ ret_msg->result = ipcpd.ops->ipcp_flow_alloc_resp(fd, resp, data);
+
+ log_info("Finished responding %d to allocation request.",
ret_msg->result);
}
@@ -612,55 +743,56 @@ static void do_flow_dealloc(int flow_id,
log_info("Deallocating flow %d.", flow_id);
- if (ipcpi.ops->ipcp_flow_dealloc == NULL) {
- log_err("Flow deallocation unsupported.");
+ if (ipcpd.ops->ipcp_flow_dealloc == NULL) {
+ log_err("Failed to dealloc: operation unsupported.");
ret_msg->result = -ENOTSUP;
- goto finish;
+ return;
}
if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_err("IPCP in wrong state.");
+ log_err("Failed to enroll: IPCP in state <%s>, need <%s>.",
+ ipcp_state_str[ipcp_get_state()],
+ ipcp_state_str[IPCP_OPERATIONAL]);
ret_msg->result = -EIPCPSTATE;
- goto finish;
+ return;
}
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;
+ return;
}
- ret_msg->result = ipcpi.ops->ipcp_flow_dealloc(fd);
- finish:
- log_info("Finished deallocating flow %d: %d.",
- flow_id, ret_msg->result);
+ ret_msg->result = ipcpd.ops->ipcp_flow_dealloc(fd);
+
+ log_info("Finished deallocating flow %d.", flow_id);
}
static void * mainloop(void * o)
{
- int sfd;
- buffer_t buffer;
- ipcp_msg_t * msg;
+ int sfd;
+ buffer_t buffer;
+ ipcp_msg_t * msg;
(void) o;
while (true) {
- ipcp_msg_t ret_msg = IPCP_MSG__INIT;
- qosspec_t qs;
- struct cmd * cmd;
- buffer_t data;
+ 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_mutex_lock(&ipcpd.cmd_lock);
- pthread_cleanup_push(__cleanup_mutex_unlock, &ipcpi.cmd_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &ipcpd.cmd_lock);
- while (list_is_empty(&ipcpi.cmds))
- pthread_cond_wait(&ipcpi.cmd_cond, &ipcpi.cmd_lock);
+ while (list_is_empty(&ipcpd.cmds))
+ pthread_cond_wait(&ipcpd.cmd_cond, &ipcpd.cmd_lock);
- cmd = list_last_entry(&ipcpi.cmds, struct cmd, next);
+ cmd = list_last_entry(&ipcpd.cmds, struct cmd, next);
list_del(&cmd->next);
pthread_cleanup_pop(true);
@@ -675,7 +807,7 @@ static void * mainloop(void * o)
continue;
}
- tpm_dec(ipcpi.tpm);
+ tpm_begin_work(ipcpd.tpm);
pthread_cleanup_push(__cleanup_close_ptr, &sfd);
pthread_cleanup_push(free_msg, msg);
@@ -749,7 +881,7 @@ static void * mainloop(void * o)
if (buffer.len == 0) {
log_err("Failed to pack reply message");
close(sfd);
- tpm_inc(ipcpi.tpm);
+ tpm_end_work(ipcpd.tpm);
continue;
}
@@ -757,7 +889,7 @@ static void * mainloop(void * o)
if (buffer.data == NULL) {
log_err("Failed to create reply buffer.");
close(sfd);
- tpm_inc(ipcpi.tpm);
+ tpm_end_work(ipcpd.tpm);
continue;
}
@@ -766,16 +898,16 @@ static void * mainloop(void * o)
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)
+ pthread_cleanup_push(__cleanup_close_ptr, &sfd);
if (write(sfd, buffer.data, buffer.len) == -1)
log_warn("Failed to send reply message");
- pthread_cleanup_pop(true);
- pthread_cleanup_pop(true);
+ pthread_cleanup_pop(true); /* close sfd */
+ pthread_cleanup_pop(true); /* free buffer.data */
- tpm_inc(ipcpi.tpm);
+ tpm_end_work(ipcpd.tpm);
}
return (void *) 0;
@@ -794,10 +926,10 @@ static int parse_args(int argc,
if (atoi(argv[1]) == 0)
return -1;
- ipcpi.irmd_pid = atoi(argv[1]);
+ ipcpd.irmd_pid = atoi(argv[1]);
/* argument 2: IPCP name */
- ipcpi.name = argv[2];
+ ipcpd.name = argv[2];
/* argument 3: syslog */
if (argv[3] != NULL)
@@ -813,71 +945,69 @@ int ipcp_init(int argc,
{
bool log;
pthread_condattr_t cattr;
- int ret = -1;
if (parse_args(argc, argv, &log))
return -1;
log_init(log);
- ipcpi.irmd_fd = -1;
- ipcpi.state = IPCP_NULL;
- ipcpi.type = type;
+ ipcpd.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)
+ ipcpd.sock_path = sock_path(getpid(), IPCP_SOCK_PATH_PREFIX);
+ if (ipcpd.sock_path == NULL)
goto fail_sock_path;
- ipcpi.sockfd = server_socket_open(ipcpi.sock_path);
- if (ipcpi.sockfd < 0) {
- log_err("Could not open server socket.");
+ ipcpd.sockfd = server_socket_open(ipcpd.sock_path);
+ if (ipcpd.sockfd < 0) {
+ log_err("Failed to open server socket at %s.",
+ ipcpd.sock_path);
goto fail_serv_sock;
}
- ipcpi.ops = ops;
+ ipcpd.ops = ops;
- if (pthread_mutex_init(&ipcpi.state_mtx, NULL)) {
- log_err("Could not create mutex.");
+ if (pthread_mutex_init(&ipcpd.state_mtx, NULL)) {
+ log_err("Failed to create mutex.");
goto fail_state_mtx;
}
if (pthread_condattr_init(&cattr)) {
- log_err("Could not create condattr.");
+ log_err("Failed to create condattr.");
goto fail_cond_attr;
}
#ifndef __APPLE__
pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
#endif
- if (pthread_cond_init(&ipcpi.state_cond, &cattr)) {
- log_err("Could not init condvar.");
+ if (pthread_cond_init(&ipcpd.state_cond, &cattr)) {
+ log_err("Failed to init condvar.");
goto fail_state_cond;
}
- if (pthread_mutex_init(&ipcpi.alloc_lock, NULL)) {
+ if (pthread_mutex_init(&ipcpd.alloc_lock, NULL)) {
log_err("Failed to init mutex.");
goto fail_alloc_lock;
}
- if (pthread_cond_init(&ipcpi.alloc_cond, &cattr)) {
+ if (pthread_cond_init(&ipcpd.alloc_cond, &cattr)) {
log_err("Failed to init convar.");
goto fail_alloc_cond;
}
- if (pthread_mutex_init(&ipcpi.cmd_lock, NULL)) {
+ if (pthread_mutex_init(&ipcpd.cmd_lock, NULL)) {
log_err("Failed to init mutex.");
goto fail_cmd_lock;
}
- if (pthread_cond_init(&ipcpi.cmd_cond, &cattr)) {
+ if (pthread_cond_init(&ipcpd.cmd_cond, &cattr)) {
log_err("Failed to init convar.");
goto fail_cmd_cond;
}
- if (rib_init(ipcpi.name)) {
+ if (rib_init(ipcpd.name)) {
log_err("Failed to initialize RIB.");
goto fail_rib_init;
}
@@ -887,21 +1017,24 @@ int ipcp_init(int argc,
goto fail_rib_reg;
}
- ipcpi.tpm = tpm_create(IPCP_MIN_THREADS, IPCP_ADD_THREADS,
+ list_head_init(&ipcpd.cmds);
+
+ ipcpd.tpm = tpm_create(IPCP_MIN_THREADS, IPCP_ADD_THREADS,
mainloop, NULL);
- if (ipcpi.tpm == NULL) {
+ if (ipcpd.tpm == NULL) {
log_err("Failed to create threadpool manager.");
goto fail_tpm_create;
}
- list_head_init(&ipcpi.cmds);
-
- ipcpi.alloc_id = -1;
+ ipcpd.alloc_id = -1;
pthread_condattr_destroy(&cattr);
ipcp_set_state(IPCP_INIT);
+ log_info("IPCP %s %d initialized.", ipcp_type_str[ipcpd.type],
+ getpid());
+
return 0;
fail_tpm_create:
@@ -909,25 +1042,25 @@ int ipcp_init(int argc,
fail_rib_reg:
rib_fini();
fail_rib_init:
- pthread_cond_destroy(&ipcpi.cmd_cond);
+ pthread_cond_destroy(&ipcpd.cmd_cond);
fail_cmd_cond:
- pthread_mutex_destroy(&ipcpi.cmd_lock);
+ pthread_mutex_destroy(&ipcpd.cmd_lock);
fail_cmd_lock:
- pthread_cond_destroy(&ipcpi.alloc_cond);
+ pthread_cond_destroy(&ipcpd.alloc_cond);
fail_alloc_cond:
- pthread_mutex_destroy(&ipcpi.alloc_lock);
+ pthread_mutex_destroy(&ipcpd.alloc_lock);
fail_alloc_lock:
- pthread_cond_destroy(&ipcpi.state_cond);
+ pthread_cond_destroy(&ipcpd.state_cond);
fail_state_cond:
pthread_condattr_destroy(&cattr);
fail_cond_attr:
- pthread_mutex_destroy(&ipcpi.state_mtx);
+ pthread_mutex_destroy(&ipcpd.state_mtx);
fail_state_mtx:
- close(ipcpi.sockfd);
+ close(ipcpd.sockfd);
fail_serv_sock:
- free(ipcpi.sock_path);
+ free(ipcpd.sock_path);
fail_sock_path:
- return ret;
+ return -1;
}
int ipcp_start(void)
@@ -944,20 +1077,22 @@ int ipcp_start(void)
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
info.pid = getpid();
- info.type = ipcpi.type;
- strcpy(info.name, ipcpi.name);
- info.state = IPCP_OPERATIONAL;
+ info.type = ipcpd.type;
+ strcpy(info.name, ipcpd.name);
+ info.state = IPCP_BOOT;
+
+ ipcp_set_state(IPCP_BOOT);
- if (tpm_start(ipcpi.tpm))
+ if (tpm_start(ipcpd.tpm)) {
+ log_err("Failed to start threadpool manager.");
goto fail_tpm_start;
+ }
- if (pthread_create(&ipcpi.acceptor, NULL, acceptloop, NULL)) {
+ if (pthread_create(&ipcpd.acceptor, NULL, acceptloop, NULL)) {
log_err("Failed to create acceptor thread.");
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;
@@ -966,14 +1101,13 @@ int ipcp_start(void)
return 0;
fail_create_r:
- pthread_cancel(ipcpi.acceptor);
- pthread_join(ipcpi.acceptor, NULL);
+ pthread_cancel(ipcpd.acceptor);
+ pthread_join(ipcpd.acceptor, NULL);
fail_acceptor:
- tpm_stop(ipcpi.tpm);
+ tpm_stop(ipcpd.tpm);
fail_tpm_start:
- tpm_destroy(ipcpi.tpm);
- ipcp_set_state(IPCP_NULL);
- info.state = IPCP_NULL;
+ tpm_destroy(ipcpd.tpm);
+ ipcp_set_state(IPCP_INIT);
ipcp_create_r(&info);
return -1;
}
@@ -993,7 +1127,7 @@ void ipcp_sigwait(void)
sigaddset(&sigset, SIGTERM);
sigaddset(&sigset, SIGPIPE);
- while(ipcp_get_state() != IPCP_NULL &&
+ while(ipcp_get_state() != IPCP_INIT &&
ipcp_get_state() != IPCP_SHUTDOWN) {
#ifdef __APPLE__
if (sigwait(&sigset, &sig) < 0) {
@@ -1007,7 +1141,7 @@ void ipcp_sigwait(void)
#ifdef __APPLE__
memset(&info, 0, sizeof(info));
info.si_signo = sig;
- info.si_pid = ipcpi.irmd_pid;
+ info.si_pid = ipcpd.irmd_pid;
#endif
switch(info.si_signo) {
case SIGINT:
@@ -1017,9 +1151,9 @@ void ipcp_sigwait(void)
case SIGHUP:
/* FALLTHRU */
case SIGQUIT:
- if (info.si_pid == ipcpi.irmd_pid) {
- if (ipcp_get_state() == IPCP_INIT)
- ipcp_set_state(IPCP_NULL);
+ if (info.si_pid == ipcpd.irmd_pid) {
+ if (ipcp_get_state() == IPCP_BOOT)
+ ipcp_set_state(IPCP_INIT);
if (ipcp_get_state() == IPCP_OPERATIONAL)
ipcp_set_state(IPCP_SHUTDOWN);
@@ -1038,58 +1172,62 @@ void ipcp_stop(void)
{
log_info("IPCP %d shutting down.", getpid());
- pthread_cancel(ipcpi.acceptor);
- pthread_join(ipcpi.acceptor, NULL);
+ pthread_cancel(ipcpd.acceptor);
+ pthread_join(ipcpd.acceptor, NULL);
- tpm_stop(ipcpi.tpm);
+ tpm_stop(ipcpd.tpm);
+
+ ipcp_set_state(IPCP_INIT);
}
void ipcp_fini(void)
{
- tpm_destroy(ipcpi.tpm);
+ tpm_destroy(ipcpd.tpm);
rib_unreg(IPCP_INFO);
rib_fini();
- close(ipcpi.sockfd);
- if (unlink(ipcpi.sock_path))
- log_warn("Could not unlink %s.", ipcpi.sock_path);
+ close(ipcpd.sockfd);
+ if (unlink(ipcpd.sock_path))
+ log_warn("Could not unlink %s.", ipcpd.sock_path);
- free(ipcpi.sock_path);
+ free(ipcpd.sock_path);
- pthread_cond_destroy(&ipcpi.state_cond);
- pthread_mutex_destroy(&ipcpi.state_mtx);
- pthread_cond_destroy(&ipcpi.alloc_cond);
- pthread_mutex_destroy(&ipcpi.alloc_lock);
- pthread_cond_destroy(&ipcpi.cmd_cond);
- pthread_mutex_destroy(&ipcpi.cmd_lock);
+ pthread_cond_destroy(&ipcpd.state_cond);
+ pthread_mutex_destroy(&ipcpd.state_mtx);
+ pthread_cond_destroy(&ipcpd.alloc_cond);
+ pthread_mutex_destroy(&ipcpd.alloc_lock);
+ pthread_cond_destroy(&ipcpd.cmd_cond);
+ pthread_mutex_destroy(&ipcpd.cmd_lock);
log_info("IPCP %d out.", getpid());
log_fini();
+
+ ipcpd.state = IPCP_NULL;
}
void ipcp_set_state(enum ipcp_state state)
{
- pthread_mutex_lock(&ipcpi.state_mtx);
+ pthread_mutex_lock(&ipcpd.state_mtx);
- ipcpi.state = state;
+ ipcpd.state = state;
- pthread_cond_broadcast(&ipcpi.state_cond);
- pthread_mutex_unlock(&ipcpi.state_mtx);
+ pthread_cond_broadcast(&ipcpd.state_cond);
+ pthread_mutex_unlock(&ipcpd.state_mtx);
}
enum ipcp_state ipcp_get_state(void)
{
enum ipcp_state state;
- pthread_mutex_lock(&ipcpi.state_mtx);
+ pthread_mutex_lock(&ipcpd.state_mtx);
- state = ipcpi.state;
+ state = ipcpd.state;
- pthread_mutex_unlock(&ipcpi.state_mtx);
+ pthread_mutex_unlock(&ipcpd.state_mtx);
return state;
}
diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h
index aab490c7..2c41f5b9 100644
--- a/src/ipcpd/ipcp.h
+++ b/src/ipcpd/ipcp.h
@@ -34,8 +34,10 @@
#include <pthread.h>
#include <time.h>
+#define ipcp_dir_hash_strlen() (ipcp_dir_hash_len() * 2)
+
struct ipcp_ops {
- int (* ipcp_bootstrap)(const struct ipcp_config * conf);
+ int (* ipcp_bootstrap)(struct ipcp_config * conf);
int (* ipcp_enroll)(const char * dst,
struct layer_info * info);
@@ -69,43 +71,6 @@ struct ipcp_ops {
int (* ipcp_flow_dealloc)(int fd);
};
-#define ipcp_dir_hash_strlen() (hash_len(ipcpi.dir_hash_algo) * 2)
-#define ipcp_dir_hash_len() (hash_len(ipcpi.dir_hash_algo))
-
-extern struct ipcp {
- pid_t irmd_pid;
- char * name;
-
- enum ipcp_type type;
- char layer_name[LAYER_NAME_SIZE + 1];
-
- uint64_t dt_addr;
-
- enum hash_algo dir_hash_algo;
-
- struct ipcp_ops * ops;
- int irmd_fd;
-
- enum ipcp_state state;
- pthread_cond_t state_cond;
- pthread_mutex_t state_mtx;
-
- int sockfd;
- char * sock_path;
-
- struct list_head cmds;
- pthread_cond_t cmd_cond;
- pthread_mutex_t cmd_lock;
-
- int alloc_id;
- pthread_cond_t alloc_cond;
- pthread_mutex_t alloc_lock;
-
- struct tpm * tpm;
-
- pthread_t acceptor;
-} ipcpi;
-
int ipcp_init(int argc,
char ** argv,
struct ipcp_ops * ops,
@@ -119,12 +84,18 @@ void ipcp_stop(void);
void ipcp_fini(void);
+enum ipcp_type ipcp_get_type(void);
+
+const char * ipcp_get_name(void);
+
+/* TODO: Only specify hash algorithm in directory policy */
+void ipcp_set_dir_hash_algo(enum hash_algo algo);
+
void ipcp_set_state(enum ipcp_state state);
enum ipcp_state ipcp_get_state(void);
-int ipcp_parse_arg(int argc,
- char * argv[]);
+int ipcp_set_layer_info(const struct layer_info * info);
/* Helper functions to handle races during flow allocation */
int ipcp_wait_flow_req_arr(const uint8_t * dst,
@@ -134,7 +105,10 @@ int ipcp_wait_flow_req_arr(const uint8_t * dst,
int ipcp_wait_flow_resp(const int fd);
+
/* Helper functions for directory entries, could be moved */
+size_t ipcp_dir_hash_len(void);
+
uint8_t * ipcp_hash_dup(const uint8_t * hash);
void ipcp_hash_str(char buf[],
diff --git a/src/ipcpd/local/CMakeLists.txt b/src/ipcpd/local/CMakeLists.txt
index 10fd0120..08abff57 100644
--- a/src/ipcpd/local/CMakeLists.txt
+++ b/src/ipcpd/local/CMakeLists.txt
@@ -13,8 +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(IPCP_LOCAL_MPL 100 CACHE STRING
+ "Default maximum packet lifetime for the Ethernet IPCPs, in ms")
set(LOCAL_SOURCES
# Add source files here
diff --git a/src/ipcpd/local/main.c b/src/ipcpd/local/main.c
index 160e07e0..ffa6dc5a 100644
--- a/src/ipcpd/local/main.c
+++ b/src/ipcpd/local/main.c
@@ -50,8 +50,6 @@
#define THIS_TYPE IPCP_LOCAL
-struct ipcp ipcpi;
-
struct {
struct shim_data * shim_data;
@@ -139,13 +137,13 @@ static void * local_ipcp_packet_loop(void * o)
return (void *) 0;
}
-static int local_ipcp_bootstrap(const struct ipcp_config * conf)
+static int local_ipcp_bootstrap(struct ipcp_config * conf)
{
+
assert(conf);
assert(conf->type == THIS_TYPE);
- ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo;
- strcpy(ipcpi.layer_name,conf->layer_info.name);
+ (void) conf;
if (pthread_create(&local_data.packet_loop, NULL,
local_ipcp_packet_loop, NULL)) {
diff --git a/src/ipcpd/shim-data.c b/src/ipcpd/shim-data.c
index 1fac63ac..8801213a 100644
--- a/src/ipcpd/shim-data.c
+++ b/src/ipcpd/shim-data.c
@@ -51,7 +51,7 @@ struct reg_entry {
struct dir_entry {
struct list_head list;
uint8_t * hash;
- uint64_t addr;
+ struct addr addr;
};
static void destroy_dir_query(struct dir_query * query)
@@ -108,14 +108,12 @@ static void reg_entry_destroy(struct reg_entry * entry)
{
assert(entry);
- if (entry->hash != NULL)
- free(entry->hash);
-
+ free(entry->hash);
free(entry);
}
-static struct dir_entry * dir_entry_create(uint8_t * hash,
- uint64_t addr)
+static struct dir_entry * dir_entry_create(uint8_t * hash,
+ struct addr addr)
{
struct dir_entry * entry = malloc(sizeof(*entry));
if (entry == NULL)
@@ -133,9 +131,7 @@ static void dir_entry_destroy(struct dir_entry * entry)
{
assert(entry);
- if (entry->hash != NULL)
- free(entry->hash);
-
+ free(entry->hash);
free(entry);
}
@@ -258,13 +254,15 @@ static struct reg_entry * find_reg_entry_by_hash(struct shim_data * data,
static struct dir_entry * find_dir_entry(struct shim_data * data,
const uint8_t * hash,
- uint64_t addr)
+ struct addr addr)
{
struct list_head * h;
list_for_each(h, &data->directory) {
struct dir_entry * e = list_entry(h, struct dir_entry, list);
- if (e->addr == addr &&
- !memcmp(e->hash, hash, ipcp_dir_hash_len()))
+ if (memcmp(&e->addr, &addr, sizeof(addr)) != 0)
+ continue;
+
+ if (memcmp(e->hash, hash, ipcp_dir_hash_len()) == 0)
return e;
}
@@ -364,7 +362,7 @@ bool shim_data_reg_has(struct shim_data * data,
int shim_data_dir_add_entry(struct shim_data * data,
const uint8_t * hash,
- uint64_t addr)
+ struct addr addr)
{
struct dir_entry * entry;
uint8_t * entry_hash;
@@ -400,7 +398,7 @@ int shim_data_dir_add_entry(struct shim_data * data,
int shim_data_dir_del_entry(struct shim_data * data,
const uint8_t * hash,
- uint64_t addr)
+ struct addr addr)
{
struct dir_entry * e;
if (data == NULL)
@@ -437,11 +435,11 @@ bool shim_data_dir_has(struct shim_data * data,
return ret;
}
-uint64_t shim_data_dir_get_addr(struct shim_data * data,
- const uint8_t * hash)
+struct addr shim_data_dir_get_addr(struct shim_data * data,
+ const uint8_t * hash)
{
struct dir_entry * entry;
- uint64_t addr;
+ struct addr addr = {0};
pthread_rwlock_rdlock(&data->dir_lock);
@@ -449,7 +447,7 @@ uint64_t shim_data_dir_get_addr(struct shim_data * data,
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 */
+ return addr; /* undefined behaviour, 0 may be a valid address */
}
addr = entry->addr;
diff --git a/src/ipcpd/shim-data.h b/src/ipcpd/shim-data.h
index 372b4ea7..ea4ce413 100644
--- a/src/ipcpd/shim-data.h
+++ b/src/ipcpd/shim-data.h
@@ -25,9 +25,12 @@
#include <ouroboros/list.h>
-#include <sys/types.h>
#include <pthread.h>
#include <stdint.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+
+#define MAC_SIZE 6
enum dir_query_state {
QUERY_INIT = 0,
@@ -46,6 +49,14 @@ struct dir_query {
pthread_cond_t cond;
};
+struct addr {
+ union {
+ uint8_t mac[MAC_SIZE];
+ struct in_addr ip4;
+ struct in6_addr ip6;
+ };
+};
+
struct shim_data {
struct list_head registry;
pthread_rwlock_t reg_lock;
@@ -72,16 +83,16 @@ bool shim_data_reg_has(struct shim_data * data,
int shim_data_dir_add_entry(struct shim_data * data,
const uint8_t * hash,
- uint64_t addr);
+ struct addr addr);
int shim_data_dir_del_entry(struct shim_data * data,
const uint8_t * hash,
- uint64_t addr);
+ struct addr addr);
bool shim_data_dir_has(struct shim_data * data,
const uint8_t * hash);
-uint64_t shim_data_dir_get_addr(struct shim_data * data,
+struct addr shim_data_dir_get_addr(struct shim_data * data,
const uint8_t * hash);
struct dir_query * shim_data_dir_query_create(struct shim_data * data,
diff --git a/src/ipcpd/udp/CMakeLists.txt b/src/ipcpd/udp/CMakeLists.txt
index 8ae5518e..27e32094 100644
--- a/src/ipcpd/udp/CMakeLists.txt
+++ b/src/ipcpd/udp/CMakeLists.txt
@@ -12,16 +12,25 @@ include_directories(${CURRENT_BINARY_PARENT_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
-set(IPCP_UDP_TARGET ipcpd-udp CACHE INTERNAL "")
+set(IPCP_UDP4_TARGET ipcpd-udp4 CACHE INTERNAL "")
+set(IPCP_UDP6_TARGET ipcpd-udp6 CACHE INTERNAL "")
-set(UDP_SOURCES
+set(UDP4_SOURCES
# Add source files here
- ${CMAKE_CURRENT_SOURCE_DIR}/main.c
- )
+ udp4.c
+)
-add_executable(ipcpd-udp ${UDP_SOURCES} ${IPCP_SOURCES})
+set(UDP6_SOURCES
+ # Add source files here
+ udp6.c
+)
+
+add_executable(ipcpd-udp4 ${UDP4_SOURCES} ${IPCP_SOURCES})
+target_link_libraries(ipcpd-udp4 LINK_PUBLIC ouroboros-dev)
+
+add_executable(ipcpd-udp6 ${UDP6_SOURCES} ${IPCP_SOURCES})
+target_link_libraries(ipcpd-udp6 LINK_PUBLIC ouroboros-dev)
-target_link_libraries(ipcpd-udp LINK_PUBLIC ouroboros-dev)
# Find the nsupdate executable
find_program(NSUPDATE_EXECUTABLE
@@ -55,15 +64,18 @@ else ()
endif ()
set(IPCP_UDP_RD_THR 3 CACHE STRING
- "Number of reader threads in UDP IPCP")
+ "Number of reader threads in UDP IPCPs")
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")
+ "Number of writer threads in UDP IPCPs")
+set(IPCP_UDP_MPL 5000 CACHE STRING
+ "Default maximum packet lifetime for the UDP IPCPs, in ms")
include(AddCompileFlags)
if (CMAKE_BUILD_TYPE MATCHES "Debug*")
- add_compile_flags(ipcpd-udp -DCONFIG_OUROBOROS_DEBUG)
+ add_compile_flags(ipcpd-udp4 -DCONFIG_OUROBOROS_DEBUG)
+ add_compile_flags(ipcpd-udp6 -DCONFIG_OUROBOROS_DEBUG)
endif ()
-install(TARGETS ipcpd-udp RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
+install(TARGETS ipcpd-udp4 RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
+install(TARGETS ipcpd-udp6 RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
+
diff --git a/src/ipcpd/udp/main.c b/src/ipcpd/udp/udp.c
index 2e8d84ce..be8069a4 100644
--- a/src/ipcpd/udp/main.c
+++ b/src/ipcpd/udp/udp.c
@@ -20,23 +20,14 @@
* 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"
-#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>
#include <ouroboros/dev.h>
-#include <ouroboros/ipcp-dev.h>
#include <ouroboros/fqueue.h>
#include <ouroboros/errno.h>
#include <ouroboros/logs.h>
@@ -59,12 +50,11 @@
#define FLOW_REQ 1
#define FLOW_REPLY 2
-#define THIS_TYPE IPCP_UDP
-#define IPCP_UDP_MAX_PACKET_SIZE 8980
#define OUR_HEADER_LEN sizeof(uint32_t) /* adds eid */
-#define IPCP_UDP_BUF_SIZE 8980
-#define IPCP_UDP_MSG_SIZE 8980
+#define IPCP_UDP_BUF_SIZE IPCP_UDP_MAX_PACKET_SIZE
+#define IPCP_UDP_MSG_SIZE IPCP_UDP_MAX_PACKET_SIZE
+
#define DNS_TTL 86400
#define SADDR ((struct sockaddr *) &udp_data.s_saddr)
@@ -81,47 +71,42 @@
#define SENDTO_FLAGS 0
#endif
-struct ipcp ipcpi;
-
/* Keep order for alignment. */
struct mgmt_msg {
uint32_t eid;
uint32_t s_eid;
uint32_t d_eid;
- uint8_t code;
- int8_t response;
- /* QoS parameters from spec */
- uint8_t availability;
- uint8_t in_order;
+ int32_t response;
uint64_t bandwidth;
uint32_t delay;
uint32_t loss;
uint32_t ber;
uint32_t max_gap;
uint32_t timeout;
- uint16_t cypher_s;
-
+ uint8_t code;
+ /* QoS parameters from spec */
+ uint8_t availability;
+ uint8_t in_order;
} __attribute__((packed));
struct mgmt_frame {
- struct list_head next;
- struct sockaddr_in r_saddr;
- uint8_t buf[MGMT_FRAME_BUF_SIZE];
- size_t len;
+ struct list_head next;
+ struct __SOCKADDR r_saddr;
+ uint8_t buf[MGMT_FRAME_BUF_SIZE];
+ size_t len;
};
/* UDP flow */
struct uf {
- int d_eid;
- struct sockaddr_in r_saddr;
+ int d_eid;
+ struct __SOCKADDR r_saddr;
};
struct {
struct shim_data * shim_data;
- uint32_t dns_addr;
-
- struct sockaddr_in s_saddr;
+ struct __ADDR dns_addr;
+ struct __SOCKADDR s_saddr;
int s_fd;
fset_t * np1_flows;
@@ -138,6 +123,12 @@ struct {
struct list_head mgmt_frames;
} udp_data;
+static const char * __inet_ntop(const struct __ADDR * addr,
+ char * buf)
+{
+ return inet_ntop(__AF, addr, buf, __ADDRSTRLEN);
+}
+
static int udp_data_init(void)
{
int i;
@@ -199,11 +190,11 @@ static void udp_data_fini(void)
pthread_mutex_destroy(&udp_data.mgmt_lock);
}
-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)
+static int udp_ipcp_port_alloc(const struct __SOCKADDR * r_saddr,
+ uint32_t s_eid,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
uint8_t * buf;
struct mgmt_msg * msg;
@@ -228,7 +219,6 @@ static int udp_ipcp_port_alloc(const struct sockaddr_in * r_saddr,
msg->ber = hton32(qs.ber);
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());
@@ -238,6 +228,8 @@ static int udp_ipcp_port_alloc(const struct sockaddr_in * r_saddr,
if (sendto(udp_data.s_fd, msg, len + data->len,
SENDTO_FLAGS,
(const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0) {
+ log_err("Failed to send flow allocation request: %s.",
+ strerror(errno));
free(buf);
return -1;
}
@@ -247,11 +239,11 @@ static int udp_ipcp_port_alloc(const struct sockaddr_in * r_saddr,
return 0;
}
-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)
+static int udp_ipcp_port_alloc_resp(const struct __SOCKADDR * r_saddr,
+ uint32_t s_eid,
+ uint32_t d_eid,
+ int32_t response,
+ const buffer_t * data)
{
struct mgmt_msg * msg;
@@ -263,7 +255,7 @@ static int udp_ipcp_port_alloc_resp(const struct sockaddr_in * r_saddr,
msg->code = FLOW_REPLY;
msg->s_eid = hton32(s_eid);
msg->d_eid = hton32(d_eid);
- msg->response = response;
+ msg->response = hton32(response);
if (data->len > 0)
memcpy(msg + 1, data->data, data->len);
@@ -280,11 +272,11 @@ static int udp_ipcp_port_alloc_resp(const struct sockaddr_in * r_saddr,
return 0;
}
-static int udp_ipcp_port_req(struct sockaddr_in * c_saddr,
- int d_eid,
- const uint8_t * dst,
- qosspec_t qs,
- const buffer_t * data)
+static int udp_ipcp_port_req(struct __SOCKADDR * c_saddr,
+ int d_eid,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
int fd;
@@ -307,20 +299,26 @@ static int udp_ipcp_port_req(struct sockaddr_in * c_saddr,
return 0;
}
-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)
+static int udp_ipcp_port_alloc_reply(const struct __SOCKADDR * saddr,
+ uint32_t s_eid,
+ uint32_t d_eid,
+ int32_t response,
+ const buffer_t * data)
{
time_t mpl = IPCP_UDP_MPL;
pthread_rwlock_wrlock(&udp_data.flows_lock);
if (memcmp(&udp_data.fd_to_uf[s_eid].r_saddr, saddr, sizeof(*saddr))) {
+ char ipstr[__ADDRSTRLEN];
pthread_rwlock_unlock(&udp_data.flows_lock);
- log_err("Flow allocation reply for %u from wrong source.",
- s_eid);
+ #ifdef BUILD_IPCP_UDP4
+ __inet_ntop(&saddr->sin_addr, ipstr);
+ #else
+ __inet_ntop(&saddr->sin6_addr, ipstr);
+ #endif
+ log_err("Flow allocation reply for %u from wrong source %s.",
+ s_eid, ipstr);
return -1;
}
@@ -340,9 +338,9 @@ static int udp_ipcp_port_alloc_reply(const struct sockaddr_in * saddr,
return 0;
}
-static int udp_ipcp_mgmt_frame(const uint8_t * buf,
- size_t len,
- struct sockaddr_in c_saddr)
+static int udp_ipcp_mgmt_frame(struct __SOCKADDR c_saddr,
+ const uint8_t * buf,
+ size_t len)
{
struct mgmt_msg * msg;
size_t msg_len;
@@ -368,7 +366,6 @@ static int udp_ipcp_mgmt_frame(const uint8_t * buf,
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);
return udp_ipcp_port_req(&c_saddr, ntoh32(msg->s_eid),
@@ -383,7 +380,7 @@ static int udp_ipcp_mgmt_frame(const uint8_t * buf,
return udp_ipcp_port_alloc_reply(&c_saddr,
ntoh32(msg->s_eid),
ntoh32(msg->d_eid),
- msg->response,
+ ntoh32(msg->response),
&data);
default:
log_err("Unknown message received %d.", msg->code);
@@ -413,7 +410,7 @@ static void * udp_ipcp_mgmt_handler(void * o)
pthread_mutex_unlock(&udp_data.mgmt_lock);
- udp_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_saddr);
+ udp_ipcp_mgmt_frame(frame->r_saddr, frame->buf, frame->len);
free(frame);
}
@@ -440,7 +437,7 @@ static void * udp_ipcp_packet_reader(void * o)
while (true) {
struct mgmt_frame * frame;
- struct sockaddr_in r_saddr;
+ struct __SOCKADDR r_saddr;
socklen_t len;
struct shm_du_buff * sdb;
uint8_t * head;
@@ -523,9 +520,9 @@ static void * udp_ipcp_packet_writer(void * o)
pthread_cleanup_push(cleanup_fqueue, fq);
while (true) {
- struct sockaddr_in saddr;
- int eid;
- int fd;
+ struct __SOCKADDR saddr;
+ int eid;
+ int fd;
fevent(udp_data.np1_flows, fq, NULL);
while ((fd = fqueue_next(fq)) >= 0) {
struct shm_du_buff * sdb;
@@ -580,31 +577,39 @@ static void * udp_ipcp_packet_writer(void * o)
return (void *) 1;
}
-static const char * inet4_ntop(const void * addr,
- char * buf)
+static bool is_addr_specified(const struct __ADDR * addr)
{
- return inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
+#ifdef BUILD_IPCP_UDP4
+ return addr->s_addr != 0;
+#else
+ return !IN6_IS_ADDR_UNSPECIFIED(addr);
+#endif
}
-static int udp_ipcp_bootstrap(const struct ipcp_config * conf)
+static int udp_ipcp_bootstrap(struct ipcp_config * conf)
{
- char ipstr[INET_ADDRSTRLEN];
- char dnsstr[INET_ADDRSTRLEN];
+ char ipstr[__ADDRSTRLEN];
+ char dnsstr[__ADDRSTRLEN];
int i = 1;
+#ifdef BUILD_IPCP_UDP4
+ struct udp4_config * udp;
+ udp = &conf->udp4;
+#else
+ struct udp6_config * udp;
+ udp = &conf->udp6;
+#endif
- assert(conf);
+ assert(conf != NULL);
assert(conf->type == THIS_TYPE);
+ assert(conf->layer_info.dir_hash_algo == (enum pol_dir_hash) HASH_MD5);
- ipcpi.dir_hash_algo = HASH_MD5;
- strcpy(ipcpi.layer_name, conf->layer_info.name);
-
- if (inet4_ntop(&conf->udp.ip_addr, ipstr) == NULL) {
+ if (__inet_ntop(&udp->ip_addr, ipstr) == NULL) {
log_err("Failed to convert IP address.");
return -1;
}
- if (conf->udp.dns_addr != 0) {
- if (inet4_ntop(&conf->udp.dns_addr, dnsstr) == NULL) {
+ if (is_addr_specified(&udp->dns_addr)) {
+ if (__inet_ntop(&udp->dns_addr, dnsstr) == NULL) {
log_err("Failed to convert DNS address.");
return -1;
}
@@ -616,24 +621,29 @@ static int udp_ipcp_bootstrap(const struct ipcp_config * conf)
}
/* UDP listen server */
- udp_data.s_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ udp_data.s_fd = socket(__AF, SOCK_DGRAM, IPPROTO_UDP);
if (udp_data.s_fd < 0) {
log_err("Can't create socket: %s", strerror(errno));
goto fail_socket;
}
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->udp.ip_addr;
- udp_data.s_saddr.sin_port = htons(conf->udp.port);
-
+#ifdef BUILD_IPCP_UDP4
+ udp_data.s_saddr.sin_family = AF_INET;
+ udp_data.s_saddr.sin_addr = udp->ip_addr;
+ udp_data.s_saddr.sin_port = htons(udp->port);
+#else
+ udp_data.s_saddr.sin6_family = AF_INET6;
+ udp_data.s_saddr.sin6_addr = udp->ip_addr;
+ udp_data.s_saddr.sin6_port = htons(udp->port);
+#endif
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));
+ ipstr, udp->port, strerror(errno));
goto fail_bind;
}
- udp_data.dns_addr = conf->udp.dns_addr;
+ udp_data.dns_addr = udp->dns_addr;
if (pthread_create(&udp_data.mgmt_handler, NULL,
udp_ipcp_mgmt_handler, NULL)) {
@@ -657,10 +667,10 @@ static int udp_ipcp_bootstrap(const struct ipcp_config * conf)
}
}
- log_dbg("Bootstrapped IPCP over UDP with pid %d.", getpid());
+ log_dbg("Bootstrapped " TYPE_STR " with pid %d.", getpid());
log_dbg("Bound to IP address %s.", ipstr);
- log_dbg("Using port %u.", conf->udp.port);
- if (conf->udp.dns_addr != 0)
+ log_dbg("Using port %u.", udp->port);
+ if (is_addr_specified(&udp_data.dns_addr))
log_dbg("DNS server address is %s.", dnsstr);
else
log_dbg("DNS server not in use.");
@@ -668,14 +678,14 @@ static int udp_ipcp_bootstrap(const struct ipcp_config * conf)
return 0;
fail_packet_writer:
- while (i > 0) {
- pthread_cancel(udp_data.packet_writer[--i]);
+ while (i-- > 0) {
+ pthread_cancel(udp_data.packet_writer[i]);
pthread_join(udp_data.packet_writer[i], NULL);
}
i = IPCP_UDP_RD_THR;
fail_packet_reader:
- while (i > 0) {
- pthread_cancel(udp_data.packet_reader[--i]);
+ while (i-- > 0) {
+ pthread_cancel(udp_data.packet_reader[i]);
pthread_join(udp_data.packet_reader[i], NULL);
}
pthread_cancel(udp_data.mgmt_handler);
@@ -738,26 +748,26 @@ static int ddns_send(char * cmd)
return 0;
}
-static uint32_t ddns_resolve(char * name,
- uint32_t dns_addr)
+static struct __ADDR ddns_resolve(char * name,
+ struct __ADDR dns_addr)
{
- pid_t pid = -1;
- int wstatus;
- int pipe_fd[2];
- char dnsstr[INET_ADDRSTRLEN];
- char buf[IPCP_UDP_BUF_SIZE];
- ssize_t count = 0;
- char * substr = NULL;
- char * substr2 = NULL;
- char * addr_str = "Address:";
- uint32_t ip_addr = 0;
-
- if (inet4_ntop(&dns_addr, dnsstr) == NULL)
- return 0;
+ pid_t pid = -1;
+ int wstatus;
+ int pipe_fd[2];
+ char dnsstr[__ADDRSTRLEN];
+ char buf[IPCP_UDP_BUF_SIZE];
+ ssize_t count = 0;
+ char * substr = NULL;
+ char * substr2 = NULL;
+ char * addr_str = "Address:";
+ struct __ADDR ip_addr = __ADDR_ANY_INIT;
+
+ if (__inet_ntop(&dns_addr, dnsstr) == NULL)
+ return ip_addr;
if (pipe(pipe_fd)) {
log_err("Failed to create pipe: %s.", strerror(errno));
- return 0;
+ return ip_addr;
}
pid = fork();
@@ -765,7 +775,7 @@ static uint32_t ddns_resolve(char * name,
log_err("Failed to fork: %s.", strerror(errno));
close(pipe_fd[0]);
close(pipe_fd[1]);
- return -1;
+ return ip_addr;
}
if (pid == 0) {
@@ -785,7 +795,7 @@ static uint32_t ddns_resolve(char * name,
if (count <= 0) {
log_err("Failed to communicate with nslookup.");
close(pipe_fd[0]);
- return 0;
+ return ip_addr;
}
close(pipe_fd[0]);
@@ -806,12 +816,13 @@ static uint32_t ddns_resolve(char * name,
if (substr2 == NULL || strstr(substr2, addr_str) == NULL) {
log_err("Failed to resolve DNS address.");
- return 0;
+ return ip_addr;
}
- if (inet_pton(AF_INET, substr2 + strlen(addr_str) + 1, &ip_addr) != 1) {
+ if (inet_pton(__AF, substr2 + strlen(addr_str) + 1, &ip_addr) != 1) {
log_err("Failed to resolve DNS address.");
- return 0;
+ assert(!is_addr_specified(&ip_addr));
+ return ip_addr;
}
return ip_addr;
@@ -821,11 +832,11 @@ static uint32_t ddns_resolve(char * name,
static int udp_ipcp_reg(const uint8_t * hash)
{
#ifdef HAVE_DDNS
- char ipstr[INET_ADDRSTRLEN];
- char dnsstr[INET_ADDRSTRLEN];
- char cmd[1000];
- uint32_t dns_addr;
- uint32_t ip_addr;
+ char ipstr[__ADDRSTRLEN];
+ char dnsstr[__ADDRSTRLEN];
+ char cmd[1000];
+ struct __ADDR dns_addr;
+ struct __ADDR ip_addr;
#endif
char * hashstr;
@@ -851,16 +862,19 @@ static int udp_ipcp_reg(const uint8_t * hash)
dns_addr = udp_data.dns_addr;
- if (dns_addr != 0) {
- ip_addr = udp_data.s_saddr.sin_addr.s_addr;
-
- if (inet4_ntop(&ip_addr, ipstr) == NULL) {
+ if (is_addr_specified(&dns_addr)) {
+#ifdef BUILD_IPCP_UDP4
+ ip_addr = udp_data.s_saddr.sin_addr;
+#else
+ ip_addr = udp_data.s_saddr.sin6_addr;
+#endif
+ if (__inet_ntop(&ip_addr, ipstr) == NULL) {
log_err("Failed to convert IP address to string.");
free(hashstr);
return -1;
}
- if (inet4_ntop(&dns_addr, dnsstr) == NULL) {
+ if (__inet_ntop(&dns_addr, dnsstr) == NULL) {
log_err("Failed to convert DNS address to string.");
free(hashstr);
return -1;
@@ -885,12 +899,12 @@ static int udp_ipcp_reg(const uint8_t * hash)
static int udp_ipcp_unreg(const uint8_t * hash)
{
#ifdef HAVE_DDNS
- char dnsstr[INET_ADDRSTRLEN];
+ char dnsstr[__ADDRSTRLEN];
/* max DNS name length + max IP length + max command length */
- char cmd[100];
- uint32_t dns_addr;
+ char cmd[100];
+ struct __ADDR dns_addr;
#endif
- char * hashstr;
+ char * hashstr;
assert(hash);
@@ -907,8 +921,8 @@ static int udp_ipcp_unreg(const uint8_t * hash)
dns_addr = udp_data.dns_addr;
- if (dns_addr != 0) {
- if (inet4_ntop(&dns_addr, dnsstr) == NULL) {
+ if (is_addr_specified(&dns_addr)) {
+ if (__inet_ntop(&dns_addr, dnsstr) == NULL) {
log_err("Failed to convert DNS address to string.");
free(hashstr);
return -1;
@@ -929,11 +943,13 @@ static int udp_ipcp_unreg(const uint8_t * hash)
static int udp_ipcp_query(const uint8_t * hash)
{
- uint32_t ip_addr = 0;
- char * hashstr;
- struct hostent * h;
+ struct addr addr = {};
+ char * hashstr;
+ struct addrinfo hints;
+ struct addrinfo * ai;
#ifdef HAVE_DDNS
- uint32_t dns_addr = 0;
+ struct __ADDR dns_addr = __ADDR_ANY_INIT;
+ struct __ADDR ip_addr = __ADDR_ANY_INIT;
#endif
assert(hash);
@@ -953,28 +969,42 @@ static int udp_ipcp_query(const uint8_t * hash)
#ifdef HAVE_DDNS
dns_addr = udp_data.dns_addr;
- if (dns_addr != 0) {
+ if (is_addr_specified(&dns_addr)) {
ip_addr = ddns_resolve(hashstr, dns_addr);
- if (ip_addr == 0) {
+ if (!is_addr_specified(&ip_addr)) {
log_err("Could not resolve %s.", hashstr);
free(hashstr);
return -1;
}
} else {
#endif
- h = gethostbyname(hashstr);
- if (h == NULL) {
- log_err("Could not resolve %s.", hashstr);
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = __AF;
+ if (getaddrinfo(hashstr, NULL, &hints, &ai) != 0) {
+ log_err("Could not resolve %s: %s.", hashstr,
+ gai_strerror(errno));
+ free(hashstr);
+ return -1;
+ }
+
+ if (ai->ai_family != __AF) {
+ log_err("Wrong addres family for %s.", hashstr);
+ freeaddrinfo(ai);
free(hashstr);
return -1;
}
- ip_addr = *((uint32_t *) (h->h_addr_list[0]));
+ #ifdef BUILD_IPCP_UDP4
+ addr.ip4 = ((struct sockaddr_in *) (ai->ai_addr))->sin_addr;
+ #else
+ addr.ip6 = ((struct sockaddr_in6 *) (ai->ai_addr))->sin6_addr;
+ #endif
+ freeaddrinfo(ai);
#ifdef HAVE_DDNS
}
#endif
-
- if (shim_data_dir_add_entry(udp_data.shim_data, hash, ip_addr)) {
+ if (shim_data_dir_add_entry(udp_data.shim_data, hash, addr)) {
log_err("Failed to add directory entry.");
free(hashstr);
return -1;
@@ -990,9 +1020,10 @@ static int udp_ipcp_flow_alloc(int fd,
qosspec_t qs,
const buffer_t * data)
{
- struct sockaddr_in r_saddr; /* Server address */
- uint32_t ip_addr = 0;
- char ipstr[INET_ADDRSTRLEN];
+ struct __SOCKADDR r_saddr; /* Server address */
+ struct __ADDR ip_addr;
+ struct addr addr;
+ char ipstr[__ADDRSTRLEN];
(void) qs;
@@ -1003,9 +1034,13 @@ static int udp_ipcp_flow_alloc(int fd,
return -1;
}
- ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst);
-
- if (inet4_ntop(&ip_addr, ipstr) == NULL) {
+ addr = shim_data_dir_get_addr(udp_data.shim_data, dst);
+#ifdef BUILD_IPCP_UDP4
+ ip_addr = addr.ip4;
+#else
+ ip_addr = addr.ip6;
+#endif
+ if (__inet_ntop(&ip_addr, ipstr) == NULL) {
log_err("Could not convert IP address.");
return -1;
}
@@ -1014,9 +1049,15 @@ static int udp_ipcp_flow_alloc(int fd,
HASH_VAL32(dst), ipstr);
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;
+#ifdef BUILD_IPCP_UDP4
+ r_saddr.sin_family = AF_INET;
+ r_saddr.sin_addr = addr.ip4;
+ r_saddr.sin_port = udp_data.s_saddr.sin_port;
+#else
+ r_saddr.sin6_family = AF_INET6;
+ r_saddr.sin6_addr = addr.ip6;
+ r_saddr.sin6_port = udp_data.s_saddr.sin6_port;
+#endif
if (udp_ipcp_port_alloc(&r_saddr, fd, dst, qs, data) < 0) {
log_err("Could not allocate port.");
@@ -1039,8 +1080,8 @@ static int udp_ipcp_flow_alloc_resp(int fd,
int resp,
const buffer_t * data)
{
- struct sockaddr_in saddr;
- int d_eid;
+ struct __SOCKADDR saddr;
+ int d_eid;
if (ipcp_wait_flow_resp(fd) < 0) {
log_err("Failed to wait for flow response.");
diff --git a/src/ipcpd/udp/udp4.c b/src/ipcpd/udp/udp4.c
new file mode 100644
index 00000000..07d5f818
--- /dev/null
+++ b/src/ipcpd/udp/udp4.c
@@ -0,0 +1,42 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * IPC process over UDP/IPv4
+ *
+ * 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 200112L
+#endif
+
+#include <ouroboros/ipcp-dev.h>
+
+#define BUILD_IPCP_UDP4
+#define THIS_TYPE IPCP_UDP4
+#define TYPE_STR "IPCP over UDP/IPv4"
+#define OUROBOROS_PREFIX "ipcpd/udp4"
+#define IPCP_UDP_MAX_PACKET_SIZE 8980
+#define __AF AF_INET
+#define __ADDRSTRLEN INET_ADDRSTRLEN
+#define __SOCKADDR sockaddr_in
+#define __ADDR in_addr
+#define __ADDR_ANY_INIT { .s_addr = INADDR_ANY }
+
+#include "udp.c"
diff --git a/src/ipcpd/udp/udp6.c b/src/ipcpd/udp/udp6.c
new file mode 100644
index 00000000..b7924a3f
--- /dev/null
+++ b/src/ipcpd/udp/udp6.c
@@ -0,0 +1,42 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * IPC process over UDP/IPv6
+ *
+ * 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 200112L
+#endif
+
+#include <ouroboros/ipcp-dev.h>
+
+#define BUILD_IPCP_UDP6
+#define THIS_TYPE IPCP_UDP6
+#define TYPE_STR "IPCP over UDP/IPv6"
+#define OUROBOROS_PREFIX "ipcpd/udp6"
+#define IPCP_UDP_MAX_PACKET_SIZE 8952
+#define __AF AF_INET6
+#define __ADDRSTRLEN INET6_ADDRSTRLEN
+#define __SOCKADDR sockaddr_in6
+#define __ADDR in6_addr
+#define __ADDR_ANY_INIT IN6ADDR_ANY_INIT
+
+#include "udp.c"
diff --git a/src/ipcpd/unicast/CMakeLists.txt b/src/ipcpd/unicast/CMakeLists.txt
index ca742871..ced045e6 100644
--- a/src/ipcpd/unicast/CMakeLists.txt
+++ b/src/ipcpd/unicast/CMakeLists.txt
@@ -13,8 +13,12 @@ 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")
+set(IPCP_UNICAST_MPL 10000 CACHE STRING
+ "Default maximum packet lifetime for the unicast IPCP, in ms")
+set(DEBUG_PROTO_DHT FALSE CACHE BOOL
+ "Add DHT protocol message output to debug logging")
+set(DEBUG_PROTO_LS FALSE CACHE BOOL
+ "Add link state protocol message output to debug logging")
protobuf_generate_c(DHT_PROTO_SRCS DHT_PROTO_HDRS dir/dht.proto)
@@ -31,7 +35,7 @@ if (HAVE_FUSE)
endif ()
endif ()
-set(SOURCE_FILES
+set(IPCP_UNICAST_SOURCE_FILES
# Add source files here
addr-auth.c
ca.c
@@ -56,7 +60,7 @@ set(SOURCE_FILES
routing/graph.c
)
-add_executable(ipcpd-unicast ${SOURCE_FILES} ${IPCP_SOURCES} ${COMMON_SOURCES}
+add_executable(ipcpd-unicast ${IPCP_UNICAST_SOURCE_FILES} ${IPCP_SOURCES} ${COMMON_SOURCES}
${DHT_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS})
target_link_libraries(ipcpd-unicast LINK_PUBLIC ouroboros-dev)
@@ -69,7 +73,4 @@ install(TARGETS ipcpd-unicast RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
add_subdirectory(pff/tests)
add_subdirectory(routing/tests)
-
-if (NOT GNU)
- add_subdirectory(dir/tests)
-endif ()
+add_subdirectory(dir/tests)
diff --git a/src/ipcpd/unicast/addr-auth.h b/src/ipcpd/unicast/addr-auth.h
index e119dff3..0d2cd4c0 100644
--- a/src/ipcpd/unicast/addr-auth.h
+++ b/src/ipcpd/unicast/addr-auth.h
@@ -27,6 +27,14 @@
#include <stdint.h>
+#define ADDR_FMT32 "%02x.%02x.%02x.%02x"
+#define ADDR_VAL32(a) \
+ ((uint8_t *) a)[0], ((uint8_t *) a)[1], \
+ ((uint8_t *) a)[2], ((uint8_t *) a)[3]
+
+#define ADDR_FMT64 ADDR_FMT32 "." ADDR_FMT32
+#define ADDR_VAL64(a) ADDR_VAL32(a), ADDR_VAL32(a + 4)
+
int addr_auth_init(enum pol_addr_auth type,
const void * info);
diff --git a/src/ipcpd/unicast/addr-auth/flat.c b/src/ipcpd/unicast/addr-auth/flat.c
index c4562935..34ca1cef 100644
--- a/src/ipcpd/unicast/addr-auth/flat.c
+++ b/src/ipcpd/unicast/addr-auth/flat.c
@@ -31,17 +31,18 @@
#include <ouroboros/logs.h>
#include <ouroboros/random.h>
+#include "addr-auth.h"
#include "ipcp.h"
#include "flat.h"
-#define NAME_LEN 8
+#define NAME_LEN 8
+#define INVALID_ADDRESS 0
struct {
- uint8_t addr_size;
+ uint8_t addr_size;
+ uint32_t addr;
} flat;
-#define INVALID_ADDRESS 0
-
struct addr_auth_ops flat_ops = {
.init = flat_init,
.fini = flat_fini,
@@ -57,6 +58,15 @@ int flat_init(const void * info)
return -1;
}
+#if defined (CONFIG_OUROBOROS_DEBUG) && defined (IPCP_DEBUG_LOCAL)
+ flat.addr = getpid();
+#else
+ while (flat.addr == INVALID_ADDRESS)
+ random_buffer(&flat.addr,sizeof(flat.addr));
+#endif
+ log_dbg("Flat address initialized to " ADDR_FMT32 ".",
+ ADDR_VAL32((uint8_t *) &flat.addr));
+
return 0;
}
@@ -67,13 +77,5 @@ int flat_fini(void)
uint64_t flat_address(void)
{
- 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;
+ return (uint64_t) flat.addr;
}
diff --git a/src/ipcpd/unicast/ca.c b/src/ipcpd/unicast/ca.c
index 287eaf41..1fcc9bb2 100644
--- a/src/ipcpd/unicast/ca.c
+++ b/src/ipcpd/unicast/ca.c
@@ -49,7 +49,6 @@ int ca_init(enum pol_cong_avoid pol)
return 0;
}
-
void ca_fini(void)
{
ca.ops = NULL;
diff --git a/src/ipcpd/unicast/connmgr.c b/src/ipcpd/unicast/connmgr.c
index 11c5d5b6..07568fb5 100644
--- a/src/ipcpd/unicast/connmgr.c
+++ b/src/ipcpd/unicast/connmgr.c
@@ -32,8 +32,4 @@
#define BUILD_IPCP_UNICAST
-#ifdef IPCP_CONN_WAIT_DIR
- #include "dir.h"
-#endif
-
#include "common/connmgr.c"
diff --git a/src/ipcpd/unicast/dir.c b/src/ipcpd/unicast/dir.c
index e0cb09fc..2b305626 100644
--- a/src/ipcpd/unicast/dir.c
+++ b/src/ipcpd/unicast/dir.c
@@ -44,50 +44,57 @@
struct {
struct dir_ops * ops;
- void * dir;
-} dirmgr;
+} dir;
-int dir_init(void)
+int dir_init(struct dir_config * conf)
{
- dirmgr.ops = &dht_dir_ops;
+ void * cfg;
- dirmgr.dir = dirmgr.ops->create();
- if (dirmgr.dir == NULL) {
- dirmgr.ops = NULL;
- return -ENOMEM;
+ assert(conf != NULL);
+
+ switch (conf->pol) {
+ case DIR_DHT:
+ log_info("Using DHT policy.");
+ dir.ops = &dht_dir_ops;
+ cfg = &conf->dht;
+ break;
+ default: /* DIR_INVALID */
+ log_err("Invalid directory policy %d.", conf->pol);
+ return -EINVAL;
}
- return 0;
+ assert(dir.ops->init != NULL);
+
+ return dir.ops->init(cfg);
}
void dir_fini(void)
{
- dirmgr.ops->destroy(dirmgr.dir);
- dirmgr.ops = NULL;
- dirmgr.dir = NULL;
+ dir.ops->fini();
+ dir.ops = NULL;
}
-int dir_bootstrap(void)
+int dir_start(void)
{
- return dirmgr.ops->bootstrap(dirmgr.dir);
+ return dir.ops->start();
}
-int dir_reg(const uint8_t * hash)
+void dir_stop(void)
{
- return dirmgr.ops->reg(dirmgr.dir, hash);
+ dir.ops->stop();
}
-int dir_unreg(const uint8_t * hash)
+int dir_reg(const uint8_t * hash)
{
- return dirmgr.ops->unreg(dirmgr.dir, hash);
+ return dir.ops->reg(hash);
}
-uint64_t dir_query(const uint8_t * hash)
+int dir_unreg(const uint8_t * hash)
{
- return dirmgr.ops->query(dirmgr.dir, hash);
+ return dir.ops->unreg(hash);
}
-int dir_wait_running(void)
+uint64_t dir_query(const uint8_t * hash)
{
- return dirmgr.ops->wait_running(dirmgr.dir);
+ return dir.ops->query(hash);
}
diff --git a/src/ipcpd/unicast/dir.h b/src/ipcpd/unicast/dir.h
index b261ea2c..dbfde19f 100644
--- a/src/ipcpd/unicast/dir.h
+++ b/src/ipcpd/unicast/dir.h
@@ -25,11 +25,14 @@
#include <inttypes.h>
-int dir_init(void);
+/* may update the config! */
+int dir_init(struct dir_config * conf);
void dir_fini(void);
-int dir_bootstrap(void);
+int dir_start(void);
+
+void dir_stop(void);
int dir_reg(const uint8_t * hash);
@@ -37,6 +40,4 @@ int dir_unreg(const uint8_t * hash);
uint64_t dir_query(const uint8_t * hash);
-int dir_wait_running(void);
-
#endif /* OUROBOROS_IPCPD_UNICAST_DIR_H */
diff --git a/src/ipcpd/unicast/dir/dht.c b/src/ipcpd/unicast/dir/dht.c
index 08a5a5a9..6b06def9 100644
--- a/src/ipcpd/unicast/dir/dht.c
+++ b/src/ipcpd/unicast/dir/dht.c
@@ -4,7 +4,6 @@
* 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
@@ -20,10 +19,12 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
-#if defined(__linux__) || defined(__CYGWIN__)
-#define _DEFAULT_SOURCE
-#else
-#define _POSIX_C_SOURCE 200112L
+#if !defined (__DHT_TEST__)
+ #if defined(__linux__) || defined(__CYGWIN__)
+ #define _DEFAULT_SOURCE
+ #else
+ #define _POSIX_C_SOURCE 200112L
+ #endif
#endif
#include "config.h"
@@ -38,13 +39,14 @@
#include <ouroboros/errno.h>
#include <ouroboros/logs.h>
#include <ouroboros/list.h>
-#include <ouroboros/notifier.h>
#include <ouroboros/random.h>
+#include <ouroboros/rib.h>
#include <ouroboros/time.h>
#include <ouroboros/tpm.h>
#include <ouroboros/utils.h>
#include <ouroboros/pthread.h>
+#include "addr-auth.h"
#include "common/connmgr.h"
#include "dht.h"
#include "dt.h"
@@ -58,143 +60,153 @@
#include <limits.h>
#include "dht.pb-c.h"
-typedef DhtMsg dht_msg_t;
-typedef DhtContactMsg dht_contact_msg_t;
+typedef DhtMsg dht_msg_t;
+typedef DhtContactMsg dht_contact_msg_t;
+typedef DhtStoreMsg dht_store_msg_t;
+typedef DhtFindReqMsg dht_find_req_msg_t;
+typedef DhtFindNodeRspMsg dht_find_node_rsp_msg_t;
+typedef DhtFindValueRspMsg dht_find_value_rsp_msg_t;
+typedef ProtobufCBinaryData binary_data_t;
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
#endif
-#define DHT_MAX_REQS 2048 /* KAD recommends rnd(), bmp can be changed. */
-#define KAD_ALPHA 3 /* Parallel factor, proven optimal value. */
-#define KAD_K 8 /* Replication factor, MDHT value. */
-#define KAD_T_REPL 900 /* Replication time, tied to k. MDHT value. */
-#define KAD_T_REFR 900 /* Refresh time stale bucket, MDHT value. */
-#define KAD_T_JOIN 8 /* Response time to wait for a join. */
-#define KAD_T_RESP 5 /* Response time to wait for a response. */
-#define KAD_R_PING 2 /* Ping retries before declaring peer dead. */
-#define KAD_QUEER 15 /* Time to declare peer questionable. */
-#define KAD_BETA 8 /* Bucket split factor, must be 1, 2, 4 or 8. */
-#define KAD_RESP_RETR 6 /* Number of retries on sending a response. */
-#define KAD_JOIN_RETR 8 /* Number of retries sending a join. */
-#define KAD_JOIN_INTV 1 /* Time (seconds) between join retries. */
+#define DHT_MAX_REQS 128 /* KAD recommends rnd(), bmp can be changed. */
+#define DHT_WARN_REQS 100 /* Warn if number of requests exceeds this. */
+#define DHT_MAX_VALS 8 /* Max number of values to return for a key. */
+#define DHT_T_CACHE 60 /* Max cache time for values (s) */
+#define DHT_T_RESP 2 /* Response time to wait for a response (s). */
+#define DHT_N_REPUB 5 /* Republish if expiry within n replications. */
+#define DHT_R_PING 2 /* Ping retries before declaring peer dead. */
+#define DHT_QUEER 15 /* Time to declare peer questionable. */
+#define DHT_BETA 8 /* Bucket split factor, must be 1, 2, 4 or 8. */
+#define DHT_RESP_RETR 6 /* Number of retries on sending a response. */
#define HANDLE_TIMEO 1000 /* Timeout for dht_handle_packet tpm check (ms) */
-#define DHT_RETR_ADDR 1 /* Number of addresses to return on retrieve */
+#define DHT_INVALID 0 /* Invalid cookie value. */
-enum dht_state {
- DHT_INIT = 0,
- DHT_SHUTDOWN,
- DHT_JOINING,
- DHT_RUNNING,
-};
+#define KEY_FMT "K<" HASH_FMT64 ">"
+#define KEY_VAL(key) HASH_VAL64(key)
-enum kad_code {
- KAD_JOIN = 0,
- KAD_FIND_NODE,
- KAD_FIND_VALUE,
- /* Messages without a response below. */
- KAD_STORE,
- KAD_RESPONSE
-};
+#define VAL_FMT "V<" HASH_FMT64 ">"
+#define VAL_VAL(val) HASH_VAL64((val).data)
-enum kad_req_state {
- REQ_NULL = 0,
- REQ_INIT,
- REQ_PENDING,
- REQ_RESPONSE,
- REQ_DONE,
- REQ_DESTROY
-};
+#define KV_FMT "<" HASH_FMT64 ", " HASH_FMT64 ">"
+#define KV_VAL(key, val) HASH_VAL64(key), HASH_VAL64((val).data)
-enum lookup_state {
- LU_NULL = 0,
- LU_INIT,
- LU_PENDING,
- LU_UPDATE,
- LU_COMPLETE,
- LU_DESTROY
-};
+#define PEER_FMT "[" HASH_FMT64 "|" ADDR_FMT32 "]"
+#define PEER_VAL(id, addr) HASH_VAL64(id), ADDR_VAL32(&(addr))
-struct kad_req {
- struct list_head next;
+#define DHT_CODE(msg) dht_code_str[(msg)->code]
- uint32_t cookie;
- enum kad_code code;
- uint8_t * key;
- uint64_t addr;
+#define TX_HDR_FMT "%s --> " PEER_FMT
+#define TX_HDR_VAL(msg, id, addr) DHT_CODE(msg), PEER_VAL(id, addr)
- enum kad_req_state state;
- pthread_cond_t cond;
- pthread_mutex_t lock;
+#define RX_HDR_FMT "%s <-- " PEER_FMT
+#define RX_HDR_VAL(msg) DHT_CODE(msg), \
+ PEER_VAL(msg->src->id.data, msg->src->addr)
- time_t t_exp;
+#define CK_FMT "|" HASH_FMT64 "|"
+#define CK_VAL(cookie) HASH_VAL64(&(cookie))
+
+#define IS_REQUEST(code) \
+ (code == DHT_FIND_NODE_REQ || code == DHT_FIND_VALUE_REQ)
+
+enum dht_code {
+ DHT_STORE,
+ DHT_FIND_NODE_REQ,
+ DHT_FIND_NODE_RSP,
+ DHT_FIND_VALUE_REQ,
+ DHT_FIND_VALUE_RSP
};
-struct cookie_el {
- struct list_head next;
+const char * dht_code_str[] = {
+ "DHT_STORE",
+ "DHT_FIND_NODE_REQ",
+ "DHT_FIND_NODE_RSP",
+ "DHT_FIND_VALUE_REQ",
+ "DHT_FIND_VALUE_RSP"
+};
- uint32_t cookie;
+enum dht_state {
+ DHT_NULL = 0,
+ DHT_INIT,
+ DHT_RUNNING
};
-struct lookup {
- struct list_head next;
+struct val_entry {
+ struct list_head next;
- struct list_head cookies;
+ buffer_t val;
- uint8_t * key;
+ time_t t_exp; /* Expiry time */
+ time_t t_repl; /* Last replication time */
+};
+
+struct dht_entry {
+ struct list_head next;
- struct list_head contacts;
- size_t n_contacts;
+ uint8_t * key;
- uint64_t * addrs;
- size_t n_addrs;
+ struct {
+ struct list_head list;
+ size_t len;
+ } vals; /* We don't own these, only replicate */
- enum lookup_state state;
- pthread_cond_t cond;
- pthread_mutex_t lock;
+ struct {
+ struct list_head list;
+ size_t len;
+ } lvals; /* We own these, must be republished */
};
-struct val {
+struct contact {
struct list_head next;
+ uint8_t * id;
uint64_t addr;
- time_t t_exp;
- time_t t_rep;
+ size_t fails;
+ time_t t_seen;
};
-struct ref_entry {
+struct peer_entry {
struct list_head next;
- uint8_t * key;
+ uint64_t cookie;
+ uint8_t * id;
+ uint64_t addr;
+ enum dht_code code;
- time_t t_rep;
+ time_t t_sent;
};
-struct dht_entry {
+struct dht_req {
struct list_head next;
uint8_t * key;
- size_t n_vals;
- struct list_head vals;
-};
-
-struct contact {
- struct list_head next;
+ time_t t_exp;
- uint8_t * id;
- uint64_t addr;
+ struct {
+ struct list_head list;
+ size_t len;
+ } peers;
- size_t fails;
- time_t t_seen;
+ struct {
+ struct list_head list;
+ size_t len;
+ } cache;
};
struct bucket {
- struct list_head contacts;
- size_t n_contacts;
+ struct {
+ struct list_head list;
+ size_t len;
+ } contacts;
- struct list_head alts;
- size_t n_alts;
+ struct {
+ struct list_head list;
+ size_t len;
+ } alts;
time_t t_refr;
@@ -202,1088 +214,1464 @@ struct bucket {
uint8_t mask;
struct bucket * parent;
- struct bucket * children[1L << KAD_BETA];
+ struct bucket * children[1L << DHT_BETA];
};
struct cmd {
- struct list_head next;
-
- struct shm_du_buff * sdb;
+ struct list_head next;
+ buffer_t cbuf;
};
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
+ .init = (int (*)(void *)) dht_init,
+ .fini = dht_fini,
+ .start = dht_start,
+ .stop = dht_stop,
+ .reg = dht_reg,
+ .unreg = dht_unreg,
+ .query = dht_query
};
-struct dht {
- size_t alpha;
- size_t b;
- size_t k;
+struct {
+ struct { /* Kademlia parameters */
+ uint32_t alpha; /* Number of concurrent requests */
+ size_t k; /* Number of replicas to store */
+ time_t t_expire; /* Expiry time for values (s) */
+ time_t t_refresh; /* Refresh time for contacts (s) */
+ time_t t_repl; /* Replication time for values (s) */
+ };
- time_t t_expire;
- time_t t_refresh;
- time_t t_replic;
- time_t t_repub;
+ buffer_t id;
- uint8_t * id;
- uint64_t addr;
+ time_t t0; /* Creation time */
+ uint64_t addr; /* Our own address */
+ uint64_t peer; /* Enrollment peer address */
+ uint64_t magic; /* Magic cookie for retransmit */
- struct bucket * buckets;
+ uint64_t eid; /* Entity ID */
- struct list_head entries;
+ struct tpm * tpm;
+ pthread_t worker;
- struct list_head refs;
+ enum dht_state state;
- struct list_head lookups;
+ struct {
+ struct {
+ struct bucket * root;
+ } contacts;
+
+ struct {
+ struct list_head list;
+ size_t len;
+ size_t vals;
+ size_t lvals;
+ } kv;
+
+ pthread_rwlock_t lock;
+ } db;
+
+ struct {
+ struct list_head list;
+ size_t len;
+ pthread_cond_t cond;
+ pthread_mutex_t mtx;
+ } reqs;
+
+ struct {
+ struct list_head list;
+ pthread_cond_t cond;
+ pthread_mutex_t mtx;
+ } cmds;
+} dht;
+
+
+/* DHT RIB */
+
+static const char * dht_dir[] = {
+ "database",
+ "stats",
+ NULL
+};
- struct list_head requests;
- struct bmp * cookies;
+const char * dht_stats = \
+ "DHT: " HASH_FMT64 "\n"
+ " Created: %s\n"
+ " Address: " ADDR_FMT32 "\n"
+ " Kademlia parameters:\n"
+ " Number of concurrent requests (alpha): %10zu\n"
+ " Number of replicas (k): %10zu\n"
+ " Expiry time for values (s): %10ld\n"
+ " Refresh time for contacts (s): %10ld\n"
+ " Replication time for values (s): %10ld\n"
+ " Number of keys: %10zu\n"
+ " Number of local values: %10zu\n"
+ " Number of non-local values: %10zu\n";
- enum dht_state state;
- struct list_head cmds;
- pthread_cond_t cond;
- pthread_mutex_t mtx;
+static int dht_rib_statfile(char * buf,
+ size_t len)
+{
+ struct tm * tm;
+ char tmstr[RIB_TM_STRLEN];
+ size_t keys;
+ size_t vals;
+ size_t lvals;
- pthread_rwlock_t lock;
+ assert(buf != NULL);
+ assert(len > 0);
- uint64_t eid;
+ pthread_rwlock_rdlock(&dht.db.lock);
- struct tpm * tpm;
+ keys = dht.db.kv.len;
+ lvals = dht.db.kv.lvals;
+ vals = dht.db.kv.vals;
- pthread_t worker;
-};
+ pthread_rwlock_unlock(&dht.db.lock);
-struct join_info {
- struct dht * dht;
- uint64_t addr;
-};
+ tm = gmtime(&dht.t0);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
-struct packet_info {
- struct dht * dht;
- struct shm_du_buff * sdb;
-};
+ snprintf(buf, len, dht_stats,
+ HASH_VAL64(dht.id.data),
+ tmstr,
+ ADDR_VAL32(&dht.addr),
+ dht.alpha, dht.k,
+ dht.t_expire, dht.t_refresh, dht.t_repl,
+ keys, vals, lvals);
+
+ return strlen(buf);
+}
-static uint8_t * dht_dup_key(const uint8_t * key,
- size_t len)
+static size_t dht_db_file_len(void)
{
- uint8_t * dup;
+ size_t sz;
+ size_t vals;
- dup = malloc(sizeof(*dup) * len);
- if (dup == NULL)
- return NULL;
+ sz = 18; /* DHT database + 2 * \n */
- memcpy(dup, key, len);
+ pthread_rwlock_rdlock(&dht.db.lock);
- return dup;
-}
+ if (dht.db.kv.len == 0) {
+ pthread_rwlock_unlock(&dht.db.lock);
+ sz += 14; /* No entries */
+ return sz;
+ }
-static enum dht_state dht_get_state(struct dht * dht)
-{
- enum dht_state state;
+ sz += 39 * 3 + 1; /* tally + extra newline */
+ sz += dht.db.kv.len * (25 + 19 + 23 + 1);
- pthread_mutex_lock(&dht->mtx);
+ vals = dht.db.kv.vals + dht.db.kv.lvals;
- state = dht->state;
+ sz += vals * (48 + 2 * RIB_TM_STRLEN);
- pthread_mutex_unlock(&dht->mtx);
+ pthread_rwlock_unlock(&dht.db.lock);
- return state;
+ return sz;
}
-static int dht_set_state(struct dht * dht,
- enum dht_state state)
+static int dht_rib_dbfile(char * buf,
+ size_t len)
{
- pthread_mutex_lock(&dht->mtx);
+ struct tm * tm;
+ char tmstr[RIB_TM_STRLEN];
+ char exstr[RIB_TM_STRLEN];
+ size_t i = 0;
+ struct list_head * p;
+
+ assert(buf != NULL);
+ assert(len > 0);
- if (state == DHT_JOINING && dht->state != DHT_INIT) {
- pthread_mutex_unlock(&dht->mtx);
- return -1;
+ pthread_rwlock_rdlock(&dht.db.lock);
+
+ if (dht.db.kv.len == 0) {
+ i += snprintf(buf, len, " No entries.\n");
+ pthread_rwlock_unlock(&dht.db.lock);
+ return i;
}
- dht->state = state;
+ i += snprintf(buf + i, len - i, "DHT database:\n\n");
+ i += snprintf(buf + i, len - i,
+ "Number of keys: %10zu\n"
+ "Number of local values: %10zu\n"
+ "Number of non-local values: %10zu\n\n",
+ dht.db.kv.len, dht.db.kv.vals, dht.db.kv.lvals);
+
+ list_for_each(p, &dht.db.kv.list) {
+ struct dht_entry * e = list_entry(p, struct dht_entry, next);
+ struct list_head * h;
+
+ i += snprintf(buf + i, len - i, "Key: " KEY_FMT "\n",
+ KEY_VAL(e->key));
+ i += snprintf(buf + i, len - i, " Local entries:\n");
+
+ list_for_each(h, &e->vals.list) {
+ struct val_entry * v;
+
+ v = list_entry(h, struct val_entry, next);
+
+ tm = gmtime(&v->t_repl);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+
+ tm = gmtime(&v->t_exp);
+ strftime(exstr, sizeof(exstr), RIB_TM_FORMAT, tm);
+
+ i += snprintf(buf + i, len - i,
+ " " VAL_FMT
+ ", t_replicated=%.*s, t_expire=%.*s\n",
+ VAL_VAL(v->val),
+ RIB_TM_STRLEN, tmstr,
+ RIB_TM_STRLEN, exstr);
+ }
+
+ i += snprintf(buf + i, len - i, "\n");
- pthread_cond_broadcast(&dht->cond);
+ i += snprintf(buf + i, len - i, " Non-local entries:\n");
- pthread_mutex_unlock(&dht->mtx);
+ list_for_each(h, &e->lvals.list) {
+ struct val_entry * v;
+
+ v= list_entry(h, struct val_entry, next);
+
+ tm = gmtime(&v->t_repl);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+
+ tm = gmtime(&v->t_exp);
+ strftime(exstr, sizeof(exstr), RIB_TM_FORMAT, tm);
+
+ i += snprintf(buf + i, len - i,
+ " " VAL_FMT
+ ", t_replicated=%.*s, t_expire=%.*s\n",
+ VAL_VAL(v->val),
+ RIB_TM_STRLEN, tmstr,
+ RIB_TM_STRLEN, exstr);
+
+ }
+ }
+
+ pthread_rwlock_unlock(&dht.db.lock);
+
+ printf("DHT RIB DB file generated (%zu bytes).\n", i);
+
+ return i;
+}
+
+static int dht_rib_read(const char * path,
+ char * buf,
+ size_t len)
+{
+ char * entry;
+
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+
+ if (strcmp(entry, "database") == 0) {
+ return dht_rib_dbfile(buf, len);
+ } else if (strcmp(entry, "stats") == 0) {
+ return dht_rib_statfile(buf, len);
+ }
return 0;
}
-int dht_wait_running(void * dir)
+static int dht_rib_readdir(char *** buf)
{
- struct dht * dht;
- int ret = 0;
+ int i = 0;
- dht = (struct dht *) dir;
+ while (dht_dir[i++] != NULL);
- pthread_mutex_lock(&dht->mtx);
+ *buf = malloc(sizeof(**buf) * i);
+ if (*buf == NULL)
+ goto fail_buf;
- pthread_cleanup_push(__cleanup_mutex_unlock, &dht->mtx);
+ i = 0;
- while (dht->state == DHT_JOINING)
- pthread_cond_wait(&dht->cond, &dht->mtx);
+ while (dht_dir[i] != NULL) {
+ (*buf)[i] = strdup(dht_dir[i]);
+ if ((*buf)[i] == NULL)
+ goto fail_dup;
+ i++;
+ }
- if (dht->state != DHT_RUNNING)
- ret = -1;
+ return i;
+ fail_dup:
+ freepp(char, *buf, i);
+ fail_buf:
+ return -ENOMEM;
+}
- pthread_cleanup_pop(true);
+static int dht_rib_getattr(const char * path,
+ struct rib_attr * attr)
+{
+ struct timespec now;
+ char * entry;
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ attr->mtime = now.tv_sec;
+
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+
+ if (strcmp(entry, "database") == 0) {
+ attr->size = dht_db_file_len();
+ } else if (strcmp(entry, "stats") == 0) {
+ attr->size = 545;
+ }
- return ret;
+ return 0;
}
-static uint8_t * create_id(size_t len)
+static struct rib_ops r_ops = {
+ .read = dht_rib_read,
+ .readdir = dht_rib_readdir,
+ .getattr = dht_rib_getattr
+};
+
+/* Helper functions */
+
+static uint8_t * generate_id(void)
{
uint8_t * id;
- id = malloc(len);
- if (id == NULL)
+ if(dht.id.len < sizeof(uint64_t)) {
+ log_err("DHT ID length is too short (%zu < %zu).",
+ dht.id.len, sizeof(uint64_t));
return NULL;
+ }
- if (random_buffer(id, len) < 0) {
- free(id);
- return NULL;
+ id = malloc(dht.id.len);
+ if (id == NULL) {
+ log_err("Failed to malloc ID.");
+ goto fail_id;
+ }
+
+ if (random_buffer(id, dht.id.len) < 0) {
+ log_err("Failed to generate random ID.");
+ goto fail_rnd;
}
return id;
+ fail_rnd:
+ free(id);
+ fail_id:
+ return NULL;
}
-static void kad_req_create(struct dht * dht,
- dht_msg_t * msg,
- uint64_t addr)
+static uint64_t generate_cookie(void)
{
- struct kad_req * req;
- pthread_condattr_t cattr;
- struct timespec t;
- size_t b;
+ uint64_t cookie = DHT_INVALID;
- clock_gettime(CLOCK_REALTIME_COARSE, &t);
+ while (cookie == DHT_INVALID)
+ random_buffer((uint8_t *) &cookie, sizeof(cookie));
- req = malloc(sizeof(*req));
- if (req == NULL)
- goto fail_malloc;
+ return cookie;
+}
- list_head_init(&req->next);
+/*
+ * If someone builds a network where the n (n > k) closest nodes all
+ * have IDs starting with the same 64 bits: by all means, change this.
+ */
+static uint64_t dist(const uint8_t * src,
+ const uint8_t * dst)
+{
+ assert(dht.id.len >= sizeof(uint64_t));
- req->t_exp = t.tv_sec + KAD_T_RESP;
- req->addr = addr;
- req->state = REQ_INIT;
- req->cookie = msg->cookie;
- req->code = msg->code;
- req->key = NULL;
+ return betoh64(*((uint64_t *) src) ^ *((uint64_t *) dst));
+}
- pthread_rwlock_rdlock(&dht->lock);
- b = dht->b;
- pthread_rwlock_unlock(&dht->lock);
+#define IS_CLOSER(x, y) (dist((x), dht.id.data) < dist((y), dht.id.data))
- if (msg->has_key) {
- req->key = dht_dup_key(msg->key.data, b);
- if (req->key == NULL)
- goto fail_dup_key;
- }
+static int addr_to_buf(const uint64_t addr,
+ buffer_t * buf)
+{
+ size_t len;
+ uint64_t _addr;
- if (pthread_mutex_init(&req->lock, NULL))
- goto fail_mutex;
+ len = sizeof(addr);
+ _addr = hton64(addr);
+ assert(buf != NULL);
- if (pthread_condattr_init(&cattr))
- goto fail_condattr;
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
+ buf->data = malloc(len);
+ if (buf->data == NULL)
+ goto fail_malloc;
- if (pthread_cond_init(&req->cond, &cattr))
- goto fail_cond_init;
+ buf->len = sizeof(_addr);
+ memcpy(buf->data, &_addr, sizeof(_addr));
- pthread_condattr_destroy(&cattr);
+ return 0;
+ fail_malloc:
+ return -ENOMEM;
+}
- pthread_rwlock_wrlock(&dht->lock);
+static int buf_to_addr(const buffer_t buf,
+ uint64_t * addr)
+{
+ assert(addr != NULL);
+ assert(buf.data != NULL);
- list_add(&req->next, &dht->requests);
+ if (buf.len != sizeof(*addr))
+ return - EINVAL;
- pthread_rwlock_unlock(&dht->lock);
+ *addr = ntoh64(*((uint64_t *) buf.data));
- return;
+ if (*addr == dht.addr)
+ *addr = INVALID_ADDR;
- 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;
+ return 0;
}
-static void cancel_req_destroy(void * o)
+static uint8_t * dht_dup_key(const uint8_t * key)
{
- struct kad_req * req = (struct kad_req *) o;
+ uint8_t * dup;
- pthread_mutex_unlock(&req->lock);
+ assert(key != NULL);
+ assert(dht.id.len != 0);
- pthread_cond_destroy(&req->cond);
- pthread_mutex_destroy(&req->lock);
+ dup = malloc(dht.id.len);
+ if (dup == NULL)
+ return NULL;
- if (req->key != NULL)
- free(req->key);
+ memcpy(dup, key, dht.id.len);
- free(req);
+ return dup;
}
-static void kad_req_destroy(struct kad_req * req)
+/* DHT */
+
+static struct val_entry * val_entry_create(const buffer_t val,
+ time_t exp)
{
- assert(req);
+ struct val_entry * e;
+ struct timespec now;
- pthread_mutex_lock(&req->lock);
+ assert(val.data != NULL);
+ assert(val.len > 0);
- switch (req->state) {
- case REQ_DESTROY:
- pthread_mutex_unlock(&req->lock);
- return;
- case REQ_PENDING:
- req->state = REQ_DESTROY;
- pthread_cond_broadcast(&req->cond);
- break;
- case REQ_INIT:
- case REQ_DONE:
- req->state = REQ_NULL;
- break;
- case REQ_RESPONSE:
- case REQ_NULL:
- default:
- break;
- }
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- pthread_cleanup_push(cancel_req_destroy, req);
+#ifndef __DHT_TEST_ALLOW_EXPIRED__
+ if (exp < now.tv_sec)
+ return NULL; /* Refuse to add expired values */
+#endif
+ e = malloc(sizeof(*e));
+ if (e == NULL)
+ goto fail_entry;
+
+ list_head_init(&e->next);
- while (req->state != REQ_NULL && req->state != REQ_DONE)
- pthread_cond_wait(&req->cond, &req->lock);
+ e->val.len = val.len;
+ e->val.data = malloc(val.len);
+ if (e->val.data == NULL)
+ goto fail_val;
- pthread_cleanup_pop(true);
+ memcpy(e->val.data, val.data, val.len);
+
+ e->t_repl = 0;
+ e->t_exp = exp;
+
+ return e;
+
+ fail_val:
+ free(e);
+ fail_entry:
+ return NULL;
}
-static int kad_req_wait(struct kad_req * req,
- time_t t)
+static void val_entry_destroy(struct val_entry * v)
{
- struct timespec timeo = TIMESPEC_INIT_S(0);
- struct timespec abs;
- int ret = 0;
+ assert(v->val.data != NULL);
- assert(req);
+ freebuf(v->val);
+ free(v);
+}
- timeo.tv_sec = t;
+static struct dht_entry * dht_entry_create(const uint8_t * key)
+{
+ struct dht_entry * e;
- clock_gettime(PTHREAD_COND_CLOCK, &abs);
+ assert(key != NULL);
- ts_add(&abs, &timeo, &abs);
+ e = malloc(sizeof(*e));
+ if (e == NULL)
+ goto fail_entry;
- pthread_mutex_lock(&req->lock);
+ list_head_init(&e->next);
+ list_head_init(&e->vals.list);
+ list_head_init(&e->lvals.list);
- req->state = REQ_PENDING;
+ e->vals.len = 0;
+ e->lvals.len = 0;
- pthread_cleanup_push(__cleanup_mutex_unlock, &req->lock);
+ e->key = dht_dup_key(key);
+ if (e->key == NULL)
+ goto fail_key;
- while (req->state == REQ_PENDING && ret != -ETIMEDOUT)
- ret = -pthread_cond_timedwait(&req->cond, &req->lock, &abs);
+ return e;
+ fail_key:
+ free(e);
+ fail_entry:
+ return NULL;
+}
- switch(req->state) {
- case REQ_DESTROY:
- ret = -1;
- req->state = REQ_NULL;
- pthread_cond_signal(&req->cond);
- break;
- case REQ_PENDING: /* ETIMEDOUT */
- case REQ_RESPONSE:
- req->state = REQ_DONE;
- pthread_cond_broadcast(&req->cond);
- break;
- default:
- break;
+static void dht_entry_destroy(struct dht_entry * e)
+{
+ struct list_head * p;
+ struct list_head * h;
+
+ assert(e != NULL);
+
+ list_for_each_safe(p, h, &e->vals.list) {
+ struct val_entry * v = list_entry(p, struct val_entry, next);
+ list_del(&v->next);
+ val_entry_destroy(v);
+ --e->vals.len;
+ --dht.db.kv.vals;
}
- pthread_cleanup_pop(true);
+ list_for_each_safe(p, h, &e->lvals.list) {
+ struct val_entry * v = list_entry(p, struct val_entry, next);
+ list_del(&v->next);
+ val_entry_destroy(v);
+ --e->lvals.len;
+ --dht.db.kv.lvals;
+ }
+
+ free(e->key);
+
+ assert(e->vals.len == 0 && e->lvals.len == 0);
- return ret;
+ free(e);
}
-static void kad_req_respond(struct kad_req * req)
+static struct val_entry * dht_entry_get_lval(const struct dht_entry * e,
+ const buffer_t val)
{
- pthread_mutex_lock(&req->lock);
+ struct list_head * p;
- req->state = REQ_RESPONSE;
- pthread_cond_signal(&req->cond);
+ assert(e != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
- pthread_mutex_unlock(&req->lock);
+ list_for_each(p, &e->lvals.list) {
+ struct val_entry * v = list_entry(p, struct val_entry, next);
+ if (bufcmp(&v->val, &val) == 0)
+ return v;
+ }
+
+ return NULL;
}
-static struct contact * contact_create(const uint8_t * id,
- size_t len,
- uint64_t addr)
+static struct val_entry * dht_entry_get_val(const struct dht_entry * e,
+ const buffer_t val)
{
- struct contact * c;
- struct timespec t;
-
- c = malloc(sizeof(*c));
- if (c == NULL)
- return NULL;
+ struct list_head * p;
- list_head_init(&c->next);
+ assert(e != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
- clock_gettime(CLOCK_REALTIME_COARSE, &t);
+ list_for_each(p, &e->vals.list) {
+ struct val_entry * v = list_entry(p, struct val_entry, next);
+ if (bufcmp(&v->val, &val) == 0)
+ return v;
- c->addr = addr;
- c->fails = 0;
- c->t_seen = t.tv_sec;
- c->id = dht_dup_key(id, len);
- if (c->id == NULL) {
- free(c);
- return NULL;
}
- return c;
+ return NULL;
}
-static void contact_destroy(struct contact * c)
+static int dht_entry_update_val(struct dht_entry * e,
+ buffer_t val,
+ time_t exp)
{
- if (c != NULL)
- free(c->id);
+ struct val_entry * v;
+ struct timespec now;
- free(c);
+ assert(e != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ if (exp < now.tv_sec)
+ return -EINVAL; /* Refuse to add expired values */
+
+ if (dht_entry_get_lval(e, val) != NULL) {
+ log_dbg(KV_FMT " Val already in lvals.", KV_VAL(e->key, val));
+ return 0; /* Refuse to add local values */
+ }
+
+ v = dht_entry_get_val(e, val);
+ if (v == NULL) {
+ v = val_entry_create(val, exp);
+ if (v == NULL)
+ return -ENOMEM;
+
+ list_add_tail(&v->next, &e->vals.list);
+ ++e->vals.len;
+ ++dht.db.kv.vals;
+
+ return 0;
+ }
+
+ if (v->t_exp < exp)
+ v->t_exp = exp;
+
+ return 0;
}
-static struct bucket * iter_bucket(struct bucket * b,
- const uint8_t * id)
+static int dht_entry_update_lval(struct dht_entry * e,
+ buffer_t val)
{
- uint8_t byte;
- uint8_t mask;
+ struct val_entry * v;
+ struct timespec now;
- assert(b);
+ assert(e != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
- if (b->children[0] == NULL)
- return b;
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- byte = id[(b->depth * KAD_BETA) / CHAR_BIT];
+ v = dht_entry_get_lval(e, val);
+ if (v == NULL) {
+ log_dbg(KV_FMT " Adding lval.", KV_VAL(e->key, val));
+ v = val_entry_create(val, now.tv_sec + dht.t_expire);
+ if (v == NULL)
+ return -ENOMEM;
- mask = ((1L << KAD_BETA) - 1) & 0xFF;
+ list_add_tail(&v->next, &e->lvals.list);
+ ++e->lvals.len;
+ ++dht.db.kv.lvals;
- byte >>= (CHAR_BIT - KAD_BETA) -
- (((b->depth) * KAD_BETA) & (CHAR_BIT - 1));
+ return 0;
+ }
- return iter_bucket(b->children[(byte & mask)], id);
+ return 0;
}
-static struct bucket * dht_get_bucket(struct dht * dht,
- const uint8_t * id)
+static int dht_entry_remove_lval(struct dht_entry * e,
+ buffer_t val)
{
- assert(dht->buckets);
+ struct val_entry * v;
+
+ assert(e != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
+
+ v = dht_entry_get_lval(e, val);
+ if (v == NULL)
+ return -ENOENT;
+
+ log_dbg(KV_FMT " Removing lval.", KV_VAL(e->key, val));
+
+ list_del(&v->next);
+ val_entry_destroy(v);
+ --e->lvals.len;
+ --dht.db.kv.lvals;
- return iter_bucket(dht->buckets, id);
+ return 0;
}
-/*
- * If someone builds a network where the n (n > k) closest nodes all
- * have IDs starting with the same 64 bits: by all means, change this.
- */
-static uint64_t dist(const uint8_t * src,
- const uint8_t * dst)
+#define IS_EXPIRED(v, now) ((now)->tv_sec > (v)->t_exp)
+static void dht_entry_remove_expired_vals(struct dht_entry * e)
{
- return betoh64(*((uint64_t *) src) ^ *((uint64_t *) dst));
+ struct list_head * p;
+ struct list_head * h;
+ struct timespec now;
+
+ assert(e != NULL);
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ list_for_each_safe(p, h, &e->vals.list) {
+ struct val_entry * v = list_entry(p, struct val_entry, next);
+ if (!IS_EXPIRED(v, &now))
+ continue;
+
+ log_dbg(KV_FMT " Value expired." , KV_VAL(e->key, v->val));
+ list_del(&v->next);
+ val_entry_destroy(v);
+ --e->vals.len;
+ --dht.db.kv.vals;
+ }
}
-static size_t list_add_sorted(struct list_head * l,
- struct contact * c,
- const uint8_t * key)
+static struct dht_entry * __dht_kv_find_entry(const uint8_t * key)
{
struct list_head * p;
- assert(l);
- assert(c);
- assert(key);
- assert(c->id);
+ assert(key != NULL);
- list_for_each(p, l) {
- struct contact * e = list_entry(p, struct contact, next);
- if (dist(c->id, key) > dist(e->id, key))
- break;
+ list_for_each(p, &dht.db.kv.list) {
+ struct dht_entry * e = list_entry(p, struct dht_entry, next);
+ if (!memcmp(key, e->key, dht.id.len))
+ return e;
}
- list_add_tail(&c->next, p);
-
- return 1;
+ return NULL;
}
-static size_t dht_contact_list(struct dht * dht,
- struct list_head * l,
- const uint8_t * key)
+static void dht_kv_remove_expired_entries(void)
{
struct list_head * p;
- struct bucket * b;
- size_t len = 0;
- size_t i;
- struct timespec t;
+ struct list_head * h;
+ struct timespec now;
- assert(l);
- assert(dht);
- assert(key);
- assert(list_is_empty(l));
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- clock_gettime(CLOCK_REALTIME_COARSE, &t);
+ pthread_rwlock_wrlock(&dht.db.lock);
- b = dht_get_bucket(dht, key);
- if (b == NULL)
- return 0;
-
- b->t_refr = t.tv_sec + KAD_T_REFR;
+ list_for_each_safe(p, h, &dht.db.kv.list) {
+ struct dht_entry * e = list_entry(p, struct dht_entry, next);
+ dht_entry_remove_expired_vals(e);
+ if (e->lvals.len > 0 || e->vals.len > 0)
+ continue;
- if (b->n_contacts == dht->k || b->parent == NULL) {
- list_for_each(p, &b->contacts) {
- struct contact * c;
- c = list_entry(p, struct contact, next);
- c = contact_create(c->id, dht->b, c->addr);
- if (list_add_sorted(l, c, key) == 1)
- if (++len == dht->k)
- break;
- }
- } else {
- struct bucket * d = b->parent;
- for (i = 0; i < (1L << KAD_BETA) && len < dht->k; ++i) {
- list_for_each(p, &d->children[i]->contacts) {
- struct contact * c;
- c = list_entry(p, struct contact, next);
- c = contact_create(c->id, dht->b, c->addr);
- if (c == NULL)
- continue;
- if (list_add_sorted(l, c, key) == 1)
- if (++len == dht->k)
- break;
- }
- }
+ log_dbg(KEY_FMT " Entry removed. ", KEY_VAL(e->key));
+ list_del(&e->next);
+ dht_entry_destroy(e);
+ --dht.db.kv.len;
}
- assert(len == dht->k || b->parent == NULL);
-
- return len;
+ pthread_rwlock_unlock(&dht.db.lock);
}
-static struct lookup * lookup_create(struct dht * dht,
- const uint8_t * id)
+
+static struct contact * contact_create(const uint8_t * id,
+ uint64_t addr)
{
- struct lookup * lu;
- pthread_condattr_t cattr;
+ struct contact * c;
+ struct timespec t;
+
+ c = malloc(sizeof(*c));
+ if (c == NULL)
+ return NULL;
- assert(dht);
- assert(id);
+ list_head_init(&c->next);
- lu = malloc(sizeof(*lu));
- if (lu == NULL)
- goto fail_malloc;
+ clock_gettime(CLOCK_REALTIME_COARSE, &t);
- list_head_init(&lu->contacts);
- list_head_init(&lu->cookies);
+ c->addr = addr;
+ c->fails = 0;
+ c->t_seen = t.tv_sec;
+ c->id = dht_dup_key(id);
+ if (c->id == NULL) {
+ free(c);
+ return NULL;
+ }
- lu->state = LU_INIT;
- lu->addrs = NULL;
- lu->n_addrs = 0;
- lu->key = dht_dup_key(id, dht->b);
- if (lu->key == NULL)
- goto fail_id;
+ return c;
+}
- if (pthread_mutex_init(&lu->lock, NULL))
- goto fail_mutex;
+static void contact_destroy(struct contact * c)
+{
+ assert(c != NULL);
+ assert(list_is_empty(&c->next));
- pthread_condattr_init(&cattr);
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
+ free(c->id);
+ free(c);
+}
- if (pthread_cond_init(&lu->cond, &cattr))
- goto fail_cond;
+static struct dht_req * dht_req_create(const uint8_t * key)
+{
+ struct dht_req * req;
+ struct timespec now;
- pthread_condattr_destroy(&cattr);
+ assert(key != NULL);
- pthread_rwlock_wrlock(&dht->lock);
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
- list_add(&lu->next, &dht->lookups);
+ req = malloc(sizeof(*req));
+ if (req == NULL)
+ goto fail_malloc;
- lu->n_contacts = dht_contact_list(dht, &lu->contacts, id);
+ list_head_init(&req->next);
- pthread_rwlock_unlock(&dht->lock);
+ req->t_exp = now.tv_sec + DHT_T_RESP;
- return lu;
+ list_head_init(&req->peers.list);
+ req->peers.len = 0;
- fail_cond:
- pthread_condattr_destroy(&cattr);
- pthread_mutex_destroy(&lu->lock);
- fail_mutex:
- free(lu->key);
- fail_id:
- free(lu);
+ req->key = dht_dup_key(key);
+ if (req->key == NULL)
+ goto fail_dup_key;
+
+ list_head_init(&req->cache.list);
+ req->cache.len = 0;
+
+ return req;
+
+ fail_dup_key:
+ free(req);
fail_malloc:
return NULL;
}
-static void cancel_lookup_destroy(void * o)
+static void dht_req_destroy(struct dht_req * req)
{
- struct lookup * lu;
struct list_head * p;
struct list_head * h;
- lu = (struct lookup *) o;
-
- if (lu->key != NULL)
- free(lu->key);
- if (lu->addrs != NULL)
- free(lu->addrs);
+ assert(req);
+ assert(req->key);
- list_for_each_safe(p, h, &lu->contacts) {
- struct contact * c = list_entry(p, struct contact, next);
- list_del(&c->next);
- contact_destroy(c);
+ list_for_each_safe(p, h, &req->peers.list) {
+ struct peer_entry * e = list_entry(p, struct peer_entry, next);
+ list_del(&e->next);
+ free(e->id);
+ free(e);
+ --req->peers.len;
}
- list_for_each_safe(p, h, &lu->cookies) {
- struct cookie_el * c = list_entry(p, struct cookie_el, next);
- list_del(&c->next);
- free(c);
+ list_for_each_safe(p, h, &req->cache.list) {
+ struct val_entry * e = list_entry(p, struct val_entry, next);
+ list_del(&e->next);
+ val_entry_destroy(e);
+ --req->cache.len;
}
- pthread_mutex_unlock(&lu->lock);
+ free(req->key);
- pthread_mutex_destroy(&lu->lock);
+ assert(req->peers.len == 0);
- free(lu);
+ free(req);
}
-static void lookup_destroy(struct lookup * lu)
+static struct peer_entry * dht_req_get_peer(struct dht_req * req,
+ struct peer_entry * e)
{
- assert(lu);
-
- pthread_mutex_lock(&lu->lock);
+ struct list_head * p;
- switch (lu->state) {
- case LU_DESTROY:
- pthread_mutex_unlock(&lu->lock);
- return;
- case LU_PENDING:
- lu->state = LU_DESTROY;
- pthread_cond_broadcast(&lu->cond);
- break;
- case LU_INIT:
- case LU_UPDATE:
- case LU_COMPLETE:
- lu->state = LU_NULL;
- break;
- case LU_NULL:
- default:
- break;
+ list_for_each(p, &req->peers.list) {
+ struct peer_entry * x = list_entry(p, struct peer_entry, next);
+ if (x->addr == e->addr)
+ return x;
}
- pthread_cleanup_push(cancel_lookup_destroy, lu);
-
- while (lu->state != LU_NULL)
- pthread_cond_wait(&lu->cond, &lu->lock);
-
- pthread_cleanup_pop(true);
+ return NULL;
}
-static void lookup_update(struct dht * dht,
- struct lookup * lu,
- dht_msg_t * msg)
+#define IS_MAGIC(peer) ((peer)->cookie == dht.magic)
+void dht_req_add_peer(struct dht_req * req,
+ struct peer_entry * e)
{
- struct list_head * p = NULL;
- struct list_head * h;
- struct contact * c = NULL;
- size_t n;
- size_t pos = 0;
- bool mod = false;
+ struct peer_entry * x; /* existing */
+ struct list_head * p; /* iterator */
+ size_t pos = 0;
- assert(lu);
- assert(msg);
+ assert(req != NULL);
+ assert(e != NULL);
+ assert(e->id != NULL);
- if (dht_get_state(dht) != DHT_RUNNING)
- return;
-
- pthread_mutex_lock(&lu->lock);
+ /*
+ * Dedupe messages to the same peer, unless
+ * 1) The previous request was FIND_NODE and now it's FIND_VALUE
+ * 2) We urgently need contacts from emergency peer (magic cookie)
+ */
+ x = dht_req_get_peer(req, e);
+ if (x != NULL && x->code >= e->code && !IS_MAGIC(e))
+ goto skip;
- list_for_each_safe(p, h, &lu->cookies) {
- struct cookie_el * e = list_entry(p, struct cookie_el, next);
- if (e->cookie == msg->cookie) {
- list_del(&e->next);
- free(e);
- break;
+ /* Find how this contact ranks in distance to the key */
+ list_for_each(p, &req->peers.list) {
+ struct peer_entry * y = list_entry(p, struct peer_entry, next);
+ if (IS_CLOSER(y->id, e->id)) {
+ pos++;
+ continue;
}
+ break;
}
- if (lu->state == LU_COMPLETE) {
- pthread_mutex_unlock(&lu->lock);
- return;
- }
+ /* Add a new peer to this request if we need to */
+ if (pos < dht.alpha || !IS_MAGIC(e)) {
+ x = malloc(sizeof(*x));
+ if (x == NULL) {
+ log_err("Failed to malloc peer entry.");
+ goto skip;
+ }
- if (msg->n_addrs > 0) {
- if (lu->addrs == NULL) {
- lu->addrs = malloc(sizeof(*lu->addrs) * msg->n_addrs);
- for (n = 0; n < msg->n_addrs; ++n)
- lu->addrs[n] = msg->addrs[n];
- lu->n_addrs = msg->n_addrs;
+ x->cookie = e->cookie;
+ x->addr = e->addr;
+ x->code = e->code;
+ x->t_sent = e->t_sent;
+ x->id = dht_dup_key(e->id);
+ if (x->id == NULL) {
+ log_err("Failed to dup peer ID.");
+ free(x);
+ goto skip;
}
- lu->state = LU_COMPLETE;
- pthread_cond_broadcast(&lu->cond);
- pthread_mutex_unlock(&lu->lock);
+ if (IS_MAGIC(e))
+ list_add(&x->next, p);
+ else
+ list_add_tail(&x->next, p);
+ ++req->peers.len;
return;
}
+ skip:
+ list_del(&e->next);
+ free(e->id);
+ free(e);
+}
+
+static size_t dht_req_add_peers(struct dht_req * req,
+ struct list_head * pl)
+{
+ struct list_head * p;
+ struct list_head * h;
+ size_t n = 0;
- pthread_cleanup_push(__cleanup_mutex_unlock, &lu->lock);
+ assert(req != NULL);
+ assert(pl != NULL);
- while (lu->state == LU_INIT) {
- pthread_rwlock_unlock(&dht->lock);
- pthread_cond_wait(&lu->cond, &lu->lock);
- pthread_rwlock_rdlock(&dht->lock);
+ list_for_each_safe(p, h, pl) {
+ struct peer_entry * e = list_entry(p, struct peer_entry, next);
+ dht_req_add_peer(req, e);
}
- pthread_cleanup_pop(false);
+ return n;
+}
- for (n = 0; n < msg->n_contacts; ++n) {
- c = contact_create(msg->contacts[n]->id.data,
- dht->b, msg->contacts[n]->addr);
- if (c == NULL)
- continue;
+static bool dht_req_has_peer(struct dht_req * req,
+ uint64_t cookie)
+{
+ struct list_head * p;
- pos = 0;
+ assert(req != NULL);
- list_for_each(p, &lu->contacts) {
- struct contact * e;
- e = list_entry(p, struct contact, next);
- if (!memcmp(e->id, c->id, dht->b)) {
- contact_destroy(c);
- c = NULL;
- break;
- }
+ list_for_each(p, &req->peers.list) {
+ struct peer_entry * e = list_entry(p, struct peer_entry, next);
+ if (e->cookie == cookie)
+ return true;
+ }
- if (dist(c->id, lu->key) > dist(e->id, lu->key))
- break;
+ return false;
+}
- pos++;
- }
+static void peer_list_destroy(struct list_head * pl)
+{
+ struct list_head * p;
+ struct list_head * h;
- if (c == NULL)
- continue;
+ assert(pl != NULL);
- if (lu->n_contacts < dht->k) {
- list_add_tail(&c->next, p);
- ++lu->n_contacts;
- mod = true;
- } else if (pos == dht->k) {
- contact_destroy(c);
- } else {
- struct contact * d;
- list_add_tail(&c->next, p);
- d = list_last_entry(&lu->contacts,
- struct contact, next);
- list_del(&d->next);
- assert(lu->contacts.prv != &d->next);
- contact_destroy(d);
- mod = true;
- }
+ list_for_each_safe(p, h, pl) {
+ struct peer_entry * e = list_entry(p, struct peer_entry, next);
+ list_del(&e->next);
+ free(e->id);
+ free(e);
}
-
- if (list_is_empty(&lu->cookies) && !mod)
- lu->state = LU_COMPLETE;
- else
- lu->state = LU_UPDATE;
-
- pthread_cond_broadcast(&lu->cond);
- pthread_mutex_unlock(&lu->lock);
- return;
}
-static ssize_t lookup_get_addrs(struct lookup * lu,
- uint64_t * addrs)
+static int dht_kv_create_peer_list(struct list_head * cl,
+ struct list_head * pl,
+ enum dht_code code)
{
- ssize_t n;
+ struct list_head * p;
+ struct list_head * h;
+ struct timespec now;
+ size_t len;
- assert(lu);
+ assert(cl != NULL);
+ assert(pl != NULL);
+ assert(list_is_empty(pl));
- pthread_mutex_lock(&lu->lock);
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- for (n = 0; (size_t) n < lu->n_addrs; ++n)
- addrs[n] = lu->addrs[n];
+ len = 0;
- assert((size_t) n == lu->n_addrs);
+ list_for_each_safe(p, h, cl) {
+ struct contact * c = list_entry(p, struct contact, next);
+ struct peer_entry * e;
+ if (len++ == dht.alpha)
+ break;
- pthread_mutex_unlock(&lu->lock);
+ e = malloc(sizeof(*e));
+ if (e == NULL)
+ return -ENOMEM;
- return n;
-}
+ e->cookie = generate_cookie();
+ e->code = code;
+ e->addr = c->addr;
+ e->t_sent = now.tv_sec;
-static ssize_t lookup_contact_addrs(struct lookup * lu,
- uint64_t * addrs)
-{
- struct list_head * p;
- ssize_t n = 0;
-
- assert(lu);
- assert(addrs);
+ e->id = c->id;
- pthread_mutex_lock(&lu->lock);
+ list_add_tail(&e->next, pl);
- list_for_each(p, &lu->contacts) {
- struct contact * c = list_entry(p, struct contact, next);
- addrs[n] = c->addr;
- n++;
+ list_del(&c->next);
+ c->id = NULL; /* we stole the id */
+ contact_destroy(c);
}
- pthread_mutex_unlock(&lu->lock);
-
- return n;
+ return 0;
}
-static void lookup_new_addrs(struct lookup * lu,
- uint64_t * addrs)
+static struct dht_req * __dht_kv_req_get_req(const uint8_t * key)
{
struct list_head * p;
- size_t n = 0;
- assert(lu);
- assert(addrs);
+ list_for_each(p, &dht.reqs.list) {
+ struct dht_req * r = list_entry(p, struct dht_req, next);
+ if (memcmp(r->key, key, dht.id.len) == 0)
+ return r;
+ }
- pthread_mutex_lock(&lu->lock);
+ return NULL;
+}
- /* Uses fails to check if the contact has been contacted. */
- list_for_each(p, &lu->contacts) {
- struct contact * c = list_entry(p, struct contact, next);
- if (c->fails == 0) {
- c->fails = 1;
- addrs[n] = c->addr;
- n++;
- }
+static struct dht_req * __dht_kv_get_req_cache(const uint8_t * key)
+{
+ struct dht_req * req;
- if (n == KAD_ALPHA)
- break;
- }
+ assert(key != NULL);
- assert(n <= KAD_ALPHA);
+ req = __dht_kv_req_get_req(key);
+ if (req == NULL)
+ return NULL;
- addrs[n] = 0;
+ if (req->cache.len == 0)
+ return NULL;
- pthread_mutex_unlock(&lu->lock);
+ return req;
}
-static void lookup_set_state(struct lookup * lu,
- enum lookup_state state)
+static void __dht_kv_req_remove(const uint8_t * key)
{
- pthread_mutex_lock(&lu->lock);
+ struct dht_req * req;
- lu->state = state;
- pthread_cond_broadcast(&lu->cond);
+ assert(key != NULL);
- pthread_mutex_unlock(&lu->lock);
-}
+ req = __dht_kv_req_get_req(key);
+ if (req == NULL)
+ return;
-static void cancel_lookup_wait(void * o)
-{
- struct lookup * lu = (struct lookup *) o;
- lu->state = LU_NULL;
- pthread_mutex_unlock(&lu->lock);
- lookup_destroy(lu);
+ list_del(&req->next);
+ --dht.reqs.len;
+
+ dht_req_destroy(req);
}
-static enum lookup_state lookup_wait(struct lookup * lu)
+static struct dht_req * __dht_kv_get_req_peer(const uint8_t * key,
+ uint64_t cookie)
{
- struct timespec timeo = TIMESPEC_INIT_S(KAD_T_RESP);
- struct timespec abs;
- enum lookup_state state;
- int ret = 0;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abs);
+ struct dht_req * req;
- ts_add(&abs, &timeo, &abs);
+ assert(key != NULL);
- pthread_mutex_lock(&lu->lock);
-
- if (lu->state == LU_INIT || lu->state == LU_UPDATE)
- lu->state = LU_PENDING;
+ req = __dht_kv_req_get_req(key);
+ if (req == NULL)
+ return NULL;
- pthread_cleanup_push(cancel_lookup_wait, lu);
+ if (!dht_req_has_peer(req, cookie))
+ return NULL;
- while (lu->state == LU_PENDING && ret != -ETIMEDOUT)
- ret = -pthread_cond_timedwait(&lu->cond, &lu->lock, &abs);
+ return req;
+}
- pthread_cleanup_pop(false);
+static bool dht_kv_has_req(const uint8_t * key,
+ uint64_t cookie)
+{
+ bool found;
- if (ret == -ETIMEDOUT)
- lu->state = LU_COMPLETE;
+ pthread_mutex_lock(&dht.reqs.mtx);
- state = lu->state;
+ found = __dht_kv_get_req_peer(key, cookie) != NULL;
- pthread_mutex_unlock(&lu->lock);
+ pthread_mutex_unlock(&dht.reqs.mtx);
- return state;
+ return found;
}
-static struct kad_req * dht_find_request(struct dht * dht,
- dht_msg_t * msg)
+/*
+ * This will filter the peer list for addresses that still need to be
+ * contacted.
+ */
+static int dht_kv_update_req(const uint8_t * key,
+ struct list_head * pl)
{
- struct list_head * p;
+ struct dht_req * req;
+ struct timespec now;
- assert(dht);
- assert(msg);
+ assert(key != NULL);
+ assert(pl != NULL);
+ assert(!list_is_empty(pl));
- list_for_each(p, &dht->requests) {
- struct kad_req * r = list_entry(p, struct kad_req, next);
- if (r->cookie == msg->cookie)
- return r;
- }
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
- return NULL;
-}
+ pthread_mutex_lock(&dht.reqs.mtx);
-static struct lookup * dht_find_lookup(struct dht * dht,
- uint32_t cookie)
-{
- struct list_head * p;
- struct list_head * p2;
- struct list_head * h2;
-
- assert(dht);
- assert(cookie > 0);
-
- list_for_each(p, &dht->lookups) {
- struct lookup * l = list_entry(p, struct lookup, next);
- pthread_mutex_lock(&l->lock);
- list_for_each_safe(p2, h2, &l->cookies) {
- struct cookie_el * e;
- e = list_entry(p2, struct cookie_el, next);
- if (e->cookie == cookie) {
- list_del(&e->next);
- free(e);
- pthread_mutex_unlock(&l->lock);
- return l;
- }
+ req = __dht_kv_req_get_req(key);
+ if (req == NULL) {
+ if (dht.reqs.len == DHT_MAX_REQS) {
+ log_err(KEY_FMT " Max reqs reached (%zu).",
+ KEY_VAL(key), dht.reqs.len);
+ peer_list_destroy(pl);
+ goto fail_req;
}
- pthread_mutex_unlock(&l->lock);
+ req = dht_req_create(key);
+ if (req == NULL) {
+ log_err(KEY_FMT "Failed to create req.", KEY_VAL(key));
+ goto fail_req;
+ }
+ list_add_tail(&req->next, &dht.reqs.list);
+ ++dht.reqs.len;
}
- return NULL;
+ if (req->cache.len > 0) /* Already have values */
+ peer_list_destroy(pl);
+
+ dht_req_add_peers(req, pl);
+ req->t_exp = now.tv_sec + DHT_T_RESP;
+
+ if (dht.reqs.len > DHT_WARN_REQS) {
+ log_warn("Number of outstanding requests (%zu) exceeds %u.",
+ dht.reqs.len, DHT_WARN_REQS);
+ }
+
+ pthread_mutex_unlock(&dht.reqs.mtx);
+
+ return 0;
+ fail_req:
+ pthread_mutex_unlock(&dht.reqs.mtx);
+ return -1;
}
-static struct val * val_create(uint64_t addr,
- time_t exp)
+static int dht_kv_respond_req(uint8_t * key,
+ binary_data_t * vals,
+ size_t len)
{
- struct val * v;
- struct timespec t;
+ struct dht_req * req;
+ struct timespec now;
+ size_t i;
- v = malloc(sizeof(*v));
- if (v == NULL)
- return NULL;
+ assert(key != NULL);
+ assert(vals != NULL);
+ assert(len > 0);
- list_head_init(&v->next);
- v->addr = addr;
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- clock_gettime(CLOCK_REALTIME_COARSE, &t);
+ pthread_mutex_lock(&dht.reqs.mtx);
+
+ req = __dht_kv_req_get_req(key);
+ if (req == NULL) {
+ log_dbg(KEY_FMT " Failed to find req.", KEY_VAL(key));
+ goto fail_req;
+ }
+
+ for (i = 0; i < len; ++i) {
+ struct val_entry * e;
+ buffer_t val;
+ val.data = vals[i].data;
+ val.len = vals[i].len;
+ e = val_entry_create(val, now.tv_sec + DHT_T_CACHE);
+ if (e == NULL) {
+ log_err(" Failed to create val_entry.");
+ continue;
+ }
- v->t_exp = t.tv_sec + exp;
- v->t_rep = t.tv_sec + KAD_T_REPL;
+ list_add_tail(&e->next, &req->cache.list);
+ ++req->cache.len;
+ }
- return v;
-}
+ pthread_cond_broadcast(&dht.reqs.cond);
-static void val_destroy(struct val * v)
-{
- assert(v);
+ pthread_mutex_unlock(&dht.reqs.mtx);
- free(v);
+ return 0;
+ fail_req:
+ pthread_mutex_unlock(&dht.reqs.mtx);
+ return -1;
}
-static struct ref_entry * ref_entry_create(struct dht * dht,
- const uint8_t * key)
+static ssize_t dht_kv_wait_req(const uint8_t * key,
+ buffer_t ** vals)
{
- struct ref_entry * e;
+ struct list_head * p;
+ struct dht_req * req;
struct timespec t;
+#ifdef __DHT_TEST__
+ struct timespec intv = TIMESPEC_INIT_MS(10);
+#else
+ struct timespec intv = TIMESPEC_INIT_S(DHT_T_RESP);
+#endif
+ size_t max;
+ size_t i = 0;
+ int ret = 0;
- assert(dht);
- assert(key);
+ assert(key != NULL);
+ assert(vals != NULL);
- e = malloc(sizeof(*e));
- if (e == NULL)
- return NULL;
+ clock_gettime(PTHREAD_COND_CLOCK, &t);
- e->key = dht_dup_key(key, dht->b);
- if (e->key == NULL) {
- free(e);
- return NULL;
+ ts_add(&t, &intv, &t);
+
+ pthread_mutex_lock(&dht.reqs.mtx);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &dht.reqs.mtx);
+
+ while ((req = __dht_kv_get_req_cache(key)) == NULL) {
+ ret = pthread_cond_timedwait(&dht.reqs.cond, &dht.reqs.mtx, &t);
+ if (ret == ETIMEDOUT)
+ break;
}
- clock_gettime(CLOCK_REALTIME_COARSE, &t);
+ pthread_cleanup_pop(false);
- e->t_rep = t.tv_sec + dht->t_repub;
+ if (ret == ETIMEDOUT) {
+ log_warn(KEY_FMT " Req timed out.", KEY_VAL(key));
+ __dht_kv_req_remove(key);
+ goto timedout;
+ }
- return e;
-}
+ max = MIN(req->cache.len, DHT_MAX_VALS);
+ if (max == 0)
+ goto no_vals;
-static void ref_entry_destroy(struct ref_entry * e)
-{
- free(e->key);
- free(e);
+ *vals = malloc(max * sizeof(**vals));
+ if (*vals == NULL) {
+ log_err(KEY_FMT "Failed to malloc val buffer.", KEY_VAL(key));
+ goto fail_vals;
+ }
+
+ memset(*vals, 0, max * sizeof(**vals));
+
+ list_for_each(p, &req->cache.list) {
+ struct val_entry * v;
+ if (i == max)
+ break; /* We have enough values */
+ v = list_entry(p, struct val_entry, next);
+ (*vals)[i].data = malloc(v->val.len);
+ if ((*vals)[i].data == NULL)
+ goto fail_val_data;
+
+ (*vals)[i].len = v->val.len;
+ memcpy((*vals)[i++].data, v->val.data, v->val.len);
+ }
+
+ pthread_mutex_unlock(&dht.reqs.mtx);
+
+ return i;
+ no_vals:
+ pthread_mutex_unlock(&dht.reqs.mtx);
+ *vals = NULL;
+ return 0;
+ fail_val_data:
+ freebufs(*vals, i);
+ fail_vals:
+ pthread_mutex_unlock(&dht.reqs.mtx);
+ return -ENOMEM;
+ timedout:
+ pthread_mutex_unlock(&dht.reqs.mtx);
+ return -ETIMEDOUT;
}
-static struct dht_entry * dht_entry_create(struct dht * dht,
- const uint8_t * key)
+static struct bucket * iter_bucket(struct bucket * b,
+ const uint8_t * id)
{
- struct dht_entry * e;
+ uint8_t byte;
+ uint8_t mask;
- assert(dht);
- assert(key);
+ assert(b != NULL);
- e = malloc(sizeof(*e));
- if (e == NULL)
- return NULL;
+ if (b->children[0] == NULL)
+ return b;
- list_head_init(&e->next);
- list_head_init(&e->vals);
+ byte = id[(b->depth * DHT_BETA) / CHAR_BIT];
- e->n_vals = 0;
+ mask = ((1L << DHT_BETA) - 1) & 0xFF;
- e->key = dht_dup_key(key, dht->b);
- if (e->key == NULL) {
- free(e);
- return NULL;
- }
+ byte >>= (CHAR_BIT - DHT_BETA) -
+ (((b->depth) * DHT_BETA) & (CHAR_BIT - 1));
- return e;
+ return iter_bucket(b->children[(byte & mask)], id);
}
-static void dht_entry_destroy(struct dht_entry * e)
+static struct bucket * __dht_kv_get_bucket(const uint8_t * id)
+{
+ assert(dht.db.contacts.root != NULL);
+
+ return iter_bucket(dht.db.contacts.root, id);
+}
+
+static void contact_list_add(struct list_head * l,
+ struct contact * c)
{
struct list_head * p;
- struct list_head * h;
- assert(e);
+ assert(l != NULL);
+ assert(c != NULL);
- list_for_each_safe(p, h, &e->vals) {
- struct val * v = list_entry(p, struct val, next);
- list_del(&v->next);
- val_destroy(v);
+ list_for_each(p, l) {
+ struct contact * e = list_entry(p, struct contact, next);
+ if (IS_CLOSER(e->id, c->id))
+ continue;
}
- free(e->key);
-
- free(e);
+ list_add_tail(&c->next, p);
}
-static int dht_entry_add_addr(struct dht_entry * e,
- uint64_t addr,
- time_t exp)
+static ssize_t dht_kv_contact_list(const uint8_t * key,
+ struct list_head * l,
+ size_t max)
{
struct list_head * p;
- struct val * val;
- struct timespec t;
+ struct bucket * b;
+ struct timespec t;
+ size_t i;
+ size_t len = 0;
+
+ assert(l != NULL);
+ assert(key != NULL);
+ assert(list_is_empty(l));
clock_gettime(CLOCK_REALTIME_COARSE, &t);
- list_for_each(p, &e->vals) {
- struct val * v = list_entry(p, struct val, next);
- if (v->addr == addr) {
- if (v->t_exp < t.tv_sec + exp) {
- v->t_exp = t.tv_sec + exp;
- v->t_rep = t.tv_sec + KAD_T_REPL;
- }
+ max = MIN(max, dht.k);
- return 0;
- }
+ pthread_rwlock_rdlock(&dht.db.lock);
+
+ b = __dht_kv_get_bucket(key);
+ if (b == NULL) {
+ log_err(KEY_FMT " Failed to get bucket.", KEY_VAL(key));
+ goto fail_bucket;
}
- val = val_create(addr, exp);
- if (val == NULL)
- return -ENOMEM;
+ b->t_refr = t.tv_sec + dht.t_refresh;
- list_add(&val->next, &e->vals);
- ++e->n_vals;
+ if (b->contacts.len == dht.k || b->parent == NULL) {
+ list_for_each(p, &b->contacts.list) {
+ struct contact * c;
+ struct contact * d;
+ c = list_entry(p, struct contact, next);
+ if (c->addr == dht.addr)
+ continue;
+ d = contact_create(c->id, c->addr);
+ if (d == NULL)
+ continue;
+ contact_list_add(l, d);
+ if (++len == max)
+ break;
+ }
+ } else {
+ struct bucket * d = b->parent;
+ for (i = 0; i < (1L << DHT_BETA) && len < dht.k; ++i) {
+ list_for_each(p, &d->children[i]->contacts.list) {
+ struct contact * c;
+ struct contact * d;
+ c = list_entry(p, struct contact, next);
+ if (c->addr == dht.addr)
+ continue;
+ d = contact_create(c->id, c->addr);
+ if (d == NULL)
+ continue;
+ contact_list_add(l, d);
+ if (++len == max)
+ break;
+ }
+ }
+ }
- return 0;
-}
+ pthread_rwlock_unlock(&dht.db.lock);
+ return len;
+ fail_bucket:
+ pthread_rwlock_unlock(&dht.db.lock);
+ return -1;
+}
-static void dht_entry_del_addr(struct dht_entry * e,
- uint64_t addr)
+static void contact_list_destroy(struct list_head * l)
{
struct list_head * p;
struct list_head * h;
- assert(e);
-
- list_for_each_safe(p, h, &e->vals) {
- struct val * v = list_entry(p, struct val, next);
- if (v->addr == addr) {
- list_del(&v->next);
- val_destroy(v);
- --e->n_vals;
- }
- }
+ assert(l != NULL);
- if (e->n_vals == 0) {
- list_del(&e->next);
- dht_entry_destroy(e);
+ list_for_each_safe(p, h, l) {
+ struct contact * c = list_entry(p, struct contact, next);
+ list_del(&c->next);
+ contact_destroy(c);
}
}
-static uint64_t dht_entry_get_addr(struct dht * dht,
- struct dht_entry * e)
+static ssize_t dht_kv_get_contacts(const uint8_t * key,
+ dht_contact_msg_t *** msgs)
{
+ struct list_head cl;
struct list_head * p;
+ struct list_head * h;
+ size_t len;
+ size_t i = 0;
- assert(e);
- assert(!list_is_empty(&e->vals));
+ assert(key != NULL);
+ assert(msgs != NULL);
- list_for_each(p, &e->vals) {
- struct val * v = list_entry(p, struct val, next);
- if (v->addr != dht->addr)
- return v->addr;
+ list_head_init(&cl);
+
+ len = dht_kv_contact_list(key, &cl, dht.k);
+ if (len == 0) {
+ *msgs = NULL;
+ return 0;
}
- return 0;
-}
+ *msgs = malloc(len * sizeof(**msgs));
+ if (*msgs == NULL)
+ goto fail_msgs;
-/* Forward declaration. */
-static struct lookup * kad_lookup(struct dht * dht,
- const uint8_t * key,
- enum kad_code code);
+ list_for_each_safe(p, h, &cl) {
+ struct contact * c;
+ (*msgs)[i] = malloc(sizeof(***msgs));
+ if ((*msgs)[i] == NULL)
+ goto fail_contact;
+ dht_contact_msg__init((*msgs)[i]);
+ c = list_entry(p, struct contact, next);
+ list_del(&c->next);
+ (*msgs)[i]->id.data = c->id;
+ (*msgs)[i]->id.len = dht.id.len;
+ (*msgs)[i++]->addr = c->addr;
+ free(c);
+ }
+
+ return i;
+ fail_contact:
+ while (i-- > 0)
+ dht_contact_msg__free_unpacked((*msgs)[i], NULL);
+ free(*msgs);
+ *msgs = NULL;
+ fail_msgs:
+ contact_list_destroy(&cl);
+ return -ENOMEM;
+}
/* Build a refresh list. */
-static void bucket_refresh(struct dht * dht,
- struct bucket * b,
- time_t t,
- struct list_head * r)
+static void __dht_kv_bucket_refresh_list(struct bucket * b,
+ time_t t,
+ struct list_head * r)
{
- size_t i;
+ struct contact * c;
+ struct contact * d;
- if (*b->children != NULL)
- for (i = 0; i < (1L << KAD_BETA); ++i)
- bucket_refresh(dht, b->children[i], t, r);
+ assert(b != NULL);
- if (b->n_contacts == 0)
+ if (t < b->t_refr)
return;
- if (t > b->t_refr) {
- struct contact * c;
- struct contact * d;
- c = list_first_entry(&b->contacts, struct contact, next);
- d = contact_create(c->id, dht->b, c->addr);
+ if (*b->children != NULL) {
+ size_t i;
+ for (i = 0; i < (1L << DHT_BETA); ++i)
+ __dht_kv_bucket_refresh_list(b->children[i], t, r);
+ }
+
+ if (b->contacts.len == 0)
+ return;
+
+ c = list_first_entry(&b->contacts.list, struct contact, next);
+ if (t > c->t_seen + dht.t_refresh) {
+ d = contact_create(c->id, c->addr);
if (d != NULL)
list_add(&d->next, r);
- return;
}
}
-
static struct bucket * bucket_create(void)
{
struct bucket * b;
@@ -1294,20 +1682,21 @@ static struct bucket * bucket_create(void)
if (b == NULL)
return NULL;
- list_head_init(&b->contacts);
- b->n_contacts = 0;
+ list_head_init(&b->contacts.list);
+ b->contacts.len = 0;
- list_head_init(&b->alts);
- b->n_alts = 0;
+ list_head_init(&b->alts.list);
+ b->alts.len = 0;
clock_gettime(CLOCK_REALTIME_COARSE, &t);
- b->t_refr = t.tv_sec + KAD_T_REFR;
+ b->t_refr = t.tv_sec + dht.t_refresh;
- for (i = 0; i < (1L << KAD_BETA); ++i)
+ for (i = 0; i < (1L << DHT_BETA); ++i)
b->children[i] = NULL;
b->parent = NULL;
b->depth = 0;
+ b->mask = 0;
return b;
}
@@ -1318,24 +1707,24 @@ static void bucket_destroy(struct bucket * b)
struct list_head * h;
size_t i;
- assert(b);
+ assert(b != NULL);
- for (i = 0; i < (1L << KAD_BETA); ++i)
+ for (i = 0; i < (1L << DHT_BETA); ++i)
if (b->children[i] != NULL)
bucket_destroy(b->children[i]);
- list_for_each_safe(p, h, &b->contacts) {
+ list_for_each_safe(p, h, &b->contacts.list) {
struct contact * c = list_entry(p, struct contact, next);
list_del(&c->next);
contact_destroy(c);
- --b->n_contacts;
+ --b->contacts.len;
}
- list_for_each_safe(p, h, &b->alts) {
+ list_for_each_safe(p, h, &b->alts.list) {
struct contact * c = list_entry(p, struct contact, next);
list_del(&c->next);
contact_destroy(c);
- --b->n_contacts;
+ --b->alts.len;
}
free(b);
@@ -1350,1534 +1739,2314 @@ static bool bucket_has_id(struct bucket * b,
if (b->depth == 0)
return true;
- byte = id[(b->depth * KAD_BETA) / CHAR_BIT];
+ byte = id[(b->depth * DHT_BETA) / CHAR_BIT];
- mask = ((1L << KAD_BETA) - 1) & 0xFF;
+ mask = ((1L << DHT_BETA) - 1) & 0xFF;
- byte >>= (CHAR_BIT - KAD_BETA) -
- (((b->depth - 1) * KAD_BETA) & (CHAR_BIT - 1));
+ byte >>= (CHAR_BIT - DHT_BETA) -
+ (((b->depth - 1) * DHT_BETA) & (CHAR_BIT - 1));
return ((byte & mask) == b->mask);
}
-static int split_bucket(struct bucket * b)
+static int move_contacts(struct bucket * b,
+ struct bucket * c)
{
struct list_head * p;
struct list_head * h;
+ struct contact * d;
+
+ assert(b != NULL);
+ assert(c != NULL);
+
+ list_for_each_safe(p, h, &b->contacts.list) {
+ d = list_entry(p, struct contact, next);
+ if (bucket_has_id(c, d->id)) {
+ list_del(&d->next);
+ --b->contacts.len;
+ list_add_tail(&d->next, &c->contacts.list);
+ ++c->contacts.len;
+ }
+ }
+
+ return 0;
+}
+
+static int split_bucket(struct bucket * b)
+{
uint8_t mask = 0;
size_t i;
- size_t c;
+ size_t b_len;
assert(b);
- assert(b->n_alts == 0);
- assert(b->n_contacts);
+ assert(b->alts.len == 0);
+ assert(b->contacts.len != 0);
assert(b->children[0] == NULL);
- c = b->n_contacts;
+ b_len = b->contacts.len;
- for (i = 0; i < (1L << KAD_BETA); ++i) {
+ for (i = 0; i < (1L << DHT_BETA); ++i) {
b->children[i] = bucket_create();
- if (b->children[i] == NULL) {
- size_t j;
- for (j = 0; j < i; ++j)
- bucket_destroy(b->children[j]);
- return -1;
- }
+ if (b->children[i] == NULL)
+ goto fail_child;
b->children[i]->depth = b->depth + 1;
b->children[i]->mask = mask;
b->children[i]->parent = b;
- list_for_each_safe(p, h, &b->contacts) {
- struct contact * c;
- c = list_entry(p, struct contact, next);
- if (bucket_has_id(b->children[i], c->id)) {
- list_del(&c->next);
- --b->n_contacts;
- list_add(&c->next, &b->children[i]->contacts);
- ++b->children[i]->n_contacts;
- }
- }
+ move_contacts(b, b->children[i]);
mask++;
}
- for (i = 0; i < (1L << KAD_BETA); ++i)
- if (b->children[i]->n_contacts == c)
+ for (i = 0; i < (1L << DHT_BETA); ++i)
+ if (b->children[i]->contacts.len == b_len)
split_bucket(b->children[i]);
return 0;
+ fail_child:
+ while (i-- > 0)
+ bucket_destroy(b->children[i]);
+ return -1;
}
-/* Locked externally to mandate update as (final) part of join transaction. */
-static int dht_update_bucket(struct dht * dht,
- const uint8_t * id,
- uint64_t addr)
+static int dht_kv_update_contacts(const uint8_t * id,
+ uint64_t addr)
{
struct list_head * p;
struct list_head * h;
struct bucket * b;
struct contact * c;
- assert(dht);
+ assert(id != NULL);
+ assert(addr != INVALID_ADDR);
- b = dht_get_bucket(dht, id);
- if (b == NULL)
- return -1;
+ pthread_rwlock_wrlock(&dht.db.lock);
- c = contact_create(id, dht->b, addr);
- if (c == NULL)
- return -1;
+ b = __dht_kv_get_bucket(id);
+ if (b == NULL) {
+ log_err(PEER_FMT " Failed to get bucket.", PEER_VAL(id, addr));
+ goto fail_update;
+ }
- list_for_each_safe(p, h, &b->contacts) {
+ c = contact_create(id, addr);
+ if (c == NULL) {
+ log_err(PEER_FMT " Failed to create contact.",
+ PEER_VAL(id, addr));
+ goto fail_update;
+ }
+
+ list_for_each_safe(p, h, &b->contacts.list) {
struct contact * d = list_entry(p, struct contact, next);
if (d->addr == addr) {
list_del(&d->next);
contact_destroy(d);
- --b->n_contacts;
+ --b->contacts.len;
}
}
- if (b->n_contacts == dht->k) {
- if (bucket_has_id(b, dht->id)) {
- list_add_tail(&c->next, &b->contacts);
- ++b->n_contacts;
+ if (b->contacts.len == dht.k) {
+ if (bucket_has_id(b, dht.id.data)) {
+ list_add_tail(&c->next, &b->contacts.list);
+ ++b->contacts.len;
if (split_bucket(b)) {
list_del(&c->next);
contact_destroy(c);
- --b->n_contacts;
+ --b->contacts.len;
}
- } else if (b->n_alts == dht->k) {
+ } else if (b->alts.len == dht.k) {
struct contact * d;
- d = list_first_entry(&b->alts, struct contact, next);
+ d = list_first_entry(&b->alts.list,
+ struct contact, next);
list_del(&d->next);
contact_destroy(d);
- list_add_tail(&c->next, &b->alts);
+ list_add_tail(&c->next, &b->alts.list);
+ ++b->alts.len;
} else {
- list_add_tail(&c->next, &b->alts);
- ++b->n_alts;
+ list_add_tail(&c->next, &b->alts.list);
+ ++b->alts.len;
}
} else {
- list_add_tail(&c->next, &b->contacts);
- ++b->n_contacts;
+ list_add_tail(&c->next, &b->contacts.list);
+ ++b->contacts.len;
}
+ pthread_rwlock_unlock(&dht.db.lock);
+
return 0;
+ fail_update:
+ pthread_rwlock_unlock(&dht.db.lock);
+ return -1;
}
-static int send_msg(struct dht * dht,
- dht_msg_t * msg,
- uint64_t addr)
+static time_t gcd(time_t a,
+ time_t b)
{
-#ifndef __DHT_TEST__
- struct shm_du_buff * sdb;
- size_t len;
-#endif
- int retr = 0;
+ if (a == 0)
+ return b;
- if (msg->code == KAD_RESPONSE)
- retr = KAD_RESP_RETR;
+ return gcd(b % a, a);
+}
- pthread_rwlock_wrlock(&dht->lock);
+static dht_contact_msg_t * dht_kv_src_contact_msg(void)
+{
+ dht_contact_msg_t * src;
- if (dht->id != NULL) {
- msg->has_s_id = true;
- msg->s_id.data = dht->id;
- msg->s_id.len = dht->b;
- }
+ src = malloc(sizeof(*src));
+ if (src == NULL)
+ goto fail_malloc;
- msg->s_addr = dht->addr;
+ dht_contact_msg__init(src);
- if (msg->code < KAD_STORE) {
- msg->cookie = bmp_allocate(dht->cookies);
- if (!bmp_is_id_valid(dht->cookies, msg->cookie)) {
- pthread_rwlock_unlock(&dht->lock);
- goto fail_bmp_alloc;
- }
- }
+ src->id.data = dht_dup_key(dht.id.data);
+ if (src->id.data == NULL)
+ goto fail_id;
- pthread_rwlock_unlock(&dht->lock);
+ src->id.len = dht.id.len;
+ src->addr = dht.addr;
-#ifndef __DHT_TEST__
- len = dht_msg__get_packed_size(msg);
- if (len == 0)
- goto fail_msg;
+ return src;
+ fail_id:
+ dht_contact_msg__free_unpacked(src, NULL);
+ fail_malloc:
+ return NULL;
+}
- while (true) {
- if (ipcp_sdb_reserve(&sdb, len))
- goto fail_msg;
+static dht_msg_t * dht_kv_find_req_msg(const uint8_t * key,
+ enum dht_code code)
+{
+ dht_msg_t * msg;
- dht_msg__pack(msg, shm_du_buff_head(sdb));
+ assert(key != NULL);
- if (dt_write_packet(addr, QOS_CUBE_BE, dht->eid, sdb) == 0)
- break;
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
- ipcp_sdb_release(sdb);
+ dht_msg__init(msg);
+ msg->code = code;
- sleep(1);
+ msg->src = dht_kv_src_contact_msg();
+ if (msg->src == NULL)
+ goto fail_msg;
- if (--retr < 0)
- goto fail_msg;
- }
+ msg->find = malloc(sizeof(*msg->find));
+ if (msg->find == NULL)
+ goto fail_msg;
-#else
- (void) addr;
- (void) retr;
-#endif /* __DHT_TEST__ */
+ dht_find_req_msg__init(msg->find);
+
+ msg->find->key.data = dht_dup_key(key);
+ if (msg->find->key.data == NULL)
+ goto fail_msg;
- if (msg->code < KAD_STORE && dht_get_state(dht) != DHT_SHUTDOWN)
- kad_req_create(dht, msg, addr);
+ msg->find->key.len = dht.id.len;
+ msg->find->cookie = DHT_INVALID;
+
+ return msg;
- return msg->cookie;
-#ifndef __DHT_TEST__
fail_msg:
- pthread_rwlock_wrlock(&dht->lock);
- bmp_release(dht->cookies, msg->cookie);
- pthread_rwlock_unlock(&dht->lock);
-#endif /* !__DHT_TEST__ */
- fail_bmp_alloc:
- return -1;
+ dht_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
}
-static struct dht_entry * dht_find_entry(struct dht * dht,
- const uint8_t * key)
+static dht_msg_t * dht_kv_find_node_req_msg(const uint8_t * key)
{
- struct list_head * p;
+ return dht_kv_find_req_msg(key, DHT_FIND_NODE_REQ);
+}
- list_for_each(p, &dht->entries) {
- struct dht_entry * e = list_entry(p, struct dht_entry, next);
- if (!memcmp(key, e->key, dht->b))
- return e;
+static dht_msg_t * dht_kv_find_value_req_msg(const uint8_t * key)
+{
+ return dht_kv_find_req_msg(key, DHT_FIND_VALUE_REQ);
+}
+
+static dht_msg_t * dht_kv_find_node_rsp_msg(uint8_t * key,
+ uint64_t cookie,
+ dht_contact_msg_t *** contacts,
+ size_t len)
+{
+ dht_msg_t * msg;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ dht_msg__init(msg);
+ msg->code = DHT_FIND_NODE_RSP;
+
+ msg->src = dht_kv_src_contact_msg();
+ if (msg->src == NULL)
+ goto fail_msg;
+
+ msg->node = malloc(sizeof(*msg->node));
+ if (msg->node == NULL)
+ goto fail_msg;
+
+ dht_find_node_rsp_msg__init(msg->node);
+
+ msg->node->key.data = dht_dup_key(key);
+ if (msg->node->key.data == NULL)
+ goto fail_msg;
+
+ msg->node->cookie = cookie;
+ msg->node->key.len = dht.id.len;
+ msg->node->n_contacts = len;
+ if (len != 0) { /* Steal the ptr */
+ msg->node->contacts = *contacts;
+ *contacts = NULL;
}
+ return msg;
+
+ fail_msg:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_malloc:
return NULL;
}
-static int kad_add(struct dht * dht,
- const dht_contact_msg_t * contacts,
- ssize_t n,
- time_t exp)
+static dht_msg_t * dht_kv_find_value_rsp_msg(uint8_t * key,
+ uint64_t cookie,
+ dht_contact_msg_t *** contacts,
+ size_t n_contacts,
+ buffer_t ** vals,
+ size_t n_vals)
{
- struct dht_entry * e;
+ dht_msg_t * msg;
- pthread_rwlock_wrlock(&dht->lock);
+ msg = dht_kv_find_node_rsp_msg(key, cookie, contacts, n_contacts);
+ if (msg == NULL)
+ goto fail_node_rsp;
- while (n-- > 0) {
- if (contacts[n].id.len != dht->b)
- log_warn("Bad key length in contact data.");
+ msg->code = DHT_FIND_VALUE_RSP;
- e = dht_find_entry(dht, contacts[n].id.data);
- if (e != NULL) {
- if (dht_entry_add_addr(e, contacts[n].addr, exp))
- goto fail;
- } else {
- e = dht_entry_create(dht, contacts[n].id.data);
- if (e == NULL)
- goto fail;
+ msg->val = malloc(sizeof(*msg->val));
+ if (msg->val == NULL)
+ goto fail_msg;
- if (dht_entry_add_addr(e, contacts[n].addr, exp)) {
- dht_entry_destroy(e);
- goto fail;
- }
+ dht_find_value_rsp_msg__init(msg->val);
- list_add(&e->next, &dht->entries);
- }
- }
+ msg->val->n_values = n_vals;
+ if (n_vals != 0) /* Steal the ptr */
+ msg->val->values = (binary_data_t *) *vals;
- pthread_rwlock_unlock(&dht->lock);
- return 0;
+ return msg;
- fail:
- pthread_rwlock_unlock(&dht->lock);
- return -ENOMEM;
+ fail_msg:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_node_rsp:
+ return NULL;
}
-static int wait_resp(struct dht * dht,
- dht_msg_t * msg,
- time_t timeo)
+static dht_msg_t * dht_kv_store_msg(const uint8_t * key,
+ const buffer_t val,
+ time_t exp)
{
- struct kad_req * req;
+ dht_msg_t * msg;
- assert(dht);
- assert(msg);
+ assert(key != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
- pthread_rwlock_rdlock(&dht->lock);
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
- req = dht_find_request(dht, msg);
- if (req == NULL) {
- pthread_rwlock_unlock(&dht->lock);
- return -EPERM;
- }
+ dht_msg__init(msg);
- pthread_rwlock_unlock(&dht->lock);
+ msg->code = DHT_STORE;
- return kad_req_wait(req, timeo);
+ msg->src = dht_kv_src_contact_msg();
+ if (msg->src == NULL)
+ goto fail_msg;
+
+ msg->store = malloc(sizeof(*msg->store));
+ if (msg->store == NULL)
+ goto fail_msg;
+
+ dht_store_msg__init(msg->store);
+
+ msg->store->key.data = dht_dup_key(key);
+ if (msg->store->key.data == NULL)
+ goto fail_msg;
+
+ msg->store->key.len = dht.id.len;
+ msg->store->val.data = malloc(val.len);
+ if (msg->store->val.data == NULL)
+ goto fail_msg;
+
+ memcpy(msg->store->val.data, val.data, val.len);
+
+ msg->store->val.len = val.len;
+ msg->store->exp = exp;
+
+ return msg;
+
+ fail_msg:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
}
-static int kad_store(struct dht * dht,
- const uint8_t * key,
- uint64_t addr,
- uint64_t r_addr,
- time_t ttl)
+static ssize_t dht_kv_retrieve(const uint8_t * key,
+ buffer_t ** vals)
{
- dht_msg_t msg = DHT_MSG__INIT;
- dht_contact_msg_t cmsg = DHT_CONTACT_MSG__INIT;
- dht_contact_msg_t * cmsgp[1];
+ struct dht_entry * e;
+ struct list_head * p;
+ size_t n;
+ size_t i;
+
+ assert(key != NULL);
- cmsg.id.data = (uint8_t *) key;
- cmsg.addr = addr;
+ pthread_rwlock_rdlock(&dht.db.lock);
- pthread_rwlock_rdlock(&dht->lock);
+ e = __dht_kv_find_entry(key);
+ if (e == NULL)
+ goto no_vals;
- cmsg.id.len = dht->b;
+ n = MIN(DHT_MAX_VALS, e->vals.len + e->lvals.len);
+ if (n == 0)
+ goto no_vals;
- pthread_rwlock_unlock(&dht->lock);
+ *vals = malloc(n * sizeof(**vals));
+ if (*vals == NULL)
+ goto fail_vals;
- cmsgp[0] = &cmsg;
+ memset(*vals, 0, n * sizeof(**vals));
- msg.code = KAD_STORE;
- msg.has_t_expire = true;
- msg.t_expire = ttl;
- msg.n_contacts = 1;
- msg.contacts = cmsgp;
+ i = 0;
- if (send_msg(dht, &msg, r_addr) < 0)
- return -1;
+ list_for_each(p, &e->vals.list) {
+ struct val_entry * v;
+ if (i == n)
+ break; /* We have enough values */
+ v = list_entry(p, struct val_entry, next);
+ (*vals)[i].data = malloc(v->val.len);
+ if ((*vals)[i].data == NULL)
+ goto fail_val_data;
+
+ (*vals)[i].len = v->val.len;
+ memcpy((*vals)[i++].data, v->val.data, v->val.len);
+ }
+
+ list_for_each(p, &e->lvals.list) {
+ struct val_entry * v;
+ if (i == n)
+ break; /* We have enough values */
+ v = list_entry(p, struct val_entry, next);
+ (*vals)[i].data = malloc(v->val.len);
+ if ((*vals)[i].data == NULL)
+ goto fail_val_data;
+
+ (*vals)[i].len = v->val.len;
+ memcpy((*vals)[i++].data, v->val.data, v->val.len);
+ }
+
+ pthread_rwlock_unlock(&dht.db.lock);
+
+ return (ssize_t) i;
+ fail_val_data:
+ pthread_rwlock_unlock(&dht.db.lock);
+ freebufs(*vals, i);
+ *vals = NULL;
+ return -ENOMEM;
+ fail_vals:
+ pthread_rwlock_unlock(&dht.db.lock);
+ return -ENOMEM;
+ no_vals:
+ pthread_rwlock_unlock(&dht.db.lock);
+ *vals = NULL;
return 0;
}
-static ssize_t kad_find(struct dht * dht,
- struct lookup * lu,
- const uint64_t * addrs,
- enum kad_code code)
+static void __cleanup_dht_msg(void * msg)
{
- dht_msg_t msg = DHT_MSG__INIT;
- ssize_t sent = 0;
+ dht_msg__free_unpacked((dht_msg_t *) msg, NULL);
+}
- assert(dht);
- assert(lu->key);
+#ifdef DEBUG_PROTO_DHT
+static void dht_kv_debug_msg(dht_msg_t * msg)
+{
+ struct tm * tm;
+ char tmstr[RIB_TM_STRLEN];
+ time_t stamp;
+ size_t i;
- msg.code = code;
+ if (msg == NULL)
+ return;
- msg.has_key = true;
- msg.key.data = (uint8_t *) lu->key;
- msg.key.len = dht->b;
+ pthread_cleanup_push(__cleanup_dht_msg, msg);
+
+ switch (msg->code) {
+ case DHT_STORE:
+ log_proto(" key: " HASH_FMT64 " [%zu bytes]",
+ HASH_VAL64(msg->store->key.data),
+ msg->store->key.len);
+ log_proto(" val: " HASH_FMT64 " [%zu bytes]",
+ HASH_VAL64(msg->store->val.data),
+ msg->store->val.len);
+ stamp = msg->store->exp;
+ tm = gmtime(&stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+ log_proto(" exp: %s.", tmstr);
+ break;
+ case DHT_FIND_NODE_REQ:
+ /* FALLTHRU */
+ case DHT_FIND_VALUE_REQ:
+ log_proto(" cookie: " HASH_FMT64,
+ HASH_VAL64(&msg->find->cookie));
+ log_proto(" key: " HASH_FMT64 " [%zu bytes]",
+ HASH_VAL64(msg->find->key.data),
+ msg->find->key.len);
+ break;
+ case DHT_FIND_VALUE_RSP:
+ log_proto(" cookie: " HASH_FMT64,
+ HASH_VAL64(&msg->node->cookie));
+ log_proto(" key: " HASH_FMT64 " [%zu bytes]",
+ HASH_VAL64(msg->node->key.data),
+ msg->node->key.len);
+ log_proto(" values: [%zd]", msg->val->n_values);
+ for (i = 0; i < msg->val->n_values; i++)
+ log_proto(" " HASH_FMT64 " [%zu bytes]",
+ HASH_VAL64(msg->val->values[i].data),
+ msg->val->values[i].len);
+ log_proto(" contacts: [%zd]", msg->node->n_contacts);
+ for (i = 0; i < msg->node->n_contacts; i++) {
+ dht_contact_msg_t * c = msg->node->contacts[i];
+ log_proto(" " PEER_FMT,
+ PEER_VAL(c->id.data, c->addr));
+ }
+ break;
+ case DHT_FIND_NODE_RSP:
+ log_proto(" cookie: " HASH_FMT64,
+ HASH_VAL64(&msg->node->cookie));
+ log_proto(" key: " HASH_FMT64 " [%zu bytes]",
+ HASH_VAL64(msg->node->key.data), msg->node->key.len);
+ log_proto(" contacts: [%zd]", msg->node->n_contacts);
+ for (i = 0; i < msg->node->n_contacts; i++) {
+ dht_contact_msg_t * c = msg->node->contacts[i];
+ log_proto(" " PEER_FMT,
+ PEER_VAL(c->id.data, c->addr));
+ }
- while (*addrs != 0) {
- struct cookie_el * c;
- int ret;
+ break;
+ default:
+ break;
+ }
- if (*addrs == dht->addr) {
- ++addrs;
- continue;
- }
+ pthread_cleanup_pop(false);
+}
- ret = send_msg(dht, &msg, *addrs);
- if (ret < 0)
- break;
+static void dht_kv_debug_msg_snd(dht_msg_t * msg,
+ uint8_t * id,
+ uint64_t addr)
+{
+ if (msg == NULL)
+ return;
- c = malloc(sizeof(*c));
- if (c == NULL)
- break;
+ log_proto(TX_HDR_FMT ".", TX_HDR_VAL(msg, id, addr));
- c->cookie = (uint32_t) ret;
+ dht_kv_debug_msg(msg);
+}
- pthread_mutex_lock(&lu->lock);
+static void dht_kv_debug_msg_rcv(dht_msg_t * msg)
+{
+ if (msg == NULL)
+ return;
+
+ log_proto(RX_HDR_FMT ".", RX_HDR_VAL(msg));
- list_add_tail(&c->next, &lu->cookies);
+ dht_kv_debug_msg(msg);
+}
+#endif
- pthread_mutex_unlock(&lu->lock);
+#ifndef __DHT_TEST__
+static int dht_send_msg(dht_msg_t * msg,
+ uint64_t addr)
+{
+ size_t len;
+ struct shm_du_buff * sdb;
+
+ if (msg == NULL)
+ return 0;
- ++sent;
- ++addrs;
+ assert(addr != INVALID_ADDR && addr != dht.addr);
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ log_warn("%s failed to pack.", DHT_CODE(msg));
+ goto fail_msg;
}
- return sent;
+ if (ipcp_sdb_reserve(&sdb, len)) {
+ log_warn("%s failed to get sdb.", DHT_CODE(msg));
+ goto fail_msg;
+ }
+
+ dht_msg__pack(msg, shm_du_buff_head(sdb));
+
+ if (dt_write_packet(addr, QOS_CUBE_BE, dht.eid, sdb) < 0) {
+ log_warn("%s write failed", DHT_CODE(msg));
+ goto fail_send;
+ }
+
+ return 0;
+ fail_send:
+ ipcp_sdb_release(sdb);
+ fail_msg:
+ return -1;
}
+#else /* funtion for testing */
+static int dht_send_msg(dht_msg_t * msg,
+ uint64_t addr)
+{
+ buffer_t buf;
+
+ assert(msg != NULL);
+ assert(addr != INVALID_ADDR && addr != dht.addr);
+
+ buf.len = dht_msg__get_packed_size(msg);
+ if (buf.len == 0) {
+ log_warn("%s failed to pack.", DHT_CODE(msg));
+ goto fail_msg;
+ }
+
+ buf.data = malloc(buf.len);
+ if (buf.data == NULL) {
+ log_warn("%s failed to malloc buf.", DHT_CODE(msg));
+ goto fail_msg;
+ }
+
+ dht_msg__pack(msg, buf.data);
-static void lookup_detach(struct dht * dht,
- struct lookup * lu)
+ if (sink_send_msg(&buf, addr) < 0) {
+ log_warn("%s write failed", DHT_CODE(msg));
+ goto fail_send;
+ }
+
+ return 0;
+ fail_send:
+ freebuf(buf);
+ fail_msg:
+ return -1;
+}
+#endif /* __DHT_TEST__ */
+
+static void __cleanup_peer_list(void * pl)
{
- pthread_rwlock_wrlock(&dht->lock);
+ struct list_head * p;
+ struct list_head * h;
- list_del(&lu->next);
+ assert(pl != NULL);
- pthread_rwlock_unlock(&dht->lock);
+ list_for_each_safe(p, h, (struct list_head *) pl) {
+ struct peer_entry * e = list_entry(p, struct peer_entry, next);
+ list_del(&e->next);
+ free(e->id);
+ free(e);
+ }
}
-static struct lookup * kad_lookup(struct dht * dht,
- const uint8_t * id,
- enum kad_code code)
+
+static int dht_kv_send_msgs(dht_msg_t * msg,
+ struct list_head * pl)
{
- uint64_t addrs[KAD_ALPHA + 1];
- enum lookup_state state;
- struct lookup * lu;
+ struct list_head * p;
+ struct list_head * h;
- lu = lookup_create(dht, id);
- if (lu == NULL)
- return NULL;
+ pthread_cleanup_push(__cleanup_dht_msg, msg);
+ pthread_cleanup_push(__cleanup_peer_list, pl);
- lookup_new_addrs(lu, addrs);
+ list_for_each_safe(p, h, pl) {
+ struct peer_entry * e = list_entry(p, struct peer_entry, next);
+ if (IS_REQUEST(msg->code)) {
+ msg->find->cookie = e->cookie;
+ assert(msg->find->cookie != DHT_INVALID);
+ }
+ if (dht_send_msg(msg, e->addr) < 0)
+ continue;
- if (addrs[0] == 0) {
- lookup_detach(dht, lu);
- lookup_destroy(lu);
- return NULL;
+#ifdef DEBUG_PROTO_DHT
+ dht_kv_debug_msg_snd(msg, e->id, e->addr);
+#endif
+ list_del(&e->next);
+ free(e->id);
+ free(e);
}
- if (kad_find(dht, lu, addrs, code) == 0) {
- lookup_detach(dht, lu);
- return lu;
+ pthread_cleanup_pop(false);
+ pthread_cleanup_pop(false);
+
+ return list_is_empty(pl) ? 0 : -1;
+}
+
+static int dht_kv_get_peer_list_for_msg(dht_msg_t * msg,
+ struct list_head * pl)
+{
+ struct list_head cl; /* contact list */
+ uint8_t * key; /* key in the request */
+ size_t max;
+
+ assert(msg != NULL);
+
+ assert(list_is_empty(pl));
+
+ max = msg->code == DHT_STORE ? dht.k : dht.alpha;
+
+ switch (msg->code) {
+ case DHT_FIND_NODE_REQ:
+ /* FALLTHRU */
+ case DHT_FIND_VALUE_REQ:
+ key = msg->find->key.data;
+ break;
+ case DHT_STORE:
+ key = msg->store->key.data;
+ break;
+ default:
+ log_err("Invalid DHT msg code (%d).", msg->code);
+ return -1;
}
- while ((state = lookup_wait(lu)) != LU_COMPLETE) {
- switch (state) {
- case LU_UPDATE:
- lookup_new_addrs(lu, addrs);
- if (addrs[0] == 0)
- break;
+ list_head_init(&cl);
- kad_find(dht, lu, addrs, code);
- break;
- case LU_DESTROY:
- lookup_detach(dht, lu);
- lookup_set_state(lu, LU_NULL);
- return NULL;
- default:
- break;
- }
+ if (dht_kv_contact_list(key, &cl, max) < 0) {
+ log_err(KEY_FMT " Failed to get contact list.", KEY_VAL(key));
+ goto fail_contacts;
}
- assert(state == LU_COMPLETE);
+ if (list_is_empty(&cl)) {
+ log_warn(KEY_FMT " No available contacts.", KEY_VAL(key));
+ goto fail_contacts;
+ }
- lookup_detach(dht, lu);
+ if (dht_kv_create_peer_list(&cl, pl, msg->code) < 0) {
+ log_warn(KEY_FMT " Failed to get peer list.", KEY_VAL(key));
+ goto fail_peers;
+ }
- return lu;
+ contact_list_destroy(&cl);
+ return 0;
+ fail_peers:
+ contact_list_destroy(&cl);
+ fail_contacts:
+ return -1;
}
-static void kad_publish(struct dht * dht,
- const uint8_t * key,
- uint64_t addr,
- time_t exp)
+static int dht_kv_store_remote(const uint8_t * key,
+ const buffer_t val,
+ time_t exp)
{
- struct lookup * lu;
- uint64_t * addrs;
- ssize_t n;
- size_t k;
- time_t t_expire;
+ dht_msg_t * msg;
+ struct timespec now;
+ struct list_head pl;
+ assert(key != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
- assert(dht);
- assert(key);
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- pthread_rwlock_rdlock(&dht->lock);
+ msg = dht_kv_store_msg(key, val, exp);
+ if (msg == NULL) {
+ log_err(KV_FMT " Failed to create %s.",
+ KV_VAL(key, val), dht_code_str[DHT_STORE]);
+ goto fail_msg;
+ }
- k = dht->k;
- t_expire = dht->t_expire;
+ list_head_init(&pl);
- pthread_rwlock_unlock(&dht->lock);
+ if (dht_kv_get_peer_list_for_msg(msg, &pl) < 0) {
+ log_dbg(KV_FMT " Failed to get peer list.", KV_VAL(key, val));
+ goto fail_peer_list;
+ }
- addrs = malloc(k * sizeof(*addrs));
- if (addrs == NULL)
- return;
+ if (dht_kv_send_msgs(msg, &pl) < 0) {
+ log_warn(KV_FMT " Failed to send any %s msg.",
+ KV_VAL(key, val), DHT_CODE(msg));
+ goto fail_msgs;
+ }
- lu = kad_lookup(dht, key, KAD_FIND_NODE);
- if (lu == NULL) {
- free(addrs);
- return;
+ dht_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail_msgs:
+ peer_list_destroy(&pl);
+ fail_peer_list:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return -1;
+}
+
+/* recursive lookup, start with pl NULL */
+static int dht_kv_query_contacts(const uint8_t * key,
+ struct list_head * pl)
+{
+ struct list_head p;
+
+ dht_msg_t * msg;
+
+ assert(key != NULL);
+
+ msg = dht_kv_find_node_req_msg(key);
+ if (msg == NULL) {
+ log_err(KEY_FMT " Failed to create %s msg.",
+ KEY_VAL(key), dht_code_str[DHT_FIND_NODE_REQ]);
+ goto fail_msg;
}
- n = lookup_contact_addrs(lu, addrs);
+ if (pl == NULL) {
+ list_head_init(&p);
+ pl = &p;
+ }
- while (n-- > 0) {
- if (addrs[n] == dht->addr) {
- dht_contact_msg_t msg = DHT_CONTACT_MSG__INIT;
- msg.id.data = (uint8_t *) key;
- msg.id.len = dht->b;
- msg.addr = addr;
- kad_add(dht, &msg, 1, exp);
- } else {
- if (kad_store(dht, key, addr, addrs[n], t_expire))
- log_warn("Failed to send store message.");
- }
+ if (list_is_empty(pl) && dht_kv_get_peer_list_for_msg(msg, pl) < 0) {
+ log_warn(KEY_FMT " Failed to get peer list.", KEY_VAL(key));
+ goto fail_peer_list;
}
- lookup_destroy(lu);
+ if (dht_kv_update_req(key, pl) < 0) {
+ log_warn(KEY_FMT " Failed to update req.", KEY_VAL(key));
+ goto fail_update;
+ }
- free(addrs);
+ if (dht_kv_send_msgs(msg, pl)) {
+ log_warn(KEY_FMT " Failed to send any %s msg.",
+ KEY_VAL(key), DHT_CODE(msg));
+ goto fail_update;
+ }
+
+ dht_msg__free_unpacked(msg, NULL);
+
+ return 0;
+ fail_update:
+ peer_list_destroy(pl);
+ fail_peer_list:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return -1;
}
-static int kad_join(struct dht * dht,
- uint64_t addr)
+/* recursive lookup, start with pl NULL */
+static ssize_t dht_kv_query_remote(const uint8_t * key,
+ buffer_t ** vals,
+ struct list_head * pl)
{
- dht_msg_t msg = DHT_MSG__INIT;
+ struct list_head p;
+ dht_msg_t * msg;
- msg.code = KAD_JOIN;
+ assert(key != NULL);
- msg.has_alpha = true;
- msg.has_b = true;
- msg.has_k = true;
- msg.has_t_refresh = true;
- msg.has_t_replicate = true;
- msg.alpha = KAD_ALPHA;
- msg.k = KAD_K;
- msg.t_refresh = KAD_T_REFR;
- msg.t_replicate = KAD_T_REPL;
+ msg = dht_kv_find_value_req_msg(key);
+ if (msg == NULL) {
+ log_err(KEY_FMT " Failed to create value req.", KEY_VAL(key));
+ goto fail_msg;
+ }
- pthread_rwlock_rdlock(&dht->lock);
+ if (pl == NULL) {
+ list_head_init(&p);
+ pl = &p;
+ }
- msg.b = dht->b;
+ if (list_is_empty(pl) && dht_kv_get_peer_list_for_msg(msg, pl) < 0) {
+ log_warn(KEY_FMT " Failed to get peer list.", KEY_VAL(key));
+ goto fail_peer_list;
+ }
- pthread_rwlock_unlock(&dht->lock);
+ if (dht_kv_update_req(key, pl) < 0) {
+ log_err(KEY_FMT " Failed to update request.", KEY_VAL(key));
+ goto fail_update;
+ }
- if (send_msg(dht, &msg, addr) < 0)
- return -1;
+ if (dht_kv_send_msgs(msg, pl)) {
+ log_warn(KEY_FMT " Failed to send %s msg.",
+ KEY_VAL(key), DHT_CODE(msg));
+ goto fail_update;
+ }
- if (wait_resp(dht, &msg, KAD_T_JOIN) < 0)
- return -1;
+ dht_msg__free_unpacked(msg, NULL);
- dht->id = create_id(dht->b);
- if (dht->id == NULL)
- return -1;
+ if (vals == NULL) /* recursive lookup, already waiting */
+ return 0;
- pthread_rwlock_wrlock(&dht->lock);
+ return dht_kv_wait_req(key, vals);
+ fail_update:
+ peer_list_destroy(pl);
+ fail_peer_list:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ return -1;
+}
- dht_update_bucket(dht, dht->id, dht->addr);
+static void __add_dht_kv_entry(struct dht_entry * e)
+{
+ struct list_head * p;
- pthread_rwlock_unlock(&dht->lock);
+ assert(e != NULL);
- return 0;
+ list_for_each(p, &dht.db.kv.list) {
+ struct dht_entry * d = list_entry(p, struct dht_entry, next);
+ if (IS_CLOSER(d->key, e->key))
+ continue;
+ break;
+ }
+
+ list_add_tail(&e->next, p);
+ ++dht.db.kv.len;
}
-static void dht_dead_peer(struct dht * dht,
- uint8_t * key,
- uint64_t addr)
+/* incoming store message */
+static int dht_kv_store(const uint8_t * key,
+ const buffer_t val,
+ time_t exp)
{
- struct list_head * p;
- struct list_head * h;
- struct bucket * b;
+ struct dht_entry * e;
+ bool new = false;
- b = dht_get_bucket(dht, key);
+ assert(key != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
- list_for_each_safe(p, h, &b->contacts) {
- struct contact * c = list_entry(p, struct contact, next);
- if (b->n_contacts + b->n_alts <= dht->k) {
- ++c->fails;
- return;
- }
+ pthread_rwlock_wrlock(&dht.db.lock);
- if (c->addr == addr) {
- list_del(&c->next);
- contact_destroy(c);
- --b->n_contacts;
- break;
- }
+ e = __dht_kv_find_entry(key);
+ if (e == NULL) {
+ log_dbg(KV_FMT " Adding entry (store).", KV_VAL(key, val));
+ e = dht_entry_create(key);
+ if (e == NULL)
+ goto fail;
+
+ new = true;
+
+ __add_dht_kv_entry(e);
}
- while (b->n_contacts < dht->k && b->n_alts > 0) {
- struct contact * c;
- c = list_first_entry(&b->alts, struct contact, next);
- list_del(&c->next);
- --b->n_alts;
- list_add(&c->next, &b->contacts);
- ++b->n_contacts;
+ if (dht_entry_update_val(e, val, exp) < 0)
+ goto fail_add;
+
+ pthread_rwlock_unlock(&dht.db.lock);
+
+ return 0;
+ fail_add:
+ if (new) {
+ list_del(&e->next);
+ dht_entry_destroy(e);
+ --dht.db.kv.len;
}
+ fail:
+ pthread_rwlock_unlock(&dht.db.lock);
+ return -1;
}
-static int dht_del(struct dht * dht,
- const uint8_t * key,
- uint64_t addr)
+static int dht_kv_publish(const uint8_t * key,
+ const buffer_t val)
{
struct dht_entry * e;
+ struct timespec now;
+ bool new = false;
+
+ assert(key != NULL);
+ assert(val.data != NULL);
+ assert(val.len > 0);
- e = dht_find_entry(dht, key);
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ pthread_rwlock_wrlock(&dht.db.lock);
+
+ e = __dht_kv_find_entry(key);
if (e == NULL) {
- return -EPERM;
+ log_dbg(KV_FMT " Adding entry (publish).", KV_VAL(key, val));
+ e = dht_entry_create(key);
+ if (e == NULL)
+ goto fail;
+
+ __add_dht_kv_entry(e);
+ new = true;
}
- dht_entry_del_addr(e, addr);
+ if (dht_entry_update_lval(e, val) < 0)
+ goto fail_add;
+
+ pthread_rwlock_unlock(&dht.db.lock);
+
+ dht_kv_store_remote(key, val, now.tv_sec + dht.t_expire);
return 0;
+ fail_add:
+ if (new) {
+ list_del(&e->next);
+ dht_entry_destroy(e);
+ --dht.db.kv.len;
+ }
+ fail:
+ pthread_rwlock_unlock(&dht.db.lock);
+ return -1;
}
-static buffer_t dht_retrieve(struct dht * dht,
- const uint8_t * key)
+static int dht_kv_unpublish(const uint8_t * key,
+ const buffer_t val)
{
struct dht_entry * e;
- struct list_head * p;
- buffer_t buf;
- uint64_t * pos;
- size_t addrs = 0;
+ int rc;
- pthread_rwlock_rdlock(&dht->lock);
+ assert(key != NULL);
- e = dht_find_entry(dht, key);
+ pthread_rwlock_wrlock(&dht.db.lock);
+
+ e = __dht_kv_find_entry(key);
if (e == NULL)
- goto fail;
+ goto no_entry;
- buf.len = MIN(DHT_RETR_ADDR, e->n_vals);
- if (buf.len == 0)
- goto fail;
+ rc = dht_entry_remove_lval(e, val);
- pos = malloc(sizeof(dht->addr) * buf.len);
- if (pos == NULL)
- goto fail;
+ pthread_rwlock_unlock(&dht.db.lock);
- buf.data = (uint8_t *) pos;
+ return rc;
+ no_entry:
+ pthread_rwlock_unlock(&dht.db.lock);
+ return -ENOENT;
- list_for_each(p, &e->vals) {
- struct val * v = list_entry(p, struct val, next);
- *pos++ = v->addr;
- if (++addrs >= buf.len)
- break;
+}
+
+/* message validation */
+static int dht_kv_validate_store_msg(const dht_store_msg_t * store)
+{
+ if (store == NULL) {
+ log_warn("Store in msg is NULL.");
+ return -EINVAL;
}
- pthread_rwlock_unlock(&dht->lock);
+ if (store->key.data == NULL || store->key.len == 0) {
+ log_warn("Invalid key in DHT store msg.");
+ return -EINVAL;
+ }
- return buf;
+ if (store->key.len != dht.id.len) {
+ log_warn("Invalid key length in DHT store msg.");
+ return -EINVAL;
+ }
- fail:
- pthread_rwlock_unlock(&dht->lock);
- buf.len = 0;
- buf.data = NULL;
- return buf;
+ if (store->val.data == NULL || store->val.len == 0) {
+ log_warn("Invalid value in DHT store msg.");
+ return -EINVAL;
+ }
+
+ return 0;
}
-static ssize_t dht_get_contacts(struct dht * dht,
- const uint8_t * key,
- dht_contact_msg_t *** msgs)
+static int validate_find_req_msg(const dht_find_req_msg_t * req)
{
- struct list_head l;
- struct list_head * p;
- struct list_head * h;
- size_t len;
- size_t i = 0;
+ if (req == NULL) {
+ log_warn("Request in msg is NULL.");
+ return -EINVAL;
+ }
- list_head_init(&l);
+ if (req->key.data == NULL || req->key.len == 0) {
+ log_warn("Find request without key.");
+ return -EINVAL;
+ }
- pthread_rwlock_wrlock(&dht->lock);
+ if (req->key.len != dht.id.len) {
+ log_warn("Invalid key length in request msg.");
+ return -EINVAL;
+ }
- len = dht_contact_list(dht, &l, key);
- if (len == 0) {
- pthread_rwlock_unlock(&dht->lock);
- *msgs = NULL;
+ return 0;
+}
+
+static int validate_node_rsp_msg(const dht_find_node_rsp_msg_t * rsp)
+{
+ if (rsp == NULL) {
+ log_warn("Node rsp in msg is NULL.");
+ return -EINVAL;
+ }
+
+ if (rsp->key.data == NULL) {
+ log_warn("Invalid key in DHT response msg.");
+ return -EINVAL;
+ }
+
+ if (rsp->key.len != dht.id.len) {
+ log_warn("Invalid key length in DHT response msg.");
+ return -EINVAL;
+ }
+
+ if (!dht_kv_has_req(rsp->key.data, rsp->cookie)) {
+ log_warn(KEY_FMT " No request " CK_FMT ".",
+ KEY_VAL(rsp->key.data), CK_VAL(rsp->cookie));
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int validate_value_rsp_msg(const dht_find_value_rsp_msg_t * rsp)
+{
+ if (rsp == NULL) {
+ log_warn("Invalid DHT find value response msg.");
+ return -EINVAL;
+ }
+
+ if (rsp->values == NULL && rsp->n_values > 0) {
+ log_dbg("No values in DHT response msg.");
return 0;
}
- *msgs = malloc(len * sizeof(**msgs));
- if (*msgs == NULL) {
- pthread_rwlock_unlock(&dht->lock);
+ if (rsp->n_values == 0 && rsp->values != NULL) {
+ log_dbg("DHT response did not set values NULL.");
return 0;
}
- list_for_each_safe(p, h, &l) {
- struct contact * c = list_entry(p, struct contact, next);
- (*msgs)[i] = malloc(sizeof(***msgs));
- if ((*msgs)[i] == NULL) {
- pthread_rwlock_unlock(&dht->lock);
- while (i > 0)
- free(*msgs[--i]);
- free(*msgs);
- *msgs = NULL;
- return 0;
- }
+ return 0;
+}
- dht_contact_msg__init((*msgs)[i]);
+static int dht_kv_validate_msg(dht_msg_t * msg)
+{
- (*msgs)[i]->id.data = c->id;
- (*msgs)[i]->id.len = dht->b;
- (*msgs)[i++]->addr = c->addr;
- list_del(&c->next);
- free(c);
+ assert(msg != NULL);
+
+ if (msg->src->id.len != dht.id.len) {
+ log_warn("%s Invalid source contact ID.", DHT_CODE(msg));
+ return -EINVAL;
}
- pthread_rwlock_unlock(&dht->lock);
+ if (msg->src->addr == INVALID_ADDR) {
+ log_warn("%s Invalid source address.", DHT_CODE(msg));
+ return -EINVAL;
+ }
- return i;
+ switch (msg->code) {
+ case DHT_FIND_VALUE_REQ:
+ /* FALLTHRU */
+ case DHT_FIND_NODE_REQ:
+ if (validate_find_req_msg(msg->find) < 0)
+ return -EINVAL;
+ break;
+ case DHT_FIND_VALUE_RSP:
+ if (validate_value_rsp_msg(msg->val) < 0)
+ return -EINVAL;
+ /* FALLTHRU */
+ case DHT_FIND_NODE_RSP:
+ if (validate_node_rsp_msg(msg->node) < 0)
+ return -EINVAL;
+ break;
+ case DHT_STORE:
+ if (dht_kv_validate_store_msg(msg->store) < 0)
+ return -EINVAL;
+ break;
+ default:
+ log_warn("Invalid DHT msg code (%d).", msg->code);
+ return -ENOENT;
+ }
+
+ return 0;
}
-static time_t gcd(time_t a,
- time_t b)
+static void do_dht_kv_store(const dht_store_msg_t * store)
{
- if (a == 0)
- return b;
+ struct tm * tm;
+ char tmstr[RIB_TM_STRLEN];
+ buffer_t val;
+ uint8_t * key;
+ time_t exp;
- return gcd(b % a, a);
+ assert(store != NULL);
+
+ val.data = store->val.data;
+ val.len = store->val.len;
+ key = store->key.data;
+ exp = store->exp;
+
+ if (dht_kv_store(store->key.data, val, store->exp) < 0) {
+ log_err(KV_FMT " Failed to store.", KV_VAL(key, val));
+ return;
+ }
+
+ tm = gmtime(&exp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+ log_dbg(KV_FMT " Stored value until %s.", KV_VAL(key, val), tmstr);
}
-static void * work(void * o)
+static dht_msg_t * do_dht_kv_find_node_req(const dht_find_req_msg_t * req)
{
- struct dht * dht;
- struct timespec now;
- struct list_head * p;
- struct list_head * h;
- struct list_head reflist;
- time_t intv;
- struct lookup * lu;
+ dht_contact_msg_t ** contacts;
+ dht_msg_t * rsp;
+ uint8_t * key;
+ uint64_t cookie;
+ ssize_t len;
- dht = (struct dht *) o;
+ assert(req != NULL);
- pthread_rwlock_rdlock(&dht->lock);
+ key = req->key.data;
+ cookie = req->cookie;
- intv = gcd(dht->t_expire, dht->t_repub);
- intv = gcd(intv, gcd(KAD_T_REPL, KAD_T_REFR)) / 2;
+ len = dht_kv_get_contacts(key, &contacts);
+ if (len < 0) {
+ log_warn(KEY_FMT " Failed to get contacts.", KEY_VAL(key));
+ goto fail_contacts;
+ }
- pthread_rwlock_unlock(&dht->lock);
+ rsp = dht_kv_find_node_rsp_msg(key, cookie, &contacts, len);
+ if (rsp == NULL) {
+ log_err(KEY_FMT " Failed to create %s.", KEY_VAL(key),
+ dht_code_str[DHT_FIND_NODE_RSP]);
+ goto fail_msg;
+ }
- list_head_init(&reflist);
+ assert(rsp->code == DHT_FIND_NODE_RSP);
- while (true) {
- clock_gettime(CLOCK_REALTIME_COARSE, &now);
-
- pthread_rwlock_wrlock(&dht->lock);
-
- /* Republish registered hashes. */
- list_for_each(p, &dht->refs) {
- struct ref_entry * e;
- uint8_t * key;
- uint64_t addr;
- time_t t_expire;
- e = list_entry(p, struct ref_entry, next);
- if (now.tv_sec > e->t_rep) {
- key = dht_dup_key(e->key, dht->b);
- if (key == NULL)
- continue;
- addr = dht->addr;
- t_expire = dht->t_expire;
- e->t_rep = now.tv_sec + dht->t_repub;
-
- pthread_rwlock_unlock(&dht->lock);
- kad_publish(dht, key, addr, t_expire);
- pthread_rwlock_wrlock(&dht->lock);
- free(key);
- }
- }
+ log_info(KEY_FMT " Responding with %zd contacts", KEY_VAL(key), len);
- /* Remove stale entries and republish if necessary. */
- list_for_each_safe(p, h, &dht->entries) {
- struct list_head * p1;
- struct list_head * h1;
- struct dht_entry * e;
- uint8_t * key;
- time_t t_expire;
- e = list_entry (p, struct dht_entry, next);
- list_for_each_safe(p1, h1, &e->vals) {
- struct val * v;
- uint64_t addr;
- v = list_entry(p1, struct val, next);
- if (now.tv_sec > v->t_exp) {
- list_del(&v->next);
- val_destroy(v);
- continue;
- }
-
- if (now.tv_sec > v->t_rep) {
- key = dht_dup_key(e->key, dht->b);
- addr = v->addr;
- t_expire = dht->t_expire = now.tv_sec;
- v->t_rep = now.tv_sec + dht->t_replic;
- pthread_rwlock_unlock(&dht->lock);
- kad_publish(dht, key, addr, t_expire);
- pthread_rwlock_wrlock(&dht->lock);
- free(key);
- }
- }
- }
+ return rsp;
+ fail_msg:
+ while (len-- > 0)
+ dht_contact_msg__free_unpacked(contacts[len], NULL);
+ free(contacts);
+ fail_contacts:
+ return NULL;
+}
- /* Check the requests list for unresponsive nodes. */
- list_for_each_safe(p, h, &dht->requests) {
- struct kad_req * r;
- r = list_entry(p, struct kad_req, next);
- if (now.tv_sec > r->t_exp) {
- list_del(&r->next);
- bmp_release(dht->cookies, r->cookie);
- dht_dead_peer(dht, r->key, r->addr);
- kad_req_destroy(r);
- }
- }
+static void dht_kv_process_node_rsp(dht_contact_msg_t ** contacts,
+ size_t len,
+ struct list_head * pl,
+ enum dht_code code)
+{
+ struct timespec now;
+ size_t i;
- /* Refresh unaccessed buckets. */
- bucket_refresh(dht, dht->buckets, now.tv_sec, &reflist);
+ assert(contacts != NULL);
+ assert(len > 0);
+ assert(pl != NULL);
+ assert(list_is_empty(pl));
- pthread_rwlock_unlock(&dht->lock);
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- list_for_each_safe(p, h, &reflist) {
- struct contact * c;
- c = list_entry(p, struct contact, next);
- lu = kad_lookup(dht, c->id, KAD_FIND_NODE);
- if (lu != NULL)
- lookup_destroy(lu);
- list_del(&c->next);
- contact_destroy(c);
+ for (i = 0; i < len; i++) {
+ dht_contact_msg_t * c = contacts[i];
+ struct peer_entry * e;
+ if (c->addr == dht.addr)
+ continue;
+
+ if (dht_kv_update_contacts(c->id.data, c->addr) < 0)
+ log_warn(PEER_FMT " Failed to update contacts.",
+ PEER_VAL(c->id.data, c->addr));
+
+ e = malloc(sizeof(*e));
+ if (e == NULL) {
+ log_err(PEER_FMT " Failed to malloc entry.",
+ PEER_VAL(c->id.data, c->addr));
+ continue;
}
- sleep(intv);
- }
+ e->id = dht_dup_key(c->id.data);
+ if (e->id == NULL) {
+ log_warn(PEER_FMT " Failed to duplicate id.",
+ PEER_VAL(c->id.data, c->addr));
+ free(e);
+ continue;
+ }
- return (void *) 0;
+ e->cookie = generate_cookie();
+ e->code = code;
+ e->addr = c->addr;
+ e->t_sent = now.tv_sec;
+
+ list_add_tail(&e->next, pl);
+ }
}
-static int kad_handle_join_resp(struct dht * dht,
- struct kad_req * req,
- dht_msg_t * msg)
+static dht_msg_t * do_dht_kv_find_value_req(const dht_find_req_msg_t * req)
{
- assert(dht);
- assert(req);
- assert(msg);
+ dht_contact_msg_t ** contacts;
+ ssize_t n_contacts;
+ buffer_t * vals;
+ ssize_t n_vals;
+ dht_msg_t * rsp;
+ uint8_t * key;
+ uint64_t cookie;
- /* We might send version numbers later to warn of updates if needed. */
- if (!(msg->has_alpha && msg->has_b && msg->has_k && msg->has_t_expire &&
- msg->has_t_refresh && msg->has_t_replicate)) {
- log_warn("Join refused by remote.");
- return -1;
+ assert(req != NULL);
+
+ key = req->key.data;
+ cookie = req->cookie;
+
+ n_contacts = dht_kv_get_contacts(key, &contacts);
+ if (n_contacts < 0) {
+ log_warn(KEY_FMT " Failed to get contacts.", KEY_VAL(key));
+ goto fail_contacts;
}
- if (msg->b < sizeof(uint64_t)) {
- log_err("Hash sizes less than 8 bytes unsupported.");
- return -1;
+ assert(n_contacts > 0 || contacts == NULL);
+
+ n_vals = dht_kv_retrieve(key, &vals);
+ if (n_vals < 0) {
+ log_dbg(KEY_FMT " Failed to get values.", KEY_VAL(key));
+ goto fail_vals;
}
- pthread_rwlock_wrlock(&dht->lock);
+ if (n_vals == 0)
+ log_dbg(KEY_FMT " No values found.", KEY_VAL(key));
- dht->buckets = bucket_create();
- if (dht->buckets == NULL) {
- pthread_rwlock_unlock(&dht->lock);
- return -1;
+ rsp = dht_kv_find_value_rsp_msg(key, cookie, &contacts, n_contacts,
+ &vals, n_vals);
+ if (rsp == NULL) {
+ log_err(KEY_FMT " Failed to create %s msg.",
+ KEY_VAL(key), dht_code_str[DHT_FIND_VALUE_RSP]);
+ goto fail_msg;
}
- /* Likely corrupt packet. The member will refuse, we might here too. */
- if (msg->alpha != KAD_ALPHA || msg->k != KAD_K)
- log_warn("Different kademlia parameters detected.");
+ log_info(KEY_FMT " Responding with %zd contacts, %zd values.",
+ KEY_VAL(req->key.data), n_contacts, n_vals);
- if (msg->t_replicate != KAD_T_REPL)
- log_warn("Different kademlia replication time detected.");
+ return rsp;
- if (msg->t_refresh != KAD_T_REFR)
- log_warn("Different kademlia refresh time detected.");
+ fail_msg:
+ freebufs(vals, n_vals);
+ fail_vals:
+ while (n_contacts-- > 0)
+ dht_contact_msg__free_unpacked(contacts[n_contacts], NULL);
+ free(contacts);
+ fail_contacts:
+ return NULL;
+}
- dht->k = msg->k;
- dht->b = msg->b;
- dht->t_expire = msg->t_expire;
- dht->t_repub = MAX(1, dht->t_expire - 10);
+static void do_dht_kv_find_node_rsp(const dht_find_node_rsp_msg_t * rsp)
+{
+ struct list_head pl;
- if (pthread_create(&dht->worker, NULL, work, dht)) {
- bucket_destroy(dht->buckets);
- pthread_rwlock_unlock(&dht->lock);
- return -1;
- }
+ assert(rsp != NULL);
- kad_req_respond(req);
+ list_head_init(&pl);
- dht_update_bucket(dht, msg->s_id.data, msg->s_addr);
+ dht_kv_process_node_rsp(rsp->contacts, rsp->n_contacts, &pl,
+ DHT_FIND_NODE_REQ);
- pthread_rwlock_unlock(&dht->lock);
+ if (list_is_empty(&pl))
+ goto no_contacts;
- log_dbg("Enrollment of DHT completed.");
+ if (dht_kv_update_req(rsp->key.data, &pl) < 0) {
+ log_err(KEY_FMT " Failed to update request.",
+ KEY_VAL(rsp->key.data));
+ goto fail_update;
+ }
- return 0;
+ dht_kv_query_contacts(rsp->key.data, &pl);
+
+ return;
+
+ fail_update:
+ peer_list_destroy(&pl);
+ no_contacts:
+ return;
}
-static int kad_handle_find_resp(struct dht * dht,
- struct kad_req * req,
- dht_msg_t * msg)
+static void do_dht_kv_find_value_rsp(const dht_find_node_rsp_msg_t * node,
+ const dht_find_value_rsp_msg_t * val)
{
- struct lookup * lu;
+ struct list_head pl;
+ uint8_t * key;
- assert(dht);
- assert(req);
- assert(msg);
+ assert(node != NULL);
+ assert(val != NULL);
- pthread_rwlock_rdlock(&dht->lock);
+ list_head_init(&pl);
- lu = dht_find_lookup(dht, req->cookie);
- if (lu == NULL) {
- pthread_rwlock_unlock(&dht->lock);
- return -1;
+ key = node->key.data;
+
+ dht_kv_process_node_rsp(node->contacts, node->n_contacts, &pl,
+ DHT_FIND_VALUE_REQ);
+
+ if (val->n_values > 0) {
+ log_dbg(KEY_FMT " %zd new values received.",
+ KEY_VAL(key), val->n_values);
+ if (dht_kv_respond_req(key, val->values, val->n_values) < 0)
+ log_warn(KEY_FMT " Failed to respond to request.",
+ KEY_VAL(key));
+ peer_list_destroy(&pl);
+ return; /* done! */
}
- lookup_update(dht, lu, msg);
+ if (list_is_empty(&pl))
+ goto no_contacts;
+
+ if (dht_kv_update_req(key, &pl) < 0) {
+ log_err(KEY_FMT " Failed to update request.", KEY_VAL(key));
+ goto fail_update;
+ }
- pthread_rwlock_unlock(&dht->lock);
+ dht_kv_query_remote(key, NULL, &pl);
- return 0;
+ return;
+ fail_update:
+ peer_list_destroy(&pl);
+ no_contacts:
+ return;
}
-static void kad_handle_response(struct dht * dht,
- dht_msg_t * msg)
+static dht_msg_t * dht_wait_for_dht_msg(void)
{
- struct kad_req * req;
+ dht_msg_t * msg;
+ struct cmd * cmd;
- assert(dht);
- assert(msg);
+ pthread_mutex_lock(&dht.cmds.mtx);
- pthread_rwlock_wrlock(&dht->lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &dht.cmds.mtx);
- req = dht_find_request(dht, msg);
- if (req == NULL) {
- pthread_rwlock_unlock(&dht->lock);
+ while (list_is_empty(&dht.cmds.list))
+ pthread_cond_wait(&dht.cmds.cond, &dht.cmds.mtx);
+
+ cmd = list_last_entry(&dht.cmds.list, struct cmd, next);
+ list_del(&cmd->next);
+
+ pthread_cleanup_pop(true);
+
+ msg = dht_msg__unpack(NULL, cmd->cbuf.len, cmd->cbuf.data);
+ if (msg == NULL)
+ log_warn("Failed to unpack DHT msg.");
+
+ freebuf(cmd->cbuf);
+ free(cmd);
+
+ return msg;
+}
+
+static void do_dht_msg(dht_msg_t * msg)
+{
+ dht_msg_t * rsp = NULL;
+ uint8_t * id;
+ uint64_t addr;
+
+#ifdef DEBUG_PROTO_DHT
+ dht_kv_debug_msg_rcv(msg);
+#endif
+ if (dht_kv_validate_msg(msg) == -EINVAL) {
+ log_warn("%s Validation failed.", DHT_CODE(msg));
+ dht_msg__free_unpacked(msg, NULL);
return;
}
- bmp_release(dht->cookies, req->cookie);
- list_del(&req->next);
+ id = msg->src->id.data;
+ addr = msg->src->addr;
+
+ if (dht_kv_update_contacts(id, addr) < 0)
+ log_warn(PEER_FMT " Failed to update contact from msg src.",
+ PEER_VAL(id, addr));
- pthread_rwlock_unlock(&dht->lock);
+ pthread_cleanup_push(__cleanup_dht_msg, msg);
- switch(req->code) {
- case KAD_JOIN:
- if (kad_handle_join_resp(dht, req, msg))
- log_err("Enrollment of DHT failed.");
+ switch(msg->code) {
+ case DHT_FIND_VALUE_REQ:
+ rsp = do_dht_kv_find_value_req(msg->find);
break;
- case KAD_FIND_VALUE:
- case KAD_FIND_NODE:
- if (dht_get_state(dht) != DHT_RUNNING)
- break;
- kad_handle_find_resp(dht, req, msg);
+ case DHT_FIND_NODE_REQ:
+ rsp = do_dht_kv_find_node_req(msg->find);
break;
- default:
+ case DHT_STORE:
+ do_dht_kv_store(msg->store);
+ break;
+ case DHT_FIND_NODE_RSP:
+ do_dht_kv_find_node_rsp(msg->node);
break;
+ case DHT_FIND_VALUE_RSP:
+ do_dht_kv_find_value_rsp(msg->node, msg->val);
+ break;
+ default:
+ assert(false); /* already validated */
}
- kad_req_destroy(req);
+ pthread_cleanup_pop(true);
+
+ if (rsp == NULL)
+ return;
+
+ pthread_cleanup_push(__cleanup_dht_msg, rsp);
+
+ dht_send_msg(rsp, addr);
+
+ pthread_cleanup_pop(true); /* free rsp */
}
-int dht_bootstrap(void * dir)
+static void * dht_handle_packet(void * o)
{
- struct dht * dht;
+ (void) o;
- dht = (struct dht *) dir;
+ while (true) {
+ dht_msg_t * msg;
- assert(dht);
+ msg = dht_wait_for_dht_msg();
+ if (msg == NULL)
+ continue;
- pthread_rwlock_wrlock(&dht->lock);
+ tpm_begin_work(dht.tpm);
+ do_dht_msg(msg);
+
+ tpm_end_work(dht.tpm);
+ }
+
+ return (void *) 0;
+}
#ifndef __DHT_TEST__
- dht->b = hash_len(ipcpi.dir_hash_algo);
-#else
- dht->b = DHT_TEST_KEY_LEN;
-#endif
+static void dht_post_packet(void * comp,
+ struct shm_du_buff * sdb)
+{
+ struct cmd * cmd;
- dht->id = create_id(dht->b);
- if (dht->id == NULL)
- goto fail_id;
+ (void) comp;
- dht->buckets = bucket_create();
- if (dht->buckets == NULL)
- goto fail_buckets;
+ cmd = malloc(sizeof(*cmd));
+ if (cmd == NULL) {
+ log_err("Command malloc failed.");
+ goto fail_cmd;
+ }
- dht->buckets->depth = 0;
- dht->buckets->mask = 0;
+ cmd->cbuf.data = malloc(shm_du_buff_len(sdb));
+ if (cmd->cbuf.data == NULL) {
+ log_err("Command buffer malloc failed.");
+ goto fail_buf;
+ }
- dht->t_expire = 86400; /* 1 day */
- dht->t_repub = dht->t_expire - 10;
- dht->k = KAD_K;
+ cmd->cbuf.len = shm_du_buff_len(sdb);
- if (pthread_create(&dht->worker, NULL, work, dht))
- goto fail_pthread_create;
+ memcpy(cmd->cbuf.data, shm_du_buff_head(sdb), cmd->cbuf.len);
- dht->state = DHT_RUNNING;
+ ipcp_sdb_release(sdb);
- dht_update_bucket(dht, dht->id, dht->addr);
+ pthread_mutex_lock(&dht.cmds.mtx);
- pthread_rwlock_unlock(&dht->lock);
+ list_add(&cmd->next, &dht.cmds.list);
- return 0;
+ pthread_cond_signal(&dht.cmds.cond);
- fail_pthread_create:
- bucket_destroy(dht->buckets);
- dht->buckets = NULL;
- fail_buckets:
- free(dht->id);
- dht->id = NULL;
- fail_id:
- pthread_rwlock_unlock(&dht->lock);
- return -1;
+ pthread_mutex_unlock(&dht.cmds.mtx);
+
+ return;
+
+ fail_buf:
+ free(cmd);
+ fail_cmd:
+ ipcp_sdb_release(sdb);
+ return;
}
+#endif
-static struct ref_entry * ref_entry_get(struct dht * dht,
- const uint8_t * key)
+int dht_reg(const uint8_t * key)
{
- struct list_head * p;
+ buffer_t val;
- list_for_each(p, &dht->refs) {
- struct ref_entry * r = list_entry(p, struct ref_entry, next);
- if (!memcmp(key, r->key, dht-> b) )
- return r;
+ if (addr_to_buf(dht.addr, &val) < 0) {
+ log_err("Failed to convert address to buffer.");
+ goto fail_a2b;
}
- return NULL;
+ if (dht_kv_publish(key, val)) {
+ log_err(KV_FMT " Failed to publish.", KV_VAL(key, val));
+ goto fail_publish;
+ }
+
+ freebuf(val);
+
+ return 0;
+ fail_publish:
+ freebuf(val);
+ fail_a2b:
+ return -1;
}
-int dht_reg(void * dir,
- const uint8_t * key)
+int dht_unreg(const uint8_t * key)
{
- struct dht * dht;
- struct ref_entry * e;
- uint64_t addr;
- time_t t_expire;
+ buffer_t val;
- dht = (struct dht *) dir;
+ if (addr_to_buf(dht.addr, &val) < 0) {
+ log_err("Failed to convert address to buffer.");
+ goto fail_a2b;
+ }
- assert(dht);
- assert(key);
- assert(dht->addr != 0);
+ if (dht_kv_unpublish(key, val)) {
+ log_err(KV_FMT " Failed to unpublish.", KV_VAL(key, val));
+ goto fail_unpublish;
+ }
- if (dht_wait_running(dht))
- return -1;
+ freebuf(val);
- pthread_rwlock_wrlock(&dht->lock);
+ return 0;
+ fail_unpublish:
+ freebuf(val);
+ fail_a2b:
+ return -ENOMEM;
+}
- if (ref_entry_get(dht, key) != NULL) {
- log_dbg("Name already registered.");
- pthread_rwlock_unlock(&dht->lock);
- return 0;
- }
+uint64_t dht_query(const uint8_t * key)
+{
+ buffer_t * vals;
+ ssize_t n;
+ uint64_t addr;
- e = ref_entry_create(dht, key);
- if (e == NULL) {
- pthread_rwlock_unlock(&dht->lock);
- return -ENOMEM;
+ n = dht_kv_retrieve(key, &vals);
+ if (n < 0) {
+ log_err(KEY_FMT " Failed to query db.", KEY_VAL(key));
+ goto fail_vals;
}
- list_add(&e->next, &dht->refs);
+ if (n == 0) {
+ assert(vals == NULL);
- t_expire = dht->t_expire;
- addr = dht->addr;
+ log_dbg(KEY_FMT " No local values.", KEY_VAL(key));
+ n = dht_kv_query_remote(key, &vals, NULL);
+ if (n < 0) {
+ log_warn(KEY_FMT " Failed to query DHT.", KEY_VAL(key));
+ goto fail_vals;
+ }
+ if (n == 0) {
+ log_dbg(KEY_FMT " No values.", KEY_VAL(key));
+ goto no_vals;
+ }
+ }
- pthread_rwlock_unlock(&dht->lock);
+ if (buf_to_addr(vals[0], &addr) < 0) {
+ log_err(VAL_FMT " Failed addr conversion.", VAL_VAL(vals[0]));
+ goto fail_b2a;
+ }
- kad_publish(dht, key, addr, t_expire);
+ if (n > 1 && addr == INVALID_ADDR && buf_to_addr(vals[1], &addr) < 0) {
+ log_err(VAL_FMT " Failed addr conversion.", VAL_VAL(vals[1]));
+ goto fail_b2a;
+ }
- return 0;
+ freebufs(vals, n);
+
+ return addr;
+ fail_b2a:
+ freebufs(vals, n);
+ return INVALID_ADDR;
+ no_vals:
+ free(vals);
+ fail_vals:
+ return INVALID_ADDR;
}
-int dht_unreg(void * dir,
- const uint8_t * key)
+static int emergency_peer(struct list_head * pl)
{
- struct dht * dht;
- struct list_head * p;
- struct list_head * h;
-
- dht = (struct dht *) dir;
+ struct peer_entry * e;
+ struct timespec now;
- assert(dht);
- assert(key);
+ assert(pl != NULL);
+ assert(list_is_empty(pl));
- if (dht_get_state(dht) != DHT_RUNNING)
+ if (dht.peer == INVALID_ADDR)
return -1;
- pthread_rwlock_wrlock(&dht->lock);
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- list_for_each_safe(p, h, &dht->refs) {
- struct ref_entry * r = list_entry(p, struct ref_entry, next);
- if (!memcmp(key, r->key, dht-> b) ) {
- list_del(&r->next);
- ref_entry_destroy(r);
- }
+ e = malloc(sizeof(*e));
+ if (e == NULL) {
+ log_err("Failed to malloc emergency peer entry.");
+ goto fail_malloc;
}
- dht_del(dht, key, dht->addr);
+ e->id = dht_dup_key(dht.id.data);
+ if (e->id == NULL) {
+ log_err("Failed to duplicate DHT ID for emergency peer.");
+ goto fail_id;
+ }
- pthread_rwlock_unlock(&dht->lock);
+ e->addr = dht.peer;
+ e->cookie = dht.magic;
+ e->code = DHT_FIND_NODE_REQ;
+ e->t_sent = now.tv_sec;
+
+ list_add_tail(&e->next, pl);
return 0;
+ fail_id:
+ free(e);
+ fail_malloc:
+ return -ENOMEM;
}
-uint64_t dht_query(void * dir,
- const uint8_t * key)
+static int dht_kv_seed_bootstrap_peer(void)
{
- struct dht * dht;
- struct dht_entry * e;
- struct lookup * lu;
- uint64_t addrs[KAD_K];
- size_t n;
+ struct list_head pl;
- dht = (struct dht *) dir;
+ list_head_init(&pl);
- assert(dht);
+ if (dht.peer == INVALID_ADDR) {
+ log_dbg("No-one to contact.");
+ return 0;
+ }
- addrs[0] = 0;
+ if (emergency_peer(&pl) < 0) {
+ log_err("Could not create emergency peer.");
+ goto fail_peer;
+ }
- if (dht_wait_running(dht))
- return 0;
+ log_dbg("Pinging emergency peer " ADDR_FMT32 ".",
+ ADDR_VAL32(&dht.peer));
- pthread_rwlock_rdlock(&dht->lock);
+ if (dht_kv_query_contacts(dht.id.data, &pl) < 0) {
+ log_warn("Failed to bootstrap peer.");
+ goto fail_query;
+ }
- e = dht_find_entry(dht, key);
- if (e != NULL)
- addrs[0] = dht_entry_get_addr(dht, e);
+ peer_list_destroy(&pl);
- pthread_rwlock_unlock(&dht->lock);
+ return 0;
+ fail_query:
+ peer_list_destroy(&pl);
+ fail_peer:
+ return -EAGAIN;
+}
- if (addrs[0] != 0)
- return addrs[0];
+static void dht_kv_check_contacts(void)
+{
+ struct list_head cl;
+ struct list_head pl;
- lu = kad_lookup(dht, key, KAD_FIND_VALUE);
- if (lu == NULL)
- return 0;
+ list_head_init(&cl);
- n = lookup_get_addrs(lu, addrs);
- if (n == 0) {
- lookup_destroy(lu);
- return 0;
+ dht_kv_contact_list(dht.id.data, &cl, dht.k);
+
+ if (!list_is_empty(&cl))
+ goto success;
+
+ contact_list_destroy(&cl);
+
+ list_head_init(&pl);
+
+ if (dht.peer == INVALID_ADDR) {
+ log_dbg("No-one to contact.");
+ return;
}
- lookup_destroy(lu);
+ if (emergency_peer(&pl) < 0) {
+ log_err("Could not create emergency peer.");
+ goto fail_peer;
+ }
- /* Current behaviour is anycast and return the first peer address. */
- if (addrs[0] != dht->addr)
- return addrs[0];
+ log_dbg("No contacts found, using emergency peer " ADDR_FMT32 ".",
+ ADDR_VAL32(&dht.peer));
- if (n > 1)
- return addrs[1];
+ dht_kv_query_contacts(dht.id.data, &pl);
- return 0;
+ peer_list_destroy(&pl);
+
+ return;
+ success:
+ contact_list_destroy(&cl);
+ return;
+ fail_peer:
+ return;
}
-static void * dht_handle_packet(void * o)
+static void dht_kv_remove_expired_reqs(void)
{
- struct dht * dht = (struct dht *) o;
+ struct list_head * p;
+ struct list_head * h;
+ struct timespec now;
- assert(dht);
+ clock_gettime(PTHREAD_COND_CLOCK, &now);
- while (true) {
- 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;
- size_t b;
- size_t t_expire;
- struct cmd * cmd;
+ pthread_mutex_lock(&dht.reqs.mtx);
- pthread_mutex_lock(&dht->mtx);
+ list_for_each_safe(p, h, &dht.reqs.list) {
+ struct dht_req * e;
+ e = list_entry(p, struct dht_req, next);
+ if (IS_EXPIRED(e, &now)) {
+ log_dbg(KEY_FMT " Removing expired request.",
+ KEY_VAL(e->key));
+ list_del(&e->next);
+ dht_req_destroy(e);
+ --dht.reqs.len;
+ }
+ }
- pthread_cleanup_push(__cleanup_mutex_unlock, &dht->mtx);
+ pthread_mutex_unlock(&dht.reqs.mtx);
+}
- while (list_is_empty(&dht->cmds))
- pthread_cond_wait(&dht->cond, &dht->mtx);
+static void value_list_destroy(struct list_head * vl)
+{
+ struct list_head * p;
+ struct list_head * h;
- cmd = list_last_entry(&dht->cmds, struct cmd, next);
- list_del(&cmd->next);
+ assert(vl != NULL);
- pthread_cleanup_pop(true);
+ list_for_each_safe(p, h, vl) {
+ struct val_entry * v = list_entry(p, struct val_entry, next);
+ list_del(&v->next);
+ val_entry_destroy(v);
+ }
+}
- i = shm_du_buff_len(cmd->sdb);
+#define MUST_REPLICATE(v, now) ((now)->tv_sec > (v)->t_repl + dht.t_repl)
+#define MUST_REPUBLISH(v, now) /* Close to expiry deadline */ \
+ (((v)->t_exp - (now)->tv_sec) < (DHT_N_REPUB * dht.t_repl))
+static void dht_entry_get_repl_lists(const struct dht_entry * e,
+ struct list_head * repl,
+ struct list_head * rebl,
+ struct timespec * now)
+{
+ struct list_head * p;
+ struct val_entry * n;
- msg = dht_msg__unpack(NULL, i, shm_du_buff_head(cmd->sdb));
-#ifndef __DHT_TEST__
- ipcp_sdb_release(cmd->sdb);
-#endif
- free(cmd);
+ list_for_each(p, &e->vals.list) {
+ struct val_entry * v = list_entry(p, struct val_entry, next);
+ if (MUST_REPLICATE(v, now) && !IS_EXPIRED(v, now)) {
+ n = val_entry_create(v->val, v->t_exp);
+ if (n == NULL)
+ continue;
- if (msg == NULL) {
- log_err("Failed to unpack message.");
- continue;
+ list_add_tail(&n->next, repl);
}
+ }
- if (msg->code != KAD_RESPONSE && dht_wait_running(dht)) {
- dht_msg__free_unpacked(msg, NULL);
- log_dbg("Got a request message when not running.");
- continue;
+ list_for_each(p, &e->lvals.list) {
+ struct val_entry * v = list_entry(p, struct val_entry, next);
+ if (MUST_REPLICATE(v, now) && MUST_REPUBLISH(v, now)) {
+ /* Add expire time here, to allow creating val_entry */
+ n = val_entry_create(v->val, now->tv_sec + dht.t_expire);
+ if (n == NULL)
+ continue;
+
+ list_add_tail(&n->next, rebl);
}
+ }
+}
- pthread_rwlock_rdlock(&dht->lock);
+static int dht_kv_next_values(uint8_t * key,
+ struct list_head * repl,
+ struct list_head * rebl)
+{
+ struct timespec now;
+ struct list_head * p;
+ struct list_head * h;
+ struct dht_entry * e = NULL;
- b = dht->b;
- t_expire = dht->t_expire;
+ assert(key != NULL);
+ assert(repl != NULL);
+ assert(rebl != NULL);
- pthread_rwlock_unlock(&dht->lock);
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- if (msg->has_key && msg->key.len != b) {
- dht_msg__free_unpacked(msg, NULL);
- log_warn("Bad key in message.");
- continue;
- }
+ assert(list_is_empty(repl));
+ assert(list_is_empty(rebl));
- if (msg->has_s_id && !msg->has_b && msg->s_id.len != b) {
- dht_msg__free_unpacked(msg, NULL);
- log_warn("Bad source ID in message of type %d.",
- msg->code);
- continue;
- }
+ pthread_rwlock_rdlock(&dht.db.lock);
- tpm_dec(dht->tpm);
+ if (dht.db.kv.len == 0)
+ goto no_entries;
- addr = msg->s_addr;
+ list_for_each_safe(p, h, &dht.db.kv.list) {
+ e = list_entry(p, struct dht_entry, next);
+ if (IS_CLOSER(e->key, key))
+ continue; /* Already processed */
+ }
- resp_msg.code = KAD_RESPONSE;
- resp_msg.cookie = msg->cookie;
+ if (e != NULL) {
+ memcpy(key, e->key, dht.id.len);
+ dht_entry_get_repl_lists(e, repl, rebl, &now);
+ }
+ no_entries:
+ pthread_rwlock_unlock(&dht.db.lock);
- switch(msg->code) {
- case KAD_JOIN:
- /* Refuse enrollee on check fails. */
- if (msg->alpha != KAD_ALPHA || msg->k != KAD_K) {
- log_warn("Parameter mismatch. "
- "DHT enrolment refused.");
- break;
- }
+ return list_is_empty(repl) && list_is_empty(rebl) ? -ENOENT : 0;
+}
- if (msg->t_replicate != KAD_T_REPL) {
- log_warn("Replication time mismatch. "
- "DHT enrolment refused.");
+static void dht_kv_replicate_value(const uint8_t * key,
+ struct val_entry * v,
+ const struct timespec * now)
+{
+ assert(MUST_REPLICATE(v, now));
- break;
- }
+ (void) now;
- if (msg->t_refresh != KAD_T_REFR) {
- log_warn("Refresh time mismatch. "
- "DHT enrolment refused.");
- break;
- }
+ if (dht_kv_store_remote(key, v->val, v->t_exp) == 0) {
+ log_dbg(KV_FMT " Replicated.", KV_VAL(key, v->val));
+ return;
+ }
- resp_msg.has_alpha = true;
- resp_msg.has_b = true;
- resp_msg.has_k = true;
- resp_msg.has_t_expire = true;
- resp_msg.has_t_refresh = true;
- resp_msg.has_t_replicate = true;
- resp_msg.alpha = KAD_ALPHA;
- resp_msg.b = b;
- resp_msg.k = KAD_K;
- resp_msg.t_expire = t_expire;
- resp_msg.t_refresh = KAD_T_REFR;
- resp_msg.t_replicate = KAD_T_REPL;
- break;
- case KAD_FIND_VALUE:
- buf = dht_retrieve(dht, msg->key.data);
- if (buf.len != 0) {
- resp_msg.n_addrs = buf.len;
- resp_msg.addrs = (uint64_t *) buf.data;
- break;
- }
- /* FALLTHRU */
- case KAD_FIND_NODE:
- /* Return k closest contacts. */
- resp_msg.n_contacts =
- dht_get_contacts(dht, msg->key.data, &cmsgs);
- resp_msg.contacts = cmsgs;
- break;
- case KAD_STORE:
- if (msg->n_contacts < 1) {
- log_warn("No contacts in store message.");
- break;
- }
+ log_dbg(KV_FMT " Replication failed.", KV_VAL(key, v->val));
- if (!msg->has_t_expire) {
- log_warn("No expiry time in store message.");
- break;
- }
+ list_del(&v->next);
+ val_entry_destroy(v);
+}
- kad_add(dht, *msg->contacts, msg->n_contacts,
- msg->t_expire);
- break;
- case KAD_RESPONSE:
- kad_handle_response(dht, msg);
- break;
- default:
- assert(false);
- break;
- }
+static void dht_kv_republish_value(const uint8_t * key,
+ struct val_entry * v,
+ const struct timespec * now)
+{
+ assert(MUST_REPLICATE(v, now));
- if (msg->code != KAD_JOIN) {
- pthread_rwlock_wrlock(&dht->lock);
- if (dht_get_state(dht) == DHT_JOINING &&
- dht->buckets == NULL) {
- pthread_rwlock_unlock(&dht->lock);
- goto finish;
- }
+ if (MUST_REPUBLISH(v, now))
+ assert(v->t_exp >= now->tv_sec + dht.t_expire);
- if (dht_update_bucket(dht, msg->s_id.data, addr))
- log_warn("Failed to update bucket.");
- pthread_rwlock_unlock(&dht->lock);
- }
+ if (dht_kv_store_remote(key, v->val, v->t_exp) == 0) {
+ log_dbg(KV_FMT " Republished.", KV_VAL(key, v->val));
+ return;
+ }
- if (msg->code < KAD_STORE && send_msg(dht, &resp_msg, addr) < 0)
- log_warn("Failed to send response.");
+ if (MUST_REPUBLISH(v, now))
+ log_warn(KV_FMT " Republish failed.", KV_VAL(key, v->val));
+ else
+ log_dbg(KV_FMT " Replication failed.", KV_VAL(key, v->val));
- finish:
- dht_msg__free_unpacked(msg, NULL);
+ list_del(&v->next);
+ val_entry_destroy(v);
+}
- if (resp_msg.n_addrs > 0)
- free(resp_msg.addrs);
+static void dht_kv_update_replication_times(const uint8_t * key,
+ struct list_head * repl,
+ struct list_head * rebl,
+ const struct timespec * now)
+{
+ struct dht_entry * e;
+ struct list_head * p;
+ struct list_head * h;
+ struct val_entry * v;
+
+ assert(key != NULL);
+ assert(repl != NULL);
+ assert(rebl != NULL);
+ assert(now != NULL);
+
+ pthread_rwlock_wrlock(&dht.db.lock);
- if (resp_msg.n_contacts == 0) {
- tpm_inc(dht->tpm);
+ e = __dht_kv_find_entry(key);
+ if (e == NULL) {
+ pthread_rwlock_unlock(&dht.db.lock);
+ return;
+ }
+
+ list_for_each_safe(p, h, repl) {
+ struct val_entry * x;
+ v = list_entry(p, struct val_entry, next);
+ x = dht_entry_get_val(e, v->val);
+ if (x == NULL) {
+ log_err(KV_FMT " Not in vals.", KV_VAL(key, v->val));
continue;
}
- for (i = 0; i < resp_msg.n_contacts; ++i)
- dht_contact_msg__free_unpacked(resp_msg.contacts[i],
- NULL);
- free(resp_msg.contacts);
+ x->t_repl = now->tv_sec;
- tpm_inc(dht->tpm);
+ list_del(&v->next);
+ val_entry_destroy(v);
}
- return (void *) 0;
+ list_for_each_safe(p, h, rebl) {
+ struct val_entry * x;
+ v = list_entry(p, struct val_entry, next);
+ x = dht_entry_get_lval(e, v->val);
+ if (x == NULL) {
+ log_err(KV_FMT " Not in lvals.", KV_VAL(key, v->val));
+ continue;
+ }
+
+ x->t_repl = now->tv_sec;
+ if (v->t_exp > x->t_exp) {
+ x->t_exp = v->t_exp; /* update expiration time */
+ }
+
+ list_del(&v->next);
+ val_entry_destroy(v);
+ }
+
+ pthread_rwlock_unlock(&dht.db.lock);
}
-static void dht_post_packet(void * comp,
- struct shm_du_buff * sdb)
+static void __cleanup_value_list(void * o)
{
- struct cmd * cmd;
- struct dht * dht = (struct dht *) comp;
+ return value_list_destroy((struct list_head *) o);
+}
- if (dht_get_state(dht) == DHT_SHUTDOWN) {
-#ifndef __DHT_TEST__
- ipcp_sdb_release(sdb);
-#endif
- return;
+static void dht_kv_replicate_values(const uint8_t * key,
+ struct list_head * repl,
+ struct list_head * rebl)
+{
+ struct timespec now;
+ struct list_head * p;
+ struct list_head * h;
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ pthread_cleanup_push(__cleanup_value_list, repl);
+ pthread_cleanup_push(__cleanup_value_list, rebl);
+
+ list_for_each_safe(p, h, repl) {
+ struct val_entry * v;
+ v = list_entry(p, struct val_entry, next);
+ dht_kv_replicate_value(key, v, &now);
}
- cmd = malloc(sizeof(*cmd));
- if (cmd == NULL) {
- log_err("Command failed. Out of memory.");
+ list_for_each_safe(p, h, rebl) {
+ struct val_entry * v;
+ v = list_entry(p, struct val_entry, next);
+ dht_kv_republish_value(key, v, &now);
+ }
+
+ pthread_cleanup_pop(false);
+ pthread_cleanup_pop(false);
+
+ /* removes non-replicated items from the list */
+ dht_kv_update_replication_times(key, repl, rebl, &now);
+
+ if (list_is_empty(repl) && list_is_empty(rebl))
+ return;
+
+ log_warn(KEY_FMT " Failed to update replication times.", KEY_VAL(key));
+}
+
+static void dht_kv_replicate(void)
+{
+ struct list_head repl; /* list of values to replicate */
+ struct list_head rebl; /* list of local values to republish */
+ uint8_t * key;
+
+ key = dht_dup_key(dht.id.data); /* dist == 0 */
+ if (key == NULL) {
+ log_err("Replicate: Failed to duplicate DHT ID.");
return;
}
- cmd->sdb = sdb;
+ list_head_init(&repl);
+ list_head_init(&rebl);
- pthread_mutex_lock(&dht->mtx);
+ pthread_cleanup_push(free, key);
- list_add(&cmd->next, &dht->cmds);
+ while (dht_kv_next_values(key, &repl, &rebl) == 0) {
+ dht_kv_replicate_values(key, &repl, &rebl);
+ if (!list_is_empty(&repl)) {
+ log_warn(KEY_FMT " Replication items left.",
+ KEY_VAL(key));
+ value_list_destroy(&repl);
+ }
- pthread_cond_signal(&dht->cond);
+ if (!list_is_empty(&rebl)) {
+ log_warn(KEY_FMT " Republish items left.",
+ KEY_VAL(key));
+ value_list_destroy(&rebl);
+ }
+ }
- pthread_mutex_unlock(&dht->mtx);
+ pthread_cleanup_pop(true);
}
-void dht_destroy(void * dir)
+static void dht_kv_refresh_contacts(void)
{
- struct dht * dht;
struct list_head * p;
struct list_head * h;
+ struct list_head rl; /* refresh list */
+ struct timespec now;
- dht = (struct dht *) dir;
- if (dht == NULL)
- return;
+ list_head_init(&rl);
-#ifndef __DHT_TEST__
- tpm_stop(dht->tpm);
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- tpm_destroy(dht->tpm);
-#endif
- if (dht_get_state(dht) == DHT_RUNNING) {
- dht_set_state(dht, DHT_SHUTDOWN);
- pthread_cancel(dht->worker);
- pthread_join(dht->worker, NULL);
- }
+ pthread_rwlock_rdlock(&dht.db.lock);
- pthread_rwlock_wrlock(&dht->lock);
+ __dht_kv_bucket_refresh_list(dht.db.contacts.root, now.tv_sec, &rl);
- list_for_each_safe(p, h, &dht->cmds) {
- struct cmd * c = list_entry(p, struct cmd, next);
+ pthread_rwlock_unlock(&dht.db.lock);
+
+ list_for_each_safe(p, h, &rl) {
+ struct contact * c;
+ c = list_entry(p, struct contact, next);
+ log_dbg(PEER_FMT " Refreshing contact.",
+ PEER_VAL(c->id, c->addr));
+ dht_kv_query_contacts(c->id, NULL);
list_del(&c->next);
-#ifndef __DHT_TEST__
- ipcp_sdb_release(c->sdb);
-#endif
- free(c);
+ contact_destroy(c);
}
- list_for_each_safe(p, h, &dht->entries) {
- struct dht_entry * e = list_entry(p, struct dht_entry, next);
- list_del(&e->next);
- dht_entry_destroy(e);
- }
+ assert(list_is_empty(&rl));
+}
- list_for_each_safe(p, h, &dht->requests) {
- struct kad_req * r = list_entry(p, struct kad_req, next);
- list_del(&r->next);
- kad_req_destroy(r);
- }
+static void (*tasks[])(void) = {
+ dht_kv_check_contacts,
+ dht_kv_remove_expired_entries,
+ dht_kv_remove_expired_reqs,
+ dht_kv_replicate,
+ dht_kv_refresh_contacts,
+ NULL
+};
- list_for_each_safe(p, h, &dht->refs) {
- struct ref_entry * e = list_entry(p, struct ref_entry, next);
- list_del(&e->next);
- ref_entry_destroy(e);
+static void * work(void * o)
+{
+ struct timespec now = TIMESPEC_INIT_MS(1);
+ time_t intv;
+ size_t n; /* number of tasks */
+
+ n = sizeof(tasks) / sizeof(tasks[0]) - 1; /* last is NULL */
+
+ (void) o;
+
+ while (dht_kv_seed_bootstrap_peer() == -EAGAIN) {
+ ts_add(&now, &now, &now); /* exponential backoff */
+ if (now.tv_sec > 1) /* cap at 1 second */
+ now.tv_sec = 1;
+ nanosleep(&now, NULL);
}
- list_for_each_safe(p, h, &dht->lookups) {
- struct lookup * l = list_entry(p, struct lookup, next);
- list_del(&l->next);
- lookup_destroy(l);
+ intv = gcd(dht.t_expire, (dht.t_expire - DHT_N_REPUB * dht.t_repl));
+ intv = gcd(intv, gcd(dht.t_repl, dht.t_refresh)) / 2;
+ intv = MAX(1, intv / n);
+
+ log_dbg("DHT worker starting %ld seconds interval.", intv * n);
+
+ while (true) {
+ int i = 0;
+ while (tasks[i] != NULL) {
+ tasks[i++]();
+ sleep(intv);
+ }
}
- pthread_rwlock_unlock(&dht->lock);
+ return (void *) 0;
+}
- if (dht->buckets != NULL)
- bucket_destroy(dht->buckets);
+int dht_start(void)
+{
+ dht.state = DHT_RUNNING;
+
+ if (tpm_start(dht.tpm))
+ goto fail_tpm_start;
+
+#ifndef __DHT_TEST__
+ if (pthread_create(&dht.worker, NULL, work, NULL)) {
+ log_err("Failed to create DHT worker thread.");
+ goto fail_worker;
+ }
- bmp_destroy(dht->cookies);
+ dht.eid = dt_reg_comp(&dht, &dht_post_packet, DHT);
+ if ((int) dht.eid < 0) {
+ log_err("Failed to register DHT component.");
+ goto fail_reg;
+ }
+#else
+ (void) work;
+#endif
+ return 0;
+#ifndef __DHT_TEST__
+ fail_reg:
+ pthread_cancel(dht.worker);
+ pthread_join(dht.worker, NULL);
+ fail_worker:
+ tpm_stop(dht.tpm);
+#endif
+ fail_tpm_start:
+ dht.state = DHT_INIT;
+ return -1;
+}
- pthread_mutex_destroy(&dht->mtx);
+void dht_stop(void)
+{
+ assert(dht.state == DHT_RUNNING);
- pthread_rwlock_destroy(&dht->lock);
+#ifndef __DHT_TEST__
+ dt_unreg_comp(dht.eid);
- free(dht->id);
+ pthread_cancel(dht.worker);
+ pthread_join(dht.worker, NULL);
+#endif
+ tpm_stop(dht.tpm);
- free(dht);
+ dht.state = DHT_INIT;
}
-static void * join_thr(void * o)
+int dht_init(struct dir_dht_config * conf)
{
- struct join_info * info = (struct join_info *) o;
- struct lookup * lu;
- size_t retr = 0;
+ struct timespec now;
+ pthread_condattr_t cattr;
- assert(info);
+ assert(conf != NULL);
- while (kad_join(info->dht, info->addr)) {
- if (dht_get_state(info->dht) == DHT_SHUTDOWN) {
- log_dbg("DHT enrollment aborted.");
- goto finish;
- }
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
- if (retr++ == KAD_JOIN_RETR) {
- dht_set_state(info->dht, DHT_INIT);
- log_warn("DHT enrollment attempt failed.");
- goto finish;
- }
+#ifndef __DHT_TEST__
+ dht.id.len = ipcp_dir_hash_len();
+ dht.addr = addr_auth_address();
+#else
+ dht.id.len = DHT_TEST_KEY_LEN;
+ dht.addr = DHT_TEST_ADDR;
+#endif
+ dht.t0 = now.tv_sec;
+ dht.alpha = conf->params.alpha;
+ dht.k = conf->params.k;
+ dht.t_expire = conf->params.t_expire;
+ dht.t_refresh = conf->params.t_refresh;
+ dht.t_repl = conf->params.t_replicate;
+ dht.peer = conf->peer;
+
+ dht.magic = generate_cookie();
+
+ /* Send my address on enrollment */
+ conf->peer = dht.addr;
+
+ dht.id.data = generate_id();
+ if (dht.id.data == NULL) {
+ log_err("Failed to create DHT ID.");
+ goto fail_id;
+ }
- sleep(KAD_JOIN_INTV);
+ list_head_init(&dht.cmds.list);
+
+ if (pthread_mutex_init(&dht.cmds.mtx, NULL)) {
+ log_err("Failed to initialize command mutex.");
+ goto fail_cmds_mutex;
}
- dht_set_state(info->dht, DHT_RUNNING);
+ if (pthread_cond_init(&dht.cmds.cond, NULL)) {
+ log_err("Failed to initialize command condvar.");
+ goto fail_cmds_cond;
+ }
- lu = kad_lookup(info->dht, info->dht->id, KAD_FIND_NODE);
- if (lu != NULL)
- lookup_destroy(lu);
+ list_head_init(&dht.reqs.list);
+ dht.reqs.len = 0;
- finish:
- free(info);
+ if (pthread_mutex_init(&dht.reqs.mtx, NULL)) {
+ log_err("Failed to initialize request mutex.");
+ goto fail_reqs_mutex;
+ }
- return (void *) 0;
-}
+ if (pthread_condattr_init(&cattr)) {
+ log_err("Failed to initialize request condvar attributes.");
+ goto fail_cattr;
+ }
+#ifndef __APPLE__
+ if (pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK)) {
+ log_err("Failed to set request condvar clock.");
+ goto fail_cattr;
+ }
+#endif
+ if (pthread_cond_init(&dht.reqs.cond, &cattr)) {
+ log_err("Failed to initialize request condvar.");
+ goto fail_reqs_cond;
+ }
-static void handle_event(void * self,
- int event,
- const void * o)
-{
- struct dht * dht = (struct dht *) self;
+ list_head_init(&dht.db.kv.list);
+ dht.db.kv.len = 0;
+ dht.db.kv.vals = 0;
+ dht.db.kv.lvals = 0;
- if (event == NOTIFY_DT_CONN_ADD) {
- pthread_t thr;
- struct join_info * inf;
- struct conn * c = (struct conn *) o;
- struct timespec slack = TIMESPEC_INIT_MS(DHT_ENROLL_SLACK);
+ if (pthread_rwlock_init(&dht.db.lock, NULL)) {
+ log_err("Failed to initialize store rwlock.");
+ goto fail_rwlock;
+ }
- /* Give the pff some time to update for the new link. */
- nanosleep(&slack, NULL);
+ dht.db.contacts.root = bucket_create();
+ if (dht.db.contacts.root == NULL) {
+ log_err("Failed to create DHT buckets.");
+ goto fail_buckets;
+ }
- switch(dht_get_state(dht)) {
- case DHT_INIT:
- inf = malloc(sizeof(*inf));
- if (inf == NULL)
- break;
+ if (rib_reg(DHT, &r_ops) < 0) {
+ log_err("Failed to register DHT RIB operations.");
+ goto fail_rib_reg;
+ }
- inf->dht = dht;
- inf->addr = c->conn_info.addr;
-
- if (dht_set_state(dht, DHT_JOINING) == 0 ||
- dht_wait_running(dht)) {
- if (pthread_create(&thr, NULL, join_thr, inf)) {
- dht_set_state(dht, DHT_INIT);
- free(inf);
- return;
- }
- pthread_detach(thr);
- } else {
- free(inf);
- }
- break;
- case DHT_RUNNING:
- /*
- * FIXME: this lookup for effiency reasons
- * causes a SEGV when stressed with rapid
- * enrollments.
- * lu = kad_lookup(dht, dht->id, KAD_FIND_NODE);
- * if (lu != NULL)
- * lookup_destroy(lu);
- */
- break;
- default:
- break;
- }
+ dht.tpm = tpm_create(2, 1, dht_handle_packet, NULL);
+ if (dht.tpm == NULL) {
+ log_err("Failed to create TPM for DHT.");
+ goto fail_tpm_create;
}
+
+ if (dht_kv_update_contacts(dht.id.data, dht.addr) < 0)
+ log_warn("Failed to update contacts with DHT ID.");
+
+ pthread_condattr_destroy(&cattr);
+#ifndef __DHT_TEST__
+ log_info("DHT initialized.");
+ log_dbg(" ID: " HASH_FMT64 " [%zu bytes].",
+ HASH_VAL64(dht.id.data), dht.id.len);
+ log_dbg(" address: " ADDR_FMT32 ".", ADDR_VAL32(&dht.addr));
+ log_dbg(" peer: " ADDR_FMT32 ".", ADDR_VAL32(&dht.peer));
+ log_dbg(" magic cookie: " HASH_FMT64 ".", HASH_VAL64(&dht.magic));
+ log_info(" parameters: alpha=%u, k=%zu, t_expire=%ld, "
+ "t_refresh=%ld, t_replicate=%ld.",
+ dht.alpha, dht.k, dht.t_expire, dht.t_refresh, dht.t_repl);
+#endif
+ dht.state = DHT_INIT;
+
+ return 0;
+
+ fail_tpm_create:
+ rib_unreg(DHT);
+ fail_rib_reg:
+ bucket_destroy(dht.db.contacts.root);
+ fail_buckets:
+ pthread_rwlock_destroy(&dht.db.lock);
+ fail_rwlock:
+ pthread_cond_destroy(&dht.reqs.cond);
+ fail_reqs_cond:
+ pthread_condattr_destroy(&cattr);
+ fail_cattr:
+ pthread_mutex_destroy(&dht.reqs.mtx);
+ fail_reqs_mutex:
+ pthread_cond_destroy(&dht.cmds.cond);
+ fail_cmds_cond:
+ pthread_mutex_destroy(&dht.cmds.mtx);
+ fail_cmds_mutex:
+ freebuf(dht.id);
+ fail_id:
+ return -1;
}
-void * dht_create(void)
+void dht_fini(void)
{
- struct dht * dht;
+ struct list_head * p;
+ struct list_head * h;
- dht = malloc(sizeof(*dht));
- if (dht == NULL)
- goto fail_malloc;
+ rib_unreg(DHT);
- dht->buckets = NULL;
+ tpm_destroy(dht.tpm);
- list_head_init(&dht->entries);
- list_head_init(&dht->requests);
- list_head_init(&dht->refs);
- list_head_init(&dht->lookups);
- list_head_init(&dht->cmds);
+ pthread_mutex_lock(&dht.cmds.mtx);
- if (pthread_rwlock_init(&dht->lock, NULL))
- goto fail_rwlock;
+ list_for_each_safe(p, h, &dht.cmds.list) {
+ struct cmd * c = list_entry(p, struct cmd, next);
+ list_del(&c->next);
+ freebuf(c->cbuf);
+ free(c);
+ }
- if (pthread_mutex_init(&dht->mtx, NULL))
- goto fail_mutex;
+ pthread_mutex_unlock(&dht.cmds.mtx);
- if (pthread_cond_init(&dht->cond, NULL))
- goto fail_cond;
+ pthread_cond_destroy(&dht.cmds.cond);
+ pthread_mutex_destroy(&dht.cmds.mtx);
- dht->cookies = bmp_create(DHT_MAX_REQS, 1);
- if (dht->cookies == NULL)
- goto fail_bmp;
+ pthread_mutex_lock(&dht.reqs.mtx);
- dht->b = 0;
- 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;
+ list_for_each_safe(p, h, &dht.reqs.list) {
+ struct dht_req * r = list_entry(p, struct dht_req, next);
+ list_del(&r->next);
+ dht_req_destroy(r);
+ dht.reqs.len--;
+ }
- if (tpm_start(dht->tpm))
- goto fail_tpm_start;
+ pthread_mutex_unlock(&dht.reqs.mtx);
- dht->eid = dt_reg_comp(dht, &dht_post_packet, DHT);
- if ((int) dht->eid < 0)
- goto fail_tpm_start;
+ pthread_cond_destroy(&dht.reqs.cond);
+ pthread_mutex_destroy(&dht.reqs.mtx);
- if (notifier_reg(handle_event, dht))
- goto fail_notifier_reg;
-#else
- (void) handle_event;
- (void) dht_handle_packet;
- (void) dht_post_packet;
-#endif
- dht->state = DHT_INIT;
+ pthread_rwlock_wrlock(&dht.db.lock);
- return (void *) dht;
-#ifndef __DHT_TEST__
- fail_notifier_reg:
- tpm_stop(dht->tpm);
- fail_tpm_start:
- tpm_destroy(dht->tpm);
- fail_tpm_create:
- bmp_destroy(dht->cookies);
-#endif
- fail_bmp:
- pthread_cond_destroy(&dht->cond);
- fail_cond:
- pthread_mutex_destroy(&dht->mtx);
- fail_mutex:
- pthread_rwlock_destroy(&dht->lock);
- fail_rwlock:
- free(dht);
- fail_malloc:
- return NULL;
+ list_for_each_safe(p, h, &dht.db.kv.list) {
+ struct dht_entry * e = list_entry(p, struct dht_entry, next);
+ list_del(&e->next);
+ dht_entry_destroy(e);
+ dht.db.kv.len--;
+ }
+
+ if (dht.db.contacts.root != NULL)
+ bucket_destroy(dht.db.contacts.root);
+
+ pthread_rwlock_unlock(&dht.db.lock);
+
+ pthread_rwlock_destroy(&dht.db.lock);
+
+ assert(dht.db.kv.len == 0);
+ assert(dht.db.kv.vals == 0);
+ assert(dht.db.kv.lvals == 0);
+ assert(dht.reqs.len == 0);
+
+ freebuf(dht.id);
}
diff --git a/src/ipcpd/unicast/dir/dht.h b/src/ipcpd/unicast/dir/dht.h
index 311c6b23..852a5130 100644
--- a/src/ipcpd/unicast/dir/dht.h
+++ b/src/ipcpd/unicast/dir/dht.h
@@ -30,22 +30,19 @@
#include <stdint.h>
#include <sys/types.h>
-void * dht_create(void);
+int dht_init(struct dir_dht_config * conf);
-void dht_destroy(void * dir);
+void dht_fini(void);
-int dht_bootstrap(void * dir);
+int dht_start(void);
-int dht_reg(void * dir,
- const uint8_t * key);
+void dht_stop(void);
-int dht_unreg(void * dir,
- const uint8_t * key);
+int dht_reg(const uint8_t * key);
-uint64_t dht_query(void * dir,
- const uint8_t * key);
+int dht_unreg(const uint8_t * key);
-int dht_wait_running(void * dir);
+uint64_t dht_query(const uint8_t * key);
extern struct dir_ops dht_dir_ops;
diff --git a/src/ipcpd/unicast/dir/dht.proto b/src/ipcpd/unicast/dir/dht.proto
index 4c5b06db..ea74805f 100644
--- a/src/ipcpd/unicast/dir/dht.proto
+++ b/src/ipcpd/unicast/dir/dht.proto
@@ -27,19 +27,32 @@ message dht_contact_msg {
required uint64 addr = 2;
}
+message dht_find_req_msg {
+ required uint64 cookie = 1;
+ required bytes key = 2;
+}
+
+message dht_find_node_rsp_msg {
+ required uint64 cookie = 1;
+ required bytes key = 2;
+ repeated dht_contact_msg contacts = 3;
+}
+
+message dht_find_value_rsp_msg {
+ repeated bytes values = 1;
+}
+
+message dht_store_msg {
+ required bytes key = 1;
+ required bytes val = 2;
+ required uint32 exp = 3;
+}
+
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 dht_contact_msg contacts = 7;
- // enrolment parameters
- optional uint32 alpha = 8;
- optional uint32 b = 9;
- optional uint32 k = 10;
- optional uint32 t_expire = 11;
- optional uint32 t_refresh = 12;
- optional uint32 t_replicate = 13;
+ required uint32 code = 1;
+ required dht_contact_msg src = 2;
+ optional dht_store_msg store = 3;
+ optional dht_find_req_msg find = 4;
+ optional dht_find_node_rsp_msg node = 5;
+ optional dht_find_value_rsp_msg val = 6;
}
diff --git a/src/ipcpd/unicast/dir/ops.h b/src/ipcpd/unicast/dir/ops.h
index 6ff61ce6..8c6e5eb5 100644
--- a/src/ipcpd/unicast/dir/ops.h
+++ b/src/ipcpd/unicast/dir/ops.h
@@ -23,24 +23,20 @@
#ifndef OUROBOROS_IPCPD_UNICAST_DIR_OPS_H
#define OUROBOROS_IPCPD_UNICAST_DIR_OPS_H
-
struct dir_ops {
- void * (* create)(void);
+ int (* init)(void * config);
- void (* destroy)(void * dir);
+ void (* fini)(void);
- int (* bootstrap)(void * dir);
+ int (* start)(void);
- int (* reg)(void * dir,
- const uint8_t * hash);
+ void (* stop)(void);
- int (* unreg)(void * dir,
- const uint8_t * hash);
+ int (* reg)(const uint8_t * hash);
- uint64_t (* query)(void * dir,
- const uint8_t * hash);
+ int (* unreg)(const uint8_t * hash);
- int (* wait_running)(void * dir);
+ uint64_t (* query)(const uint8_t * hash);
};
#endif /* OUROBOROS_IPCPD_UNICAST_DIR_OPS_H */
diff --git a/src/ipcpd/unicast/dir/tests/CMakeLists.txt b/src/ipcpd/unicast/dir/tests/CMakeLists.txt
index c850e41d..f62ed993 100644
--- a/src/ipcpd/unicast/dir/tests/CMakeLists.txt
+++ b/src/ipcpd/unicast/dir/tests/CMakeLists.txt
@@ -28,7 +28,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/dir/tests/dht_test.c b/src/ipcpd/unicast/dir/tests/dht_test.c
index bea2c3e7..cb6b0f9f 100644
--- a/src/ipcpd/unicast/dir/tests/dht_test.c
+++ b/src/ipcpd/unicast/dir/tests/dht_test.c
@@ -4,7 +4,6 @@
* Unit tests of the DHT
*
* 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,76 +20,1906 @@
*/
#define __DHT_TEST__
-#define DHT_TEST_KEY_LEN 32
-#include "dht.c"
+#if defined(__linux__) || defined(__CYGWIN__)
+#define _DEFAULT_SOURCE
+#else
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+#include <ouroboros/test.h>
+#include <ouroboros/list.h>
+#include <ouroboros/utils.h>
-#include <pthread.h>
+#include "dht.pb-c.h"
+
+#include <assert.h>
+#include <inttypes.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
-#define CONTACTS 1000
+#define DHT_MAX_RAND_SIZE 64
+#define DHT_TEST_KEY_LEN 32
+#define DHT_TEST_ADDR 0x1234567890abcdefULL
-int dht_test(int argc,
- char ** argv)
+/* forward declare for use in the dht code */
+/* Packet sink for DHT tests */
+struct {
+ bool enabled;
+
+ struct list_head list;
+ size_t len;
+} sink;
+
+struct message {
+ struct list_head next;
+ void * msg;
+ uint64_t dst;
+};
+
+static int sink_send_msg(buffer_t * pkt,
+ uint64_t addr)
{
- struct dht * dht;
- uint8_t key[DHT_TEST_KEY_LEN];
- size_t i;
+ struct message * m;
- (void) argc;
- (void) argv;
+ assert(pkt != NULL);
+ assert(addr != 0);
+
+ assert(!list_is_empty(&sink.list) || sink.len == 0);
+
+ if (!sink.enabled)
+ goto finish;
+
+ m = malloc(sizeof(*m));
+ if (m == NULL) {
+ printf("Failed to malloc message.");
+ goto fail_malloc;
+ }
+
+ m->msg = dht_msg__unpack(NULL, pkt->len, pkt->data);
+ if (m->msg == NULL)
+ goto fail_unpack;
+
+ m->dst = addr;
+
+ list_add_tail(&m->next, &sink.list);
+
+ ++sink.len;
+ finish:
+ freebuf(*pkt);
+
+ return 0;
+ fail_unpack:
+ free(m);
+ fail_malloc:
+ freebuf(*pkt);
+ return -1;
+}
+
+#include "dht.c"
+
+/* Test helpers */
+
+static void sink_init(void)
+{
+ list_head_init(&sink.list);
+ sink.len = 0;
+ sink.enabled = true;
+}
+
+static void sink_clear(void)
+{
+ struct list_head * p;
+ struct list_head * h;
+
+ list_for_each_safe(p, h, &sink.list) {
+ struct message * m = list_entry(p, struct message, next);
+ list_del(&m->next);
+ dht_msg__free_unpacked((dht_msg_t *) m->msg, NULL);
+ free(m);
+ --sink.len;
+ }
+
+ assert(list_is_empty(&sink.list));
+}
+
+static void sink_fini(void)
+{
+ sink_clear();
+
+ assert(list_is_empty(&sink.list) || sink.len != 0);
+}
+
+static dht_msg_t * sink_read(void)
+{
+ struct message * m;
+ dht_msg_t * msg;
+
+ assert(!list_is_empty(&sink.list) || sink.len == 0);
+
+ if (list_is_empty(&sink.list))
+ return NULL;
+
+ m = list_first_entry(&sink.list, struct message, next);
+
+ --sink.len;
+
+ list_del(&m->next);
+
+ msg = m->msg;
+
+ free(m);
+
+ return (dht_msg_t *) msg;
+}
+
+static const buffer_t test_val = {
+ .data = (uint8_t *) "test_value",
+ .len = 10
+};
+
+static const buffer_t test_val2 = {
+ .data = (uint8_t *) "test_value_2",
+ .len = 12
+};
+
+static int random_value_len(buffer_t * b)
+{
+ assert(b != NULL);
+ assert(b->len > 0 && b->len <= DHT_MAX_RAND_SIZE);
+
+ b->data = malloc(b->len);
+ if (b->data == NULL)
+ goto fail_malloc;
+
+ random_buffer(b->data, b->len);
+
+ return 0;
+
+ fail_malloc:
+ return -ENOMEM;
+}
+
+static int random_value(buffer_t * b)
+{
+ assert(b != NULL);
+
+ b->len = rand() % DHT_MAX_RAND_SIZE + 1;
+
+ return random_value_len(b);
+}
+
+static int fill_dht_with_contacts(size_t n)
+{
+ size_t i;
+ uint8_t * id;
+
+ for (i = 0; i < n; i++) {
+ uint64_t addr = generate_cookie();
+ id = generate_id();
+ if (id == NULL)
+ goto fail_id;
+
+ if (dht_kv_update_contacts(id, addr) < 0)
+ goto fail_update;
+ free(id);
+ }
+
+ return 0;
+
+ fail_update:
+ free(id);
+ fail_id:
+ return -1;
+}
+
+static int fill_store_with_random_values(const uint8_t * key,
+ size_t len,
+ size_t n_values)
+{
+ buffer_t val;
+ struct timespec now;
+ size_t i;
+ uint8_t * _key;
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ for (i = 0; i < n_values; ++i) {
+ if (key != NULL)
+ _key = (uint8_t *) key;
+ else {
+ _key = generate_id();
+ if (_key == NULL)
+ goto fail_key;
+ }
+
+ if (len == 0)
+ val.len = rand() % DHT_MAX_RAND_SIZE + 1;
+ else
+ val.len = len;
+
+ if (random_value_len(&val) < 0)
+ goto fail_value;
+
+ if (dht_kv_store(_key, val, now.tv_sec + 10) < 0)
+ goto fail_store;
+
+ freebuf(val);
+ if (key == NULL)
+ free(_key);
+ }
+
+ return 0;
- dht = dht_create();
- if (dht == NULL) {
+ fail_store:
+ freebuf(val);
+ fail_value:
+ free(_key);
+ fail_key:
+ return -1;
+}
+
+static int random_contact_list(dht_contact_msg_t *** contacts,
+ size_t max)
+{
+ size_t i;
+
+ assert(contacts != NULL);
+ assert(max > 0);
+
+ *contacts = malloc(max * sizeof(**contacts));
+ if (*contacts == NULL)
+ goto fail_malloc;
+
+ for (i = 0; i < max; i++) {
+ (*contacts)[i] = malloc(sizeof(*(*contacts)[i]));
+ if ((*contacts)[i] == NULL)
+ goto fail_contacts;
+
+ dht_contact_msg__init((*contacts)[i]);
+
+ (*contacts)[i]->id.data = generate_id();
+ if ((*contacts)[i]->id.data == NULL)
+ goto fail_contact;
+
+ (*contacts)[i]->id.len = dht.id.len;
+ (*contacts)[i]->addr = generate_cookie();
+ }
+
+ return 0;
+
+ fail_contact:
+ dht_contact_msg__free_unpacked((*contacts)[i], NULL);
+ fail_contacts:
+ while (i-- > 0)
+ free((*contacts)[i]);
+ free(*contacts);
+ fail_malloc:
+ return -ENOMEM;
+}
+
+static void clear_contacts(dht_contact_msg_t ** contacts,
+ size_t len)
+{
+ size_t i;
+
+ assert(contacts != NULL);
+ if (*contacts == NULL)
+ return;
+
+ for (i = 0; i < len; ++i)
+ dht_contact_msg__free_unpacked((contacts)[i], NULL);
+
+ free(*contacts);
+ *contacts = NULL;
+}
+
+/* Start of actual tests */
+static struct dir_dht_config test_dht_config = {
+ .params = {
+ .alpha = 3,
+ .k = 8,
+ .t_expire = 86400,
+ .t_refresh = 900,
+ .t_replicate = 900
+ }
+};
+
+static int test_dht_init_fini(void)
+{
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_start_stop(void)
+{
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (dht_start() < 0) {
+ printf("Failed to start dht.\n");
+ goto fail_start;
+ }
+
+ dht_stop();
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_start:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_val_entry_create_destroy(void)
+{
+ struct val_entry * e;
+ struct timespec now;
+
+ TEST_START();
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ if (dht_init(&test_dht_config) < 0) {
printf("Failed to create dht.\n");
- return -1;
+ goto fail_init;
}
- dht_destroy(dht);
+ e = val_entry_create(test_val, now.tv_sec + 10);
+ if (e == NULL) {
+ printf("Failed to create val entry.\n");
+ goto fail_entry;
+ }
+
+ val_entry_destroy(e);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
- dht = dht_create();
- if (dht == NULL) {
- printf("Failed to re-create dht.\n");
- return -1;
+ fail_entry:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_entry_create_destroy(void)
+{
+ struct dht_entry * e;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
}
- if (dht_bootstrap(dht)) {
- printf("Failed to bootstrap dht.\n");
- dht_destroy(dht);
- return -1;
+ e = dht_entry_create(dht.id.data);
+ if (e == NULL) {
+ printf("Failed to create dht entry.\n");
+ goto fail_entry;
}
- dht_destroy(dht);
+ dht_entry_destroy(e);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_entry:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_entry_update_get_val(void)
+{
+ struct dht_entry * e;
+ struct val_entry * v;
+ struct timespec now;
+
+ TEST_START();
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ e = dht_entry_create(dht.id.data);
+ if (e == NULL) {
+ printf("Failed to create dht entry.\n");
+ goto fail_entry;
+ }
+
+ if (dht_entry_get_val(e, test_val) != NULL) {
+ printf("Found value in empty dht entry.\n");
+ goto fail_get;
+ }
+
+ if (dht_entry_update_val(e, test_val, now.tv_sec + 10) < 0) {
+ printf("Failed to update dht entry value.\n");
+ goto fail_get;
+ }
+
+ if (dht_entry_get_val(e, test_val2) != NULL) {
+ printf("Found value in dht entry with different key.\n");
+ goto fail_get;
+ }
+
+ v = dht_entry_get_val(e, test_val);
+ if (v == NULL) {
+ printf("Failed to get value from dht entry.\n");
+ goto fail_get;
+ }
+
+ if (v->val.len != test_val.len) {
+ printf("Length in dht entry does not match expected.\n");
+ goto fail_get;
+ }
+
+ if(memcmp(v->val.data, test_val.data, test_val.len) != 0) {
+ printf("Data in dht entry does not match expected.\n");
+ goto fail_get;
+ }
- dht = dht_create();
- if (dht == NULL) {
- printf("Failed to re-create dht.\n");
- return -1;
+ if (dht_entry_update_val(e, test_val, now.tv_sec + 15) < 0) {
+ printf("Failed to update exsting dht entry value.\n");
+ goto fail_get;
}
- if (dht_bootstrap(dht)) {
- printf("Failed to bootstrap dht.\n");
- dht_destroy(dht);
- return -1;
+ if (v->t_exp != now.tv_sec + 15) {
+ printf("Expiration time in dht entry value not updated.\n");
+ goto fail_get;
}
- for (i = 0; i < CONTACTS; ++i) {
- uint64_t addr;
- random_buffer(&addr, sizeof(addr));
- random_buffer(key, DHT_TEST_KEY_LEN);
- pthread_rwlock_wrlock(&dht->lock);
- if (dht_update_bucket(dht, key, addr)) {
- pthread_rwlock_unlock(&dht->lock);
- printf("Failed to update bucket.\n");
- dht_destroy(dht);
- return -1;
+ if (dht_entry_update_val(e, test_val, now.tv_sec + 5) < 0) {
+ printf("Failed to update existing dht entry value (5).\n");
+ goto fail_get;
+ }
+
+ if (v->t_exp != now.tv_sec + 15) {
+ printf("Expiration time in dht entry shortened.\n");
+ goto fail_get;
+ }
+
+ if (dht_entry_get_val(e, test_val) != v) {
+ printf("Wrong value in dht entry found after update.\n");
+ goto fail_get;
+ }
+
+ dht_entry_destroy(e);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_get:
+ dht_entry_destroy(e);
+ fail_entry:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_entry_update_get_lval(void)
+{
+ struct dht_entry * e;
+ struct val_entry * v;
+ struct timespec now;
+
+ TEST_START();
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ e = dht_entry_create(dht.id.data);
+ if (e == NULL) {
+ printf("Failed to create dht entry.\n");
+ goto fail_entry;
+ }
+
+ if (dht_entry_get_lval(e, test_val) != NULL) {
+ printf("Found value in empty dht entry.\n");
+ goto fail_get;
+ }
+
+ if (dht_entry_update_lval(e, test_val) < 0) {
+ printf("Failed to update dht entry value.\n");
+ goto fail_get;
+ }
+
+ v = dht_entry_get_lval(e, test_val);
+ if (v== NULL) {
+ printf("Failed to get value from dht entry.\n");
+ goto fail_get;
+ }
+
+ if (dht_entry_get_lval(e, test_val2) != NULL) {
+ printf("Found value in dht entry in vals.\n");
+ goto fail_get;
+ }
+
+ if (v->val.len != test_val.len) {
+ printf("Length in dht entry does not match expected.\n");
+ goto fail_get;
+ }
+
+ if(memcmp(v->val.data, test_val.data, test_val.len) != 0) {
+ printf("Data in dht entry does not match expected.\n");
+ goto fail_get;
+ }
+
+ if (dht_entry_update_lval(e, test_val) < 0) {
+ printf("Failed to update existing dht entry value.\n");
+ goto fail_get;
+ }
+
+ if (dht_entry_get_lval(e, test_val) != v) {
+ printf("Wrong value in dht entry found after update.\n");
+ goto fail_get;
+ }
+
+ dht_entry_destroy(e);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_get:
+ dht_entry_destroy(e);
+ fail_entry:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_contact_create_destroy(void)
+{
+ struct contact * c;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ c = contact_create(dht.id.data, dht.addr);
+ if (c == NULL) {
+ printf("Failed to create contact.\n");
+ goto fail_contact;
+ }
+
+ contact_destroy(c);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_contact:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_update_bucket(void)
+{
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (fill_dht_with_contacts(1000) < 0) {
+ printf("Failed to fill bucket with contacts.\n");
+ goto fail_update;
+ }
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_update:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_contact_list(void)
+{
+ struct list_head cl;
+ ssize_t len;
+ ssize_t items;
+
+ TEST_START();
+
+ list_head_init(&cl);
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ items = 5;
+
+ if (fill_dht_with_contacts(items) < 0) {
+ printf("Failed to fill bucket with contacts.\n");
+ goto fail_fill;
+ }
+
+ len = dht_kv_contact_list(dht.id.data, &cl, dht.k);
+ if (len < 0) {
+ printf("Failed to get contact list.\n");
+ goto fail_fill;
+ }
+
+ if (len != items) {
+ printf("Failed to get contacts (%zu != %zu).\n", len, items);
+ goto fail_contact_list;
+ }
+
+ contact_list_destroy(&cl);
+
+ items = 100;
+
+ if (fill_dht_with_contacts(items) < 0) {
+ printf("Failed to fill bucket with contacts.\n");
+ goto fail_fill;
+ }
+
+ len = dht_kv_contact_list(dht.id.data, &cl, items);
+ if (len < 0) {
+ printf("Failed to get contact list.\n");
+ goto fail_fill;
+ }
+
+ if ((size_t) len < dht.k) {
+ printf("Failed to get contacts (%zu < %zu).\n", len, dht.k);
+ goto fail_contact_list;
+ }
+
+ contact_list_destroy(&cl);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_contact_list:
+ contact_list_destroy(&cl);
+ fail_fill:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_get_values(void)
+{
+ buffer_t * vals;
+ ssize_t len;
+ size_t n = sizeof(uint64_t);
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (fill_store_with_random_values(dht.id.data, n, 3) < 0) {
+ printf("Failed to fill store with random values.\n");
+ goto fail_fill;
+ }
+
+ len = dht_kv_retrieve(dht.id.data, &vals);
+ if (len < 0) {
+ printf("Failed to get values from store.\n");
+ goto fail_fill;
+ }
+
+ if (len != 3) {
+ printf("Failed to get %ld values (%zu).\n", 3L, len);
+ goto fail_get_values;
+ }
+
+ freebufs(vals, len);
+
+ if (fill_store_with_random_values(dht.id.data, n, 20) < 0) {
+ printf("Failed to fill store with random values.\n");
+ goto fail_fill;
+ }
+
+ len = dht_kv_retrieve(dht.id.data, &vals);
+ if (len < 0) {
+ printf("Failed to get values from store.\n");
+ goto fail_fill;
+ }
+
+ if (len != DHT_MAX_VALS) {
+ printf("Failed to get %d values.\n", DHT_MAX_VALS);
+ goto fail_get_values;
+ }
+
+ freebufs(vals, len);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_get_values:
+ freebufs(vals, len);
+ fail_fill:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_find_node_req_msg(void)
+{
+ dht_msg_t * msg;
+ dht_msg_t * upk;
+ size_t len;
+ uint8_t * buf;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ msg = dht_kv_find_node_req_msg(dht.id.data);
+ if (msg == NULL) {
+ printf("Failed to get find node request message.\n");
+ goto fail_msg;
+ }
+
+ if (msg->code != DHT_FIND_NODE_REQ) {
+ printf("Wrong code in find_node_req message (%s != %s).\n",
+ dht_code_str[msg->code],
+ dht_code_str[DHT_FIND_NODE_REQ]);
+ goto fail_msg;
+ }
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ printf("Failed to get packed length of find_node_req.\n");
+ goto fail_msg;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ printf("Failed to malloc find_node_req buf.\n");
+ goto fail_msg;
+ }
+
+ if (dht_msg__pack(msg, buf) != len) {
+ printf("Failed to pack find_node_req message.\n");
+ goto fail_pack;
+ }
+
+ upk = dht_msg__unpack(NULL, len, buf);
+ if (upk == NULL) {
+ printf("Failed to unpack find_value_req message.\n");
+ goto fail_unpack;
+ }
+
+ free(buf);
+ dht_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(upk, NULL);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_unpack:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_pack:
+ free(buf);
+ fail_msg:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_find_node_rsp_msg(void)
+{
+ dht_contact_msg_t ** contacts;
+ dht_msg_t * msg;
+ dht_msg_t * upk;
+ size_t len;
+ uint8_t * buf;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ msg = dht_kv_find_node_rsp_msg(dht.id.data, 0, &contacts, 0);
+ if (msg == NULL) {
+ printf("Failed to get find node response message.\n");
+ goto fail_msg;
+ }
+
+ if (msg->code != DHT_FIND_NODE_RSP) {
+ printf("Wrong code in find_node_rsp message (%s != %s).\n",
+ dht_code_str[msg->code],
+ dht_code_str[DHT_FIND_NODE_RSP]);
+ goto fail_msg;
+ }
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ printf("Failed to get packed length of find_node_rsp.\n");
+ goto fail_msg;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ printf("Failed to malloc find_node_rsp buf.\n");
+ goto fail_msg;
+ }
+
+ if (dht_msg__pack(msg, buf) != len) {
+ printf("Failed to pack find_node_rsp message.\n");
+ goto fail_pack;
+ }
+
+ upk = dht_msg__unpack(NULL, len, buf);
+ if (upk == NULL) {
+ printf("Failed to unpack find_node_rsp message.\n");
+ goto fail_unpack;
+ }
+
+ free(buf);
+ dht_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(upk, NULL);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_unpack:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_pack:
+ free(buf);
+ fail_msg:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_find_node_rsp_msg_contacts(void)
+{
+ dht_contact_msg_t ** contacts;
+ dht_msg_t * msg;
+ dht_msg_t * upk;
+ uint8_t * buf;
+ size_t len;
+ ssize_t n;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (fill_dht_with_contacts(100) < 0) {
+ printf("Failed to fill bucket with contacts.\n");
+ goto fail_fill;
+ }
+
+ n = dht_kv_get_contacts(dht.id.data, &contacts);
+ if (n < 0) {
+ printf("Failed to get contacts.\n");
+ goto fail_fill;
+ }
+
+ if ((size_t) n < dht.k) {
+ printf("Failed to get enough contacts (%zu < %zu).\n", n, dht.k);
+ goto fail_fill;
+ }
+
+ msg = dht_kv_find_node_rsp_msg(dht.id.data, 0, &contacts, n);
+ if (msg == NULL) {
+ printf("Failed to build find node response message.\n");
+ goto fail_msg;
+ }
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ printf("Failed to get packed length of find_node_rsp.\n");
+ goto fail_msg;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ printf("Failed to malloc find_node_rsp buf.\n");
+ goto fail_msg;
+ }
+
+ if (dht_msg__pack(msg, buf) != len) {
+ printf("Failed to pack find_node_rsp message.\n");
+ goto fail_pack;
+ }
+
+ upk = dht_msg__unpack(NULL, len, buf);
+ if (upk == NULL) {
+ printf("Failed to unpack find_node_rsp message.\n");
+ goto fail_unpack;
+ }
+
+ free(buf);
+ dht_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(upk, NULL);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_unpack:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_pack:
+ free(buf);
+ fail_msg:
+ clear_contacts(contacts, n);
+ fail_fill:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_find_value_req_msg(void)
+{
+ dht_msg_t * msg;
+ dht_msg_t * upk;
+ size_t len;
+ uint8_t * buf;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ msg = dht_kv_find_value_req_msg(dht.id.data);
+ if (msg == NULL) {
+ printf("Failed to build find value request message.\n");
+ goto fail_msg;
+ }
+
+ if (msg->code != DHT_FIND_VALUE_REQ) {
+ printf("Wrong code in find_value_req message (%s != %s).\n",
+ dht_code_str[msg->code],
+ dht_code_str[DHT_FIND_VALUE_REQ]);
+ goto fail_msg;
+ }
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ printf("Failed to get packed length of find_value_req.\n");
+ goto fail_msg;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ printf("Failed to malloc find_node_req buf.\n");
+ goto fail_msg;
+ }
+
+ if (dht_msg__pack(msg, buf) != len) {
+ printf("Failed to pack find_value_req message.\n");
+ goto fail_pack;
+ }
+
+ upk = dht_msg__unpack(NULL, len, buf);
+ if (upk == NULL) {
+ printf("Failed to unpack find_value_req message.\n");
+ goto fail_unpack;
+ }
+
+ free(buf);
+ dht_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(upk, NULL);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_unpack:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_pack:
+ free(buf);
+ fail_msg:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_find_value_rsp_msg(void)
+{
+ dht_msg_t * msg;
+ dht_msg_t * upk;
+ size_t len;
+ uint8_t * buf;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ msg = dht_kv_find_value_rsp_msg(dht.id.data, 0, NULL, 0, NULL, 0);
+ if (msg == NULL) {
+ printf("Failed to build find value response message.\n");
+ goto fail_msg;
+ }
+
+ if (msg->code != DHT_FIND_VALUE_RSP) {
+ printf("Wrong code in find_value_rsp message (%s != %s).\n",
+ dht_code_str[msg->code],
+ dht_code_str[DHT_FIND_VALUE_RSP]);
+ goto fail_msg;
+ }
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ printf("Failed to get packed length of find_value_rsp.\n");
+ goto fail_msg;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ printf("Failed to malloc find_value_rsp buf.\n");
+ goto fail_msg;
+ }
+
+ if (dht_msg__pack(msg, buf) != len) {
+ printf("Failed to pack find_value_rsp message.\n");
+ goto fail_pack;
+ }
+
+ upk = dht_msg__unpack(NULL, len, buf);
+ if (upk == NULL) {
+ printf("Failed to unpack find_value_rsp message.\n");
+ goto fail_unpack;
+ }
+
+ free(buf);
+ dht_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(upk, NULL);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_unpack:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_pack:
+ free(buf);
+ fail_msg:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_find_value_rsp_msg_contacts(void)
+{
+ dht_msg_t * msg;
+ dht_msg_t * upk;
+ size_t len;
+ uint8_t * buf;
+ dht_contact_msg_t ** contacts;
+ ssize_t n;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (fill_dht_with_contacts(100) < 0) {
+ printf("Failed to fill bucket with contacts.\n");
+ goto fail_fill;
+ }
+
+ n = dht_kv_get_contacts(dht.id.data, &contacts);
+ if (n < 0) {
+ printf("Failed to get contacts.\n");
+ goto fail_fill;
+ }
+
+ if ((size_t) n < dht.k) {
+ printf("Failed to get enough contacts (%zu < %zu).\n", n, dht.k);
+ goto fail_fill;
+ }
+
+ msg = dht_kv_find_value_rsp_msg(dht.id.data, 0, &contacts, n, NULL, 0);
+ if (msg == NULL) {
+ printf("Failed to build find value response message.\n");
+ goto fail_msg;
+ }
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ printf("Failed to get packed length of find_value_rsp.\n");
+ goto fail_msg;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ printf("Failed to malloc find_value_rsp buf.\n");
+ goto fail_msg;
+ }
+
+ if (dht_msg__pack(msg, buf) != len) {
+ printf("Failed to pack find_value_rsp message.\n");
+ goto fail_pack;
+ }
+
+ upk = dht_msg__unpack(NULL, len, buf);
+ if (upk == NULL) {
+ printf("Failed to unpack find_value_rsp message.\n");
+ goto fail_unpack;
+ }
+
+ free(buf);
+ dht_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(upk, NULL);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_unpack:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_pack:
+ free(buf);
+ fail_msg:
+ clear_contacts(contacts, n);
+ fail_fill:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_find_value_rsp_msg_values(void)
+{
+ dht_msg_t * msg;
+ dht_msg_t * upk;
+ size_t len;
+ uint8_t * buf;
+ buffer_t * values;
+ size_t i;
+ uint64_t ck;
+
+ TEST_START();
+
+ ck = generate_cookie();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ values = malloc(sizeof(*values) * 8);
+ if (values == NULL) {
+ printf("Failed to malloc values.\n");
+ goto fail_values;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (random_value(&values[i]) < 0) {
+ printf("Failed to create random value.\n");
+ goto fail_fill;
}
- pthread_rwlock_unlock(&dht->lock);
}
- dht_destroy(dht);
+ msg = dht_kv_find_value_rsp_msg(dht.id.data, ck, NULL, 0, &values, 8);
+ if (msg == NULL) {
+ printf("Failed to build find value response message.\n");
+ goto fail_msg;
+ }
- return 0;
+ values = NULL; /* msg owns the values now */
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ printf("Failed to get packed length of find_value_rsp.\n");
+ goto fail_msg;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ printf("Failed to malloc find_value_rsp buf.\n");
+ goto fail_msg;
+ }
+
+ if (dht_msg__pack(msg, buf) != len) {
+ printf("Failed to pack find_value_rsp message.\n");
+ goto fail_pack;
+ }
+
+ upk = dht_msg__unpack(NULL, len, buf);
+ if (upk == NULL) {
+ printf("Failed to unpack find_value_rsp message.\n");
+ goto fail_unpack;
+ }
+
+ if (upk->code != DHT_FIND_VALUE_RSP) {
+ printf("Wrong code in find_value_rsp message (%s != %s).\n",
+ dht_code_str[upk->code],
+ dht_code_str[DHT_FIND_VALUE_RSP]);
+ goto fail_unpack;
+ }
+
+ if (upk->val == NULL) {
+ printf("No values in find_value_rsp message.\n");
+ goto fail_unpack;
+ }
+
+ if (upk->val->n_values != 8) {
+ printf("Not enough values in find_value_rsp (%zu != %lu).\n",
+ upk->val->n_values, 8UL);
+ goto fail_unpack;
+ }
+
+ free(buf);
+ dht_msg__free_unpacked(msg, NULL);
+ dht_msg__free_unpacked(upk, NULL);
+
+ free(values);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_unpack:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_pack:
+ free(buf);
+ fail_msg:
+ fail_fill:
+ while((i--) > 0)
+ freebuf(values[i]);
+ free(values);
+ fail_values:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_store_msg(void)
+{
+ dht_msg_t * msg;
+ size_t len;
+ uint8_t * buf;
+ struct timespec now;
+
+ TEST_START();
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ msg = dht_kv_store_msg(dht.id.data, test_val, now.tv_sec + 10);
+ if (msg == NULL) {
+ printf("Failed to get store message.\n");
+ goto fail_msg;
+ }
+
+ if (msg->code != DHT_STORE) {
+ printf("Wrong code in store message (%s != %s).\n",
+ dht_code_str[msg->code],
+ dht_code_str[DHT_STORE]);
+ goto fail_store_msg;
+ }
+
+ if (dht_kv_validate_msg(msg) < 0) {
+ printf("Failed to validate store message.\n");
+ goto fail_store_msg;
+ }
+
+ len = dht_msg__get_packed_size(msg);
+ if (len == 0) {
+ printf("Failed to get packed msg length.\n");
+ goto fail_msg;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ printf("Failed to malloc store msg buf.\n");
+ goto fail_msg;
+ }
+
+ if (dht_msg__pack(msg, buf) != len) {
+ printf("Failed to pack store message.\n");
+ goto fail_pack;
+ }
+
+ free(buf);
+
+ dht_msg__free_unpacked(msg, NULL);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_pack:
+ free(buf);
+ fail_store_msg:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_kv_query_contacts_req_rsp(void)
+{
+ dht_msg_t * req;
+ dht_msg_t * rsp;
+ dht_contact_msg_t ** contacts;
+ size_t len = 2;
+
+ uint8_t * key;
+
+ TEST_START();
+
+ sink_init();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (fill_dht_with_contacts(1) < 0) {
+ printf("Failed to fill bucket with contacts.\n");
+ goto fail_prep;
+ }
+
+ key = generate_id();
+ if (key == NULL) {
+ printf("Failed to generate key.\n");
+ goto fail_prep;
+ }
+
+ if (dht_kv_query_contacts(key, NULL) < 0) {
+ printf("Failed to query contacts.\n");
+ goto fail_query;
+ }
+
+ req = sink_read();
+ if (req == NULL) {
+ printf("Failed to read request from sink.\n");
+ goto fail_query;
+ }
+
+ if (dht_kv_validate_msg(req) < 0) {
+ printf("Failed to validate find node req.\n");
+ goto fail_val_req;
+ }
+
+ if (random_contact_list(&contacts, len) < 0) {
+ printf("Failed to create random contact.\n");
+ goto fail_val_req;
+ }
+
+ rsp = dht_kv_find_node_rsp_msg(key, req->find->cookie, &contacts, len);
+ if (rsp == NULL) {
+ printf("Failed to create find node response message.\n");
+ goto fail_rsp;
+ }
+
+ memcpy(rsp->src->id.data, dht.id.data, dht.id.len);
+ rsp->src->addr = generate_cookie();
+
+ if (dht_kv_validate_msg(rsp) < 0) {
+ printf("Failed to validate find node response message.\n");
+ goto fail_val_rsp;
+ }
+
+ do_dht_kv_find_node_rsp(rsp->node);
+
+ /* dht_contact_msg__free_unpacked(contacts[0], NULL); set to NULL */
+
+ free(contacts);
+
+ dht_msg__free_unpacked(rsp, NULL);
+
+ free(key);
+
+ dht_msg__free_unpacked(req, NULL);
+
+ sink_fini();
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_val_rsp:
+ dht_msg__free_unpacked(rsp, NULL);
+ fail_rsp:
+ while (len-- > 0)
+ dht_contact_msg__free_unpacked(contacts[len], NULL);
+ free(contacts);
+ fail_val_req:
+ dht_msg__free_unpacked(req, NULL);
+ fail_query:
+ free(key);
+ fail_prep:
+ dht_fini();
+ fail_init:
+ sink_fini();
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_req_create_destroy(void)
+{
+ struct dht_req * req;
+
+ TEST_START();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ req = dht_req_create(dht.id.data);
+ if (req == NULL) {
+ printf("Failed to create kad request.\n");
+ goto fail_req;
+ }
+
+ dht_req_destroy(req);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_req:
+ dht_fini();
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_reg_unreg(void)
+{
+ TEST_START();
+
+ sink_init();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (dht_reg(dht.id.data) < 0) {
+ printf("Failed to register own id.\n");
+ goto fail_reg;
+ }
+
+ if (sink.len != 0) {
+ printf("Packet sent without contacts!");
+ goto fail_msg;
+ }
+
+ if (dht_unreg(dht.id.data) < 0) {
+ printf("Failed to unregister own id.\n");
+ goto fail_msg;
+ }
+
+ dht_fini();
+
+ sink_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_msg:
+ dht_unreg(dht.id.data);
+ fail_reg:
+ dht_fini();
+ fail_init:
+ sink_fini();
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_reg_unreg_contacts(void)
+{
+ dht_msg_t * msg;
+
+ TEST_START();
+
+ sink_init();
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (fill_dht_with_contacts(4) < 0) {
+ printf("Failed to fill bucket with contacts.\n");
+ goto fail_reg;
+ }
+
+ if (dht_reg(dht.id.data) < 0) {
+ printf("Failed to register own id.\n");
+ goto fail_reg;
+ }
+
+ if (sink.len != dht.alpha) {
+ printf("Packet sent to too few contacts!\n");
+ goto fail_msg;
+ }
+
+ msg = sink_read();
+ if (msg == NULL) {
+ printf("Failed to read message from sink.\n");
+ goto fail_msg;
+ }
+
+ if (msg->code != DHT_STORE) {
+ printf("Wrong code in dht reg message (%s != %s).\n",
+ dht_code_str[msg->code],
+ dht_code_str[DHT_STORE]);
+ goto fail_validation;
+ }
+
+ if (dht_kv_validate_msg(msg) < 0) {
+ printf("Failed to validate dht message.\n");
+ goto fail_validation;
+ }
+
+ if (dht_unreg(dht.id.data) < 0) {
+ printf("Failed to unregister own id.\n");
+ goto fail_validation;
+ }
+
+ dht_msg__free_unpacked(msg, NULL);
+
+ dht_fini();
+
+ sink_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_validation:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_msg:
+ sink_clear();
+ dht_unreg(dht.id.data);
+ fail_reg:
+ dht_fini();
+ fail_init:
+ sink_fini();
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_reg_query_local(void)
+{
+ struct timespec now;
+ buffer_t test_addr;
+
+ TEST_START();
+
+ clock_gettime(CLOCK_REALTIME_COARSE, &now);
+
+ if (addr_to_buf(1234321, &test_addr) < 0) {
+ printf("Failed to convert test address to buffer.\n");
+ goto fail_buf;
+ }
+
+ if (dht_init(&test_dht_config) < 0) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (dht_reg(dht.id.data) < 0) {
+ printf("Failed to register own id.\n");
+ goto fail_reg;
+ }
+
+ if (dht_query(dht.id.data) == dht.addr) {
+ printf("Succeeded to query own id.\n");
+ goto fail_get;
+ }
+
+ if (dht_kv_store(dht.id.data, test_addr, now.tv_sec + 5) < 0) {
+ printf("Failed to publish value.\n");
+ goto fail_get;
+ }
+
+ if (dht_query(dht.id.data) != 1234321) {
+ printf("Failed to return remote addr.\n");
+ goto fail_get;
+ }
+
+ if (dht_unreg(dht.id.data) < 0) {
+ printf("Failed to unregister own id.\n");
+ goto fail_get;
+ }
+
+ freebuf(test_addr);
+
+ dht_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_get:
+ dht_unreg(dht.id.data);
+ fail_reg:
+ dht_fini();
+ fail_init:
+ freebuf(test_addr);
+ fail_buf:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_query(void)
+{
+ uint8_t * key;
+ struct dir_dht_config cfg;
+
+ TEST_START();
+
+ sink_init();
+
+ cfg = test_dht_config;
+ cfg.peer = generate_cookie();
+
+ if (dht_init(&cfg)) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ key = generate_id();
+ if (key == NULL) {
+ printf("Failed to generate key.\n");
+ goto fail_key;
+ }
+
+ if (dht_query(key) != INVALID_ADDR) {
+ printf("Succeeded to get address without contacts.\n");
+ goto fail_get;
+ }
+
+ if (sink.len != 0) {
+ printf("Packet sent without contacts!");
+ goto fail_test;
+ }
+
+ free(key);
+
+ dht_fini();
+
+ sink_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_test:
+ sink_clear();
+ fail_get:
+ free(key);
+ fail_key:
+ dht_fini();
+ fail_init:
+ sink_fini();
+ return TEST_RC_FAIL;
+}
+
+static int test_dht_query_contacts(void)
+{
+ dht_msg_t * msg;
+ uint8_t * key;
+ struct dir_dht_config cfg;
+
+
+ TEST_START();
+
+ sink_init();
+
+ cfg = test_dht_config;
+ cfg.peer = generate_cookie();
+
+ if (dht_init(&cfg)) {
+ printf("Failed to create dht.\n");
+ goto fail_init;
+ }
+
+ if (fill_dht_with_contacts(10) < 0) {
+ printf("Failed to fill with contacts!");
+ goto fail_contacts;
+ }
+
+ key = generate_id();
+ if (key == NULL) {
+ printf("Failed to generate key.");
+ goto fail_contacts;
+ }
+
+ if (dht_query(key) != INVALID_ADDR) {
+ printf("Succeeded to get address for random id.\n");
+ goto fail_query;
+ }
+
+ msg = sink_read();
+ if (msg == NULL) {
+ printf("Failed to read message.!\n");
+ goto fail_read;
+ }
+
+ if (dht_kv_validate_msg(msg) < 0) {
+ printf("Failed to validate dht message.\n");
+ goto fail_msg;
+ }
+
+ if (msg->code != DHT_FIND_VALUE_REQ) {
+ printf("Failed to validate dht message.\n");
+ goto fail_msg;
+ }
+
+ dht_msg__free_unpacked(msg, NULL);
+
+ free(key);
+
+ sink_clear();
+
+ dht_fini();
+
+ sink_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_msg:
+ dht_msg__free_unpacked(msg, NULL);
+ fail_read:
+ sink_clear();
+ fail_query:
+ free(key);
+ fail_contacts:
+ dht_fini();
+ fail_init:
+ sink_fini();
+ return TEST_RC_FAIL;
+}
+
+int dht_test(int argc,
+ char ** argv)
+{
+ int rc = 0;
+
+ (void) argc;
+ (void) argv;
+
+ rc |= test_dht_init_fini();
+ rc |= test_dht_start_stop();
+ rc |= test_val_entry_create_destroy();
+ rc |= test_dht_entry_create_destroy();
+ rc |= test_dht_entry_update_get_val();
+ rc |= test_dht_entry_update_get_lval();
+ rc |= test_dht_kv_contact_create_destroy();
+ rc |= test_dht_kv_contact_list();
+ rc |= test_dht_kv_update_bucket();
+ rc |= test_dht_kv_get_values();
+ rc |= test_dht_kv_find_node_req_msg();
+ rc |= test_dht_kv_find_node_rsp_msg();
+ rc |= test_dht_kv_find_node_rsp_msg_contacts();
+ rc |= test_dht_kv_query_contacts_req_rsp();
+ rc |= test_dht_kv_find_value_req_msg();
+ rc |= test_dht_kv_find_value_rsp_msg();
+ rc |= test_dht_kv_find_value_rsp_msg_contacts();
+ rc |= test_dht_kv_find_value_rsp_msg_values();
+ rc |= test_dht_kv_store_msg();
+ rc |= test_dht_req_create_destroy();
+ rc |= test_dht_reg_unreg();
+ rc |= test_dht_reg_unreg_contacts();
+ rc |= test_dht_reg_query_local();
+ rc |= test_dht_query();
+ rc |= test_dht_query_contacts();
+
+ return rc;
}
diff --git a/src/ipcpd/unicast/dt.c b/src/ipcpd/unicast/dt.c
index 2bb5ed2f..e2679ffe 100644
--- a/src/ipcpd/unicast/dt.c
+++ b/src/ipcpd/unicast/dt.c
@@ -41,6 +41,7 @@
#include <ouroboros/fccntl.h>
#endif
+#include "addr-auth.h"
#include "common/comp.h"
#include "common/connmgr.h"
#include "ca.h"
@@ -59,7 +60,7 @@
#include <assert.h>
#define QOS_BLOCK_LEN 672
-#define RIB_FILE_STRLEN (189 + QOS_BLOCK_LEN * QOS_CUBE_MAX)
+#define RIB_FILE_STRLEN (169 + RIB_TM_STRLEN + QOS_BLOCK_LEN * QOS_CUBE_MAX)
#define RIB_NAME_STRLEN 256
#ifndef CLOCK_REALTIME_COARSE
@@ -144,6 +145,8 @@ static void dt_pci_shrink(struct shm_du_buff * sdb)
struct {
struct psched * psched;
+ uint64_t addr;
+
struct pff * pff[QOS_CUBE_MAX];
struct routing_i * routing[QOS_CUBE_MAX];
#ifdef IPCP_FLOW_STATS
@@ -186,7 +189,7 @@ static int dt_rib_read(const char * path,
char str[QOS_BLOCK_LEN + 1];
char addrstr[20];
char * entry;
- char tmstr[20];
+ char tmstr[RIB_TM_STRLEN];
size_t rxqlen = 0;
size_t txqlen = 0;
struct tm * tm;
@@ -209,13 +212,13 @@ static int dt_rib_read(const char * path,
return 0;
}
- if (dt.stat[fd].addr == ipcpi.dt_addr)
+ if (dt.stat[fd].addr == dt.addr)
sprintf(addrstr, "%s", dt.comps[fd].name);
else
- sprintf(addrstr, "%" PRIu64, dt.stat[fd].addr);
+ sprintf(addrstr, ADDR_FMT32, ADDR_VAL32(&dt.stat[fd].addr));
- tm = localtime(&dt.stat[fd].stamp);
- strftime(tmstr, sizeof(tmstr), "%F %T", tm);
+ tm = gmtime(&dt.stat[fd].stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
if (fd >= PROG_RES_FDS) {
fccntl(fd, FLOWGRXQLEN, &rxqlen);
@@ -223,11 +226,11 @@ static int dt_rib_read(const char * path,
}
sprintf(buf,
- "Flow established at: %20s\n"
+ "Flow established at: %.*s\n"
"Endpoint address: %20s\n"
"Queued packets (rx): %20zu\n"
"Queued packets (tx): %20zu\n\n",
- tmstr, addrstr, rxqlen, txqlen);
+ RIB_TM_STRLEN - 1, tmstr, addrstr, rxqlen, txqlen);
for (i = 0; i < QOS_CUBE_MAX; ++i) {
sprintf(str,
"Qos cube %3d:\n"
@@ -285,48 +288,45 @@ static int dt_rib_readdir(char *** buf)
pthread_rwlock_rdlock(&dt.lock);
if (dt.n_flows < 1) {
- pthread_rwlock_unlock(&dt.lock);
- return 0;
+ *buf = NULL;
+ goto no_flows;
}
*buf = malloc(sizeof(**buf) * dt.n_flows);
- if (*buf == NULL) {
- pthread_rwlock_unlock(&dt.lock);
- return -ENOMEM;
- }
+ if (*buf == NULL)
+ goto fail_entries;
for (i = 0; i < PROG_MAX_FLOWS; ++i) {
pthread_mutex_lock(&dt.stat[i].lock);
if (dt.stat[i].stamp == 0) {
pthread_mutex_unlock(&dt.stat[i].lock);
- /* Optimization: skip unused res_fds. */
- if (i < PROG_RES_FDS)
- i = PROG_RES_FDS;
- continue;
+ break;
}
+ pthread_mutex_unlock(&dt.stat[i].lock);
+
sprintf(entry, "%zu", i);
(*buf)[idx] = malloc(strlen(entry) + 1);
- if ((*buf)[idx] == NULL) {
- while (idx-- > 0)
- free((*buf)[idx]);
- free(*buf);
- pthread_mutex_unlock(&dt.stat[i].lock);
- pthread_rwlock_unlock(&dt.lock);
- return -ENOMEM;
- }
+ if ((*buf)[idx] == NULL)
+ goto fail_entry;
strcpy((*buf)[idx++], entry);
- pthread_mutex_unlock(&dt.stat[i].lock);
}
- assert((size_t) idx == dt.n_flows);
-
+ no_flows:
pthread_rwlock_unlock(&dt.lock);
return idx;
+
+ fail_entry:
+ while (idx-- > 0)
+ free((*buf)[idx]);
+ free(*buf);
+ fail_entries:
+ pthread_rwlock_unlock(&dt.lock);
+ return -ENOMEM;
#else
(void) buf;
return 0;
@@ -454,7 +454,7 @@ static void packet_handler(int fd,
head = shm_du_buff_head(sdb);
dt_pci_des(head, &dt_pci);
- if (dt_pci.dst_addr != ipcpi.dt_addr) {
+ if (dt_pci.dst_addr != dt.addr) {
if (dt_pci.ttl == 0) {
log_dbg("TTL was zero.");
ipcp_sdb_release(sdb);
@@ -570,16 +570,22 @@ int dt_init(struct dt_config cfg)
int i;
int j;
char dtstr[RIB_NAME_STRLEN + 1];
- int pp;
+ enum pol_pff pp;
struct conn_info info;
memset(&info, 0, sizeof(info));
+ dt.addr = addr_auth_address();
+ if (dt.addr == INVALID_ADDR) {
+ log_err("Failed to get address");
+ return -1;
+ }
+
strcpy(info.comp_name, DT_COMP);
strcpy(info.protocol, DT_PROTO);
info.pref_version = 1;
info.pref_syntax = PROTO_FIXED;
- info.addr = ipcpi.dt_addr;
+ info.addr = dt.addr;
if (cfg.eid_size != 8) { /* only support 64 bits from now */
log_warn("Invalid EID size. Only 64 bit is supported.");
@@ -601,8 +607,7 @@ int dt_init(struct dt_config cfg)
goto fail_connmgr_comp_init;
}
- pp = routing_init(cfg.routing_type);
- if (pp < 0) {
+ if (routing_init(&cfg.routing, &pp) < 0) {
log_err("Failed to init routing.");
goto fail_routing;
}
@@ -647,7 +652,7 @@ int dt_init(struct dt_config cfg)
dt.n_flows = 0;
#endif
- sprintf(dtstr, "%s.%" PRIu64, DT, ipcpi.dt_addr);
+ sprintf(dtstr, "%s." ADDR_FMT32, DT, ADDR_VAL32(&dt.addr));
if (rib_reg(dtstr, &r_ops)) {
log_err("Failed to register RIB.");
goto fail_rib_reg;
@@ -683,7 +688,7 @@ void dt_fini(void)
char dtstr[RIB_NAME_STRLEN + 1];
int i;
- sprintf(dtstr, "%s.%" PRIu64, DT, ipcpi.dt_addr);
+ sprintf(dtstr, "%s.%" PRIu64, DT, dt.addr);
rib_unreg(dtstr);
#ifdef IPCP_FLOW_STATS
for (i = 0; i < PROG_MAX_FLOWS; ++i)
@@ -719,21 +724,31 @@ int dt_start(void)
if (pthread_create(&dt.listener, NULL, dt_conn_handle, NULL)) {
log_err("Failed to create listener thread.");
- psched_destroy(dt.psched);
- return -1;
+ goto fail_listener;
+ }
+
+ if (routing_start() < 0) {
+ log_err("Failed to start routing.");
+ goto fail_routing;
}
return 0;
+ fail_routing:
+ pthread_cancel(dt.listener);
+ pthread_join(dt.listener, NULL);
+ fail_listener:
+ notifier_unreg(&handle_event);
fail_notifier_reg:
psched_destroy(dt.psched);
fail_psched:
return -1;
-
}
void dt_stop(void)
{
+ routing_stop();
+
pthread_cancel(dt.listener);
pthread_join(dt.listener, NULL);
@@ -748,7 +763,7 @@ int dt_reg_comp(void * comp,
{
int eid;
- assert(func);
+ assert(func != NULL);
pthread_rwlock_wrlock(&dt.lock);
@@ -769,11 +784,28 @@ int dt_reg_comp(void * comp,
pthread_rwlock_unlock(&dt.lock);
#ifdef IPCP_FLOW_STATS
- stat_used(eid, ipcpi.dt_addr);
+ stat_used(eid, dt.addr);
#endif
return eid;
}
+void dt_unreg_comp(int eid)
+{
+ assert(eid >= 0 && eid < PROG_RES_FDS);
+
+ pthread_rwlock_wrlock(&dt.lock);
+
+ assert(dt.comps[eid].post_packet != NULL);
+
+ dt.comps[eid].post_packet = NULL;
+ dt.comps[eid].comp = NULL;
+ dt.comps[eid].name = NULL;
+
+ pthread_rwlock_unlock(&dt.lock);
+
+ return;
+}
+
int dt_write_packet(uint64_t dst_addr,
qoscube_t qc,
uint64_t eid,
@@ -786,7 +818,7 @@ int dt_write_packet(uint64_t dst_addr,
size_t len;
assert(sdb);
- assert(dst_addr != ipcpi.dt_addr);
+ assert(dst_addr != dt.addr);
len = shm_du_buff_len(sdb);
@@ -802,7 +834,8 @@ int dt_write_packet(uint64_t dst_addr,
#endif
fd = pff_nhop(dt.pff[qc], dst_addr);
if (fd < 0) {
- log_dbg("Could not get nhop for addr %" PRIu64 ".", dst_addr);
+ log_dbg("Could not get nhop for " ADDR_FMT32 ".",
+ ADDR_VAL32(&dst_addr));
#ifdef IPCP_FLOW_STATS
if (eid < PROG_RES_FDS) {
pthread_mutex_lock(&dt.stat[eid].lock);
diff --git a/src/ipcpd/unicast/dt.h b/src/ipcpd/unicast/dt.h
index 7198a013..2c5b7978 100644
--- a/src/ipcpd/unicast/dt.h
+++ b/src/ipcpd/unicast/dt.h
@@ -39,9 +39,11 @@ int dt_start(void);
void dt_stop(void);
-int dt_reg_comp(void * comp,
+int dt_reg_comp(void * comp,
void (* func)(void * comp, struct shm_du_buff * sdb),
- char * name);
+ char * name);
+
+void dt_unreg_comp(int eid);
int dt_write_packet(uint64_t dst_addr,
qoscube_t qc,
diff --git a/src/ipcpd/unicast/fa.c b/src/ipcpd/unicast/fa.c
index 3631fd7b..ac168bd9 100644
--- a/src/ipcpd/unicast/fa.c
+++ b/src/ipcpd/unicast/fa.c
@@ -41,6 +41,7 @@
#include <ouroboros/random.h>
#include <ouroboros/pthread.h>
+#include "addr-auth.h"
#include "dir.h"
#include "fa.h"
#include "psched.h"
@@ -69,17 +70,15 @@ struct fa_msg {
uint64_t s_addr;
uint64_t r_eid;
uint64_t s_eid;
- uint8_t code;
- int8_t response;
- uint16_t ece;
- /* QoS parameters from spec, aligned */
- uint32_t delay;
uint64_t bandwidth;
+ int32_t response;
+ uint32_t delay;
uint32_t loss;
uint32_t ber;
uint32_t max_gap;
uint32_t timeout;
- uint16_t cypher_s;
+ uint16_t ece;
+ uint8_t code;
uint8_t availability;
uint8_t in_order;
} __attribute__((packed));
@@ -135,7 +134,7 @@ static int fa_rib_read(const char * path,
char r_addrstr[21];
char s_eidstr[21];
char r_eidstr[21];
- char tmstr[20];
+ char tmstr[RIB_TM_STRLEN];
char castr[1024];
char * entry;
struct tm * tm;
@@ -166,8 +165,8 @@ static int fa_rib_read(const char * path,
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);
+ tm = gmtime(&flow->stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
ca_print_stats(flow->ctx, castr, 1024);
@@ -217,15 +216,13 @@ static int fa_rib_readdir(char *** buf)
pthread_rwlock_rdlock(&fa.flows_lock);
if (fa.n_flows < 1) {
- pthread_rwlock_unlock(&fa.flows_lock);
- return 0;
+ *buf = NULL;
+ goto no_flows;
}
*buf = malloc(sizeof(**buf) * fa.n_flows);
- if (*buf == NULL) {
- pthread_rwlock_unlock(&fa.flows_lock);
- return -ENOMEM;
- }
+ if (*buf == NULL)
+ goto fail_entries;
for (i = 0; i < PROG_MAX_FLOWS; ++i) {
struct fa_flow * flow;
@@ -237,22 +234,25 @@ static int fa_rib_readdir(char *** buf)
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;
- }
+ if ((*buf)[idx] == NULL)
+ goto fail_entry;
strcpy((*buf)[idx++], entry);
}
assert((size_t) idx == fa.n_flows);
-
+ no_flows:
pthread_rwlock_unlock(&fa.flows_lock);
return idx;
+
+ fail_entry:
+ while (idx-- > 0)
+ free((*buf)[idx]);
+ free(*buf);
+ fail_entries:
+ pthread_rwlock_unlock(&fa.flows_lock);
+ return -ENOMEM;
#else
(void) buf;
return 0;
@@ -497,7 +497,6 @@ static int fa_handle_flow_req(struct fa_msg * msg,
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);
fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UNICAST_MPL, &data);
@@ -526,6 +525,7 @@ static int fa_handle_flow_reply(struct fa_msg * msg,
struct fa_flow * flow;
buffer_t data; /* Piggbacked data on flow alloc request. */
time_t mpl = IPCP_UNICAST_MPL;
+ int response;
assert(len >= sizeof(*msg));
@@ -545,15 +545,19 @@ static int fa_handle_flow_reply(struct fa_msg * msg,
flow = &fa.flows[fd];
flow->r_eid = ntoh64(msg->s_eid);
+ response = ntoh32(msg->response);
- if (msg->response < 0)
+ log_dbg("IPCP received msg response %d for flow on fd %d.",
+ response, fd);
+
+ if (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) {
+ if (ipcp_flow_alloc_reply(fd, response, mpl, &data) < 0) {
log_err("Failed to reply for flow allocation on fd %d.", fd);
return -EIRMD;
}
@@ -647,19 +651,21 @@ int fa_init(void)
if (pthread_cond_init(&fa.cond, &cattr))
goto fail_cond;
- pthread_condattr_destroy(&cattr);
-
- list_head_init(&fa.cmds);
-
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;
+ goto fail_dt_reg;
+
+ list_head_init(&fa.cmds);
+
+ pthread_condattr_destroy(&cattr);
return 0;
+ fail_dt_reg:
+ rib_unreg(FA);
fail_rib_reg:
pthread_cond_destroy(&fa.cond);
fail_cond:
@@ -669,7 +675,6 @@ int fa_init(void)
fail_mtx:
pthread_rwlock_destroy(&fa.flows_lock);
fail_rwlock:
-
return -1;
}
@@ -765,7 +770,7 @@ int fa_alloc(int fd,
msg->code = FLOW_REQ;
msg->s_eid = hton64(eid);
- msg->s_addr = hton64(ipcpi.dt_addr);
+ msg->s_addr = hton64(addr_auth_address());
msg->delay = hton32(qs.delay);
msg->bandwidth = hton64(qs.bandwidth);
msg->availability = qs.availability;
@@ -773,7 +778,6 @@ int fa_alloc(int fd,
msg->ber = hton32(qs.ber);
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());
@@ -825,7 +829,7 @@ int fa_alloc_resp(int fd,
memset(msg, 0, sizeof(*msg));
msg->code = FLOW_REPLY;
- msg->response = response;
+ msg->response = hton32(response);
if (data->len > 0)
memcpy(msg + 1, data->data, data->len);
@@ -842,7 +846,7 @@ int fa_alloc_resp(int fd,
}
if (response < 0) {
- pthread_rwlock_rdlock(&fa.flows_lock);
+ pthread_rwlock_wrlock(&fa.flows_lock);
fa_flow_fini(flow);
pthread_rwlock_unlock(&fa.flows_lock);
} else {
diff --git a/src/ipcpd/unicast/main.c b/src/ipcpd/unicast/main.c
index e6cb2994..7989d3e1 100644
--- a/src/ipcpd/unicast/main.c
+++ b/src/ipcpd/unicast/main.c
@@ -55,13 +55,8 @@
#include <assert.h>
#include <inttypes.h>
-struct ipcp ipcpi;
-
-static int initialize_components(const struct ipcp_config * conf)
+static int initialize_components(struct ipcp_config * conf)
{
- 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->unicast.addr_auth_type,
@@ -70,13 +65,7 @@ static int initialize_components(const struct ipcp_config * conf)
goto fail_addr_auth;
}
- ipcpi.dt_addr = addr_auth_address();
- if (ipcpi.dt_addr == 0) {
- log_err("Failed to get a valid address.");
- goto fail_addr_auth;
- }
-
- log_info("IPCP got address %" PRIu64 ".", ipcpi.dt_addr);
+ log_info("IPCP got address %" PRIu64 ".", addr_auth_address());
if (ca_init(conf->unicast.cong_avoid)) {
log_err("Failed to initialize congestion avoidance.");
@@ -88,23 +77,25 @@ static int initialize_components(const struct ipcp_config * conf)
goto fail_dt;
}
- if (fa_init()) {
- log_err("Failed to initialize flow allocator component.");
- goto fail_fa;
- }
+ ipcp_set_dir_hash_algo((enum hash_algo) conf->layer_info.dir_hash_algo);
- if (dir_init()) {
+ if (dir_init(&conf->unicast.dir)) {
log_err("Failed to initialize directory.");
goto fail_dir;
}
+ if (fa_init()) {
+ log_err("Failed to initialize flow allocator component.");
+ goto fail_fa;
+ }
+
ipcp_set_state(IPCP_INIT);
return 0;
- fail_dir:
- fa_fini();
fail_fa:
+ dir_fini();
+ fail_dir:
dt_fini();
fail_dt:
ca_fini();
@@ -116,10 +107,10 @@ static int initialize_components(const struct ipcp_config * conf)
static void finalize_components(void)
{
- dir_fini();
-
fa_fini();
+ dir_fini();
+
dt_fini();
ca_fini();
@@ -129,6 +120,11 @@ static void finalize_components(void)
static int start_components(void)
{
+ if (connmgr_start() < 0) {
+ log_err("Failed to start AP connection manager.");
+ goto fail_connmgr_start;
+ }
+
if (dt_start() < 0) {
log_err("Failed to start data transfer.");
goto fail_dt_start;
@@ -144,27 +140,29 @@ static int start_components(void)
goto fail_enroll_start;
}
- if (connmgr_start() < 0) {
- log_err("Failed to start AP connection manager.");
- goto fail_connmgr_start;
+ if (dir_start() < 0) {
+ log_err("Failed to start directory.");
+ goto fail_dir_start;
}
return 0;
- fail_connmgr_start:
+ fail_dir_start:
enroll_stop();
fail_enroll_start:
fa_stop();
fail_fa_start:
dt_stop();
fail_dt_start:
+ connmgr_stop();
+ fail_connmgr_start:
ipcp_set_state(IPCP_INIT);
return -1;
}
static void stop_components(void)
{
- connmgr_stop();
+ dir_stop();
enroll_stop();
@@ -172,24 +170,17 @@ static void stop_components(void)
dt_stop();
- ipcp_set_state(IPCP_INIT);
-}
-
-static int bootstrap_components(void)
-{
- if (dir_bootstrap()) {
- log_err("Failed to bootstrap directory.");
- return -1;
- }
+ connmgr_stop();
- return 0;
+ ipcp_set_state(IPCP_BOOT);
}
static int unicast_ipcp_enroll(const char * dst,
struct layer_info * info)
{
- struct conn conn;
- uint8_t id[ENROLL_ID_LEN];
+ struct ipcp_config * conf;
+ struct conn conn;
+ uint8_t id[ENROLL_ID_LEN];
if (random_buffer(id, ENROLL_ID_LEN) < 0) {
log_err("Failed to generate enrollment ID.");
@@ -209,7 +200,11 @@ static int unicast_ipcp_enroll(const char * dst,
goto fail_enroll_boot;
}
- if (initialize_components(enroll_get_conf()) < 0) {
+ conf = enroll_get_conf();
+
+ *info = conf->layer_info;
+
+ if (initialize_components(conf) < 0) {
log_err_id(id, "Failed to initialize components.");
goto fail_enroll_boot;
}
@@ -227,9 +222,6 @@ static int unicast_ipcp_enroll(const char * dst,
log_info_id(id, "Enrolled with %s.", dst);
- info->dir_hash_algo = (enum pol_dir_hash) ipcpi.dir_hash_algo;
- strcpy(info->name, ipcpi.layer_name);
-
return 0;
fail_start_comp:
@@ -240,32 +232,25 @@ static int unicast_ipcp_enroll(const char * dst,
return -1;
}
-static int unicast_ipcp_bootstrap(const struct ipcp_config * conf)
+static int unicast_ipcp_bootstrap(struct ipcp_config * conf)
{
assert(conf);
assert(conf->type == THIS_TYPE);
- enroll_bootstrap(conf);
-
if (initialize_components(conf) < 0) {
log_err("Failed to init IPCP components.");
goto fail_init;
}
+ enroll_bootstrap(conf);
+
if (start_components() < 0) {
log_err("Failed to init IPCP components.");
goto fail_start;
}
- if (bootstrap_components() < 0) {
- log_err("Failed to bootstrap IPCP components.");
- goto fail_bootstrap;
- }
-
return 0;
- fail_bootstrap:
- stop_components();
fail_start:
finalize_components();
fail_init:
@@ -323,11 +308,12 @@ int main(int argc,
if (ipcp_get_state() == IPCP_SHUTDOWN) {
stop_components();
+ ipcp_stop();
finalize_components();
+ } else {
+ ipcp_stop();
}
- ipcp_stop();
-
enroll_fini();
connmgr_fini();
diff --git a/src/ipcpd/unicast/pff/tests/CMakeLists.txt b/src/ipcpd/unicast/pff/tests/CMakeLists.txt
index e7082372..65705714 100644
--- a/src/ipcpd/unicast/pff/tests/CMakeLists.txt
+++ b/src/ipcpd/unicast/pff/tests/CMakeLists.txt
@@ -26,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/routing.c b/src/ipcpd/unicast/routing.c
index f5417c24..2ad7b234 100644
--- a/src/ipcpd/unicast/routing.c
+++ b/src/ipcpd/unicast/routing.c
@@ -30,31 +30,26 @@
struct routing_ops * r_ops;
-int routing_init(enum pol_routing pr)
+int routing_init(struct routing_config * conf,
+ enum pol_pff * pff_type)
{
- enum pol_pff pff_type;
+ void * cfg;
- switch (pr) {
+ switch (conf->pol) {
case ROUTING_LINK_STATE:
- pff_type = PFF_SIMPLE;
- r_ops = &link_state_ops;
- break;
- case ROUTING_LINK_STATE_LFA:
- pff_type = PFF_ALTERNATE;
- r_ops = &link_state_ops;
- break;
- case ROUTING_LINK_STATE_ECMP:
- pff_type=PFF_MULTIPATH;
r_ops = &link_state_ops;
+ cfg = &conf->ls;
break;
default:
return -ENOTSUP;
}
- if (r_ops->init(pr))
- return -1;
+ return r_ops->init(cfg, pff_type);
+}
- return pff_type;
+int routing_start(void)
+{
+ return r_ops->start();
}
struct routing_i * routing_i_create(struct pff * pff)
@@ -67,6 +62,11 @@ void routing_i_destroy(struct routing_i * instance)
return r_ops->routing_i_destroy(instance);
}
+void routing_stop(void)
+{
+ r_ops->stop();
+}
+
void routing_fini(void)
{
r_ops->fini();
diff --git a/src/ipcpd/unicast/routing.h b/src/ipcpd/unicast/routing.h
index d5d833ae..e14960b5 100644
--- a/src/ipcpd/unicast/routing.h
+++ b/src/ipcpd/unicast/routing.h
@@ -30,10 +30,15 @@
#include <stdint.h>
-int routing_init(enum pol_routing pr);
+int routing_init(struct routing_config * conf,
+ enum pol_pff * pff_type);
void routing_fini(void);
+int routing_start(void);
+
+void routing_stop(void);
+
struct routing_i * routing_i_create(struct pff * pff);
void routing_i_destroy(struct routing_i * instance);
diff --git a/src/ipcpd/unicast/routing/graph.c b/src/ipcpd/unicast/routing/graph.c
index 32f3e6fb..32442dad 100644
--- a/src/ipcpd/unicast/routing/graph.c
+++ b/src/ipcpd/unicast/routing/graph.c
@@ -57,8 +57,11 @@ struct edge {
};
struct graph {
- size_t nr_vertices;
- struct list_head vertices;
+ struct {
+ struct list_head list;
+ size_t len;
+ } vertices;
+
pthread_mutex_t lock;
};
@@ -67,7 +70,7 @@ static struct edge * find_edge_by_addr(struct vertex * vertex,
{
struct list_head * p;
- assert(vertex);
+ assert(vertex != NULL);
list_for_each(p, &vertex->edges) {
struct edge * e = list_entry(p, struct edge, next);
@@ -85,7 +88,7 @@ static struct vertex * find_vertex_by_addr(struct graph * graph,
assert(graph);
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
struct vertex * e = list_entry(p, struct vertex, next);
if (e->addr == addr)
return e;
@@ -99,8 +102,8 @@ static struct edge * add_edge(struct vertex * vertex,
{
struct edge * edge;
- assert(vertex);
- assert(nb);
+ assert(vertex != NULL);
+ assert(nb != NULL);
edge = malloc(sizeof(*edge));
if (edge == NULL)
@@ -139,7 +142,7 @@ static struct vertex * add_vertex(struct graph * graph,
vertex->addr = addr;
/* Keep them ordered on address. */
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
struct vertex * v = list_entry(p, struct vertex, next);
if (v->addr > addr)
break;
@@ -151,13 +154,13 @@ static struct vertex * add_vertex(struct graph * graph,
list_add_tail(&vertex->next, p);
/* Increase the index of the vertices to the right. */
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &vertex->next) {
struct vertex * v = list_entry(p, struct vertex, next);
if (v->addr > addr)
v->index++;
}
- graph->nr_vertices++;
+ ++graph->vertices.len;
return vertex;
}
@@ -168,13 +171,13 @@ static void del_vertex(struct graph * graph,
struct list_head * p;
struct list_head * h;
- assert(graph);
- assert(vertex);
+ assert(graph != NULL);
+ assert(vertex != NULL);
list_del(&vertex->next);
/* Decrease the index of the vertices to the right. */
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
struct vertex * v = list_entry(p, struct vertex, next);
if (v->addr > vertex->addr)
v->index--;
@@ -187,7 +190,7 @@ static void del_vertex(struct graph * graph,
free(vertex);
- graph->nr_vertices--;
+ --graph->vertices.len;
}
struct graph * graph_create(void)
@@ -203,8 +206,8 @@ struct graph * graph_create(void)
return NULL;
}
- graph->nr_vertices = 0;
- list_head_init(&graph->vertices);
+ graph->vertices.len = 0;
+ list_head_init(&graph->vertices.list);
return graph;
}
@@ -218,7 +221,7 @@ void graph_destroy(struct graph * graph)
pthread_mutex_lock(&graph->lock);
- list_for_each_safe(p, n, &graph->vertices) {
+ list_for_each_safe(p, n, &graph->vertices.list) {
struct vertex * e = list_entry(p, struct vertex, next);
del_vertex(graph, e);
}
@@ -227,6 +230,8 @@ void graph_destroy(struct graph * graph)
pthread_mutex_destroy(&graph->lock);
+ assert(graph->vertices.len == 0);
+
free(graph);
}
@@ -240,63 +245,35 @@ int graph_update_edge(struct graph * graph,
struct vertex * nb;
struct edge * nb_e;
- assert(graph);
+ assert(graph != NULL);
pthread_mutex_lock(&graph->lock);
v = find_vertex_by_addr(graph, s_addr);
- if (v == NULL) {
- v = add_vertex(graph, s_addr);
- if (v == NULL) {
- pthread_mutex_unlock(&graph->lock);
- log_err("Failed to add vertex.");
- return -ENOMEM;
- }
+ if (v == NULL && ((v = add_vertex(graph, s_addr)) == NULL)) {;
+ log_err("Failed to add src vertex.");
+ goto fail_add_s;
}
nb = find_vertex_by_addr(graph, d_addr);
- if (nb == NULL) {
- nb = add_vertex(graph, d_addr);
- if (nb == NULL) {
- if (list_is_empty(&v->edges))
- del_vertex(graph, v);
- pthread_mutex_unlock(&graph->lock);
- log_err("Failed to add vertex.");
- return -ENOMEM;
- }
+ if (nb == NULL && ((nb = add_vertex(graph, d_addr)) == NULL)) {
+ log_err("Failed to add dst vertex.");
+ goto fail_add_d;
}
e = find_edge_by_addr(v, d_addr);
- if (e == NULL) {
- e = add_edge(v, nb);
- if (e == NULL) {
- if (list_is_empty(&v->edges))
- del_vertex(graph, v);
- if (list_is_empty(&nb->edges))
- del_vertex(graph, nb);
- pthread_mutex_unlock(&graph->lock);
- log_err("Failed to add edge.");
- return -ENOMEM;
- }
+ if (e == NULL && ((e = add_edge(v, nb)) == NULL)) {
+ log_err("Failed to add edge to dst.");
+ goto fail_add_edge_d;
}
e->announced++;
e->qs = qs;
nb_e = find_edge_by_addr(nb, s_addr);
- if (nb_e == NULL) {
- nb_e = add_edge(nb, v);
- if (nb_e == NULL) {
- if (--e->announced == 0)
- del_edge(e);
- if (list_is_empty(&v->edges))
- del_vertex(graph, v);
- if (list_is_empty(&nb->edges))
- del_vertex(graph, nb);
- pthread_mutex_unlock(&graph->lock);
- log_err("Failed to add edge.");
- return -ENOMEM;
- }
+ if (nb_e == NULL && ((nb_e = add_edge(nb, v)) == NULL)) {;
+ log_err("Failed to add edge to src.");
+ goto fail_add_edge_s;
}
nb_e->announced++;
@@ -305,6 +282,19 @@ int graph_update_edge(struct graph * graph,
pthread_mutex_unlock(&graph->lock);
return 0;
+ fail_add_edge_s:
+ if (--e->announced == 0)
+ del_edge(e);
+ fail_add_edge_d:
+ if (list_is_empty(&nb->edges))
+ del_vertex(graph, nb);
+ fail_add_d:
+ if (list_is_empty(&v->edges))
+ del_vertex(graph, v);
+ fail_add_s:
+ pthread_mutex_unlock(&graph->lock);
+ return -ENOMEM;
+
}
int graph_del_edge(struct graph * graph,
@@ -322,30 +312,26 @@ int graph_del_edge(struct graph * graph,
v = find_vertex_by_addr(graph, s_addr);
if (v == NULL) {
- pthread_mutex_unlock(&graph->lock);
- log_err("No such source vertex.");
- return -1;
+ log_err("Failed to find src vertex.");
+ goto fail;
}
nb = find_vertex_by_addr(graph, d_addr);
if (nb == NULL) {
- pthread_mutex_unlock(&graph->lock);
log_err("No such destination vertex.");
- return -1;
+ goto fail;
}
e = find_edge_by_addr(v, d_addr);
if (e == NULL) {
- pthread_mutex_unlock(&graph->lock);
log_err("No such source edge.");
- return -1;
+ goto fail;
}
nb_e = find_edge_by_addr(nb, s_addr);
if (nb_e == NULL) {
- pthread_mutex_unlock(&graph->lock);
log_err("No such destination edge.");
- return -1;
+ goto fail;
}
if (--e->announced == 0)
@@ -362,6 +348,10 @@ int graph_del_edge(struct graph * graph,
pthread_mutex_unlock(&graph->lock);
return 0;
+
+ fail:
+ pthread_mutex_unlock(&graph->lock);
+ return -1;
}
static int get_min_vertex(struct graph * graph,
@@ -381,7 +371,7 @@ static int get_min_vertex(struct graph * graph,
*v = NULL;
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
if (!used[i] && dist[i] < min) {
min = dist[i];
index = i;
@@ -413,24 +403,24 @@ static int dijkstra(struct graph * graph,
assert(nhops);
assert(dist);
- *nhops = malloc(sizeof(**nhops) * graph->nr_vertices);
+ *nhops = malloc(sizeof(**nhops) * graph->vertices.len);
if (*nhops == NULL)
goto fail_pnhops;
- *dist = malloc(sizeof(**dist) * graph->nr_vertices);
+ *dist = malloc(sizeof(**dist) * graph->vertices.len);
if (*dist == NULL)
goto fail_pdist;
- used = malloc(sizeof(*used) * graph->nr_vertices);
+ used = malloc(sizeof(*used) * graph->vertices.len);
if (used == NULL)
goto fail_used;
/* Init the data structures */
- memset(used, 0, sizeof(*used) * graph->nr_vertices);
- memset(*nhops, 0, sizeof(**nhops) * graph->nr_vertices);
- memset(*dist, 0, sizeof(**dist) * graph->nr_vertices);
+ memset(used, 0, sizeof(*used) * graph->vertices.len);
+ memset(*nhops, 0, sizeof(**nhops) * graph->vertices.len);
+ memset(*dist, 0, sizeof(**dist) * graph->vertices.len);
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
v = list_entry(p, struct vertex, next);
(*dist)[i++] = (v->addr == src) ? 0 : INT_MAX;
}
@@ -527,7 +517,7 @@ static int graph_routing_table_simple(struct graph * graph,
assert(dist);
/* We need at least 2 vertices for a table */
- if (graph->nr_vertices < 2)
+ if (graph->vertices.len < 2)
goto fail_vertices;
if (dijkstra(graph, s_addr, &nhops, dist))
@@ -536,7 +526,7 @@ static int graph_routing_table_simple(struct graph * graph,
list_head_init(table);
/* Now construct the routing table from the nhops. */
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
v = list_entry(p, struct vertex, next);
/* This is the src */
@@ -634,7 +624,7 @@ static int graph_routing_table_lfa(struct graph * graph,
addrs[j] = -1;
}
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
v = list_entry(p, struct vertex, next);
if (v->addr != s_addr)
@@ -660,7 +650,7 @@ static int graph_routing_table_lfa(struct graph * graph,
}
/* Loop though all nodes to see if we have a LFA for them. */
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
v = list_entry(p, struct vertex, next);
if (v->addr == s_addr)
@@ -717,14 +707,14 @@ static int graph_routing_table_ecmp(struct graph * graph,
assert(graph);
assert(dist);
- if (graph-> nr_vertices < 2)
+ if (graph->vertices.len < 2)
goto fail_vertices;
- forwarding = malloc(sizeof(*forwarding) * graph->nr_vertices);
+ forwarding = malloc(sizeof(*forwarding) * graph->vertices.len);
if (forwarding == NULL)
goto fail_vertices;
- for (i = 0; i < graph->nr_vertices; ++i)
+ for (i = 0; i < graph->vertices.len; ++i)
list_head_init(&forwarding[i]);
if (dijkstra(graph, s_addr, &nhops, dist))
@@ -745,7 +735,7 @@ static int graph_routing_table_ecmp(struct graph * graph,
free(nhops);
- list_for_each(h, &graph->vertices) {
+ list_for_each(h, &graph->vertices.list) {
v = list_entry(h, struct vertex, next);
if (tmp_dist[v->index] + 1 == (*dist)[v->index]) {
n = malloc(sizeof(*n));
@@ -763,7 +753,7 @@ static int graph_routing_table_ecmp(struct graph * graph,
list_head_init(table);
i = 0;
- list_for_each(p, &graph->vertices) {
+ list_for_each(p, &graph->vertices.list) {
v = list_entry(p, struct vertex, next);
if (v->addr == s_addr) {
++i;
diff --git a/src/ipcpd/unicast/routing/link-state.c b/src/ipcpd/unicast/routing/link-state.c
index 57c0c7cb..e5edf539 100644
--- a/src/ipcpd/unicast/routing/link-state.c
+++ b/src/ipcpd/unicast/routing/link-state.c
@@ -42,6 +42,7 @@
#include <ouroboros/rib.h>
#include <ouroboros/utils.h>
+#include "addr-auth.h"
#include "common/comp.h"
#include "common/connmgr.h"
#include "graph.h"
@@ -54,9 +55,6 @@
#include <inttypes.h>
#include <string.h>
-#define RECALC_TIME 4
-#define LS_UPDATE_TIME 15
-#define LS_TIMEO 60
#define LS_ENTRY_SIZE 104
#define LSDB "lsdb"
@@ -64,6 +62,12 @@
#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
#endif
+#define LINK_FMT ADDR_FMT32 "--" ADDR_FMT32
+#define LINK_VAL(src, dst) ADDR_VAL32(&src), ADDR_VAL32(&dst)
+
+#define LSU_FMT "LSU ["ADDR_FMT32 " -- " ADDR_FMT32 " seq: %09" PRIu64 "]"
+#define LSU_VAL(src, dst, seqno) ADDR_VAL32(&src), ADDR_VAL32(&dst), seqno
+
struct lsa {
uint64_t d_addr;
uint64_t s_addr;
@@ -106,30 +110,45 @@ struct nb {
};
struct {
- struct list_head nbs;
- size_t nbs_len;
+ uint64_t addr;
+
+ enum routing_algo routing_algo;
+
+ struct ls_config conf;
+
fset_t * mgmt_set;
- struct list_head db;
- size_t db_len;
+ struct graph * graph;
+
+ struct {
+ struct {
+ struct list_head list;
+ size_t len;
+ } nbs;
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } db;
- pthread_rwlock_t db_lock;
+ pthread_rwlock_t lock;
+ };
- struct graph * graph;
+ struct {
+ struct list_head list;
+ pthread_mutex_t mtx;
+ } instances;
pthread_t lsupdate;
pthread_t lsreader;
pthread_t listener;
-
- struct list_head routing_instances;
- pthread_mutex_t routing_i_lock;
-
- enum routing_algo routing_algo;
} ls;
struct routing_ops link_state_ops = {
- .init = link_state_init,
+ .init = (int (*)(void *, enum pol_pff *)) link_state_init,
.fini = link_state_fini,
+ .start = link_state_start,
+ .stop = link_state_stop,
.routing_i_create = link_state_routing_i_create,
.routing_i_destroy = link_state_routing_i_destroy
};
@@ -138,7 +157,7 @@ static int str_adj(struct adjacency * adj,
char * buf,
size_t len)
{
- char tmbuf[64];
+ char tmstr[RIB_TM_STRLEN];
char srcbuf[64];
char dstbuf[64];
char seqnobuf[64];
@@ -149,15 +168,16 @@ static int str_adj(struct adjacency * adj,
if (len < LS_ENTRY_SIZE)
return -1;
- tm = localtime(&adj->stamp);
- strftime(tmbuf, sizeof(tmbuf), "%F %T", tm); /* 19 chars */
+ tm = gmtime(&adj->stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
- sprintf(srcbuf, "%" PRIu64, adj->src);
- sprintf(dstbuf, "%" PRIu64, adj->dst);
+ sprintf(srcbuf, ADDR_FMT32, ADDR_VAL32(&adj->src));
+ sprintf(dstbuf, ADDR_FMT32, ADDR_VAL32(&adj->dst));
sprintf(seqnobuf, "%" PRIu64, adj->seqno);
- sprintf(buf, "src: %20s\ndst: %20s\nseqno: %18s\nupd: %20s\n",
- srcbuf, dstbuf, seqnobuf, tmbuf);
+ sprintf(buf, "src: %20s\ndst: %20s\nseqno: %18s\n"
+ "upd: %s\n",
+ srcbuf, dstbuf, seqnobuf, tmstr);
return LS_ENTRY_SIZE;
}
@@ -169,9 +189,9 @@ static struct adjacency * get_adj(const char * path)
assert(path);
- list_for_each(p, &ls.db) {
+ list_for_each(p, &ls.db.list) {
struct adjacency * a = list_entry(p, struct adjacency, next);
- sprintf(entry, "%" PRIu64 ".%" PRIu64, a->src, a->dst);
+ sprintf(entry, LINK_FMT, LINK_VAL(a->src, a->dst));
if (strcmp(entry, path) == 0)
return a;
}
@@ -194,7 +214,7 @@ static int lsdb_rib_getattr(const char * path,
clock_gettime(CLOCK_REALTIME_COARSE, &now);
- pthread_rwlock_rdlock(&ls.db_lock);
+ pthread_rwlock_rdlock(&ls.lock);
adj = get_adj(entry);
if (adj != NULL) {
@@ -205,7 +225,7 @@ static int lsdb_rib_getattr(const char * path,
attr->size = 0;
}
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return 0;
}
@@ -223,9 +243,9 @@ static int lsdb_rib_read(const char * path,
entry = strstr(path, RIB_SEPARATOR) + 1;
assert(entry);
- pthread_rwlock_rdlock(&ls.db_lock);
+ pthread_rwlock_rdlock(&ls.lock);
- if (ls.db_len + ls.nbs_len == 0)
+ if (ls.db.len + ls.nbs.len == 0)
goto fail;
a = get_adj(entry);
@@ -236,11 +256,11 @@ static int lsdb_rib_read(const char * path,
if (size < 0)
goto fail;
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return size;
fail:
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return -1;
}
@@ -250,60 +270,52 @@ static int lsdb_rib_readdir(char *** buf)
char entry[RIB_PATH_LEN + 1];
ssize_t idx = 0;
- assert(buf);
+ assert(buf != NULL);
- pthread_rwlock_rdlock(&ls.db_lock);
+ pthread_rwlock_rdlock(&ls.lock);
- if (ls.db_len + ls.nbs_len == 0) {
- pthread_rwlock_unlock(&ls.db_lock);
- return 0;
+ if (ls.db.len + ls.nbs.len == 0) {
+ *buf = NULL;
+ goto no_entries;
}
- *buf = malloc(sizeof(**buf) * (ls.db_len + ls.nbs_len));
- if (*buf == NULL) {
- pthread_rwlock_unlock(&ls.db_lock);
- return -ENOMEM;
- }
- list_for_each(p, &ls.nbs) {
+ *buf = malloc(sizeof(**buf) * (ls.db.len + ls.nbs.len));
+ if (*buf == NULL)
+ goto fail_entries;
+
+ list_for_each(p, &ls.nbs.list) {
struct nb * nb = list_entry(p, struct nb, next);
- char * str = (nb->type == NB_DT ? "dt." : "mgmt.");
- sprintf(entry, "%s%" PRIu64, str, nb->addr);
+ char * str = (nb->type == NB_DT ? ".dt " : ".mgmt ");
+ sprintf(entry, "%s" ADDR_FMT32 , str, ADDR_VAL32(&nb->addr));
(*buf)[idx] = malloc(strlen(entry) + 1);
- if ((*buf)[idx] == NULL) {
- while (idx-- > 0)
- free((*buf)[idx]);
- free(*buf);
- pthread_rwlock_unlock(&ls.db_lock);
- return -ENOMEM;
- }
-
- strcpy((*buf)[idx], entry);
+ if ((*buf)[idx] == NULL)
+ goto fail_entry;
- idx++;
+ strcpy((*buf)[idx++], entry);
}
- list_for_each(p, &ls.db) {
+ list_for_each(p, &ls.db.list) {
struct adjacency * a = list_entry(p, struct adjacency, next);
- sprintf(entry, "%" PRIu64 ".%" PRIu64, a->src, a->dst);
+ sprintf(entry, LINK_FMT, LINK_VAL(a->src, a->dst));
(*buf)[idx] = malloc(strlen(entry) + 1);
- if ((*buf)[idx] == NULL) {
- ssize_t j;
- for (j = 0; j < idx; ++j)
- free(*buf[j]);
- free(buf);
- pthread_rwlock_unlock(&ls.db_lock);
- return -ENOMEM;
- }
-
- strcpy((*buf)[idx], entry);
+ if ((*buf)[idx] == NULL)
+ goto fail_entry;
- idx++;
+ strcpy((*buf)[idx++], entry);
}
-
- pthread_rwlock_unlock(&ls.db_lock);
+ no_entries:
+ pthread_rwlock_unlock(&ls.lock);
return idx;
+
+ fail_entry:
+ while (idx-- > 0)
+ free((*buf)[idx]);
+ free(*buf);
+ fail_entries:
+ pthread_rwlock_unlock(&ls.lock);
+ return -ENOMEM;
}
static struct rib_ops r_ops = {
@@ -319,28 +331,28 @@ static int lsdb_add_nb(uint64_t addr,
struct list_head * p;
struct nb * nb;
- pthread_rwlock_wrlock(&ls.db_lock);
+ pthread_rwlock_wrlock(&ls.lock);
- list_for_each(p, &ls.nbs) {
+ list_for_each(p, &ls.nbs.list) {
struct nb * el = list_entry(p, struct nb, next);
- if (el->addr == addr && el->type == type) {
- log_dbg("Already know %s neighbor %" PRIu64 ".",
- type == NB_DT ? "dt" : "mgmt", addr);
- if (el->fd != fd) {
- log_warn("Existing neighbor assigned new fd.");
- el->fd = fd;
- }
- pthread_rwlock_unlock(&ls.db_lock);
- return -EPERM;
- }
-
if (addr > el->addr)
break;
+ if (el->addr != addr || el->type != type)
+ continue;
+
+ log_dbg("Already know %s neighbor " ADDR_FMT32 ".",
+ type == NB_DT ? "dt" : "mgmt", ADDR_VAL32(&addr));
+ if (el->fd != fd) {
+ log_warn("Existing neighbor assigned new fd.");
+ el->fd = fd;
+ }
+ pthread_rwlock_unlock(&ls.lock);
+ return -EPERM;
}
nb = malloc(sizeof(*nb));
if (nb == NULL) {
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return -ENOMEM;
}
@@ -350,12 +362,12 @@ static int lsdb_add_nb(uint64_t addr,
list_add_tail(&nb->next, p);
- ++ls.nbs_len;
+ ++ls.nbs.len;
- log_dbg("Type %s neighbor %" PRIu64 " added.",
- nb->type == NB_DT ? "dt" : "mgmt", addr);
+ log_dbg("Type %s neighbor " ADDR_FMT32 " added.",
+ nb->type == NB_DT ? "dt" : "mgmt", ADDR_VAL32(&addr));
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return 0;
}
@@ -366,22 +378,23 @@ static int lsdb_del_nb(uint64_t addr,
struct list_head * p;
struct list_head * h;
- pthread_rwlock_wrlock(&ls.db_lock);
+ pthread_rwlock_wrlock(&ls.lock);
- list_for_each_safe(p, h, &ls.nbs) {
+ list_for_each_safe(p, h, &ls.nbs.list) {
struct nb * nb = list_entry(p, struct nb, next);
- if (nb->addr == addr && nb->fd == fd) {
- list_del(&nb->next);
- --ls.nbs_len;
- pthread_rwlock_unlock(&ls.db_lock);
- log_dbg("Type %s neighbor %" PRIu64 " deleted.",
- nb->type == NB_DT ? "dt" : "mgmt", addr);
- free(nb);
- return 0;
- }
+ if (nb->addr != addr || nb->fd != fd)
+ continue;
+
+ list_del(&nb->next);
+ --ls.nbs.len;
+ pthread_rwlock_unlock(&ls.lock);
+ log_dbg("Type %s neighbor " ADDR_FMT32 " deleted.",
+ nb->type == NB_DT ? "dt" : "mgmt", ADDR_VAL32(&addr));
+ free(nb);
+ return 0;
}
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return -EPERM;
}
@@ -391,18 +404,18 @@ static int nbr_to_fd(uint64_t addr)
struct list_head * p;
int fd;
- pthread_rwlock_rdlock(&ls.db_lock);
+ pthread_rwlock_rdlock(&ls.lock);
- list_for_each(p, &ls.nbs) {
+ list_for_each(p, &ls.nbs.list) {
struct nb * nb = list_entry(p, struct nb, next);
if (nb->addr == addr && nb->type == NB_DT) {
fd = nb->fd;
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return fd;
}
}
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return -1;
}
@@ -417,8 +430,7 @@ static void calculate_pff(struct routing_i * instance)
assert(instance);
- if (graph_routing_table(ls.graph, ls.routing_algo,
- ipcpi.dt_addr, &table))
+ if (graph_routing_table(ls.graph, ls.routing_algo, ls.addr, &table))
return;
pff_lock(instance->pff);
@@ -453,8 +465,8 @@ static void set_pff_modified(bool calc)
{
struct list_head * p;
- pthread_mutex_lock(&ls.routing_i_lock);
- list_for_each(p, &ls.routing_instances) {
+ pthread_mutex_lock(&ls.instances.mtx);
+ list_for_each(p, &ls.instances.list) {
struct routing_i * inst =
list_entry(p, struct routing_i, next);
pthread_mutex_lock(&inst->lock);
@@ -463,7 +475,7 @@ static void set_pff_modified(bool calc)
if (calc)
calculate_pff(inst);
}
- pthread_mutex_unlock(&ls.routing_i_lock);
+ pthread_mutex_unlock(&ls.instances.mtx);
}
static int lsdb_add_link(uint64_t src,
@@ -480,9 +492,9 @@ static int lsdb_add_link(uint64_t src,
clock_gettime(CLOCK_REALTIME_COARSE, &now);
- pthread_rwlock_wrlock(&ls.db_lock);
+ pthread_rwlock_wrlock(&ls.lock);
- list_for_each(p, &ls.db) {
+ list_for_each(p, &ls.db.list) {
struct adjacency * a = list_entry(p, struct adjacency, next);
if (a->dst == dst && a->src == src) {
if (a->seqno < seqno) {
@@ -490,7 +502,7 @@ static int lsdb_add_link(uint64_t src,
a->seqno = seqno;
ret = 0;
}
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return ret;
}
@@ -500,7 +512,7 @@ static int lsdb_add_link(uint64_t src,
adj = malloc(sizeof(*adj));
if (adj == NULL) {
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return -ENOMEM;
}
@@ -511,12 +523,12 @@ static int lsdb_add_link(uint64_t src,
list_add_tail(&adj->next, p);
- ls.db_len++;
+ ls.db.len++;
if (graph_update_edge(ls.graph, src, dst, *qs))
log_warn("Failed to add edge to graph.");
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
set_pff_modified(true);
@@ -529,25 +541,25 @@ static int lsdb_del_link(uint64_t src,
struct list_head * p;
struct list_head * h;
- pthread_rwlock_wrlock(&ls.db_lock);
+ pthread_rwlock_wrlock(&ls.lock);
- list_for_each_safe(p, h, &ls.db) {
+ list_for_each_safe(p, h, &ls.db.list) {
struct adjacency * a = list_entry(p, struct adjacency, next);
if (a->dst == dst && a->src == src) {
list_del(&a->next);
if (graph_del_edge(ls.graph, src, dst))
log_warn("Failed to delete edge from graph.");
- ls.db_len--;
+ ls.db.len--;
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
set_pff_modified(false);
free(a);
return 0;
}
}
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
return -EPERM;
}
@@ -570,7 +582,7 @@ static void * periodic_recalc_pff(void * o)
if (modified)
calculate_pff(inst);
- sleep(RECALC_TIME);
+ sleep(ls.conf.t_recalc);
}
return (void *) 0;
@@ -587,10 +599,20 @@ static void send_lsm(uint64_t src,
lsm.s_addr = hton64(src);
lsm.seqno = hton64(seqno);
- list_for_each(p, &ls.nbs) {
+ list_for_each(p, &ls.nbs.list) {
struct nb * nb = list_entry(p, struct nb, next);
- if (nb->type == NB_MGMT)
- flow_write(nb->fd, &lsm, sizeof(lsm));
+ if (nb->type != NB_MGMT)
+ continue;
+
+ if (flow_write(nb->fd, &lsm, sizeof(lsm)) < 0)
+ log_err("Failed to send LSM to " ADDR_FMT32,
+ ADDR_VAL32(&nb->addr));
+#ifdef DEBUG_PROTO_LS
+ else
+ log_proto(LSU_FMT " --> " ADDR_FMT32,
+ LSU_VAL(src, dst, seqno),
+ ADDR_VAL32(&nb->addr));
+#endif
}
}
@@ -604,9 +626,9 @@ static void lsdb_replicate(int fd)
list_head_init(&copy);
/* Lock the lsdb, copy the lsms and send outside of lock. */
- pthread_rwlock_rdlock(&ls.db_lock);
+ pthread_rwlock_rdlock(&ls.lock);
- list_for_each(p, &ls.db) {
+ list_for_each(p, &ls.db.list) {
struct adjacency * adj;
struct adjacency * cpy;
adj = list_entry(p, struct adjacency, next);
@@ -623,7 +645,7 @@ static void lsdb_replicate(int fd)
list_add_tail(&cpy->next, &copy);
}
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
list_for_each_safe(p, h, &copy) {
struct lsa lsm;
@@ -649,17 +671,17 @@ static void * lsupdate(void * o)
while (true) {
clock_gettime(CLOCK_REALTIME_COARSE, &now);
- pthread_rwlock_wrlock(&ls.db_lock);
+ pthread_rwlock_wrlock(&ls.lock);
- pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock);
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.lock);
- list_for_each_safe(p, h, &ls.db) {
+ list_for_each_safe(p, h, &ls.db.list) {
struct adjacency * adj;
adj = list_entry(p, struct adjacency, next);
- if (now.tv_sec - adj->stamp > LS_TIMEO) {
+ if (now.tv_sec > adj->stamp + ls.conf.t_timeo) {
list_del(&adj->next);
- log_dbg("%" PRIu64 " - %" PRIu64" timed out.",
- adj->src, adj->dst);
+ log_dbg(LINK_FMT " timed out.",
+ LINK_VAL(adj->src, adj->dst));
if (graph_del_edge(ls.graph, adj->src,
adj->dst))
log_err("Failed to del edge.");
@@ -667,7 +689,7 @@ static void * lsupdate(void * o)
continue;
}
- if (adj->src == ipcpi.dt_addr) {
+ if (adj->src == ls.addr) {
adj->seqno++;
send_lsm(adj->src, adj->dst, adj->seqno);
adj->stamp = now.tv_sec;
@@ -676,7 +698,7 @@ static void * lsupdate(void * o)
pthread_cleanup_pop(true);
- sleep(LS_UPDATE_TIME);
+ sleep(ls.conf.t_update);
}
return (void *) 0;
@@ -708,15 +730,36 @@ static void forward_lsm(uint8_t * buf,
int in_fd)
{
struct list_head * p;
+#ifdef DEBUG_PROTO_LS
+ struct lsa lsm;
- pthread_rwlock_rdlock(&ls.db_lock);
+ assert(buf);
+ assert(len >= sizeof(struct lsa));
+
+ memcpy(&lsm, buf, sizeof(lsm));
+
+ lsm.s_addr = ntoh64(lsm.s_addr);
+ lsm.d_addr = ntoh64(lsm.d_addr);
+ lsm.seqno = ntoh64(lsm.seqno);
+#endif
+ pthread_rwlock_rdlock(&ls.lock);
- pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock);
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.lock);
- list_for_each(p, &ls.nbs) {
+ list_for_each(p, &ls.nbs.list) {
struct nb * nb = list_entry(p, struct nb, next);
- if (nb->type == NB_MGMT && nb->fd != in_fd)
- flow_write(nb->fd, buf, len);
+ if (nb->type != NB_MGMT || nb->fd == in_fd)
+ continue;
+
+ if (flow_write(nb->fd, buf, len) < 0)
+ log_err("Failed to forward LSM to " ADDR_FMT32,
+ ADDR_VAL32(&nb->addr));
+#ifdef DEBUG_PROTO_LS
+ else
+ log_proto(LSU_FMT " --> " ADDR_FMT32 " [forwarded]",
+ LSU_VAL(lsm.s_addr, lsm.d_addr, lsm.seqno),
+ ADDR_VAL32(&nb->addr));
+#endif
}
pthread_cleanup_pop(true);
@@ -729,13 +772,13 @@ static void cleanup_fqueue(void * fq)
static void * lsreader(void * o)
{
- fqueue_t * fq;
- int ret;
- uint8_t buf[sizeof(struct lsa)];
- int fd;
- qosspec_t qs;
- struct lsa * msg;
- size_t len;
+ fqueue_t * fq;
+ int ret;
+ uint8_t buf[sizeof(struct lsa)];
+ int fd;
+ qosspec_t qs;
+ struct lsa msg;
+ size_t len;
(void) o;
@@ -758,15 +801,22 @@ static void * lsreader(void * o)
if (fqueue_type(fq) != FLOW_PKT)
continue;
- len = flow_read(fd, buf, sizeof(*msg));
- if (len <= 0 || len != sizeof(*msg))
+ len = flow_read(fd, buf, sizeof(msg));
+ if (len <= 0 || len != sizeof(msg))
continue;
- msg = (struct lsa *) buf;
-
- if (lsdb_add_link(ntoh64(msg->s_addr),
- ntoh64(msg->d_addr),
- ntoh64(msg->seqno),
+ memcpy(&msg, buf, sizeof(msg));
+ msg.s_addr = ntoh64(msg.s_addr);
+ msg.d_addr = ntoh64(msg.d_addr);
+ msg.seqno = ntoh64(msg.seqno);
+#ifdef DEBUG_PROTO_LS
+ log_proto(LSU_FMT " <-- " ADDR_FMT32,
+ LSU_VAL(msg.s_addr, msg.d_addr, msg.seqno),
+ ADDR_VAL32(&ls.addr));
+#endif
+ if (lsdb_add_link(msg.s_addr,
+ msg.d_addr,
+ msg.seqno,
&qs))
continue;
@@ -787,14 +837,14 @@ static void flow_event(int fd,
log_dbg("Notifying routing instances of flow event.");
- pthread_mutex_lock(&ls.routing_i_lock);
+ pthread_mutex_lock(&ls.instances.mtx);
- list_for_each(p, &ls.routing_instances) {
+ list_for_each(p, &ls.instances.list) {
struct routing_i * ri = list_entry(p, struct routing_i, next);
pff_flow_state_change(ri->pff, fd, up);
}
- pthread_mutex_unlock(&ls.routing_i_lock);
+ pthread_mutex_unlock(&ls.instances.mtx);
}
static void handle_event(void * self,
@@ -816,17 +866,17 @@ static void handle_event(void * self,
switch (event) {
case NOTIFY_DT_CONN_ADD:
- pthread_rwlock_rdlock(&ls.db_lock);
+ pthread_rwlock_rdlock(&ls.lock);
- pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.db_lock);
+ pthread_cleanup_push(__cleanup_rwlock_unlock, &ls.lock);
- send_lsm(ipcpi.dt_addr, c->conn_info.addr, 0);
+ send_lsm(ls.addr, c->conn_info.addr, 0);
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.");
- if (lsdb_add_link(ipcpi.dt_addr, c->conn_info.addr, 0, &qs))
+ if (lsdb_add_link(ls.addr, c->conn_info.addr, 0, &qs))
log_dbg("Failed to add new adjacency to LSDB.");
break;
case NOTIFY_DT_CONN_DEL:
@@ -835,7 +885,7 @@ static void handle_event(void * self,
if (lsdb_del_nb(c->conn_info.addr, c->flow_info.fd))
log_dbg("Failed to delete neighbor from LSDB.");
- if (lsdb_del_link(ipcpi.dt_addr, c->conn_info.addr))
+ if (lsdb_del_link(ls.addr, c->conn_info.addr))
log_dbg("Local link was not in LSDB.");
break;
case NOTIFY_DT_CONN_QOS:
@@ -886,11 +936,11 @@ struct routing_i * link_state_routing_i_create(struct pff * pff)
periodic_recalc_pff, tmp))
goto fail_pthread_create_lsupdate;
- pthread_mutex_lock(&ls.routing_i_lock);
+ pthread_mutex_lock(&ls.instances.mtx);
- list_add(&tmp->next, &ls.routing_instances);
+ list_add(&tmp->next, &ls.instances.list);
- pthread_mutex_unlock(&ls.routing_i_lock);
+ pthread_mutex_unlock(&ls.instances.mtx);
return tmp;
@@ -906,11 +956,11 @@ void link_state_routing_i_destroy(struct routing_i * instance)
{
assert(instance);
- pthread_mutex_lock(&ls.routing_i_lock);
+ pthread_mutex_lock(&ls.instances.mtx);
list_del(&instance->next);
- pthread_mutex_unlock(&ls.routing_i_lock);
+ pthread_mutex_unlock(&ls.instances.mtx);
pthread_cancel(instance->calculator);
@@ -921,96 +971,146 @@ void link_state_routing_i_destroy(struct routing_i * instance)
free(instance);
}
-int link_state_init(enum pol_routing pr)
+int link_state_start(void)
+{
+ if (notifier_reg(handle_event, NULL)) {
+ log_err("Failed to register link-state with notifier.");
+ goto fail_notifier_reg;
+ }
+
+ if (pthread_create(&ls.lsupdate, NULL, lsupdate, NULL)) {
+ log_err("Failed to create lsupdate thread.");
+ goto fail_pthread_create_lsupdate;
+ }
+
+ if (pthread_create(&ls.lsreader, NULL, lsreader, NULL)) {
+ log_err("Failed to create lsreader thread.");
+ goto fail_pthread_create_lsreader;
+ }
+
+ if (pthread_create(&ls.listener, NULL, ls_conn_handle, NULL)) {
+ log_err("Failed to create listener thread.");
+ goto fail_pthread_create_listener;
+ }
+
+ return 0;
+
+ fail_pthread_create_listener:
+ pthread_cancel(ls.lsreader);
+ pthread_join(ls.lsreader, NULL);
+ fail_pthread_create_lsreader:
+ pthread_cancel(ls.lsupdate);
+ pthread_join(ls.lsupdate, NULL);
+ fail_pthread_create_lsupdate:
+ notifier_unreg(handle_event);
+ fail_notifier_reg:
+ return -1;
+}
+
+void link_state_stop(void)
+{
+ pthread_cancel(ls.listener);
+ pthread_cancel(ls.lsreader);
+ pthread_cancel(ls.lsupdate);
+
+ pthread_join(ls.listener, NULL);
+ pthread_join(ls.lsreader, NULL);
+ pthread_join(ls.lsupdate, NULL);
+
+ notifier_unreg(handle_event);
+}
+
+
+int link_state_init(struct ls_config * conf,
+ enum pol_pff * pff_type)
{
struct conn_info info;
+ assert(conf != NULL);
+ assert(pff_type != NULL);
+
memset(&info, 0, sizeof(info));
+ ls.addr = addr_auth_address();
+
strcpy(info.comp_name, LS_COMP);
strcpy(info.protocol, LS_PROTO);
info.pref_version = 1;
info.pref_syntax = PROTO_GPB;
- info.addr = ipcpi.dt_addr;
+ info.addr = ls.addr;
- switch (pr) {
- case ROUTING_LINK_STATE:
- log_dbg("Using link state routing policy.");
+ ls.conf = *conf;
+
+ switch (conf->pol) {
+ case LS_SIMPLE:
+ *pff_type = PFF_SIMPLE;
ls.routing_algo = ROUTING_SIMPLE;
+ log_dbg("Using Link State Routing policy.");
break;
- case ROUTING_LINK_STATE_LFA:
- log_dbg("Using Loop-Free Alternates policy.");
+ case LS_LFA:
ls.routing_algo = ROUTING_LFA;
+ *pff_type = PFF_ALTERNATE;
+ log_dbg("Using Loop-Free Alternates policy.");
break;
- case ROUTING_LINK_STATE_ECMP:
- log_dbg("Using Equal-Cost Multipath policy.");
+ case LS_ECMP:
ls.routing_algo = ROUTING_ECMP;
+ *pff_type = PFF_MULTIPATH;
+ log_dbg("Using Equal-Cost Multipath policy.");
break;
default:
goto fail_graph;
}
+ log_dbg("LS update interval: %ld seconds.", ls.conf.t_update);
+ log_dbg("LS link timeout : %ld seconds.", ls.conf.t_timeo);
+ log_dbg("LS recalc interval: %ld seconds.", ls.conf.t_recalc);
+
ls.graph = graph_create();
if (ls.graph == NULL)
goto fail_graph;
- if (notifier_reg(handle_event, NULL))
- goto fail_notifier_reg;
-
- if (pthread_rwlock_init(&ls.db_lock, NULL))
- goto fail_db_lock_init;
+ if (pthread_rwlock_init(&ls.lock, NULL)) {
+ log_err("Failed to init lock.");
+ goto fail_lock_init;
+ }
- if (pthread_mutex_init(&ls.routing_i_lock, NULL))
+ if (pthread_mutex_init(&ls.instances.mtx, NULL)) {
+ log_err("Failed to init instances mutex.");
goto fail_routing_i_lock_init;
+ }
- if (connmgr_comp_init(COMPID_MGMT, &info))
+ if (connmgr_comp_init(COMPID_MGMT, &info)) {
+ log_err("Failed to init connmgr.");
goto fail_connmgr_comp_init;
+ }
ls.mgmt_set = fset_create();
- if (ls.mgmt_set == NULL)
+ if (ls.mgmt_set == NULL) {
+ log_err("Failed to create fset.");
goto fail_fset_create;
+ }
- list_head_init(&ls.db);
- list_head_init(&ls.nbs);
- list_head_init(&ls.routing_instances);
-
- if (pthread_create(&ls.lsupdate, NULL, lsupdate, NULL))
- goto fail_pthread_create_lsupdate;
-
- if (pthread_create(&ls.lsreader, NULL, lsreader, NULL))
- goto fail_pthread_create_lsreader;
-
- if (pthread_create(&ls.listener, NULL, ls_conn_handle, NULL))
- goto fail_pthread_create_listener;
+ list_head_init(&ls.db.list);
+ list_head_init(&ls.nbs.list);
+ list_head_init(&ls.instances.list);
if (rib_reg(LSDB, &r_ops))
goto fail_rib_reg;
- ls.db_len = 0;
- ls.nbs_len = 0;
+ ls.db.len = 0;
+ ls.nbs.len = 0;
return 0;
fail_rib_reg:
- pthread_cancel(ls.listener);
- pthread_join(ls.listener, NULL);
- fail_pthread_create_listener:
- pthread_cancel(ls.lsreader);
- pthread_join(ls.lsreader, NULL);
- fail_pthread_create_lsreader:
- pthread_cancel(ls.lsupdate);
- pthread_join(ls.lsupdate, NULL);
- fail_pthread_create_lsupdate:
fset_destroy(ls.mgmt_set);
fail_fset_create:
connmgr_comp_fini(COMPID_MGMT);
fail_connmgr_comp_init:
- pthread_mutex_destroy(&ls.routing_i_lock);
+ pthread_mutex_destroy(&ls.instances.mtx);
fail_routing_i_lock_init:
- pthread_rwlock_destroy(&ls.db_lock);
- fail_db_lock_init:
- notifier_unreg(handle_event);
- fail_notifier_reg:
+ pthread_rwlock_destroy(&ls.lock);
+ fail_lock_init:
graph_destroy(ls.graph);
fail_graph:
return -1;
@@ -1023,33 +1123,23 @@ void link_state_fini(void)
rib_unreg(LSDB);
- notifier_unreg(handle_event);
-
- pthread_cancel(ls.listener);
- pthread_cancel(ls.lsreader);
- pthread_cancel(ls.lsupdate);
-
- pthread_join(ls.listener, NULL);
- pthread_join(ls.lsreader, NULL);
- pthread_join(ls.lsupdate, NULL);
-
fset_destroy(ls.mgmt_set);
connmgr_comp_fini(COMPID_MGMT);
graph_destroy(ls.graph);
- pthread_rwlock_wrlock(&ls.db_lock);
+ pthread_rwlock_wrlock(&ls.lock);
- list_for_each_safe(p, h, &ls.db) {
+ list_for_each_safe(p, h, &ls.db.list) {
struct adjacency * a = list_entry(p, struct adjacency, next);
list_del(&a->next);
free(a);
}
- pthread_rwlock_unlock(&ls.db_lock);
+ pthread_rwlock_unlock(&ls.lock);
- pthread_rwlock_destroy(&ls.db_lock);
+ pthread_rwlock_destroy(&ls.lock);
- pthread_mutex_destroy(&ls.routing_i_lock);
+ pthread_mutex_destroy(&ls.instances.mtx);
}
diff --git a/src/ipcpd/unicast/routing/link-state.h b/src/ipcpd/unicast/routing/link-state.h
index d77d72df..69eb6781 100644
--- a/src/ipcpd/unicast/routing/link-state.h
+++ b/src/ipcpd/unicast/routing/link-state.h
@@ -28,10 +28,15 @@
#include "ops.h"
-int link_state_init(enum pol_routing pr);
+int link_state_init(struct ls_config * ls,
+ enum pol_pff * pff_type);
void link_state_fini(void);
+int link_state_start(void);
+
+void link_state_stop(void);
+
struct routing_i * link_state_routing_i_create(struct pff * pff);
void link_state_routing_i_destroy(struct routing_i * instance);
diff --git a/src/ipcpd/unicast/routing/ops.h b/src/ipcpd/unicast/routing/ops.h
index 8a79b7ec..4bf75c80 100644
--- a/src/ipcpd/unicast/routing/ops.h
+++ b/src/ipcpd/unicast/routing/ops.h
@@ -26,10 +26,15 @@
#include "pff.h"
struct routing_ops {
- int (* init)(enum pol_routing pr);
+ int (* init)(void * conf,
+ enum pol_pff * pff_type);
void (* fini)(void);
+ int (* start)(void);
+
+ void (* stop)(void);
+
struct routing_i * (* routing_i_create)(struct pff * pff);
void (* routing_i_destroy)(struct routing_i * instance);
diff --git a/src/ipcpd/unicast/routing/tests/CMakeLists.txt b/src/ipcpd/unicast/routing/tests/CMakeLists.txt
index d0652533..9d24bf03 100644
--- a/src/ipcpd/unicast/routing/tests/CMakeLists.txt
+++ b/src/ipcpd/unicast/routing/tests/CMakeLists.txt
@@ -26,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/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt
index c9c2e553..46d49391 100644
--- a/src/irmd/CMakeLists.txt
+++ b/src/irmd/CMakeLists.txt
@@ -4,13 +4,14 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
+set(OUROBOROS_CONFIG_DIR /etc/ouroboros CACHE STRING
+ "Configuration directory")
+
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)
@@ -23,11 +24,11 @@ if (LIBTOML_LIBRARIES)
install(FILES "${CMAKE_BINARY_DIR}/irmd.conf.example"
DESTINATION "${OUROBOROS_CONFIG_DIR}")
unset(INSTALL_DIR)
- mark_as_advanced(LIBTOML_LIBRARIES)
+ find_path(LIBTOML_INCLUDE toml.h)
+ mark_as_advanced(LIBTOML_LIBRARIES LIBTOML_INCLUDE)
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 ()
@@ -38,16 +39,26 @@ else ()
unset(HAVE_TOML)
endif ()
+set(OUROBOROS_SECURITY_DIR "${OUROBOROS_CONFIG_DIR}/security" CACHE STRING
+ "Security directory holding authentication information")
+set(OUROBOROS_CA_CRT_DIR "${OUROBOROS_SECURITY_DIR}/cacert" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_SRV_CRT_DIR "${OUROBOROS_SECURITY_DIR}/server" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_CLI_CRT_DIR "${OUROBOROS_SECURITY_DIR}/client" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_UNTRUSTED_DIR "${OUROBOROS_SECURITY_DIR}/untrusted" CACHE STRING
+ "Directory holding untrusted intermediate certificates")
+
set(IRMD_REQ_ARR_TIMEOUT 1000 CACHE STRING
"Timeout for an application to respond to a new flow (ms)")
-
set(BOOTSTRAP_TIMEOUT 5000 CACHE STRING
"Timeout for an IPCP to bootstrap (ms)")
set(ENROLL_TIMEOUT 20000 CACHE STRING
"Timeout for an IPCP to enroll (ms)")
set(REG_TIMEOUT 20000 CACHE STRING
"Timeout for registering a name (ms)")
-set(QUERY_TIMEOUT 20000 CACHE STRING
+set(QUERY_TIMEOUT 200 CACHE STRING
"Timeout to query a name with an IPCP (ms)")
set(CONNECT_TIMEOUT 20000 CACHE STRING
"Timeout to connect an IPCP to another IPCP (ms)")
@@ -61,6 +72,8 @@ 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")
+set(DEBUG_PROTO_OAP FALSE CACHE BOOL
+ "Add Flow allocation protocol message output to IRMd debug logging")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
@@ -70,6 +83,7 @@ set(SOURCE_FILES
ipcp.c
configfile.c
main.c
+ oap.c
reg/flow.c
reg/ipcp.c
reg/proc.c
@@ -83,6 +97,10 @@ add_executable (irmd ${SOURCE_FILES})
target_link_libraries (irmd LINK_PUBLIC ouroboros-common
${LIBTOML_LIBRARIES})
+if (HAVE_TOML)
+ target_include_directories(irmd PUBLIC ${LIBTOML_INCLUDE})
+endif ()
+
include(AddCompileFlags)
if (CMAKE_BUILD_TYPE MATCHES "Debug*")
add_compile_flags(irmd -DCONFIG_OUROBOROS_DEBUG)
@@ -90,6 +108,5 @@ endif ()
install(TARGETS irmd RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
-# Enable once irmd has tests
-#add_subdirectory(tests)
add_subdirectory(reg)
+add_subdirectory(tests)
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index fa1156b9..527694c0 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -21,7 +21,8 @@
*/
-#define IPCP_UDP_EXEC "@IPCP_UDP_TARGET@"
+#define IPCP_UDP4_EXEC "@IPCP_UDP4_TARGET@"
+#define IPCP_UDP6_EXEC "@IPCP_UDP6_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@"
@@ -50,7 +51,6 @@
#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@"
@@ -62,36 +62,33 @@
#define OUROBOROS_CONFIG_FILE "@OUROBOROS_CONFIG_FILE@"
#endif
+#define OUROBOROS_SECURITY_DIR "@OUROBOROS_SECURITY_DIR@"
+#define OUROBOROS_CA_CRT_DIR "@OUROBOROS_CA_CRT_DIR@"
+#define OUROBOROS_SRV_CRT_DIR "@OUROBOROS_SRV_CRT_DIR@"
+#define OUROBOROS_CLI_CRT_DIR "@OUROBOROS_CLI_CRT_DIR@"
+#define OUROBOROS_CHAIN_DIR "@OUROBOROS_UNTRUSTED_DIR@"
+
#define IRMD_PKILL_TIMEOUT @IRMD_PKILL_TIMEOUT@
#cmakedefine IRMD_KILL_ALL_PROCESSES
#cmakedefine HAVE_LIBGCRYPT
+#cmakedefine HAVE_OPENSSL
+#ifdef CONFIG_OUROBOROS_DEBUG
+#cmakedefine DEBUG_PROTO_OAP
+#endif
+
+#define _B ""
+#define _G ""
+#define RST ""
-#define O7S_ASCII_ART \
-"\n" \
-" ▄▄█████▄▄▄\n" \
-" ▄█▀▀ ▀▀███▄ " \
-"â–ˆ\n" \
-" ██ ▄▄▄ ▄███▄ " \
-"â–„ â–„ â–„ â–„â–„" \
-" â–„â–„ â–ˆ â–„â–„ " \
-" â–„â–„ â–„ â–„â–„ " \
-"â–„â–„ â–„â–„\n" \
-" ██ █ █ " \
-"[38;5;4m█████ █ █ " \
-"█▀ ▀ █ █" \
-" █▀ █ █ " \
-"█ █▀ ▀ █" \
-" █ ▀▄ ▀\n" \
-" ██ ▀▄▄▄▀ ▀█▀ " \
-"â–ˆ â–ˆ â–ˆ " \
-"█ █ █▄ █ " \
-"â–ˆ â–ˆ â–ˆ â–ˆ" \
-" █ ▄ ▀▄\n" \
-" █▄ █ ▀▀▀" \
-" ▀ ▀ ▀▀" \
-" ▀ ▀▀ ▀▀ " \
-"▀ ▀▀ ▀▀\n" \
-" ▀█▄▄▄▄▄▄▄▄▀\n" \
-" ▀▀▀▀▀▀\n" \
-"\n"
+#define O7S_ASCII_ART \
+RST "\n" \
+_B " ▄▄█████▄▄▄ \n" \
+_B " ▄█▀▀ ▀▀███▄ " _G " █ \n" \
+_B " ██ ▄▄▄ ▄███▄ " _G "▄ ▄ ▄ ▄ ▄▄ █▄▄ ▄▄ ▄ ▄ ▄▄ ▄▄ \n" \
+_B " ██ █ █ █████ " _G "█ █ █▀ ▀ █ █ █ █ █ █ █▀ ▀ █ █ ▀▄ ▀\n" \
+_B " ██ ▀▄▄▄▀ ▀█▀ " _G "█ █ █ █ █ █ █ █ █ █ █ █ ▄ ▀▄\n" \
+_B " █▄ █ " _G " ▀▀ ▀ ▀ ▀▀ ▀▀▀ ▀▀ ▀ ▀▀ ▀▀ \n" \
+_B " ▀█▄▄▄▄▄▄▄▄▀ \n" \
+_B " ▀▀▀▀▀▀ \n" \
+RST "\n"
diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c
index 688c4ade..ce9fc8fc 100644
--- a/src/irmd/configfile.c
+++ b/src/irmd/configfile.c
@@ -47,8 +47,12 @@
#include <string.h>
#include <toml.h>
#include <arpa/inet.h>
+#ifdef __FreeBSD__
+#include <sys/socket.h>
+#endif
#define ERRBUFSZ 200
+#define DATUMSZ 256
static int toml_hash(toml_table_t * table,
struct layer_info * info)
@@ -157,14 +161,66 @@ static int toml_eth_dix(toml_table_t * table,
return 0;
}
-static int toml_udp(toml_table_t * table,
- struct ipcp_config * conf)
+static int toml_udp4(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ struct udp4_config * udp4;
+ toml_datum_t ip;
+ toml_datum_t port;
+ toml_datum_t dns;
+
+ *conf = udp4_default_conf;
+ udp4 = &conf->udp4;
+
+ 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, &udp4->ip_addr.s_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)
+ udp4->port = port.u.i;
+
+ dns = toml_string_in(table, "dns");
+ if (dns.ok) {
+ if (inet_pton(AF_INET, dns.u.s, &udp4->dns_addr.s_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_udp6(toml_table_t * table,
+ struct ipcp_config * conf)
{
+ struct in6_addr ip6;
+ struct in6_addr dns6;
toml_datum_t ip;
toml_datum_t port;
toml_datum_t dns;
- *conf = udp_default_conf;
+ *conf = udp6_default_conf;
+ ip6 = conf->udp6.ip_addr;
+ dns6 = conf->udp6.dns_addr;
ip = toml_string_in(table, "ip");
if (!ip.ok) {
@@ -172,18 +228,18 @@ static int toml_udp(toml_table_t * table,
goto fail_ip;
}
- if (inet_pton (AF_INET, ip.u.s, &conf->udp.ip_addr) != 1) {
+ if (inet_pton (AF_INET6, ip.u.s, &ip6.s6_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;
+ conf->udp6.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) {
+ if (inet_pton(AF_INET6, dns.u.s, &dns6.s6_addr) < 0) {
log_err("Failed to parse DNS address %s.", ip.u.s);
goto fail_dns;
}
@@ -214,26 +270,160 @@ static int toml_broadcast(toml_table_t * table,
return 0;
}
+#define BETWEEN(a, b, c) ((a) >= (b) && (a) <= (c))
+#define DHT(conf, x) (conf)->dht.params.x
+static int toml_dir(toml_table_t * table,
+ struct dir_config * conf)
+{
+ toml_datum_t dir;
+ toml_datum_t alpha;
+ toml_datum_t t_expire;
+ toml_datum_t t_refresh;
+ toml_datum_t t_replicate;
+ toml_datum_t k;
+
+ dir = toml_string_in(table, "directory");
+ if (dir.ok) {
+ log_dbg("Found directory type: %s", dir.u.s);
+ if (strlen(dir.u.s) > DATUMSZ) {
+ log_err("Directory name too long: %s", dir.u.s);
+ free(dir.u.s);
+ return -1;
+ }
+ if (strcmp(dir.u.s, "DHT") == 0)
+ conf->pol = DIR_DHT;
+ else if (strcmp(dir.u.s, "dht") == 0)
+ conf->pol = DIR_DHT;
+ else {
+ log_err("Unknown directory type: %s", dir.u.s);
+ free(dir.u.s);
+ return -EINVAL;
+ }
+ free(dir.u.s);
+ }
+
+ switch(conf->pol) {
+ case DIR_DHT:
+ log_info("Using DHT directory policy.");
+ alpha = toml_int_in(table, "dht_alpha");
+ if (alpha.ok) {
+ if (!BETWEEN(alpha.u.i,
+ DHT_ALPHA_MIN, DHT_ALPHA_MAX)) {
+ log_err("Invalid alpha value: %ld",
+ (long) alpha.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, alpha) = alpha.u.i;
+ }
+ t_expire = toml_int_in(table, "dht_t_expire");
+ if (t_expire.ok) {
+ if (!BETWEEN(t_expire.u.i,
+ DHT_T_EXPIRE_MIN, DHT_T_EXPIRE_MAX)) {
+ log_err("Invalid expire time: %ld",
+ (long) t_expire.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, t_expire) = t_expire.u.i;
+ }
+ t_refresh = toml_int_in(table, "dht_t_refresh");
+ if (t_refresh.ok) {
+ if (!BETWEEN(t_refresh.u.i,
+ DHT_T_REFRESH_MIN, DHT_T_REFRESH_MAX)) {
+ log_err("Invalid refresh time: %ld",
+ (long) t_refresh.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, t_refresh) = t_refresh.u.i;
+ }
+ t_replicate = toml_int_in(table, "dht_t_replicate");
+ if (t_replicate.ok) {
+ if (!BETWEEN(t_replicate.u.i,
+ DHT_T_REPLICATE_MIN, DHT_T_REPLICATE_MAX)) {
+ log_err("Invalid replication time: %ld",
+ (long) t_replicate.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, t_replicate) = t_replicate.u.i;
+ }
+ k = toml_int_in(table, "dht_k");
+ if (k.ok) {
+ if (!BETWEEN(k.u.i, DHT_K_MIN, DHT_K_MAX)) {
+ log_err("Invalid replication factor: %ld",
+ (long) k.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, k) = k.u.i;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ return 0;
+}
+
static int toml_routing(toml_table_t * table,
struct dt_config * conf)
{
toml_datum_t routing;
+ toml_datum_t t_recalc;
+ toml_datum_t t_update;
+ toml_datum_t t_timeo;
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;
+ if (strcmp(routing.u.s, "link-state") == 0) {
+ conf->routing.pol = ROUTING_LINK_STATE;
+ conf->routing.ls.pol = LS_SIMPLE;
+ } else if (strcmp(routing.u.s, "lfa") == 0) {
+ conf->routing.pol = ROUTING_LINK_STATE;
+ conf->routing.ls.pol = LS_LFA;
+ } else if (strcmp(routing.u.s, "ecmp") == 0) {
+ conf->routing.pol = ROUTING_LINK_STATE;
+ conf->routing.ls.pol = LS_ECMP;
+ } else {
+ conf->routing.pol = ROUTING_INVALID;
+ return -EINVAL;
+ }
free(routing.u.s);
}
- if (conf->routing_type == ROUTING_INVALID)
- return -1;
+ switch (conf->routing.pol) {
+ case ROUTING_LINK_STATE:
+ log_info("Using Link State routing policy.");
+ t_recalc = toml_int_in(table, "ls_t_recalc");
+ if (t_recalc.ok) {
+ if (t_recalc.u.i < 1) {
+ log_err("Invalid ls_t_recalc value: %ld",
+ (long) t_recalc.u.i);
+ return -EINVAL;
+ }
+ conf->routing.ls.t_recalc = t_recalc.u.i;
+ }
+ t_update = toml_int_in(table, "ls_t_update");
+ if (t_update.ok) {
+ if (t_update.u.i < 1) {
+ log_err("Invalid ls_t_update value: %ld",
+ (long) t_update.u.i);
+ return -EINVAL;
+ }
+ conf->routing.ls.t_update = t_update.u.i;
+ }
+ t_timeo = toml_int_in(table, "ls_t_timeo");
+ if (t_timeo.ok) {
+ if (t_timeo.u.i < 1) {
+ log_err("Invalid ls_t_timeo value: %ld",
+ (long) t_timeo.u.i);
+ return -EINVAL;
+ }
+ conf->routing.ls.t_timeo = t_timeo.u.i;
+ }
+ break;
+ default:
+ log_err("Invalid routing policy: %d", conf->routing.pol);
+ return -EINVAL;
+ }
return 0;
}
@@ -311,12 +501,12 @@ static int toml_dt(toml_table_t * table,
static int toml_unicast(toml_table_t * table,
struct ipcp_config * conf)
{
-
-
*conf = uni_default_conf;
- if (toml_hash(table, &conf->layer_info) < 0)
+ if (toml_dir(table, &conf->unicast.dir) < 0) {
+ log_err("Invalid directory configuration.");
return -1;
+ }
if (toml_dt(table, &conf->unicast.dt) < 0) {
log_err("Invalid DT configuration.");
@@ -333,6 +523,7 @@ static int toml_unicast(toml_table_t * table,
return -1;
}
+
return 0;
}
@@ -504,8 +695,11 @@ static int toml_ipcp(toml_table_t * table,
case IPCP_ETH_LLC:
ret = toml_eth_llc(table, conf);
break;
- case IPCP_UDP:
- ret = toml_udp(table, conf);
+ case IPCP_UDP4:
+ ret = toml_udp4(table, conf);
+ break;
+ case IPCP_UDP6:
+ ret = toml_udp6(table, conf);
break;
case IPCP_BROADCAST:
ret = toml_broadcast(table, conf);
@@ -563,7 +757,7 @@ static int toml_ipcp_list(toml_table_t * table,
}
info.type = type;
- strcpy(info.name,key);
+ strcpy(info.name, key);
conf.type = type;
ret = toml_ipcp(toml_table_in(table, key), &info, &conf);
@@ -691,18 +885,63 @@ static int toml_prog_list(toml_array_t * progs,
return ret;
}
+static int cp_chk_path(char * buf,
+ char * path)
+{
+ char * rp;
+
+ assert(path != NULL);
+
+ rp = realpath(path, NULL);
+ if (rp == NULL) {
+ log_err("Failed to check path %s: %s.", path, strerror(errno));
+ goto fail_rp;
+ }
+
+ if (strlen(rp) > NAME_PATH_SIZE) {
+ log_err("File path too long: %s.", rp);
+ goto fail_len;
+ }
+
+ strcpy(buf, rp);
+ free(rp);
+ free(path);
+
+ return 0;
+
+ fail_len:
+ free(rp);
+ fail_rp:
+ free(path);
+ return -1;
+}
+
static int toml_name(toml_table_t * table,
const char * name)
{
- toml_array_t * progs;
- toml_array_t * args;
- toml_datum_t lb;
+ toml_array_t * progs;
+ toml_array_t * args;
+ toml_datum_t lb;
+ toml_datum_t senc;
+ toml_datum_t scrt;
+ toml_datum_t skey;
+ toml_datum_t cenc;
+ toml_datum_t ccrt;
+ toml_datum_t ckey;
+
struct name_info info = {
.pol_lb = LB_SPILL
};
log_dbg("Found service name %s in configuration file.", name);
+ if (strlen(name) > NAME_SIZE) {
+ log_err("Name too long: %s", name);
+ return -1;
+ }
+
+ strcpy(info.name, name);
+
lb = toml_string_in(table, "lb");
if (lb.ok) {
if (strcmp(lb.u.s, "spill") == 0)
@@ -718,8 +957,29 @@ static int toml_name(toml_table_t * table,
log_err("Invalid load-balancing policy for %s.", name);
return -1;
}
+ senc = toml_string_in(table, "server_enc_file");
+ if (senc.ok && cp_chk_path(info.s.enc, senc.u.s) < 0)
+ return -1;
- strcpy(info.name, name);
+ scrt = toml_string_in(table, "server_crt_file");
+ if (scrt.ok && cp_chk_path(info.s.crt, scrt.u.s) < 0)
+ return -1;
+
+ skey = toml_string_in(table, "server_key_file");
+ if (skey.ok && cp_chk_path(info.s.key, skey.u.s) < 0)
+ return -1;
+
+ cenc = toml_string_in(table, "client_enc_file");
+ if (cenc.ok && cp_chk_path(info.c.enc, cenc.u.s) < 0)
+ return -1;
+
+ ccrt = toml_string_in(table, "client_crt_file");
+ if (ccrt.ok && cp_chk_path(info.c.crt, ccrt.u.s) < 0)
+ return -1;
+
+ ckey = toml_string_in(table, "client_key_file");
+ if (ckey.ok && cp_chk_path(info.c.key, ckey.u.s) < 0)
+ return -1;
if (name_create(&info) < 0) {
log_err("Failed to create name %s.", name);
@@ -762,23 +1022,24 @@ static int toml_toplevel(toml_table_t * table,
toml_table_t * subtable;
subtable = toml_table_in(table, key);
-
- if (strcmp(key, "local") == 0)
+ if (strcmp(key, "name") == 0)
+ return toml_name_list(subtable);
+ else 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, "udp4") == 0)
+ return toml_ipcp_list(subtable, IPCP_UDP4);
+ else if (strcmp(key, "udp6") == 0)
+ return toml_ipcp_list(subtable, IPCP_UDP6);
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);
+ else
+ log_err("Unkown toplevel key: %s.", key);
return -1;
}
@@ -838,7 +1099,8 @@ int irm_configure(const char * path)
rp = realpath(path, NULL);
if (rp == NULL) {
- log_err("Failed to resolve path for %s", path);
+ log_err("Failed to check path for %s: %s.",
+ path, strerror(errno));
goto fail_resolve;
}
diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c
index 5a9a79d3..6226aeda 100644
--- a/src/irmd/ipcp.c
+++ b/src/irmd/ipcp.c
@@ -83,28 +83,30 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
{
int sockfd;
uint8_t buf[SOCK_BUF_SIZE];
- char * sock_path;
+ char * spath;
ssize_t len;
- ipcp_msg_t * recv_msg;
struct timeval tv;
struct timespec tic;
struct timespec toc;
- bool dealloc = false;
+ bool may_fail = false;
if (kill(pid, 0) < 0)
return NULL;
- sock_path = ipcp_sock_path(pid);
- if (sock_path == NULL)
+ spath = sock_path(pid, IPCP_SOCK_PATH_PREFIX);
+ if (spath == NULL) {
+ log_err("Failed to get IPCP socket path for pid %d.", pid);
return NULL;
+ }
- sockfd = client_socket_open(sock_path);
+ sockfd = client_socket_open(spath);
if (sockfd < 0) {
- free(sock_path);
+ log_err("Failed to open client socket at %s.", spath);
+ free(spath);
return NULL;
}
- free(sock_path);
+ free(spath);
len = ipcp_msg__get_packed_size(msg);
if (len == 0 || len >= SOCK_BUF_SIZE) {
@@ -127,6 +129,7 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
tv.tv_usec = (REG_TIMEOUT % 1000) * 1000;
break;
case IPCP_MSG_CODE__IPCP_QUERY:
+ may_fail = true; /* name not always in Layer */
tv.tv_sec = QUERY_TIMEOUT / 1000;
tv.tv_usec = (QUERY_TIMEOUT % 1000) * 1000;
break;
@@ -139,7 +142,7 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
tv.tv_usec = (FLOW_ALLOC_TIMEOUT % 1000) * 1000;
break;
case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
- dealloc = true;
+ may_fail = true;
tv.tv_sec = 0; /* FIX DEALLOC: don't wait for dealloc */
tv.tv_usec = 500;
break;
@@ -167,17 +170,15 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
pthread_cleanup_pop(true); /* close socket */
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 ipcp_msg__unpack(NULL, len, buf);
+
+ if (errno == EAGAIN && !may_fail) {
+ int diff = ts_diff_ms(&toc, &tic);
+ log_warn("IPCP %s timed out after %d ms.",
+ str_ipcp_cmd(msg->code), diff);
}
- return recv_msg;
+ return NULL;
}
int ipcp_bootstrap(pid_t pid,
@@ -496,7 +497,7 @@ int ipcp_flow_alloc_resp(const struct flow_info * flow,
msg.pid = flow->n_pid;
msg.has_response = true;
msg.response = response;
- msg.has_pk = true;
+ msg.has_pk = response == 0;
msg.pk.data = data.data;
msg.pk.len = data.len;
diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h
index cf8f6953..3e54904a 100644
--- a/src/irmd/irmd.h
+++ b/src/irmd/irmd.h
@@ -39,7 +39,7 @@ int connect_ipcp(pid_t pid,
const char * component,
qosspec_t qs);
-int name_create(const struct name_info * info);
+int name_create(struct name_info * info);
int name_reg(const char * name,
pid_t pid);
diff --git a/src/irmd/main.c b/src/irmd/main.c
index bc13fa7c..834a7a8c 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -40,6 +40,7 @@
#include <ouroboros/lockfile.h>
#include <ouroboros/logs.h>
#include <ouroboros/pthread.h>
+#include <ouroboros/random.h>
#include <ouroboros/rib.h>
#include <ouroboros/shm_rdrbuff.h>
#include <ouroboros/sockets.h>
@@ -50,9 +51,11 @@
#include "irmd.h"
#include "ipcp.h"
+#include "oap.h"
#include "reg/reg.h"
#include "configfile.h"
+#include <dirent.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
@@ -71,15 +74,24 @@
#define SHM_SAN_HOLDOFF 1000 /* ms */
#define IPCP_HASH_LEN(p) hash_len((p)->dir_hash_algo)
#define BIND_TIMEOUT 10 /* ms */
+#define TIMESYNC_SLACK 100 /* ms */
+#define OAP_SEEN_TIMER 20 /* s */
#define DEALLOC_TIME 300 /* s */
-#define MSGBUFSZ 2048
enum irm_state {
IRMD_NULL = 0,
+ IRMD_INIT,
IRMD_RUNNING,
IRMD_SHUTDOWN
};
+struct oaph {
+ struct list_head next;
+
+ uint64_t stamp;
+ uint8_t id[OAP_ID_SIZE];
+};
+
struct cmd {
struct list_head next;
@@ -93,6 +105,12 @@ struct {
#ifdef HAVE_TOML
char * cfg_file; /* configuration file path */
#endif
+ struct {
+ struct auth_ctx * ctx; /* default authentication ctx */
+ struct list_head list; /* OAP headers seen before */
+ pthread_mutex_t mtx; /* mutex for OAP headers */
+ } auth;
+
struct lockfile * lf; /* single irmd per system */
struct shm_rdrbuff * rdrb; /* rdrbuff for packets */
@@ -173,8 +191,11 @@ static pid_t spawn_ipcp(struct ipcp_info * info)
case IPCP_BROADCAST:
exec_name = IPCP_BROADCAST_EXEC;
break;
- case IPCP_UDP:
- exec_name = IPCP_UDP_EXEC;
+ case IPCP_UDP4:
+ exec_name = IPCP_UDP4_EXEC;
+ break;
+ case IPCP_UDP6:
+ exec_name = IPCP_UDP6_EXEC;
break;
case IPCP_ETH_LLC:
exec_name = IPCP_ETH_LLC_EXEC;
@@ -217,7 +238,7 @@ static pid_t spawn_ipcp(struct ipcp_info * info)
}
info->pid = pid;
- info->state = IPCP_BOOT;
+ info->state = IPCP_INIT;
return 0;
}
@@ -312,7 +333,7 @@ int bootstrap_ipcp(pid_t pid,
goto fail;
}
- if (conf->type == IPCP_UDP)
+ if (conf->type == IPCP_UDP4 || conf->type == IPCP_UDP6)
conf->layer_info.dir_hash_algo = (enum pol_dir_hash) HASH_MD5;
if (ipcp_bootstrap(pid, conf, &layer)) {
@@ -320,7 +341,7 @@ int bootstrap_ipcp(pid_t pid,
goto fail;
}
- info.state = IPCP_BOOTSTRAPPED;
+ info.state = IPCP_BOOT;
if (reg_set_layer_for_ipcp(&info, &layer) < 0) {
log_err("Failed to set layer info for IPCP.");
@@ -352,6 +373,8 @@ int enroll_ipcp(pid_t pid,
goto fail;
}
+ info.state = IPCP_BOOT;
+
if (reg_set_layer_for_ipcp(&info, &layer) < 0) {
log_err("Failed to set layer info for IPCP.");
goto fail;
@@ -425,6 +448,71 @@ static int disconnect_ipcp(pid_t pid,
return 0;
}
+static void name_update_sec_paths(struct name_info * info)
+{
+ char * srv_dir = OUROBOROS_SRV_CRT_DIR;
+ char * cli_dir = OUROBOROS_CLI_CRT_DIR;
+
+ assert(info != NULL);
+
+ if (strlen(info->s.enc) == 0)
+ sprintf(info->s.enc, "%s/%s/enc.cfg", srv_dir, info->name);
+
+ if (strlen(info->s.crt) == 0)
+ sprintf(info->s.crt, "%s/%s/crt.pem", srv_dir, info->name);
+
+ if (strlen(info->s.key) == 0)
+ sprintf(info->s.key, "%s/%s/key.pem", srv_dir, info->name);
+
+ if (strlen(info->c.enc) == 0)
+ sprintf(info->c.enc, "%s/%s/enc.cfg", cli_dir, info->name);
+
+ if (strlen(info->c.crt) == 0)
+ sprintf(info->c.crt, "%s/%s/crt.pem", cli_dir, info->name);
+
+ if (strlen(info->c.key) == 0)
+ sprintf(info->c.key, "%s/%s/key.pem", cli_dir, info->name);
+}
+
+int name_create(struct name_info * info)
+{
+ int ret;
+
+ assert(info != NULL);
+
+ name_update_sec_paths(info);
+
+ ret = reg_create_name(info);
+ if (ret == -EEXIST) {
+ log_info("Name %s already exists.", info->name);
+ return 0;
+ }
+
+ if (ret < 0) {
+ log_err("Failed to create name %s.", info->name);
+ return -1;
+ }
+
+ log_info("Created new name: %s.", info->name);
+
+ return 0;
+}
+
+static int name_destroy(const char * name)
+{
+
+ assert(name != NULL);
+
+ if (reg_destroy_name(name) < 0) {
+ log_err("Failed to destroy name %s.", name);
+ return -1;
+ }
+
+ log_info("Destroyed name: %s.", name);
+
+ return 0;
+}
+
int bind_program(char ** exec,
const char * name,
uint8_t flags)
@@ -448,10 +536,8 @@ int bind_program(char ** exec,
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);
+ if (name_create(&ni) < 0)
goto fail_name;
- }
}
if (reg_bind_prog(name, exec, flags) < 0) {
@@ -497,10 +583,8 @@ int bind_process(pid_t pid,
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);
+ if (name_create(&ni) < 0)
goto fail;
- }
}
if (reg_bind_proc(name, pid) < 0) {
@@ -581,43 +665,6 @@ static int list_ipcps(ipcp_list_msg_t *** ipcps,
return -1;
}
-int name_create(const struct name_info * info)
-{
- int ret;
-
- assert(info != NULL);
-
- ret = reg_create_name(info);
- if (ret == -EEXIST) {
- log_info("Name %s already exists.", info->name);
- return 0;
- }
-
- if (ret < 0) {
- log_err("Failed to create name %s.", info->name);
- return -1;
- }
-
- log_info("Created new name: %s.", info->name);
-
- return 0;
-}
-
-static int name_destroy(const char * name)
-{
-
- assert(name != NULL);
-
- if (reg_destroy_name(name) < 0) {
- log_err("Failed to destroy name %s.", name);
- return -1;
- }
-
- log_info("Destroyed name: %s.", name);
-
- return 0;
-}
-
static int list_names(name_info_msg_t *** names,
size_t * n_names)
{
@@ -760,67 +807,279 @@ static void __cleanup_flow(void * flow)
reg_destroy_flow(((struct flow_info *) flow)->id);
}
+static bool file_exists(const char * path)
+{
+ struct stat s;
+
+ if (stat(path, &s) < 0 && errno == ENOENT) {
+ log_dbg("File %s does not exist.", path);
+ return false;
+ }
+
+ return true;
+}
+
+static int load_credentials(const char * name,
+ const struct name_sec_paths * paths,
+ void ** pkp,
+ void ** crt,
+ bool * crypt)
+{
+ assert(paths != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ *pkp = NULL;
+ *crt = NULL;
+
+ /* TODO: Allow configuration. For now, encrypt if path exists */
+ *crypt = file_exists(paths->enc);
+ if (*crypt)
+ log_info("Encryption enabled for %s.", name);
+
+ if (!file_exists(paths->crt) || !file_exists(paths->key)) {
+ log_info("No security info for %s.", name);
+ return 0;
+ }
+
+ if (crypt_load_crt_file(paths->crt, crt) < 0) {
+ log_err("Failed to load %s for %s.", paths->crt, name);
+ goto fail_crt;
+ }
+
+ if (crypt_load_privkey_file(paths->key, pkp) < 0) {
+ log_err("Failed to load %s for %s.", paths->key, name);
+ goto fail_key;
+ }
+
+ log_info("Loaded security keys for %s.", name);
+
+ return 0;
+
+ fail_key:
+ crypt_free_crt(*crt);
+ *crt = NULL;
+ fail_crt:
+ return -EAUTH;
+}
+
+static int load_srv_credentials(const char * name,
+ void ** pkp,
+ void ** crt,
+ bool * crypt)
+{
+ struct name_info info;
+
+ assert(name != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ if (reg_get_name_info(name, &info) < 0) {
+ log_err("Failed to get name info for %s.", name);
+ return -ENAME;
+ }
+
+ return load_credentials(name, &info.s, pkp, crt, crypt);
+}
+
+static int load_cli_credentials(const char * name,
+ void ** pkp,
+ void ** crt,
+ bool * crypt)
+{
+ struct name_info info;
+
+ assert(name != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ if (reg_get_name_info(name, &info) < 0) {
+ log_err("Failed to get name info for %s.", name);
+ return -ENAME;
+ }
+
+ return load_credentials(name, &info.c, pkp, crt, crypt);
+}
+
+#define ID_IS_EQUAL(id1, id2) (memcmp(id1, id2, OAP_ID_SIZE) == 0)
+static int irm_check_oap_hdr(const struct oap_hdr * oap_hdr,
+ time_t mpl)
+{
+ struct list_head * p;
+ struct list_head * h;
+ struct timespec now;
+ struct oaph * new;
+ uint64_t stamp;
+ uint64_t cur;
+ uint8_t * id;
+ ssize_t delta;
+
+ assert(oap_hdr != NULL);
+
+ stamp = oap_hdr->timestamp;
+ id = oap_hdr->id.data;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ cur = TS_TO_UINT64(now);
+
+ delta = (ssize_t)(cur - stamp) / MILLION;
+ if (delta > mpl)
+ log_warn("Transit time exceeds MPL by %zd ms.", delta);
+ if (delta < -TIMESYNC_SLACK)
+ log_warn("OAP header sent %zd ms from the future.", -delta);
+
+ new = malloc(sizeof(*new));
+ if (new == NULL) {
+ log_err("Failed to allocate memory for OAP element.");
+ return -ENOMEM;
+ }
+
+ pthread_mutex_lock(&irmd.auth.mtx);
+
+ list_for_each_safe(p, h, &irmd.auth.list) {
+ struct oaph * oaph = list_entry(p, struct oaph, next);
+ if (cur > oaph->stamp + OAP_SEEN_TIMER * BILLION) {
+ list_del(&oaph->next);
+ free(oaph);
+ continue;
+ }
+
+ if (oaph->stamp == stamp && ID_IS_EQUAL(oaph->id, id)) {
+ log_warn("OAP header already known: " HASH_FMT64 ".",
+ HASH_VAL64(id));
+ goto fail_replay;
+ }
+ }
+
+ memcpy(new->id, id, OAP_ID_SIZE);
+ new->stamp = stamp;
+
+ list_add_tail(&new->next, &irmd.auth.list);
+
+ pthread_mutex_unlock(&irmd.auth.mtx);
+
+ return 0;
+
+ fail_replay:
+ pthread_mutex_unlock(&irmd.auth.mtx);
+ free(new);
+ return -EAUTH;
+}
+
+static int irm_auth_peer(const char * name,
+ const struct oap_hdr * oap_hdr,
+ const struct oap_hdr * r_oap_hdr)
+{
+ void * crt;
+ void * pk;
+ buffer_t sign;
+ const char * n = name == NULL ? "<client>" : name;
+
+ if (memcmp(r_oap_hdr->id.data, oap_hdr->id.data, OAP_ID_SIZE) != 0) {
+ log_err("OAP ID mismatch in flow allocation.");
+ goto fail_check;
+ }
+
+ if (r_oap_hdr->crt.len == 0) {
+ log_info("No certificate provided by %s.", n);
+ return 0;
+ }
+
+ if (crypt_load_crt_der(r_oap_hdr->crt, &crt) < 0) {
+ log_err("Failed to load certificate from %s.", n);
+ goto fail_check;
+ }
+
+ log_dbg("Loaded peer certificate for %s.", n);
+
+ if (name != NULL) {
+ if (crypt_check_crt_name(crt, n) < 0) {
+ log_err("Certificate does not match %s.", n);
+ goto fail_crt;
+ }
+ log_dbg("Certificate matches name %s.", n);
+ }
+
+ if (crypt_get_pubkey_crt(crt, &pk) < 0) {
+ log_err("Failed to get pubkey from certificate for %s.", n);
+ goto fail_crt;
+ }
+
+ log_dbg("Got public key from certificate for %s.", n);
+
+ if (auth_verify_crt(irmd.auth.ctx, crt) < 0) {
+ log_err("Failed to verify peer %s with CA store.", n);
+ goto fail_crt;
+ }
+
+ log_info("Successfully verified peer certificate for %s.", n);
+
+ sign = r_oap_hdr->hdr;
+ sign.len -= (r_oap_hdr->sig.len + sizeof(uint16_t));
+
+ if (auth_verify_sig(pk, sign, r_oap_hdr->sig) < 0) {
+ log_err("Failed to verify signature for peer %s.", n);
+ goto fail_check_sig;
+ }
+
+ crypt_free_key(pk);
+ crypt_free_crt(crt);
+
+ log_info("Successfully authenticated %s.", n);
+
+ return 0;
+
+ fail_check_sig:
+ crypt_free_key(pk);
+ fail_crt:
+ crypt_free_crt(crt);
+ fail_check:
+ return -1;
+}
+
static int flow_accept(struct flow_info * flow,
+ buffer_t * symmkey,
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;
+ struct oap_hdr oap_hdr; /* incoming request */
+ struct oap_hdr r_oap_hdr; /* outgoing response */
+ uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
+ buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
+ char name[NAME_SIZE + 1]; /* name for flow */
+ void * pkp = NULL; /* signing private key */
+ void * crt = NULL; /* signing certificate */
+ int err;
+ bool crypt;
/* piggyback of user data not yet implemented */
- assert(data != NULL && data->len == 0 && data->data == NULL);
+ assert(data != NULL && BUF_IS_EMPTY(data));
+ assert(symmkey != NULL && BUF_IS_EMPTY(symmkey));
if (!reg_has_proc(flow->n_pid)) {
log_err("Unknown process %d calling accept.", flow->n_pid);
err = -EINVAL;
- goto fail;
- }
-
- s = malloc(SYMMKEYSZ);
- if (s == NULL) {
- log_err("Failed to malloc symmkey.");
- err = -ENOMEM;
- goto fail;
- }
-
- key_len = crypt_dh_pkp_create(&pkp, buf);
- if (key_len < 0) {
- log_err("Failed to generate key pair.");
- err = -ECRYPT;
- goto fail_pkp;
+ goto fail_flow;
}
- lpk.data = buf;
- lpk.len = (size_t) key_len;
-
- log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
-
if (reg_create_flow(flow) < 0) {
log_err("Failed to create flow.");
err = -EBADF;
goto fail_flow;
}
- if (reg_prepare_flow_accept(flow, &lpk) < 0) {
+ if (reg_prepare_flow_accept(flow) < 0) {
log_err("Failed to prepare accept.");
err = -EBADF;
goto fail_wait;
}
pthread_cleanup_push(__cleanup_flow, flow);
- pthread_cleanup_push(__cleanup_pkp, pkp);
- pthread_cleanup_push(free, s);
- err = reg_wait_flow_accepted(flow, &rpk, abstime);
+ err = reg_wait_flow_accepted(flow, &oap_hdr.hdr, abstime);
pthread_cleanup_pop(false);
- pthread_cleanup_pop(false);
- pthread_cleanup_pop(false);
if (err == -ETIMEDOUT) {
log_err("Flow accept timed out.");
@@ -835,45 +1094,135 @@ static int flow_accept(struct flow_info * flow,
assert(err == 0);
- if (flow->qs.cypher_s != 0) { /* crypto requested */
- if (crypt_dh_derive(pkp, rpk, s) < 0) {
+ if (reg_get_name_for_flow_id(name, flow->id) < 0) {
+ log_err("Failed to get name for flow %d.", flow->id);
+ err = -EIPCP;
+ goto fail_cred;
+ }
+
+ log_dbg("IPCP %d accepting flow %d for %s.",
+ flow->n_pid, flow->id, name);
+
+ if (load_srv_credentials(name, &pkp, &crt, &crypt) < 0) {
+ log_err("Failed to load security keys for %s.", name);
+ err = -EAUTH;
+ goto fail_cred;
+ }
+
+ if (oap_hdr_decode(oap_hdr.hdr, &oap_hdr) < 0) {
+ log_err("Failed to decode OAP header from %s.", name);
+ err = -EIPCP;
+ goto fail_oap_hdr;
+ }
+#ifdef DEBUG_PROTO_OAP
+ debug_oap_hdr_rcv(&oap_hdr);
+#endif
+ if (irm_check_oap_hdr(&oap_hdr, flow->mpl) < 0) {
+ log_err("OAP header failed replay check.");
+ goto fail_oap_hdr;
+ }
+
+ if (crypt && oap_hdr.eph.len == 0) {
+ log_warn("Encryption required but no key provided.");
+ err = -ECRYPT;
+ goto fail_oap_hdr;
+ }
+
+ if (oap_hdr.eph.len > 0) { /* crypto requested */
+ uint8_t * s; /* symmetric encryption key */
+ ssize_t key_len; /* length of local pubkey */
+ void * pkp = NULL; /* ephemeral private key pair */
+
+ s = malloc(SYMMKEYSZ);
+ if (s == NULL) {
+ log_err("Failed to malloc symmkey.");
+ err = -ENOMEM;
+ goto fail_keys;
+ }
+
+ key_len = crypt_dh_pkp_create(&pkp, buf);
+ if (key_len < 0) {
+ free(s);
+ log_err("Failed to generate key pair.");
+ err = -ECRYPT;
+ goto fail_keys;
+ }
+
+ lpk.data = buf;
+ lpk.len = (size_t) key_len;
+
+ log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
+
+ if (crypt_dh_derive(pkp, oap_hdr.eph, s) < 0) {
log_err("Failed to derive secret for %d.", flow->id);
+ crypt_dh_pkp_destroy(pkp);
+ free(s);
err = -ECRYPT;
goto fail_derive;
}
- freebuf(rpk);
- data->data = s;
- data->len = SYMMKEYSZ;
- s= NULL;
- } else {
- clrbuf(lpk);
+
+ symmkey->data = s;
+ symmkey->len = SYMMKEYSZ;
+
+ crypt_dh_pkp_destroy(pkp);
}
- if (ipcp_flow_alloc_resp(flow, 0, lpk) < 0) {
+ if (oap_hdr_init(oap_hdr.id, pkp, crt, lpk, *data, &r_oap_hdr) < 0) {
+ log_err("Failed to create OAP header.");
+ err = -ENOMEM;
+ goto fail_r_oap_hdr;
+ }
+
+ if (irm_auth_peer(NULL, &r_oap_hdr, &oap_hdr) < 0) {
+ log_err("Failed to auth %s client, flow %d.", name, flow->id);
+ err = -EAUTH;
+ goto fail_r_oap_hdr;
+ }
+
+ crypt_free_crt(crt);
+ crypt_free_key(pkp);
+
+#ifdef DEBUG_PROTO_OAP
+ debug_oap_hdr_snd(&r_oap_hdr);
+#endif
+ if (ipcp_flow_alloc_resp(flow, 0, r_oap_hdr.hdr) < 0) {
log_err("Failed to respond to flow allocation.");
- err = -EIPCP;
- goto fail_alloc_resp;
+ goto fail_resp;
}
- crypt_dh_pkp_destroy(pkp);
- free(s);
+ log_info("Flow %d accepted by %d for %s.",
+ flow->id, flow->n_pid, name);
+
+ oap_hdr_fini(&oap_hdr);
+ oap_hdr_fini(&r_oap_hdr);
return 0;
+ fail_r_oap_hdr:
+ freebuf(*symmkey);
fail_derive:
- freebuf(rpk);
clrbuf(lpk);
+ fail_keys:
+ oap_hdr_fini(&oap_hdr);
+ fail_oap_hdr:
+ crypt_free_crt(crt);
+ crypt_free_key(pkp);
+ fail_cred:
+ assert(lpk.data == NULL && lpk.len == 0);
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;
+
+ fail_resp:
+ flow->state = FLOW_NULL;
+ oap_hdr_fini(&r_oap_hdr);
+ freebuf(*symmkey);
+ clrbuf(lpk);
+ oap_hdr_fini(&oap_hdr);
+ reg_destroy_flow(flow->id);
+ return -EIPCP;
}
static int flow_join(struct flow_info * flow,
@@ -883,7 +1232,7 @@ static int flow_join(struct flow_info * flow,
struct ipcp_info ipcp;
struct layer_info layer;
buffer_t hash;
- buffer_t pbuf = {NULL, 0}; /* nothing to piggyback */
+ buffer_t pbuf = BUF_INIT; /* nothing to piggyback */
int err;
log_info("Allocating flow for %d to %s.", flow->n_pid, dst);
@@ -936,6 +1285,7 @@ static int flow_join(struct flow_info * flow,
goto fail_alloc;
}
+ assert(pbuf.data == NULL && pbuf.len == 0);
assert(err == 0);
freebuf(hash);
@@ -1009,23 +1359,46 @@ static int get_ipcp_by_dst(const char * dst,
static int flow_alloc(struct flow_info * flow,
const char * dst,
+ buffer_t * symmkey,
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;
+ struct oap_hdr oap_hdr; /* outgoing request */
+ struct oap_hdr r_oap_hdr; /* incoming response */
+ uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
+ buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
+ void * pkp = NULL; /* ephemeral private key pair */
+ uint8_t * s = NULL; /* symmetric key */
+ void * cpkp = NULL; /* signing private key */
+ void * ccrt = NULL; /* signing certificate */
+ buffer_t hash;
+ uint8_t idbuf[OAP_ID_SIZE];
+ buffer_t id;
+ int err;
+ bool crypt;
+
/* piggyback of user data not yet implemented */
- assert(data != NULL && data->len == 0 && data->data == NULL);
+ assert(data != NULL && BUF_IS_EMPTY(data));
+ assert(symmkey != NULL && BUF_IS_EMPTY(symmkey));
log_info("Allocating flow for %d to %s.", flow->n_pid, dst);
+ if (random_buffer(idbuf, OAP_ID_SIZE) < 0) {
+ log_err("Failed to generate ID.");
+ err = -EIRMD;
+ goto fail_id;
+ }
+
+ id.data = idbuf;
+ id.len = OAP_ID_SIZE;
- if (flow->qs.cypher_s > 0) {
+ if (load_cli_credentials(dst, &cpkp, &ccrt, &crypt) < 0) {
+ log_err("Failed to load security keys for %s.", dst);
+ err = -EAUTH;
+ goto fail_cred;
+ }
+
+ if (crypt > 0) {
ssize_t key_len;
s = malloc(SYMMKEYSZ);
@@ -1048,6 +1421,14 @@ static int flow_alloc(struct flow_info * flow,
log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
}
+ if (oap_hdr_init(id, cpkp, ccrt, lpk, *data, &oap_hdr) < 0) {
+ log_err("Failed to create OAP header.");
+ err = -ENOMEM;
+ goto fail_oap_hdr;
+ }
+#ifdef DEBUG_PROTO_OAP
+ debug_oap_hdr_snd(&oap_hdr);
+#endif
if (reg_create_flow(flow) < 0) {
log_err("Failed to create flow.");
err = -EBADF;
@@ -1062,7 +1443,7 @@ static int flow_alloc(struct flow_info * flow,
reg_prepare_flow_alloc(flow);
- if (ipcp_flow_alloc(flow, hash, lpk)) {
+ if (ipcp_flow_alloc(flow, hash, oap_hdr.hdr)) {
log_err("Flow allocation %d failed.", flow->id);
err = -ENOTALLOC;
goto fail_alloc;
@@ -1073,7 +1454,7 @@ static int flow_alloc(struct flow_info * flow,
pthread_cleanup_push(free, hash.data);
pthread_cleanup_push(free, s);
- err = reg_wait_flow_allocated(flow, &rpk, abstime);
+ err = reg_wait_flow_allocated(flow, &r_oap_hdr.hdr, abstime);
pthread_cleanup_pop(false);
pthread_cleanup_pop(false);
@@ -1087,48 +1468,86 @@ static int flow_alloc(struct flow_info * flow,
if (err == -1) {
log_dbg("Flow allocation terminated.");
- err = -EPIPE;
+ err = -EIPCP;
goto fail_alloc;
}
- assert(err == 0);
+ log_dbg("Response received for flow %d to %s.", flow->id, dst);
+
+ if (err < 0) {
+ log_warn("Flow allocation rejected for %s: %d.", dst, err);
+ goto fail_alloc;
+ }
+
+ if (oap_hdr_decode(r_oap_hdr.hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to decode OAP header.");
+ err = -EIPCP;
+ goto fail_r_oap_hdr;
+ }
+#ifdef DEBUG_PROTO_OAP
+ debug_oap_hdr_rcv(&r_oap_hdr);
+#endif
+ if (irm_check_oap_hdr(&r_oap_hdr, flow->mpl) < 0) {
+ log_err("OAP header failed replay check.");
+ err = -EAUTH;
+ goto fail_r_oap_hdr;
+ }
- if (flow->qs.cypher_s != 0) { /* crypto requested */
- if (crypt_dh_derive(pkp, rpk, s) < 0) {
+ if (irm_auth_peer(dst, &oap_hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to authenticate %s (flow %d).", dst, flow->id);
+ err = -EAUTH;
+ goto fail_r_oap_hdr;
+ }
+
+ if (lpk.len > 0) { /* crypto requested */
+ if (crypt_dh_derive(pkp, r_oap_hdr.eph, s) < 0) {
log_err("Failed to derive secret for %d.", flow->id);
err = -ECRYPT;
- goto fail_derive;
+ goto fail_r_oap_hdr;
}
crypt_dh_pkp_destroy(pkp);
- freebuf(rpk);
- data->data = s;
- data->len = SYMMKEYSZ;
+
+ symmkey->data = s;
+ symmkey->len = SYMMKEYSZ;
s = NULL;
}
+ oap_hdr_fini(&r_oap_hdr);
+ oap_hdr_fini(&oap_hdr);
+
+ crypt_free_crt(ccrt);
+ crypt_free_key(cpkp);
+
+ /* TODO: piggyback user data if needed */
+
freebuf(hash);
free(s);
return 0;
- fail_derive:
- freebuf(rpk);
+ fail_r_oap_hdr:
flow->state = FLOW_DEALLOCATED;
+ oap_hdr_fini(&r_oap_hdr);
fail_alloc:
freebuf(hash);
fail_ipcp:
reg_destroy_flow(flow->id);
fail_flow:
- if (flow->qs.cypher_s > 0)
- crypt_dh_pkp_destroy(pkp);
+ oap_hdr_fini(&oap_hdr);
+ fail_oap_hdr:
+ crypt_dh_pkp_destroy(pkp);
fail_pkp:
free(s);
fail_malloc:
+ crypt_free_crt(ccrt);
+ crypt_free_key(cpkp);
+ fail_cred:
+ clrbuf(id);
+ fail_id:
return err;
}
-static int wait_for_accept(enum hash_algo algo,
- const uint8_t * hash)
+static int wait_for_accept(const char * name)
{
struct timespec timeo = TIMESPEC_INIT_MS(IRMD_REQ_ARR_TIMEOUT);
struct timespec abstime;
@@ -1138,25 +1557,23 @@ static int wait_for_accept(enum hash_algo algo,
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- ret = reg_wait_flow_accepting(algo, hash, &abstime);
+ ret = reg_wait_flow_accepting(name, &abstime);
if (ret == -ETIMEDOUT) {
- if (reg_get_exec(algo, hash, &exec) < 0) {
- log_dbg("No program bound to " HASH_FMT32 ".",
- HASH_VAL32(hash));
+ if (reg_get_exec(name, &exec) < 0) {
+ log_dbg("No program bound for %s.", name);
goto fail;
}
- log_info("Autostarting %s.", exec[0]);
-
if (spawn_program(exec) < 0) {
- log_dbg("Failed to autostart " HASH_FMT32 ".",
- HASH_VAL32(hash));
+ log_err("Failed to start %s for %s.", exec[0], name);
goto fail_spawn;
}
+ log_info("Starting %s for %s.", exec[0], name);
+
ts_add(&abstime, &timeo, &abstime);
- ret = reg_wait_flow_accepting(algo, hash, &abstime);
+ ret = reg_wait_flow_accepting(name, &abstime);
if (ret == -ETIMEDOUT)
goto fail_spawn;
@@ -1179,10 +1596,11 @@ static int flow_req_arr(struct flow_info * flow,
struct layer_info layer;
enum hash_algo algo;
int ret;
+ char name[NAME_SIZE + 1];
info.pid = flow->n_1_pid;
- log_info("Flow req arrived from IPCP %d for " HASH_FMT32 ".",
+ log_dbg("Flow req arrived from IPCP %d for " HASH_FMT32 ".",
info.pid, HASH_VAL32(hash));
if (reg_get_ipcp(&info, &layer) < 0) {
@@ -1193,10 +1611,17 @@ static int flow_req_arr(struct flow_info * flow,
algo = (enum hash_algo) layer.dir_hash_algo;
- ret = wait_for_accept(algo, hash);
+ if (reg_get_name_for_hash(name, algo, hash) < 0) {
+ log_warn("No name for " HASH_FMT32 ".", HASH_VAL32(hash));
+ ret = -ENAME;
+ goto fail;
+ }
+
+ log_info("Flow request arrived for %s.", name);
+
+ ret = wait_for_accept(name);
if (ret < 0) {
- log_err("No activeprocess for " HASH_FMT32 ".",
- HASH_VAL32(hash));
+ log_err("No active process for %s.", name);
goto fail;
}
@@ -1218,9 +1643,9 @@ static int flow_alloc_reply(struct flow_info * flow,
int response,
buffer_t * data)
{
- flow->state = response ? FLOW_DEALLOCATED : FLOW_ALLOCATED;
+ flow->state = response != 0 ? FLOW_DEALLOCATED : FLOW_ALLOCATED;
- if (reg_respond_alloc(flow, data) < 0) {
+ if (reg_respond_alloc(flow, data, response) < 0) {
log_err("Failed to reply to flow %d.", flow->id);
flow->state = FLOW_DEALLOCATED;
return -EBADF;
@@ -1232,7 +1657,7 @@ static int flow_alloc_reply(struct flow_info * flow,
static int flow_dealloc(struct flow_info * flow,
struct timespec * ts)
{
- log_info("Deallocating flow %d for process %d (timeout: %zd s).",
+ log_info("Deallocating flow %d for process %d (timeout: %ld s).",
flow->id, flow->n_pid, ts->tv_sec);
reg_dealloc_flow(flow);
@@ -1308,7 +1733,7 @@ static void * acceptloop(void * o)
return (void *) 0;
}
-static void free_msg(void * o)
+static void __cleanup_irm_msg(void * o)
{
irm_msg__free_unpacked((irm_msg_t *) o, NULL);
}
@@ -1327,6 +1752,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
int res;
irm_msg_t * ret_msg;
buffer_t data;
+ buffer_t symmkey = BUF_INIT;;
memset(&flow, 0, sizeof(flow));
@@ -1351,7 +1777,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
ret_msg->code = IRM_MSG_CODE__IRM_REPLY;
- pthread_cleanup_push(free_msg, ret_msg);
+ pthread_cleanup_push(__cleanup_irm_msg, ret_msg);
switch (msg->code) {
case IRM_MSG_CODE__IRM_CREATE_IPCP:
@@ -1380,7 +1806,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
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 */
+ /* Terminate with NULL instead of "" */
free(msg->exec[msg->n_exec - 1]);
msg->exec[msg->n_exec - 1] = NULL;
res = bind_program(msg->exec, msg->name, msg->opts);
@@ -1406,8 +1832,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
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;
+ name = name_info_msg_to_s(msg->name_info);
res = name_create(&name);
break;
case IRM_MSG_CODE__IRM_DESTROY_NAME:
@@ -1423,17 +1848,21 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
res = name_unreg(msg->name, msg->pid);
break;
case IRM_MSG_CODE__IRM_FLOW_ACCEPT:
+ tpm_wait_work(irmd.tpm);
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);
+ res = flow_accept(&flow, &symmkey, &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;
+ ret_msg->has_symmkey = symmkey.len != 0;
+ ret_msg->symmkey.data = symmkey.data;
+ ret_msg->symmkey.len = symmkey.len;
+ ret_msg->has_pk = data.len != 0;
+ ret_msg->pk.data = data.data;
+ ret_msg->pk.len = data.len;
}
break;
case IRM_MSG_CODE__IRM_FLOW_ALLOC:
@@ -1443,12 +1872,15 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
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);
+ res = flow_alloc(&flow, msg->dst, &symmkey, &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;
+ ret_msg->has_symmkey = symmkey.len != 0;
+ ret_msg->symmkey.data = symmkey.data;
+ ret_msg->symmkey.len = symmkey.len;
+ ret_msg->has_pk = data.len != 0;
+ ret_msg->pk.data = data.data;
+ ret_msg->pk.len = data.len;
}
break;
case IRM_MSG_CODE__IRM_FLOW_JOIN:
@@ -1540,10 +1972,10 @@ static void * mainloop(void * o)
continue;
}
- tpm_dec(irmd.tpm);
+ tpm_begin_work(irmd.tpm);
pthread_cleanup_push(__cleanup_close_ptr, &sfd);
- pthread_cleanup_push(free_msg, msg);
+ pthread_cleanup_push(__cleanup_irm_msg, msg);
ret_msg = do_command_msg(msg);
@@ -1556,12 +1988,12 @@ static void * mainloop(void * o)
}
if (ret_msg->result == -EPIPE) {
- log_dbg("Terminated command: application closed socket.");
+ log_dbg("Terminated command: remote closed socket.");
goto fail;
}
if (ret_msg->result == -EIRMD) {
- log_dbg("Terminated command: IRMd not in running state.");
+ log_dbg("Terminated command: IRMd not running.");
goto fail;
}
@@ -1596,54 +2028,20 @@ static void * mainloop(void * o)
pthread_cleanup_pop(true);
pthread_cleanup_pop(true);
- tpm_inc(irmd.tpm);
+ tpm_end_work(irmd.tpm);
continue;
fail:
irm_msg__free_unpacked(ret_msg, NULL);
fail_msg:
close(sfd);
- tpm_inc(irmd.tpm);
+ tpm_end_work(irmd.tpm);
continue;
}
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)
{
@@ -1719,6 +2117,79 @@ void * irm_sanitize(void * o)
return (void *) 0;
}
+static int irm_load_store(char * dpath)
+{
+ struct stat st;
+ struct dirent * dent;
+ DIR * dir;
+ void * crt;
+
+ if (stat(dpath, &st) == -1) {
+ log_dbg("Store directory %s not found.", dpath);
+ return 0;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ log_err("%s is not a directory.", dpath);
+ goto fail_dir;
+ }
+
+ /* loop through files in directory and load certificates */
+ dir = opendir(dpath);
+ if (dir == NULL) {
+ log_err("Failed to open %s.", dpath);
+ goto fail_dir;
+ }
+
+ while ((dent = readdir(dir)) != NULL) {
+ char path[NAME_PATH_SIZE + 1];
+
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", dpath,
+ dent->d_name);
+
+ if (stat(path, &st) == -1) {
+ log_dbg("Failed to stat %s.", path);
+ continue;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ log_dbg("%s is not a regular file.", path);
+ goto fail_file;
+ }
+
+ if (crypt_load_crt_file(path, &crt) < 0) {
+ log_err("Failed to load certificate from %s.", path);
+ goto fail_file;
+ }
+
+ if (auth_add_crt_to_store(irmd.auth.ctx, crt) < 0) {
+ log_err("Failed to add certificate from %s to store.",
+ path);
+ goto fail_crt_add;
+ }
+
+ log_dbg("Loaded certificate: %s.", path);
+
+ crypt_free_crt(crt);
+ }
+
+ closedir(dir);
+
+ log_info("Loaded certificates from %s.", dpath);
+
+ return 0;
+
+ fail_crt_add:
+ crypt_free_crt(crt);
+ fail_file:
+ closedir(dir);
+ fail_dir:
+ return -1;
+}
static int irm_init(void)
{
@@ -1819,6 +2290,30 @@ static int irm_init(void)
log_err("Failed to greate thread pool.");
goto fail_tpm_create;
}
+
+ if (pthread_mutex_init(&irmd.auth.mtx, NULL) < 0) {
+ log_err("Failed to initialize auth mutex.");
+ goto fail_auth_mtx;
+ }
+
+ irmd.auth.ctx = auth_create_ctx();
+ if (irmd.auth.ctx == NULL) {
+ log_err("Failed to create auth store context.");
+ goto fail_auth_ctx;
+ }
+
+ list_head_init(&irmd.auth.list);
+
+ if (irm_load_store(OUROBOROS_CA_CRT_DIR) < 0) {
+ log_err("Failed to load CA certificates.");
+ goto fail_auth_ctx;
+ }
+
+ if (irm_load_store(OUROBOROS_CHAIN_DIR) < 0) {
+ log_err("Failed to load intermediate certificates.");
+ goto fail_auth_ctx;
+ }
+
#ifdef HAVE_FUSE
mask = umask(0);
@@ -1844,6 +2339,8 @@ static int irm_init(void)
gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
#endif
+ irmd_set_state(IRMD_INIT);
+
return 0;
#ifdef HAVE_LIBGCRYPT
@@ -1851,8 +2348,12 @@ static int irm_init(void)
#ifdef HAVE_FUSE
rmdir(FUSE_PREFIX);
#endif
- tpm_destroy(irmd.tpm);
+ auth_destroy_ctx(irmd.auth.ctx);
#endif
+ fail_auth_ctx:
+ pthread_mutex_destroy(&irmd.auth.mtx);
+ fail_auth_mtx:
+ tpm_destroy(irmd.tpm);
fail_tpm_create:
shm_rdrbuff_destroy(irmd.rdrb);
fail_rdrbuff:
@@ -1872,6 +2373,69 @@ static int irm_init(void)
return -1;
}
+static void irm_fini(void)
+{
+ struct list_head * p;
+ struct list_head * h;
+#ifdef HAVE_FUSE
+ struct timespec wait = TIMESPEC_INIT_MS(1);
+ int retries = 5;
+#endif
+ if (irmd_get_state() != IRMD_INIT)
+ log_warn("Unsafe destroy.");
+
+ pthread_mutex_lock(&irmd.auth.mtx);
+
+ list_for_each_safe(p, h, &irmd.auth.list) {
+ struct oaph * oaph = list_entry(p, struct oaph, next);
+ list_del(&oaph->next);
+ free(oaph);
+ }
+
+ pthread_mutex_unlock(&irmd.auth.mtx);
+ pthread_mutex_destroy(&irmd.auth.mtx);
+
+ auth_destroy_ctx(irmd.auth.ctx);
+
+ 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_lock(&irmd.cmd_lock);
+
+ list_for_each_safe(p, h, &irmd.cmds) {
+ struct cmd * cmd = list_entry(p, struct cmd, next);
+ list_del(&cmd->next);
+ close(cmd->fd);
+ free(cmd);
+ }
+
+ pthread_mutex_unlock(&irmd.cmd_lock);
+
+ 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
+ assert(list_is_empty(&irmd.cmds));
+
+ irmd.state = IRMD_NULL;
+}
+
static void usage(void)
{
printf("Usage: irmd \n"
@@ -1885,11 +2449,11 @@ static void usage(void)
static int irm_start(void)
{
+ irmd_set_state(IRMD_RUNNING);
+
if (tpm_start(irmd.tpm))
goto fail_tpm_start;
- irmd_set_state(IRMD_RUNNING);
-
if (pthread_create(&irmd.irm_sanitize, NULL, irm_sanitize, NULL))
goto fail_irm_sanitize;
@@ -1904,9 +2468,9 @@ static int irm_start(void)
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:
+ irmd_set_state(IRMD_INIT);
return -1;
}
@@ -1947,7 +2511,7 @@ static void irm_stop(void)
tpm_stop(irmd.tpm);
- irmd_set_state(IRMD_NULL);
+ irmd_set_state(IRMD_INIT);
}
static void irm_argparse(int argc,
@@ -1998,8 +2562,8 @@ static void * kill_dash_nine(void * o)
slept += intv;
}
- log_dbg("I am become Death, destroyer of hung processes.");
-
+ log_dbg("I guess I’ll have to shut you down for good this time,");
+ log_dbg("already tried a SIGQUIT, so now it’s KILL DASH 9.");
#ifdef IRMD_KILL_ALL_PROCESSES
reg_kill_all_proc(SIGKILL);
nanosleep(&ts, NULL);
@@ -2058,7 +2622,7 @@ int main(int argc,
if (geteuid() != 0) {
printf("IPC Resource Manager must be run as root.\n");
- exit(EXIT_FAILURE);
+ goto fail_irm_init;
}
if (irm_init() < 0)
@@ -2076,7 +2640,7 @@ int main(int argc,
#ifdef HAVE_TOML
if (irm_configure(irmd.cfg_file) < 0) {
- irmd_set_state(IRMD_NULL);
+ irmd_set_state(IRMD_SHUTDOWN);
ret = EXIT_FAILURE;
}
#endif
diff --git a/src/irmd/oap.c b/src/irmd/oap.c
new file mode 100644
index 00000000..500da6f1
--- /dev/null
+++ b/src/irmd/oap.c
@@ -0,0 +1,288 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros flow allocation protocol header
+ *
+ * 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
+
+#define OUROBOROS_PREFIX "irmd/oap"
+
+#include <ouroboros/crypt.h>
+#include <ouroboros/endian.h>
+#include <ouroboros/logs.h>
+#include <ouroboros/rib.h>
+#include <ouroboros/time.h>
+
+#include "config.h"
+
+#include "oap.h"
+
+#include <assert.h>
+
+int oap_hdr_init(buffer_t id,
+ void * pkp,
+ void * pubcrt,
+ buffer_t ephkey,
+ buffer_t data,
+ struct oap_hdr * oap_hdr)
+{
+ struct timespec now;
+ uint64_t stamp;
+ buffer_t hdr;
+ buffer_t der = BUF_INIT;
+ buffer_t sig = BUF_INIT;
+ buffer_t sign;
+ uint16_t len;
+ off_t offset;
+
+ assert(id.data != NULL && id.len == OAP_ID_SIZE);
+ assert(oap_hdr != NULL);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ stamp = hton64(TS_TO_UINT64(now));
+
+ if (pubcrt != NULL && crypt_crt_der(pubcrt, &der) < 0)
+ goto fail_der;
+
+ hdr.len = id.len +
+ sizeof(stamp) +
+ sizeof(len) + der.len +
+ sizeof(len) + ephkey.len +
+ sizeof(len) + data.len +
+ sizeof(len); /* sig len */
+
+ hdr.data = malloc(hdr.len);
+ if (hdr.data == NULL)
+ goto fail_hdr;
+
+ offset = 0;
+
+ memcpy(hdr.data, id.data, id.len);
+ offset += id.len;
+
+ memcpy(hdr.data + offset, &stamp, sizeof(stamp));
+ offset += sizeof(stamp);
+
+ /* pubcrt */
+ len = hton16((uint16_t) der.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (der.len != 0)
+ memcpy(hdr.data + offset, der.data, der.len);
+ offset += der.len;
+
+ /* ephkey */
+ len = hton16((uint16_t) ephkey.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (ephkey.len != 0)
+ memcpy(hdr.data + offset, ephkey.data, ephkey.len);
+ offset += ephkey.len;
+
+ /* data */
+ len = hton16((uint16_t) data.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (data.len != 0)
+ memcpy(hdr.data + offset, data.data, data.len);
+ offset += data.len;
+
+ sign.data = hdr.data;
+ sign.len = hdr.len - sizeof(len);
+
+ if (pkp != NULL && auth_sign(pkp, sign, &sig) < 0)
+ goto fail_sig;
+
+ len = hton16((uint16_t) sig.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+
+ oap_hdr->hdr = hdr;
+
+ assert((size_t) offset == hdr.len);
+
+ if (sig.len > 0) {
+ oap_hdr->hdr.len += sig.len;
+ oap_hdr->hdr.data = realloc(hdr.data, oap_hdr->hdr.len);
+ if (oap_hdr->hdr.data == NULL)
+ goto fail_oap_hdr;
+
+ memcpy(oap_hdr->hdr.data + offset, sig.data, sig.len);
+ clrbuf(hdr);
+ }
+
+ if (oap_hdr_decode(oap_hdr->hdr, oap_hdr) < 0)
+ goto fail_decode;
+
+ freebuf(der);
+ freebuf(sig);
+
+ return 0;
+
+ fail_decode:
+ oap_hdr_fini(oap_hdr);
+ fail_oap_hdr:
+ freebuf(sig);
+ fail_sig:
+ freebuf(hdr);
+ fail_hdr:
+ freebuf(der);
+ fail_der:
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+ return -1;
+}
+
+void oap_hdr_fini(struct oap_hdr * oap_hdr)
+{
+ assert(oap_hdr != NULL);
+
+ freebuf(oap_hdr->hdr);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+}
+
+int oap_hdr_decode(buffer_t hdr,
+ struct oap_hdr * oap_hdr)
+{
+ off_t offset;
+
+ assert(oap_hdr != NULL);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+
+ if (hdr.len < OAP_HDR_MIN_SIZE)
+ goto fail_decode;
+
+ oap_hdr->id.data = hdr.data;
+ oap_hdr->id.len = OAP_ID_SIZE;
+
+ offset = OAP_ID_SIZE;
+
+ oap_hdr->timestamp = ntoh64(*(uint64_t *)(hdr.data + offset));
+
+ offset += sizeof(uint64_t);
+
+ oap_hdr->crt.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->crt.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->crt.len;
+
+ if ((size_t) offset + sizeof(uint16_t) >= hdr.len)
+ goto fail_decode;
+
+ oap_hdr->eph.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->eph.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->eph.len;
+
+ if ((size_t) offset + sizeof(uint16_t) >= hdr.len)
+ goto fail_decode;
+
+ oap_hdr->data.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->data.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->data.len;
+
+ if ((size_t) offset + sizeof(uint16_t) > hdr.len)
+ goto fail_decode;
+
+ oap_hdr->sig.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->sig.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->sig.len;
+
+ if ((size_t) offset != hdr.len)
+ goto fail_decode;
+
+ oap_hdr->hdr = hdr;
+
+ return 0;
+
+ fail_decode:
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+ return -1;
+}
+
+#ifdef DEBUG_PROTO_OAP
+static void debug_oap_hdr(const struct oap_hdr * hdr)
+{
+ assert(hdr);
+
+ if (hdr->crt.len > 0)
+ log_proto(" Certificate: [%zu bytes]", hdr->crt.len);
+ else
+ log_proto(" Certificate: <none>");
+
+ if (hdr->eph.len > 0)
+ log_proto(" Ephemeral Public Key: [%zu bytes]", hdr->eph.len);
+ else
+ log_proto(" Ephemeral Public Key: <none>");
+ if (hdr->data.len > 0)
+ log_proto(" Data: [%zu bytes]", hdr->data.len);
+ else
+ log_proto(" Data: <none>");
+ if (hdr->sig.len > 0)
+ log_proto(" Signature: [%zu bytes]", hdr->sig.len);
+ else
+ log_proto(" Signature: <none>");
+}
+
+void debug_oap_hdr_rcv(const struct oap_hdr * hdr)
+{
+ struct tm * tm;
+ char tmstr[RIB_TM_STRLEN];
+ time_t stamp;
+
+ assert(hdr);
+
+ stamp = (time_t) hdr->timestamp / BILLION;
+
+ tm = gmtime(&stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+
+ log_proto("OAP_HDR [" HASH_FMT64 " @ %s ] <--",
+ HASH_VAL64(hdr->id.data), tmstr);
+
+ debug_oap_hdr(hdr);
+}
+
+void debug_oap_hdr_snd(const struct oap_hdr * hdr)
+{
+ struct tm * tm;
+ char tmstr[RIB_TM_STRLEN];
+ time_t stamp;
+
+ assert(hdr);
+
+ stamp = (time_t) hdr->timestamp / BILLION;
+
+ tm = gmtime(&stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+
+ log_proto("OAP_HDR [" HASH_FMT64 " @ %s ] -->",
+ HASH_VAL64(hdr->id.data), tmstr);
+
+ debug_oap_hdr(hdr);
+}
+#endif
+
diff --git a/src/irmd/oap.h b/src/irmd/oap.h
new file mode 100644
index 00000000..ccdfa804
--- /dev/null
+++ b/src/irmd/oap.h
@@ -0,0 +1,94 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros flow allocation protocol header
+ *
+ * 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_OAP_H
+#define OUROBOROS_IRMD_OAP_H
+
+#include <ouroboros/utils.h>
+
+#define OAP_ID_SIZE (16)
+#define OAP_HDR_MIN_SIZE (OAP_ID_SIZE + sizeof(uint64_t) + 4 * sizeof(uint16_t))
+
+
+/*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +---------------------------------------------------------------+
+ * | |
+ * | id (128 bits) |
+ * | |
+ * | |
+ * +---------------------------------------------------------------+
+ * | timestamp (64 bits) |
+ * | |
+ * +---------------------------------------------------------------+
+ * | crt_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | certificate |
+ * | |
+ * +---------------------------------------------------------------+
+ * | eph_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | public key for ECDHE |
+ * | |
+ * +---------------------------------------------------------------+
+ * | data_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | piggy backed application data |
+ * | |
+ * +---------------------------------------------------------------+
+ * | sig_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | signature |
+ * | |
+ * +---------------------------------------------------------------+
+ */
+
+struct oap_hdr {
+ uint64_t timestamp;
+ buffer_t id;
+ buffer_t crt;
+ buffer_t eph;
+ buffer_t data;
+ buffer_t sig;
+ buffer_t hdr;
+};
+
+int oap_hdr_init(buffer_t id,
+ void * pkp,
+ void * pubcrt,
+ buffer_t ephkey,
+ buffer_t data,
+ struct oap_hdr * oap_hdr);
+
+void oap_hdr_fini(struct oap_hdr * oap_hdr);
+
+int oap_hdr_decode(buffer_t hdr,
+ struct oap_hdr * oap_hdr);
+
+#ifdef DEBUG_PROTO_OAP
+void debug_oap_hdr_snd(const struct oap_hdr * hdr);
+
+void debug_oap_hdr_rcv(const struct oap_hdr * hdr);
+#endif /* DEBUG_PROTO_OAP */
+
+#endif /* OUROBOROS_IRMD_OAP_H */
diff --git a/src/irmd/reg/flow.h b/src/irmd/reg/flow.h
index 75ada971..d1e4811c 100644
--- a/src/irmd/reg/flow.h
+++ b/src/irmd/reg/flow.h
@@ -25,6 +25,7 @@
#include <ouroboros/list.h>
#include <ouroboros/flow.h>
+#include <ouroboros/name.h>
#include <ouroboros/pthread.h>
#include <ouroboros/qos.h>
#include <ouroboros/shm_rbuff.h>
@@ -34,12 +35,15 @@
#include <time.h>
struct reg_flow {
- struct list_head next;
+ struct list_head next;
- struct flow_info info;
+ struct flow_info info;
+ int response;
- buffer_t data;
- struct timespec t0;
+ buffer_t data;
+ struct timespec t0;
+
+ char name[NAME_SIZE + 1];
struct shm_rbuff * n_rb;
struct shm_rbuff * n_1_rb;
diff --git a/src/irmd/reg/ipcp.c b/src/irmd/reg/ipcp.c
index 6580cb5b..474527a4 100644
--- a/src/irmd/reg/ipcp.c
+++ b/src/irmd/reg/ipcp.c
@@ -40,7 +40,7 @@ struct reg_ipcp * reg_ipcp_create(const struct ipcp_info * info)
struct reg_ipcp * ipcp;
assert(info != NULL);
- assert(info->state == IPCP_BOOT);
+ assert(info->state == IPCP_INIT);
ipcp = malloc(sizeof(*ipcp));
if (ipcp == NULL) {
@@ -54,7 +54,7 @@ struct reg_ipcp * reg_ipcp_create(const struct ipcp_info * info)
list_head_init(&ipcp->next);
ipcp->info = *info;
- ipcp->info.state = IPCP_BOOT;
+ ipcp->info.state = IPCP_INIT;
strcpy(ipcp->layer.name, "Not enrolled.");
@@ -77,7 +77,7 @@ void reg_ipcp_update(struct reg_ipcp * ipcp,
const struct ipcp_info * info)
{
assert(ipcp != NULL);
- assert(info->state != IPCP_INIT);
+ assert(info->state != IPCP_NULL);
ipcp->info = *info;
}
@@ -86,7 +86,7 @@ void reg_ipcp_set_layer(struct reg_ipcp * ipcp,
const struct layer_info * info)
{
assert(ipcp != NULL);
- assert(ipcp->info.state == IPCP_OPERATIONAL);
+ assert(ipcp->info.state == IPCP_BOOT);
ipcp->layer = *info;
}
diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c
index 1ac939a5..4e609711 100644
--- a/src/irmd/reg/name.c
+++ b/src/irmd/reg/name.c
@@ -66,15 +66,14 @@ struct reg_name * reg_name_create(const struct name_info * info)
goto fail_malloc;
}
+ memset(name, 0, sizeof(*name));
+
list_head_init(&name->next);
- list_head_init(&name->progs);
- list_head_init(&name->procs);
- list_head_init(&name->active);
+ list_head_init(&name->progs.list);
+ list_head_init(&name->procs.list);
+ list_head_init(&name->active.list);
- name->info = *info;
- name->n_progs = 0;
- name->n_procs = 0;
- name->n_active = 0;
+ name->info = *info;
return name;
@@ -88,13 +87,13 @@ void reg_name_destroy(struct reg_name * name)
assert(list_is_empty(&name->next));
- assert(name->n_progs == 0);
- assert(name->n_procs == 0);
- assert(name->n_active == 0);
+ assert(name->progs.len == 0);
+ assert(name->procs.len == 0);
+ assert(name->active.len == 0);
- assert(list_is_empty(&name->progs));
- assert(list_is_empty(&name->procs));
- assert(list_is_empty(&name->active));
+ assert(list_is_empty(&name->progs.list));
+ assert(list_is_empty(&name->procs.list));
+ assert(list_is_empty(&name->active.list));
free(name);
}
@@ -107,7 +106,7 @@ static struct proc_entry * __reg_name_get_active(const struct reg_name * name,
assert(name != NULL);
assert(pid > 0);
- list_for_each(p, &name->active) {
+ list_for_each(p, &name->active.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid)
@@ -123,13 +122,13 @@ static void __reg_name_del_all_active(struct reg_name * name,
struct list_head * p;
struct list_head * h;
- list_for_each_safe(p, h, &name->active) {
+ list_for_each_safe(p, h, &name->active.list) {
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--;
+ --name->active.len;
}
}
}
@@ -142,7 +141,7 @@ static struct proc_entry * __reg_name_get_proc(const struct reg_name * name,
assert(name != NULL);
assert(pid > 0);
- list_for_each(p, &name->procs) {
+ list_for_each(p, &name->procs.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid)
@@ -160,7 +159,7 @@ static struct prog_entry * __reg_name_get_prog(const struct reg_name * name,
assert(name != NULL);
assert(prog != NULL);
- list_for_each(p, &name->progs) {
+ list_for_each(p, &name->progs.list) {
struct prog_entry * entry;
entry = list_entry(p, struct prog_entry, next);
if (strcmp(entry->exec[0], prog) == 0)
@@ -195,16 +194,16 @@ int reg_name_add_active(struct reg_name * name,
switch (name->info.pol_lb) {
case LB_RR: /* Round robin policy. */
- list_add_tail(&entry->next, &name->active);
+ list_add_tail(&entry->next, &name->active.list);
break;
case LB_SPILL: /* Keep accepting flows on the current process */
- list_add(&entry->next, &name->active);
+ list_add(&entry->next, &name->active.list);
break;
default:
goto fail_unreachable;
}
- name->n_active++;
+ ++name->active.len;
return 0;
@@ -226,19 +225,23 @@ void reg_name_del_active(struct reg_name * name,
list_del(&entry->next);
- name->n_active--;
+ --name->active.len;
free(entry);
}
pid_t reg_name_get_active(struct reg_name * name)
{
+ struct proc_entry * e;
+
assert(name != NULL);
- if (list_is_empty(&name->active))
+ if (list_is_empty(&name->active.list))
return -1;
- return list_first_entry(&name->active, struct proc_entry, next)->pid;
+ e = list_first_entry(&name->active.list, struct proc_entry, next);
+
+ return e->pid;
}
int reg_name_add_proc(struct reg_name * name,
@@ -259,9 +262,9 @@ int reg_name_add_proc(struct reg_name * name,
entry->pid = pid;
- list_add(&entry->next, &name->procs);
+ list_add(&entry->next, &name->procs.list);
- name->n_procs++;
+ ++name->procs.len;
return 0;
@@ -287,7 +290,7 @@ void reg_name_del_proc(struct reg_name * name,
free(entry);
- name->n_procs--;
+ --name->procs.len;
assert(__reg_name_get_proc(name, pid) == NULL);
}
@@ -296,8 +299,7 @@ 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)
@@ -322,11 +324,11 @@ int reg_name_add_prog(struct reg_name * name,
goto fail_exec;
}
- list_add(&entry->next, &name->progs);
+ list_add(&entry->next, &name->progs.list);
log_dbg("Add prog %s to name %s.", exec[0], name->info.name);
- name->n_progs++;
+ ++name->progs.len;
return 0;
@@ -352,7 +354,7 @@ void reg_name_del_prog(struct reg_name * name,
__free_prog_entry(entry);
- name->n_progs--;
+ --name->progs.len;
assert(__reg_name_get_prog(name, prog) == NULL);
}
@@ -368,8 +370,12 @@ bool reg_name_has_prog(const struct reg_name * name,
char ** reg_name_get_exec(const struct reg_name * name)
{
- if (list_is_empty(&name->progs))
+ struct prog_entry * e;
+
+ if (list_is_empty(&name->progs.list))
return NULL;
- return list_first_entry(&name->progs, struct prog_entry, next)->exec;
+ e = list_first_entry(&name->progs.list, struct prog_entry, next);
+
+ return e->exec;
}
diff --git a/src/irmd/reg/name.h b/src/irmd/reg/name.h
index 97ca7f04..30a64e1c 100644
--- a/src/irmd/reg/name.h
+++ b/src/irmd/reg/name.h
@@ -33,14 +33,25 @@ struct reg_name {
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 {
+ void * key;
+ void * crt;
+ } cache;
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } progs; /* autostart programs for this name */
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } procs; /* processes bound to this name */
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } active; /* processes actively calling accept */
};
struct reg_name * reg_name_create(const struct name_info * info);
@@ -74,5 +85,4 @@ 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.h b/src/irmd/reg/proc.h
index 99f74fef..499ecc72 100644
--- a/src/irmd/reg/proc.h
+++ b/src/irmd/reg/proc.h
@@ -32,8 +32,8 @@ struct reg_proc {
struct proc_info info;
- struct list_head names; /* names for which process accepts flows */
- size_t n_names; /* number of names */
+ struct list_head names; /* process accepts flows for names */
+ size_t n_names; /* number of names */
struct shm_flow_set * set;
};
diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c
index d95a4722..a24a9d1d 100644
--- a/src/irmd/reg/reg.c
+++ b/src/irmd/reg/reg.c
@@ -28,6 +28,7 @@ The IPC Resource Manager - Registry
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
#include <ouroboros/logs.h>
+#include <ouroboros/protobuf.h>
#include <ouroboros/pthread.h>
#include "reg.h"
@@ -46,6 +47,7 @@ The IPC Resource Manager - Registry
struct {
struct bmp * flow_ids; /* flow_ids for flows */
+
struct list_head flows; /* flow information */
size_t n_flows; /* number of flows */
@@ -151,16 +153,23 @@ static struct reg_ipcp * __reg_get_ipcp_by_layer(const char * layer)
return NULL;
}
-static struct list_head * __reg_after_ipcp(pid_t pid)
+
+static struct list_head * __reg_after_ipcp(const struct ipcp_info * info)
{
struct list_head * p;
- assert(pid > 0);
+ assert(info != NULL);
list_for_each(p, &reg.ipcps) {
struct reg_ipcp * entry;
entry = list_entry(p, struct reg_ipcp, next);
- if (entry->info.pid > pid)
+ if (entry->info.type < info->type)
+ continue;
+
+ if (entry->info.type > info->type)
+ break;
+
+ if (entry->info.pid > info->pid)
break;
}
@@ -183,41 +192,17 @@ static struct reg_name * __reg_get_name(const char * name)
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)
+static int __reg_get_pending_flow_id(const char * name)
{
struct reg_name * entry;
struct reg_flow * flow;
pid_t pid;
- entry =__reg_get_name_by_hash(algo, hash);
+ assert(name != NULL);
+ assert(strlen(name) > 0);
+ assert(strlen(name) < NAME_SIZE + 1);
+
+ entry =__reg_get_name(name);
if (entry == NULL)
return -ENAME;
@@ -226,7 +211,10 @@ static int __reg_get_pending_flow_id_for_hash(enum hash_algo algo,
return -EAGAIN;
flow = __reg_get_accept_flow(pid);
- assert(flow != NULL);
+ if (flow == NULL) /* compiler barks, this can't be NULL */
+ return -EAGAIN;
+
+ strcpy(flow->name, name);
return flow->info.id;
}
@@ -388,30 +376,17 @@ static struct reg_prog * __reg_get_prog(const char * name)
return NULL;
}
-static char ** __reg_get_exec(enum hash_algo algo,
- const uint8_t * hash)
+static char ** __reg_get_exec(const char * name)
{
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);
+ if (strcmp(entry->info.name, name) == 0)
return reg_name_get_exec(entry);
- }
}
- free(buf);
-
return NULL;
}
@@ -614,6 +589,14 @@ void reg_clear(void)
reg.n_procs--;
}
+ 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--;
+ }
+
list_for_each_safe(p, h, &reg.names) {
struct reg_name * entry;
entry = list_entry(p, struct reg_name, next);
@@ -630,14 +613,6 @@ void reg_clear(void)
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);
}
@@ -757,7 +732,7 @@ int reg_create_ipcp(const struct ipcp_info * info)
assert(info != NULL);
assert(info->pid != 0);
- assert(info->state == IPCP_BOOT);
+ assert(info->state == IPCP_INIT);
pthread_mutex_lock(&reg.mtx);
@@ -780,7 +755,7 @@ int reg_create_ipcp(const struct ipcp_info * info)
entry->pid = info->pid;
- list_add(&ipcp->next, __reg_after_ipcp(info->pid));
+ list_add_tail(&ipcp->next, __reg_after_ipcp(info));
list_add(&entry->next, __reg_after_spawned(info->pid));
reg.n_ipcps++;
@@ -848,11 +823,11 @@ static int __get_ipcp_info(ipcp_list_msg_t ** msg,
(*msg)->name = strdup(ipcp->info.name);
if ((*msg)->name == NULL)
- goto fail_name;
+ goto fail_msg;
(*msg)->layer = strdup(ipcp->layer.name);
if ((*msg)->layer == NULL)
- goto fail_layer;
+ goto fail_msg;
(*msg)->pid = ipcp->info.pid;
(*msg)->type = ipcp->info.type;
@@ -860,10 +835,8 @@ static int __get_ipcp_info(ipcp_list_msg_t ** msg,
return 0;
- fail_layer:
- free((*msg)->name);
- fail_name:
- free(*msg);
+ fail_msg:
+ ipcp_list_msg__free_unpacked(*msg, NULL);
*msg = NULL;
fail:
return -1;
@@ -876,10 +849,8 @@ int reg_list_ipcps(ipcp_list_msg_t *** ipcps)
pthread_mutex_lock(&reg.mtx);
- if (reg.n_ipcps == 0) {
- *ipcps = NULL;
+ if (reg.n_ipcps == 0)
goto finish;
- }
*ipcps = malloc(reg.n_ipcps * sizeof(**ipcps));
if (*ipcps == NULL) {
@@ -890,24 +861,19 @@ int reg_list_ipcps(ipcp_list_msg_t *** ipcps)
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.");
+ if (__get_ipcp_info(&(*ipcps)[i], entry) < 0)
goto fail;
- }
- ++i;
+ 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);
-
+ while (i-- > 0)
+ ipcp_list_msg__free_unpacked((*ipcps)[i], NULL);
free(*ipcps);
fail_malloc:
pthread_mutex_unlock(&reg.mtx);
@@ -993,28 +959,84 @@ bool reg_has_name(const char * name)
return ret;
}
-static int __get_name_info(name_info_msg_t ** msg,
- struct reg_name * n)
+int reg_get_name_info(const char * name,
+ struct name_info * info)
{
- *msg = malloc(sizeof(**msg));
- if (*msg == NULL)
- goto fail;
+ struct reg_name * n;
- name_info_msg__init(*msg);
+ assert(name != NULL);
+ assert(info != NULL);
- (*msg)->name = strdup(n->info.name);
- if ((*msg)->name == NULL)
- goto fail_name;
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Name %s does not exist.", name);
+ goto no_name;
+ }
- (*msg)->pol_lb = n->info.pol_lb;
+ *info = n->info;
+
+ pthread_mutex_unlock(&reg.mtx);
return 0;
- fail_name:
- free(*msg);
- *msg = NULL;
- fail:
- return -1;
+ no_name:
+ pthread_mutex_unlock(&reg.mtx);
+ return -ENOENT;
+
+}
+
+int reg_get_name_for_hash(char * buf,
+ enum hash_algo algo,
+ const uint8_t * hash)
+{
+ struct list_head * p;
+ uint8_t * thash;
+ size_t len;
+ char * name = NULL;
+
+ len = hash_len(algo);
+
+ thash = malloc(len);
+ if (thash == NULL)
+ return -ENOMEM;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ 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) {
+ name = n->info.name;
+ break;
+ }
+ }
+
+ if (name != NULL)
+ strcpy(buf, name);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ free(thash);
+
+ return name == NULL ? -ENOENT : 0;
+}
+
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id)
+{
+ struct reg_flow * f;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ f = __reg_get_flow(flow_id);
+ if (f != NULL)
+ strcpy(buf, f->name);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return f == NULL ? -ENOENT : 0;
}
int reg_list_names(name_info_msg_t *** names)
@@ -1036,24 +1058,31 @@ int reg_list_names(name_info_msg_t *** names)
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) {
+ (*names)[i] = name_info_s_to_msg(&entry->info);
+ if ((*names)[i] == NULL) {
log_err("Failed to create name list info.");
goto fail;
}
-
- ++i;
+ /* wipe security info to avoid huge messages */
+ free((*names)[i]->scrt);
+ (*names)[i]->scrt = NULL;
+ free((*names)[i]->skey);
+ (*names)[i]->skey = NULL;
+ free((*names)[i]->ccrt);
+ (*names)[i]->ccrt = NULL;
+ free((*names)[i]->ckey);
+ (*names)[i]->ckey = NULL;
+
+ 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);
-
+ while (i-- > 0)
+ name_info_msg__free_unpacked((*names)[i], NULL);
free(*names);
fail_malloc:
pthread_mutex_unlock(&reg.mtx);
@@ -1419,19 +1448,18 @@ bool reg_has_prog(const char * name)
return ret;
}
-int reg_get_exec(enum hash_algo algo,
- const uint8_t * hash,
- char *** prog)
+int reg_get_exec(const char * name,
+ char *** prog)
{
char ** exec;
int ret = 0;
- assert(hash != NULL);
+ assert(name != NULL);
assert(prog != NULL);
pthread_mutex_lock(&reg.mtx);
- exec = __reg_get_exec(algo, hash);
+ exec = __reg_get_exec(name);
if (exec == NULL) {
ret = -EPERM;
goto finish;
@@ -1444,12 +1472,9 @@ int reg_get_exec(enum hash_algo algo,
goto finish;
}
- pthread_mutex_unlock(&reg.mtx);
-
- return 0;
-
finish:
pthread_mutex_unlock(&reg.mtx);
+
return ret;
}
@@ -1557,8 +1582,7 @@ int reg_set_layer_for_ipcp(struct ipcp_info * info,
struct reg_ipcp * ipcp;
assert(info != NULL);
- assert(info->state > IPCP_BOOT);
- assert(info->state < IPCP_SHUTDOWN);
+ assert(info->state == IPCP_BOOT);
pthread_mutex_lock(&reg.mtx);
@@ -1690,7 +1714,7 @@ int reg_wait_flow_allocated(struct flow_info * info,
stop = true;
break;
case FLOW_DEALLOCATED:
- ret = -1;
+ ret = flow->response;
stop = true;
break;
default:
@@ -1722,7 +1746,8 @@ int reg_wait_flow_allocated(struct flow_info * info,
}
int reg_respond_alloc(struct flow_info * info,
- buffer_t * pbuf)
+ buffer_t * pbuf,
+ int response)
{
struct reg_flow * flow;
@@ -1755,7 +1780,9 @@ int reg_respond_alloc(struct flow_info * info,
if (reg_flow_update(flow, info) < 0) {
log_err("Failed to create flow structs.");
goto fail_flow;
- };
+ }
+
+ flow->response = response;
if (info->state == FLOW_ALLOCATED)
reg_flow_set_data(flow, pbuf);
@@ -1771,8 +1798,7 @@ int reg_respond_alloc(struct flow_info * info,
return -1;
}
-int reg_prepare_flow_accept(struct flow_info * info,
- buffer_t * pbuf)
+int reg_prepare_flow_accept(struct flow_info * info)
{
struct reg_flow * flow;
int ret;
@@ -1790,8 +1816,6 @@ int reg_prepare_flow_accept(struct flow_info * info,
ret = reg_flow_update(flow, info);
- reg_flow_set_data(flow, pbuf);
-
pthread_mutex_unlock(&reg.mtx);
return ret;
@@ -1824,8 +1848,6 @@ int reg_wait_flow_accepted(struct flow_info * info,
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);
@@ -1883,13 +1905,12 @@ int reg_wait_flow_accepted(struct flow_info * info,
return -1;
}
-int reg_wait_flow_accepting(enum hash_algo algo,
- const uint8_t * hash,
+int reg_wait_flow_accepting(const char * name,
const struct timespec * abstime)
{
int ret;
- assert(hash != NULL);
+ assert(name != NULL);
assert(abstime != NULL);
pthread_mutex_lock(&reg.mtx);
@@ -1897,7 +1918,7 @@ int reg_wait_flow_accepting(enum hash_algo algo,
pthread_cleanup_push(__cleanup_mutex_unlock, &reg.mtx);
while (true) {
- ret = __reg_get_pending_flow_id_for_hash(algo, hash);
+ ret = __reg_get_pending_flow_id(name);
if (ret != -EAGAIN)
break;
@@ -1915,7 +1936,6 @@ 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);
@@ -1933,11 +1953,8 @@ int reg_respond_accept(struct flow_info * info,
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;
- }
+ reg_flow_set_data(flow, pbuf);
+ clrbuf(pbuf);
if (reg_flow_update(flow, info) < 0) {
log_err("Failed to create flow structs.");
@@ -1970,12 +1987,14 @@ void reg_dealloc_flow(struct flow_info * info)
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;
+ memset(flow->name, 0, sizeof(flow->name));
+
reg_flow_update(flow, info);
pthread_mutex_unlock(&reg.mtx);
@@ -2043,7 +2062,7 @@ int reg_wait_ipcp_boot(struct ipcp_info * info,
int ret;
bool stop = false;
- assert(info->state == IPCP_BOOT);
+ assert(info->state == IPCP_INIT);
pthread_mutex_lock(&reg.mtx);
@@ -2063,16 +2082,18 @@ int reg_wait_ipcp_boot(struct ipcp_info * info,
ret = -1;
stop = true;
break;
+ case IPCP_BOOT:
+ /* FALLTHRU*/
case IPCP_OPERATIONAL:
ret = 0;
stop = true;
break;
- case IPCP_BOOT:
+ case IPCP_INIT:
ret = -__timedwait(&reg.cond, &reg.mtx, abstime);
break;
default:
assert(false);
- continue; /* Shut up static analyzer. */
+ break; /* Shut up static analyzer. */
}
ipcp = __reg_get_ipcp(info->pid);
diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h
index 17dfcc32..7728c80f 100644
--- a/src/irmd/reg/reg.h
+++ b/src/irmd/reg/reg.h
@@ -90,6 +90,16 @@ int reg_destroy_name(const char * name);
bool reg_has_name(const char * name);
+int reg_get_name_info(const char * name,
+ struct name_info * info);
+
+int reg_get_name_for_hash(char * buf,
+ enum hash_algo algo,
+ const uint8_t * hash);
+
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id);
+
/* TODO don't rely on protobuf here */
int reg_list_names(name_info_msg_t *** names);
@@ -99,9 +109,8 @@ 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_get_exec(const char * name,
+ char *** exec);
int reg_bind_prog(const char * name,
char ** exec,
@@ -117,17 +126,16 @@ int reg_wait_flow_allocated(struct flow_info * info,
const struct timespec * abstime);
int reg_respond_alloc(struct flow_info * info,
- buffer_t * pbuf);
+ buffer_t * pbuf,
+ int response);
-int reg_prepare_flow_accept(struct flow_info * info,
- buffer_t * pbuf);
+int reg_prepare_flow_accept(struct flow_info * info);
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,
+int reg_wait_flow_accepting(const char * name,
const struct timespec * abstime);
int reg_respond_accept(struct flow_info * info,
diff --git a/src/irmd/reg/tests/CMakeLists.txt b/src/irmd/reg/tests/CMakeLists.txt
index bc1354ed..7bc98571 100644
--- a/src/irmd/reg/tests/CMakeLists.txt
+++ b/src/irmd/reg/tests/CMakeLists.txt
@@ -21,7 +21,11 @@ endif ()
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)
diff --git a/src/irmd/reg/tests/flow_test.c b/src/irmd/reg/tests/flow_test.c
index f9d23fd1..27fd61b0 100644
--- a/src/irmd/reg/tests/flow_test.c
+++ b/src/irmd/reg/tests/flow_test.c
@@ -28,7 +28,7 @@
#define TEST_DATA "testpiggybackdata"
-static int test_reg_flow_create(void)
+static int test_reg_flow_create_destroy(void)
{
struct reg_flow * f;
@@ -51,10 +51,10 @@ static int test_reg_flow_create(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_flow_create_no_id(void) {
@@ -67,7 +67,7 @@ static int test_reg_flow_create_no_id(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_create_no_pid(void) {
@@ -80,7 +80,7 @@ static int test_reg_flow_create_no_pid(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_create_has_n_1_pid(void) {
@@ -94,7 +94,7 @@ static int test_reg_flow_create_has_n_1_pid(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_create_wrong_state(void) {
@@ -108,7 +108,7 @@ static int test_reg_flow_create_wrong_state(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_create_has_mpl(void) {
@@ -123,7 +123,7 @@ static int test_reg_flow_create_has_mpl(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_update(void)
@@ -163,10 +163,10 @@ static int test_reg_flow_update(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_flow_update_wrong_id(void)
@@ -199,10 +199,10 @@ static int test_reg_flow_update_wrong_id(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_flow_assert_fails(void)
@@ -210,15 +210,10 @@ 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;
@@ -237,7 +232,7 @@ static int test_flow_data(void)
char * data;
buffer_t buf;
- buffer_t rcv = {NULL, 0};
+ buffer_t rcv = {0, NULL};
TEST_START();
@@ -267,11 +262,11 @@ static int test_flow_data(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
free(data);
TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
int flow_test(int argc,
@@ -282,12 +277,9 @@ int flow_test(int argc,
(void) argc;
(void) argv;
- ret |= test_reg_flow_create();
-
+ ret |= test_reg_flow_create_destroy();
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
index fb8ba71b..d7d8e524 100644
--- a/src/irmd/reg/tests/ipcp_test.c
+++ b/src/irmd/reg/tests/ipcp_test.c
@@ -31,7 +31,7 @@ static int test_reg_ipcp_create(void)
struct reg_ipcp * ipcp;
struct ipcp_info info = {
.pid = TEST_PID,
- .state = IPCP_BOOT
+ .state = IPCP_INIT
};
struct layer_info layer = {
.name = "testlayer",
@@ -51,7 +51,7 @@ static int test_reg_ipcp_create(void)
goto fail;
}
- ipcp->info.state = IPCP_OPERATIONAL;
+ ipcp->info.state = IPCP_BOOT;
reg_ipcp_set_layer(ipcp, &layer);
@@ -60,11 +60,6 @@ static int test_reg_ipcp_create(void)
goto fail;
}
- if (ipcp->info.state != IPCP_OPERATIONAL) {
- printf("IPCP state was not set.\n");
- goto fail;
- }
-
reg_ipcp_destroy(ipcp);
TEST_SUCCESS();
diff --git a/src/irmd/reg/tests/name_test.c b/src/irmd/reg/tests/name_test.c
index 48f132e9..9071364b 100644
--- a/src/irmd/reg/tests/name_test.c
+++ b/src/irmd/reg/tests/name_test.c
@@ -20,8 +20,11 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
+
#include "../name.c"
+#include <ouroboros/test.h>
+
#define TEST_PID 65534
#define TEST_PROG "/usr/bin/testprog"
#define TEST_NAME "testservicename"
@@ -34,6 +37,8 @@ static int test_reg_name_create(void)
.pol_lb = LB_RR,
};
+ TEST_START();
+
n = reg_name_create(&info);
if (n == NULL) {
printf("Failed to create name %s.\n", info.name);
@@ -42,9 +47,12 @@ static int test_reg_name_create(void)
reg_name_destroy(n);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_name_add_proc(void)
@@ -55,6 +63,8 @@ static int test_reg_name_add_proc(void)
.pol_lb = LB_RR,
};
+ TEST_START();
+
n = reg_name_create(&info);
if (n == NULL) {
printf("Failed to create name %s.\n", info.name);
@@ -66,8 +76,8 @@ static int test_reg_name_add_proc(void)
goto fail;
}
- if (n->n_procs != 1) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 1) {
+ printf("Proc not added to list.\n");
goto fail;
}
@@ -78,16 +88,19 @@ static int test_reg_name_add_proc(void)
reg_name_del_proc(n, TEST_PID);
- if (n->n_procs != 0) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 0) {
+ printf("Proc not removed from list.\n");
goto fail;
}
reg_name_destroy(n);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_name_add_prog(void)
@@ -100,6 +113,8 @@ static int test_reg_name_add_prog(void)
char * exec[] = { TEST_PROG, "--argswitch", "argvalue", NULL};
+ TEST_START();
+
n = reg_name_create(&info);
if (n == NULL) {
printf("Failed to create name %s.\n", info.name);
@@ -111,8 +126,8 @@ static int test_reg_name_add_prog(void)
goto fail;
}
- if (n->n_progs != 1) {
- printf("n_progs not updated.\n");
+ if (n->progs.len != 1) {
+ printf("Prog not added to list.\n");
goto fail;
}
@@ -123,16 +138,19 @@ static int test_reg_name_add_prog(void)
reg_name_del_prog(n, TEST_PROG);
- if (n->n_progs != 0) {
- printf("n_progs not updated.\n");
+ if (n->progs.len != 0) {
+ printf("Prog not removed from list.\n");
goto fail;
}
reg_name_destroy(n);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_name_add_active(enum pol_balance lb)
@@ -144,6 +162,8 @@ static int test_reg_name_add_active(enum pol_balance lb)
.pol_lb = lb,
};
+ TEST_START();
+
n = reg_name_create(&info);
if (n == NULL) {
printf("Failed to create name %s.\n", info.name);
@@ -175,8 +195,8 @@ static int test_reg_name_add_active(enum pol_balance lb)
goto fail;
}
- if (n->n_active != 1) {
- printf("n_active not updated.\n");
+ if (n->active.len != 1) {
+ printf("Active list not updated.\n");
goto fail;
}
@@ -206,13 +226,13 @@ static int test_reg_name_add_active(enum pol_balance lb)
goto fail;
}
- if (n->n_procs != 3) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 3) {
+ printf("Procs list not updated.\n");
goto fail;
}
- if (n->n_active != 4) {
- printf("n_active not updated.\n");
+ if (n->active.len != 4) {
+ printf("Active list not updated.\n");
goto fail;
}
@@ -243,41 +263,39 @@ static int test_reg_name_add_active(enum pol_balance lb)
reg_name_del_proc(n, TEST_PID);
- if (n->n_procs != 0) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 0) {
+ printf("Procs list not cleared.\n");
goto fail;
}
- if (n->n_active != 0) {
- printf("n_active not updated.\n");
+ if (n->active.len != 0) {
+ printf("Active list not cleared.\n");
goto fail;
}
reg_name_destroy(n);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
-
int name_test(int argc,
char ** argv)
{
- int res = 0;
+ int rc = 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);
+ rc |= test_reg_name_create();
+ rc |= test_reg_name_add_proc();
+ rc |= test_reg_name_add_prog();
+ rc |= test_reg_name_add_active(LB_RR);
+ rc |= test_reg_name_add_active(LB_SPILL);
- return res;
+ return rc;
}
diff --git a/src/irmd/reg/tests/proc_test.c b/src/irmd/reg/tests/proc_test.c
index 5c9dd865..df0527fb 100644
--- a/src/irmd/reg/tests/proc_test.c
+++ b/src/irmd/reg/tests/proc_test.c
@@ -22,10 +22,12 @@
#include "../proc.c"
+#include <ouroboros/test.h>
+
#define TEST_PID 65534
#define TEST_PROG "usr/bin/testprog"
-static int test_reg_proc_create(void)
+static int test_reg_proc_create_destroy(void)
{
struct reg_proc * proc;
struct proc_info info = {
@@ -33,6 +35,8 @@ static int test_reg_proc_create(void)
.prog = TEST_PROG
};
+ TEST_START();
+
proc = reg_proc_create(&info);
if (proc == NULL) {
printf("Failed to create proc.\n");
@@ -41,9 +45,12 @@ static int test_reg_proc_create(void)
reg_proc_destroy(proc);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_proc_add_name(void)
@@ -56,6 +63,8 @@ static int test_reg_proc_add_name(void)
char * name = "testname";
+ TEST_START();
+
proc = reg_proc_create(&info);
if (proc == NULL) {
printf("Failed to create proc.\n");
@@ -86,9 +95,12 @@ static int test_reg_proc_add_name(void)
reg_proc_destroy(proc);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
int proc_test(int argc,
@@ -99,8 +111,7 @@ int proc_test(int argc,
(void) argc;
(void) argv;
- res |= test_reg_proc_create();
-
+ res |= test_reg_proc_create_destroy();
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
index 5e6931d8..c394c222 100644
--- a/src/irmd/reg/tests/prog_test.c
+++ b/src/irmd/reg/tests/prog_test.c
@@ -22,8 +22,9 @@
#include "../prog.c"
-#define TEST_PROG "usr/bin/testprog"
+#include <ouroboros/test.h>
+#define TEST_PROG "usr/bin/testprog"
static int test_reg_prog_create(void)
{
@@ -32,6 +33,8 @@ static int test_reg_prog_create(void)
.name = TEST_PROG
};
+ TEST_START();
+
prog = reg_prog_create(&info);
if (prog == NULL) {
printf("Failed to create prog.\n");
@@ -40,9 +43,12 @@ static int test_reg_prog_create(void)
reg_prog_destroy(prog);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_prog_add_name(void)
@@ -54,6 +60,8 @@ static int test_reg_prog_add_name(void)
char * name = "testname";
+ TEST_START();
+
prog = reg_prog_create(&info);
if (prog == NULL) {
printf("Failed to create prog.\n");
@@ -84,9 +92,12 @@ static int test_reg_prog_add_name(void)
reg_prog_destroy(prog);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
int prog_test(int argc,
@@ -98,7 +109,6 @@ int prog_test(int 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
index c341c297..4699beab 100644
--- a/src/irmd/reg/tests/reg_test.c
+++ b/src/irmd/reg/tests/reg_test.c
@@ -36,7 +36,7 @@
#define TEST_DATA2 "testpbufdata2"
#define TEST_LAYER "testlayer"
#define REG_TEST_FAIL() \
- do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); } while(0)
+ do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); abort();} while(0)
static int test_reg_init(void)
{
@@ -51,10 +51,10 @@ static int test_reg_init(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_create_flow(void)
@@ -105,18 +105,17 @@ static int test_reg_create_flow(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
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};
+ buffer_t rbuf = BUF_INIT;
struct flow_info info = {
.n_pid = TEST_PID,
@@ -125,14 +124,6 @@ static int test_reg_allocate_flow_timeout(void)
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);
@@ -147,7 +138,7 @@ static int test_reg_allocate_flow_timeout(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -162,12 +153,6 @@ static int test_reg_allocate_flow_timeout(void)
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) {
@@ -179,16 +164,19 @@ static int test_reg_allocate_flow_timeout(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static void * test_flow_respond_alloc(void * o)
{
struct flow_info * info = (struct flow_info *) o;
- buffer_t pbuf = {NULL, 0};
+ buffer_t pbuf = BUF_INIT;
+ int response;
+
+ response = (info->state == FLOW_ALLOCATED) ? 0 : -1;
if (info->state == FLOW_ALLOCATED) {
pbuf.data = (uint8_t *) strdup(TEST_DATA2);
@@ -199,7 +187,7 @@ static void * test_flow_respond_alloc(void * o)
pbuf.len = strlen((char *) pbuf.data) + 1;
}
- reg_respond_alloc(info, &pbuf);
+ reg_respond_alloc(info, &pbuf, response);
return (void *) 0;
fail:
@@ -220,13 +208,6 @@ static void * test_flow_respond_accept(void * o)
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;
@@ -237,8 +218,7 @@ 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};
+ buffer_t rbuf = BUF_INIT;
struct flow_info info = {
.n_pid = TEST_PID,
@@ -247,7 +227,7 @@ static int test_reg_accept_flow_success(void)
struct flow_info n_1_info = {
.n_1_pid = TEST_N_1_PID,
- .qs = qos_data_crypt,
+ .qs = qos_data,
.state = FLOW_ALLOCATED /* RESPONSE SUCCESS */
};
@@ -267,7 +247,7 @@ static int test_reg_accept_flow_success(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -277,7 +257,7 @@ static int test_reg_accept_flow_success(void)
pthread_create(&thr, NULL, test_flow_respond_accept, &n_1_info);
- if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0 ) {
+ if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0) {
printf("Flow allocation failed.\n");
goto fail;
}
@@ -321,10 +301,10 @@ static int test_reg_accept_flow_success(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_accept_flow_success_no_crypt(void)
@@ -332,8 +312,7 @@ 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};
+ buffer_t rbuf = BUF_INIT;
struct flow_info info = {
.n_pid = TEST_PID,
@@ -362,7 +341,7 @@ static int test_reg_accept_flow_success_no_crypt(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -389,10 +368,7 @@ static int test_reg_accept_flow_success_no_crypt(void)
goto fail;
}
- if (strcmp((char *) rbuf.data, TEST_DATA) != 0) {
- printf("Data was updated.\n");
- goto fail;
- }
+ freebuf(rbuf);
n_1_info.state = FLOW_DEALLOCATED;
@@ -416,16 +392,16 @@ static int test_reg_accept_flow_success_no_crypt(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_allocate_flow_fail(void)
{
- buffer_t buf = {NULL, 0};
+ buffer_t buf = BUF_INIT;
pthread_t thr;
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
@@ -486,26 +462,22 @@ static int test_reg_allocate_flow_fail(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_flow(void) {
- int ret = 0;
+ int rc = 0;
- ret |= test_reg_create_flow();
+ rc |= test_reg_create_flow();
+ rc |= test_reg_allocate_flow_timeout();
+ rc |= test_reg_accept_flow_success();
+ rc |= test_reg_accept_flow_success_no_crypt();
+ rc |= test_reg_allocate_flow_fail();
- 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;
+ return rc;
}
static int test_reg_create_ipcp(void)
@@ -513,7 +485,7 @@ static int test_reg_create_ipcp(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
TEST_START();
@@ -552,10 +524,130 @@ static int test_reg_create_ipcp(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
+ fail:
+ REG_TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_reg_list_ipcps(void)
+{
+ ipcp_list_msg_t ** ipcps;
+ int i;
+ ssize_t len;
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < 10; i++) {
+ struct ipcp_info info = {
+ .pid = TEST_PID + i,
+ .state = IPCP_INIT /* set by spawn_ipcp */
+ };
+
+ sprintf(info.name, "%s%d", TEST_IPCP, i);
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp %d.\n", i);
+ goto fail;
+ }
+ }
+
+ len = reg_list_ipcps(&ipcps);
+ if (len < 0) {
+ printf("Failed to list ipcps.\n");
+ goto fail;
+ }
+
+ if (len != 10) {
+ printf("Failed to list all ipcps.\n");
+ goto fail;
+ }
+
+ while (len-- > 0)
+ ipcp_list_msg__free_unpacked(ipcps[len], NULL);
+ free(ipcps);
+
+ for (i = 0; i < 10; i++)
+ reg_destroy_proc(TEST_PID + i);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
+}
+
+static int test_insert_ipcps(void)
+{
+ ipcp_list_msg_t ** ipcps;
+ struct ipcp_info info;
+ size_t i;
+ size_t len;
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < 100; i++) {
+ sprintf(info.name, "%s-%zd", TEST_IPCP, i);
+ info.pid = TEST_PID + rand() % 10000;
+ info.type = rand() % IPCP_INVALID;
+ info.state = IPCP_INIT; /* set by spawn_ipcp */
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp %s.\n", info.name);
+ goto fail;
+ }
+ }
+
+ len = reg_list_ipcps(&ipcps);
+ if (len != 100) {
+ printf("Failed to list all ipcps.\n");
+ goto fail;
+ }
+
+ for (i = 1; i < len; i++) {
+ if (ipcps[i]->type < ipcps[i - 1]->type) {
+ printf("IPCPS not sorted by type.\n");
+ goto fail;
+ }
+
+ if (ipcps[i]->type != ipcps[i - 1]->type)
+ continue;
+
+ /* allow occasional duplicate PID in test */
+ if (ipcps[i]->pid < ipcps[i - 1]->pid) {
+ printf("IPCPS not sorted by pid.\n");
+ goto fail;
+ }
+ }
+
+ while (len-- > 0)
+ ipcp_list_msg__free_unpacked(ipcps[len], NULL);
+ free(ipcps);
+
+ reg_clear();
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+fail:
+ REG_TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_set_layer(void)
@@ -564,7 +656,7 @@ static int test_set_layer(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
struct layer_info layer = {
.name = TEST_LAYER,
@@ -588,8 +680,9 @@ static int test_set_layer(void)
}
ipcp = __reg_get_ipcp(info.pid);
- ipcp->info.state = IPCP_OPERATIONAL;
- info.state = IPCP_ENROLLED;
+
+ ipcp->info.state = IPCP_BOOT;
+ info.state = IPCP_BOOT;
reg_set_layer_for_ipcp(&info, &layer);
@@ -614,21 +707,22 @@ static int test_set_layer(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_ipcp(void)
{
- int ret = 0;
-
- ret |= test_reg_create_ipcp();
+ int rc = 0;
- ret |= test_set_layer();
+ rc |= test_reg_create_ipcp();
+ rc |= test_reg_list_ipcps();
+ rc |= test_insert_ipcps();
+ rc |= test_set_layer();
- return ret;
+ return rc;
}
static int test_reg_create_name(void)
@@ -674,19 +768,77 @@ static int test_reg_create_name(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
+}
+
+static int test_reg_list_names(void)
+{
+ name_info_msg_t ** names;
+ int i;
+ ssize_t len;
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < 10; i++) {
+ struct name_info info = {
+ .pol_lb = LB_RR
+ };
+
+ sprintf(info.name, "%s%d", TEST_NAME, i);
+
+ if (reg_create_name(&info) < 0) {
+ printf("Failed to create name %d.\n", i);
+ goto fail;
+ }
+ }
+
+ len = reg_list_names(&names);
+ if (len < 0) {
+ printf("Failed to list names.\n");
+ goto fail;
+ }
+
+ if (len != 10) {
+ printf("Failed to list all names.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < len; i++)
+ name_info_msg__free_unpacked(names[i], NULL);
+ free(names);
+
+ for (i = 0; i < 10; i++) {
+ char name[NAME_MAX];
+ sprintf(name, "%s%d", TEST_NAME, i);
+ reg_destroy_name(name);
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ REG_TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_name(void)
{
- int ret = 0;
+ int rc = 0;
- ret |= test_reg_create_name();
+ rc |= test_reg_create_name();
+ rc |= test_reg_list_names();
- return ret;
+ return rc;
}
static int test_reg_create_proc(void)
@@ -732,19 +884,19 @@ static int test_reg_create_proc(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_proc(void)
{
- int ret = 0;
+ int rc = 0;
- ret |= test_reg_create_proc();
+ rc |= test_reg_create_proc();
- return ret;
+ return rc;
}
static int test_reg_spawned(void)
@@ -785,10 +937,10 @@ static int test_reg_spawned(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_create_prog(void)
@@ -833,19 +985,19 @@ static int test_reg_create_prog(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_prog(void)
{
- int ret = 0;
+ int rc = 0;
- ret |= test_reg_create_prog();
+ rc |= test_reg_create_prog();
- return ret;
+ return rc;
}
static int test_bind_proc(void)
@@ -900,10 +1052,10 @@ static int test_bind_proc(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_bind_prog(void)
@@ -989,10 +1141,10 @@ static int test_bind_prog(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_inherit_prog(void)
@@ -1060,10 +1212,10 @@ static int test_inherit_prog(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_accepting_timeout(void)
@@ -1071,7 +1223,6 @@ 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
@@ -1089,12 +1240,10 @@ static int test_wait_accepting_timeout(void)
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);
+ flow_id = reg_wait_flow_accepting(ninfo.name, &abstime);
if (flow_id != -ETIMEDOUT) {
printf("Wait accept did not time out: %d.\n", flow_id);
goto fail;
@@ -1106,10 +1255,10 @@ static int test_wait_accepting_timeout(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_accepting_fail_name(void)
@@ -1117,7 +1266,6 @@ 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();
@@ -1128,11 +1276,10 @@ static int test_wait_accepting_fail_name(void)
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);
+ flow_id = reg_wait_flow_accepting(TEST_NAME, &abstime);
if (flow_id != -ENAME) {
- printf("Wait accept did not fail on name: %d.\n", flow_id);
+ printf("Wait accept did not fail: %d.\n", flow_id);
goto fail;
}
@@ -1140,17 +1287,17 @@ static int test_wait_accepting_fail_name(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static void * test_call_flow_accept(void * o)
{
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_MS(1);
- buffer_t pbuf = {NULL, 0};
+ buffer_t pbuf = BUF_INIT;
struct proc_info pinfo = {
.pid = TEST_PID,
@@ -1182,7 +1329,7 @@ static void * test_call_flow_accept(void * o)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- reg_prepare_flow_accept(&info, &pbuf);
+ reg_prepare_flow_accept(&info);
if (reg_wait_flow_accepted(&info, &pbuf, &abstime) != -ETIMEDOUT) {
printf("Wait allocated did not timeout.\n");
@@ -1201,14 +1348,14 @@ 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];
+ int flow_id;
struct name_info ninfo = {
.name = TEST_NAME,
.pol_lb = LB_RR
};
+
TEST_START();
if (reg_init()) {
@@ -1226,9 +1373,7 @@ static int test_wait_accepting_success(void)
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);
+ flow_id = reg_wait_flow_accepting(ninfo.name, &abstime);
if (flow_id < 0) {
printf("Wait accept did not return a flow id: %d.", flow_id);
goto fail;
@@ -1242,23 +1387,21 @@ static int test_wait_accepting_success(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_accepting(void)
{
- int ret = 0;
-
- ret |= test_wait_accepting_timeout();
+ int rc = 0;
- ret |= test_wait_accepting_fail_name();
+ rc |= test_wait_accepting_timeout();
+ rc |= test_wait_accepting_fail_name();
+ rc |= test_wait_accepting_success();
- ret |= test_wait_accepting_success();
-
- return ret;
+ return rc;
}
static int test_wait_ipcp_boot_timeout(void)
@@ -1268,7 +1411,7 @@ static int test_wait_ipcp_boot_timeout(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
TEST_START();
@@ -1300,10 +1443,10 @@ static int test_wait_ipcp_boot_timeout(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static void * test_ipcp_respond(void * o)
@@ -1323,12 +1466,12 @@ static int test_wait_ipcp_boot_fail(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
struct ipcp_info resp_info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_NULL
+ .state = IPCP_INIT
};
TEST_START();
@@ -1348,7 +1491,7 @@ static int test_wait_ipcp_boot_fail(void)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- info.state = IPCP_BOOT;
+ info.state = IPCP_INIT;
if (reg_wait_ipcp_boot(&info, &abstime) == 0) {
printf("IPCP boot reported success.\n");
@@ -1371,10 +1514,10 @@ static int test_wait_ipcp_boot_fail(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_ipcp_boot_success(void)
@@ -1385,7 +1528,7 @@ static int test_wait_ipcp_boot_success(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
struct ipcp_info resp_info = {
.name = TEST_IPCP,
@@ -1410,7 +1553,7 @@ static int test_wait_ipcp_boot_success(void)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- info.state = IPCP_BOOT;
+ info.state = IPCP_INIT;
if (reg_wait_ipcp_boot(&info, &abstime) < 0) {
printf("IPCP boot failed.\n");
@@ -1433,23 +1576,21 @@ static int test_wait_ipcp_boot_success(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_ipcp_boot(void)
{
- int ret = 0;
-
- ret |= test_wait_ipcp_boot_timeout();
-
- ret |= test_wait_ipcp_boot_fail();
+ int rc = 0;
- ret |= test_wait_ipcp_boot_success();
+ rc |= test_wait_ipcp_boot_timeout();
+ rc |= test_wait_ipcp_boot_fail();
+ rc |= test_wait_ipcp_boot_success();
- return ret;
+ return rc;
}
static int test_wait_proc_timeout(void)
@@ -1477,10 +1618,10 @@ static int test_wait_proc_timeout(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static void * test_proc(void * o)
@@ -1527,57 +1668,43 @@ static int test_wait_proc_success(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_proc(void)
{
- int ret = 0;
+ int rc = 0;
- ret |= test_wait_proc_timeout();
+ rc |= test_wait_proc_timeout();
+ rc |= test_wait_proc_success();
- ret |= test_wait_proc_success();
-
- return ret;
+ return rc;
}
-
int reg_test(int argc,
char ** argv)
{
- int ret = 0;
+ int rc = 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;
+ rc |= test_reg_init();
+ rc |= test_reg_flow();
+ rc |= test_reg_ipcp();
+ rc |= test_reg_name();
+ rc |= test_reg_proc();
+ rc |= test_reg_prog();
+ rc |= test_reg_spawned();
+ rc |= test_bind_proc();
+ rc |= test_bind_prog();
+ rc |= test_inherit_prog();
+ rc |= test_wait_accepting();
+ rc |= test_wait_ipcp_boot();
+ rc |= test_wait_proc();
+
+ return rc;
}
diff --git a/src/irmd/tests/CMakeLists.txt b/src/irmd/tests/CMakeLists.txt
index e005d194..e860acce 100644
--- a/src/irmd/tests/CMakeLists.txt
+++ b/src/irmd/tests/CMakeLists.txt
@@ -3,6 +3,8 @@ get_filename_component(src_folder "${tmp}" NAME)
create_test_sourcelist(${src_folder}_tests test_suite.c
# Add new tests here
+ irm_test.c
+ oap_test.c
)
add_executable(${src_folder}_test EXCLUDE_FROM_ALL ${${src_folder}_tests})
@@ -11,9 +13,15 @@ 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(irmd/${test_name} ${C_TEST_PATH}/${src_folder}_test ${test_name})
endforeach(test)
+
+set_property(TEST irmd/oap_test PROPERTY SKIP_RETURN_CODE 1)
diff --git a/src/irmd/tests/irm_test.c b/src/irmd/tests/irm_test.c
new file mode 100644
index 00000000..d440289c
--- /dev/null
+++ b/src/irmd/tests/irm_test.c
@@ -0,0 +1,33 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Unit tests of IRMd 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/.
+ */
+
+
+
+int irm_test(int argc,
+ char **argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ return ret;
+}
diff --git a/src/irmd/tests/oap_test.c b/src/irmd/tests/oap_test.c
new file mode 100644
index 00000000..4e7fb2d1
--- /dev/null
+++ b/src/irmd/tests/oap_test.c
@@ -0,0 +1,285 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Unit tests of Ouroboros flow allocation protocol
+ * 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"
+
+#include "oap.c"
+
+#include <ouroboros/random.h>
+#include <ouroboros/test.h>
+
+static const char * pkp_str = \
+"-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEIC13y+5jdKe80HBJD7WITpQamcn3rrkTX1r0v+JwSk4NoAoGCCqGSM49\n"
+"AwEHoUQDQgAEcC0yLAfUtufH8cdLybrdWPc6U+xRuhDhqqrEcBO5+eob2xyqEaNk\n"
+"nIV/86724zPptGRahWz0rzW2PvNppJdNBg==\n"
+"-----END EC PRIVATE KEY-----\n";
+
+/* Valid signed server certificate for server-2.unittest.o7s */
+static const char * crt_str = \
+"-----BEGIN CERTIFICATE-----\n"
+"MIIDgjCCAyigAwIBAgICEAIwCgYIKoZIzj0EAwIwWzELMAkGA1UEBhMCQkUxDDAK\n"
+"BgNVBAgMA09WTDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3Mx\n"
+"GTAXBgNVBAMMEGltMi51bml0dGVzdC5vN3MwHhcNMjUwNzA0MTMxODI5WhcNMzUw\n"
+"NzAyMTMxODI5WjBwMQswCQYDVQQGEwJCRTEMMAoGA1UECAwDT1ZMMQ4wDAYDVQQH\n"
+"DAVHaGVudDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3MxHjAc\n"
+"BgNVBAMMFXNlcnZlci0yLnVuaXR0ZXN0Lm83czBZMBMGByqGSM49AgEGCCqGSM49\n"
+"AwEHA0IABHAtMiwH1Lbnx/HHS8m63Vj3OlPsUboQ4aqqxHATufnqG9scqhGjZJyF\n"
+"f/Ou9uMz6bRkWoVs9K81tj7zaaSXTQajggHFMIIBwTAJBgNVHRMEAjAAMBEGCWCG\n"
+"SAGG+EIBAQQEAwIGQDA6BglghkgBhvhCAQ0ELRYrR3JpbGxlZCBDaGVlc2UgR2Vu\n"
+"ZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUTt3xHTwE9amoglxh\n"
+"cEMqWv+PpDMwgb8GA1UdIwSBtzCBtIAUFfeZRx8QWWKQr7Aw8zjDu2shvcShgZek\n"
+"gZQwgZExCzAJBgNVBAYTAkJFMQwwCgYDVQQIDANPVkwxDjAMBgNVBAcMBUdoZW50\n"
+"MQwwCgYDVQQKDANvN3MxFTATBgNVBAsMDHVuaXR0ZXN0Lm83czEZMBcGA1UEAwwQ\n"
+"Y2EyLnVuaXR0ZXN0Lm83czEkMCIGCSqGSIb3DQEJARYVZHVtbXlAb3Vyb2Jvcm9z\n"
+"LnJvY2tzggIQAjAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEw\n"
+"EQYDVR0fBAowCDAGoASgAoYAMCoGCCsGAQUFBwEBBB4wHDAMBggrBgEFBQcwAoYA\n"
+"MAwGCCsGAQUFBzABhgAwIAYDVR0RBBkwF4IVc2VydmVyLTEudW5pdHRlc3Qubzdz\n"
+"MAoGCCqGSM49BAMCA0gAMEUCIQDHuDb62w/Uah4nKwUFoJVkr4rgdNGh2Rn3SWaK\n"
+"0FV/gAIgOLKorTwSgrTFdyOUkuPOhRs8BEMpah+dp8UTO8AnLvY=\n"
+"-----END CERTIFICATE-----\n";
+
+static int test_oap_hdr_init_fini(void)
+{
+ struct oap_hdr oap_hdr;
+ struct timespec now;
+ uint64_t stamp;
+ buffer_t ephkey = BUF_INIT;
+ buffer_t data = BUF_INIT;
+ uint8_t buf[OAP_ID_SIZE];
+ buffer_t id;
+ void * pkp = NULL;
+ void * pubcrt = NULL;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ stamp = TS_TO_UINT64(now);
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to init OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.hdr.len != OAP_HDR_MIN_SIZE) {
+ printf("OAP request header wrong: %zu < %zu.\n",
+ oap_hdr.hdr.len, OAP_HDR_MIN_SIZE);
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.id.len != OAP_ID_SIZE) {
+ printf("OAP request header ID wrong size: %zu != %zu.\n",
+ oap_hdr.id.len, (size_t) OAP_ID_SIZE);
+ goto fail_req_hdr_chk;
+ }
+
+ if (memcmp(oap_hdr.id.data, id.data, OAP_ID_SIZE) != 0) {
+ printf("OAP request header ID mismatch.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.timestamp < stamp) {
+ printf("OAP request header timestamp is too old.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.timestamp > stamp + 1 * BILLION) {
+ printf("OAP request header timestamp is too new.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ oap_hdr_fini(&oap_hdr);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_req_hdr_chk:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_oap_hdr_init_fini_data(void)
+
+{
+ struct oap_hdr oap_hdr;
+ buffer_t data;
+ buffer_t ephkey = BUF_INIT;
+ uint8_t buf[OAP_ID_SIZE];
+ buffer_t id;
+ void * pkp = NULL;
+ void * pubcrt = NULL;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ data.len = 100;
+ data.data = malloc(data.len);
+ if (data.data == NULL) {
+ printf("Failed to allocate data buffer.\n");
+ goto fail_data;
+ }
+
+ random_buffer(data.data, data.len);
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to create OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.hdr.len != OAP_HDR_MIN_SIZE + data.len) {
+ printf("OAP request header wrong: %zu < %zu.\n",
+ oap_hdr.hdr.len, OAP_HDR_MIN_SIZE + data.len);
+ goto fail_req_hdr_sz;
+ }
+
+ freebuf(data);
+ oap_hdr_fini(&oap_hdr);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_req_hdr_sz:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ freebuf(data);
+ fail_data:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_oap_hdr_init_fini_signed(void)
+{
+ struct oap_hdr oap_hdr;
+ buffer_t ephkey = BUF_INIT;
+ buffer_t data = BUF_INIT;
+ buffer_t sign;
+ buffer_t id;
+ uint8_t buf[OAP_ID_SIZE];
+ void * pkp;
+ void * pk;
+ void * pubcrt;
+ void * pubcrt2;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ if (crypt_load_privkey_str(pkp_str, &pkp) < 0) {
+ printf("Failed to load private key.\n");
+ goto fail_pkp;
+ }
+
+ if (crypt_load_crt_str(crt_str, &pubcrt) < 0) {
+ printf("Failed to load public certificate.\n");
+ goto fail_pubcrt;
+ }
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to create OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.crt.len == 0) {
+ printf("OAP request header has no public certificate.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.sig.len == 0) {
+ printf("OAP request header no signature.\n");
+ goto fail_req_hdr;
+ }
+
+ if (crypt_load_crt_der(oap_hdr.crt, &pubcrt2) < 0) {
+ printf("Failed to load public certificate from DER.\n");
+ goto fail_crt_der;
+ }
+
+ if (crypt_get_pubkey_crt(pubcrt2, &pk) < 0) {
+ printf("Failed to get public key from certificate.\n");
+ goto fail_crt_pk;
+ }
+
+ sign = oap_hdr.hdr;
+ sign.len -= (oap_hdr.sig.len + sizeof(uint16_t));
+
+ if (auth_verify_sig(pk, sign, oap_hdr.sig) < 0) {
+ printf("Failed to verify OAP request header signature.\n");
+ goto fail_check_sig;
+ }
+
+ oap_hdr_fini(&oap_hdr);
+
+ crypt_free_crt(pubcrt2);
+ crypt_free_crt(pubcrt);
+ crypt_free_key(pk);
+ crypt_free_key(pkp);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_check_sig:
+ crypt_free_key(pk);
+ fail_crt_pk:
+ crypt_free_crt(pubcrt2);
+ fail_crt_der:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ crypt_free_crt(pubcrt);
+ fail_pubcrt:
+ crypt_free_key(pkp);
+ fail_pkp:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int oap_test(int argc,
+ char **argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_oap_hdr_init_fini();
+ ret |= test_oap_hdr_init_fini_data();
+#ifdef HAVE_OPENSSL
+ ret |= test_oap_hdr_init_fini_signed();
+#else
+ (void) test_oap_hdr_init_fini_signed;
+
+ ret = TEST_RC_SKIP;
+#endif
+ return ret;
+}
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index a6d7ac98..04a8f089 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -46,6 +46,9 @@ if (HAVE_ROBUST_MUTEX)
message(STATUS "Robust mutex support disabled by user")
unset(HAVE_ROBUST_MUTEX)
endif ()
+else()
+ message(STATUS "Robust mutex support not available")
+ unset(HAVE_ROBUST_MUTEX)
endif ()
find_library(FUSE_LIBRARIES fuse QUIET)
@@ -112,18 +115,21 @@ if (OPENSSL_FOUND)
set(DISABLE_OPENSSL FALSE CACHE BOOL "Disable OpenSSL support")
if (NOT DISABLE_OPENSSL)
message(STATUS "OpenSSL support enabled")
- set(HAVE_OPENSSL TRUE)
+ set(HAVE_OPENSSL TRUE CACHE INTERNAL "")
else()
message(STATUS "OpenSSL support disabled")
unset(HAVE_OPENSSL)
endif()
endif ()
-endif ()
-
-if (NOT HAVE_OPENSSL_RNG)
+ set(OPENSSL_SOURCES crypt/openssl.c)
+else()
+ message(STATUS "Install openSSL version >= \"1.1.0\" to enable OpenSSL support")
+ unset(HAVE_OPENSSL_RNG)
+ unset(HAVE_OPENSSL)
set(OPENSSL_INCLUDE_DIR "")
set(OPENSSL_LIBRARIES "")
set(OPENSSL_CRYPTO_LIBRARY "")
+ set(OPENSSL_SOURCES "")
endif ()
if (APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
@@ -228,6 +234,10 @@ 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")
+set(TPM_DEBUG_REPORT_INTERVAL 0 CACHE STRING
+ "Interval at wich the TPM will report long running threads (s), 0 disables")
+set(TPM_DEBUG_ABORT_TIMEOUT 0 CACHE STRING
+ "TPM abort process after a thread reaches this timeout (s), 0 disables")
if (HAVE_FUSE)
set(PROC_FLOW_STATS TRUE CACHE BOOL
@@ -280,7 +290,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
add_library(ouroboros-common SHARED ${SOURCE_FILES_COMMON} ${IRM_PROTO_SRCS}
${IPCP_PROTO_SRCS} ${IPCP_CONFIG_PROTO_SRCS} ${MODEL_PROTO_SRCS}
- ${ENROLL_PROTO_SRCS})
+ ${ENROLL_PROTO_SRCS} ${OPENSSL_SOURCES})
add_library(ouroboros-dev SHARED ${SOURCE_FILES_DEV} ${CEP_PROTO_SRCS})
diff --git a/src/lib/config.h.in b/src/lib/config.h.in
index 604038b4..8326a332 100644
--- a/src/lib/config.h.in
+++ b/src/lib/config.h.in
@@ -28,21 +28,24 @@
#define HAVE_ENCRYPTION
#endif
-#define SYS_MAX_FLOWS @SYS_MAX_FLOWS@
-
-#cmakedefine SHM_RBUFF_LOCKLESS
-#cmakedefine SHM_RDRB_MULTI_BLOCK
-#cmakedefine QOS_DISABLE_CRC
-#cmakedefine HAVE_OPENSSL_RNG
-
-#define SHM_RBUFF_PREFIX "@SHM_RBUFF_PREFIX@"
-#define SHM_LOCKFILE_NAME "@SHM_LOCKFILE_NAME@"
-#define SHM_FLOW_SET_PREFIX "@SHM_FLOW_SET_PREFIX@"
-#define SHM_RDRB_NAME "@SHM_RDRB_NAME@"
-#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@
+#define SYS_MAX_FLOWS @SYS_MAX_FLOWS@
+
+#cmakedefine SHM_RBUFF_LOCKLESS
+#cmakedefine SHM_RDRB_MULTI_BLOCK
+#cmakedefine QOS_DISABLE_CRC
+#cmakedefine HAVE_OPENSSL_RNG
+
+#define SHM_RBUFF_PREFIX "@SHM_RBUFF_PREFIX@"
+#define SHM_LOCKFILE_NAME "@SHM_LOCKFILE_NAME@"
+#define SHM_FLOW_SET_PREFIX "@SHM_FLOW_SET_PREFIX@"
+#define SHM_RDRB_NAME "@SHM_RDRB_NAME@"
+#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@
+
+#define TPM_DEBUG_REPORT_INTERVAL @TPM_DEBUG_REPORT_INTERVAL@
+#define TPM_DEBUG_ABORT_TIMEOUT @TPM_DEBUG_ABORT_TIMEOUT@
#if defined(__linux__) || (defined(__MACH__) && !defined(__APPLE__))
/* Avoid a bug in robust mutex implementation of glibc 2.25 */
diff --git a/src/lib/crypt.c b/src/lib/crypt.c
index ad679501..8b18140e 100644
--- a/src/lib/crypt.c
+++ b/src/lib/crypt.c
@@ -1,8 +1,7 @@
/*
* Ouroboros - Copyright (C) 2016 - 2024
*
- * Elliptic curve Diffie-Hellman key exchange and
- * AES encryption for flows using OpenSSL
+ * Cryptographic operations
*
* Dimitri Staessens <dimitri@ouroboros.rocks>
* Sander Vrijders <sander@ouroboros.rocks>
@@ -20,436 +19,420 @@
* 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>
+#ifdef HAVE_OPENSSL
+ #include "crypt/openssl.h"
+#endif /* HAVE_OPENSSL */
#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>
-
-#include <openssl/bio.h>
+struct crypt_ctx {
+ void * ctx;
+ uint8_t key[SYMMKEYSZ];
+};
-#define IVSZ 16
-/* SYMMKEYSZ defined in dev.c */
+struct auth_ctx {
+ void * store;
+};
-/*
- * Derive the common secret from
- * your public key pair (kp)
- * the remote public key (pub).
- * Store it in a preallocated buffer (s).
- */
-static int __openssl_ecdh_derive_secret(EVP_PKEY * kp,
- EVP_PKEY * pub,
- uint8_t * s)
+int crypt_dh_pkp_create(void ** pkp,
+ uint8_t * pk)
{
- EVP_PKEY_CTX * ctx;
- int ret;
- uint8_t * secret;
- size_t secret_len;
-
- ctx = EVP_PKEY_CTX_new(kp, NULL);
- if (ctx == NULL)
- goto fail_new;
-
- ret = EVP_PKEY_derive_init(ctx);
- if (ret != 1)
- goto fail_ctx;
-
- ret = EVP_PKEY_derive_set_peer(ctx, pub);
- if (ret != 1)
- goto fail_ctx;
-
- ret = EVP_PKEY_derive(ctx, NULL, &secret_len);
- if (ret != 1)
- goto fail_ctx;
-
- if (secret_len < SYMMKEYSZ)
- goto fail_ctx;
-
- secret = OPENSSL_malloc(secret_len);
- if (secret == NULL)
- goto fail_ctx;
-
- ret = EVP_PKEY_derive(ctx, secret, &secret_len);
- if (ret != 1)
- goto fail_derive;
-
- /* Hash the secret for use as AES key. */
- mem_hash(HASH_SHA3_256, s, secret, secret_len);
+#ifdef HAVE_OPENSSL
+ assert(pkp != NULL);
+ *pkp = NULL;
+ return openssl_ecdh_pkp_create(pkp, pk);
+#else
+ (void) pkp;
+ (void) pk;
- OPENSSL_free(secret);
- EVP_PKEY_CTX_free(ctx);
+ *pkp = NULL;
return 0;
-
- fail_derive:
- OPENSSL_free(secret);
- fail_ctx:
- EVP_PKEY_CTX_free(ctx);
- fail_new:
- return -ECRYPT;
+#endif
}
-static int __openssl_ecdh_gen_key(void ** kp)
+void crypt_dh_pkp_destroy(void * pkp)
{
- EVP_PKEY_CTX * ctx = NULL;
- EVP_PKEY_CTX * kctx = NULL;
- EVP_PKEY * params = NULL;
- int ret;
+ if (pkp == NULL)
+ return;
+#ifdef HAVE_OPENSSL
+ openssl_ecdh_pkp_destroy(pkp);
+#else
+ (void) pkp;
- ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
- if (ctx == NULL)
- goto fail_new_id;
+ return;
+#endif
+}
- ret = EVP_PKEY_paramgen_init(ctx);
- if (ret != 1)
- goto fail_paramgen;
+int crypt_dh_derive(void * pkp,
+ buffer_t pk,
+ uint8_t * s)
+{
+#ifdef HAVE_OPENSSL
+ return openssl_ecdh_derive(pkp, pk, s);
+#else
+ (void) pkp;
+ (void) pk;
- ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1);
- if (ret != 1)
- goto fail_paramgen;
+ memset(s, 0, SYMMKEYSZ);
- ret = EVP_PKEY_paramgen(ctx, &params);
- if (ret != 1)
- goto fail_paramgen;
+ return -ECRYPT;
+#endif
+}
- kctx = EVP_PKEY_CTX_new(params, NULL);
- if (kctx == NULL)
- goto fail_keygen_init;
+int crypt_encrypt(struct crypt_ctx * ctx,
+ buffer_t in,
+ buffer_t * out)
+{
+ assert(ctx != NULL);
+ assert(ctx->ctx != NULL);
- ret = EVP_PKEY_keygen_init(kctx);
- if (ret != 1)
- goto fail_keygen;
+#ifdef HAVE_OPENSSL
+ return openssl_encrypt(ctx->ctx, ctx->key, in, out);
+#else
+ (void) ctx;
+ (void) in;
+ (void) out;
- ret = EVP_PKEY_keygen(kctx, (EVP_PKEY **) kp);
- if (ret != 1)
- goto fail_keygen;
+ return -ECRYPT;
+#endif
+}
- EVP_PKEY_free(params);
- EVP_PKEY_CTX_free(kctx);
- EVP_PKEY_CTX_free(ctx);
+int crypt_decrypt(struct crypt_ctx * ctx,
+ buffer_t in,
+ buffer_t * out)
+{
+ assert(ctx != NULL);
+ assert(ctx->ctx != NULL);
- return 0;
+#ifdef HAVE_OPENSSL
+ return openssl_decrypt(ctx->ctx, ctx->key, in, out);
+#else
+ (void) ctx;
+ (void) in;
+ (void) out;
- fail_keygen:
- EVP_PKEY_CTX_free(kctx);
- fail_keygen_init:
- EVP_PKEY_free(params);
- fail_paramgen:
- EVP_PKEY_CTX_free(ctx);
- fail_new_id:
return -ECRYPT;
+#endif
}
-static ssize_t openssl_ecdh_pkp_create(void ** pkp,
- uint8_t * pk)
+struct crypt_ctx * crypt_create_ctx(const uint8_t * key)
{
- uint8_t * pos;
- ssize_t len;
+ struct crypt_ctx * crypt;
- assert(pkp != NULL);
- assert(*pkp == NULL);
- assert(pk != NULL);
-
- if (__openssl_ecdh_gen_key(pkp) < 0)
- return -ECRYPT;
-
- assert(*pkp != NULL);
+ crypt = malloc(sizeof(*crypt));
+ if (crypt == NULL)
+ goto fail_crypt;
- pos = pk; /* i2d_PUBKEY increments the pointer, don't use buf! */
- len = i2d_PUBKEY(*pkp, &pos);
- if (len < 0) {
- EVP_PKEY_free(*pkp);
- return -ECRYPT;
- }
+ memset(crypt, 0, sizeof(*crypt));
- return len;
+ if (key != NULL)
+ memcpy(crypt->key, key, SYMMKEYSZ);
+#ifdef HAVE_OPENSSL
+ crypt->ctx=openssl_crypt_create_ctx();
+ if (crypt->ctx == NULL)
+ goto fail_ctx;
+#endif
+ return crypt;
+#ifdef HAVE_OPENSSL
+ fail_ctx:
+ free(crypt);
+#endif
+ fail_crypt:
+ return NULL;
}
-static void openssl_ecdh_pkp_destroy(void * pkp)
+void crypt_destroy_ctx(struct crypt_ctx * crypt)
{
- EVP_PKEY_free((EVP_PKEY *) pkp);
+ if (crypt == NULL)
+ return;
+
+#ifdef HAVE_OPENSSL
+ assert(crypt->ctx != NULL);
+ openssl_crypt_destroy_ctx(crypt->ctx);
+#else
+ assert(crypt->ctx == NULL);
+#endif
+ free(crypt);
}
-static int openssl_ecdh_derive(void * pkp,
- buffer_t pk,
- uint8_t * s)
+int crypt_load_privkey_file(const char * path,
+ void ** key)
{
- uint8_t * pos;
- EVP_PKEY * pub;
+ *key = NULL;
- 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;
-
- if (__openssl_ecdh_derive_secret(pkp, pub, s) < 0) {
- EVP_PKEY_free(pub);
- return -ECRYPT;
- }
-
- EVP_PKEY_free(pub);
+#ifdef HAVE_OPENSSL
+ return openssl_load_privkey_file(path, key);
+#else
+ (void) path;
return 0;
+#endif
}
-/*
- * AES encryption calls. If FRCT is disabled, we should generate a
- * 128-bit random IV and append it to the packet. If the flow is
- * reliable, we could initialize the context once, and consider the
- * stream a single encrypted message to avoid initializing the
- * encryption context for each packet.
- */
-
-static int openssl_encrypt(void * ctx,
- uint8_t * key,
- struct shm_du_buff * sdb)
+int crypt_load_privkey_str(const char * str,
+ void ** key)
{
- uint8_t * out;
- uint8_t * in;
- uint8_t * head;
- uint8_t iv[IVSZ];
- int in_sz;
- int out_sz;
- int tmp_sz;
- int ret;
-
- 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;
-
- out = malloc(in_sz + EVP_MAX_BLOCK_LENGTH);
- if (out == NULL)
- goto fail_iv;
+ *key = NULL;
- EVP_CIPHER_CTX_reset(ctx);
-
- ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
- if (ret != 1)
- goto fail_encrypt_init;
-
- ret = EVP_EncryptUpdate(ctx, out, &tmp_sz, in, in_sz);
- if (ret != 1)
- goto fail_encrypt;
-
- out_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(ctx);
+#ifdef HAVE_OPENSSL
+ return openssl_load_privkey_str(str, key);
+#else
+ (void) str;
- assert(out_sz >= in_sz);
+ return 0;
+#endif
+}
- head = shm_du_buff_head_alloc(sdb, IVSZ);
- if (head == NULL)
- goto fail_encrypt;
+int crypt_load_pubkey_str(const char * str,
+ void ** key)
+{
+ *key = NULL;
- if (shm_du_buff_tail_alloc(sdb, out_sz - in_sz) == NULL)
- goto fail_tail_alloc;
+#ifdef HAVE_OPENSSL
+ return openssl_load_pubkey_str(str, key);
+#else
+ (void) str;
- memcpy(head, iv, IVSZ);
- memcpy(in, out, out_sz);
+ return 0;
+#endif
+}
- free(out);
+int crypt_cmp_key(const void * key1,
+ const void * key2)
+{
+#ifdef HAVE_OPENSSL
+ return openssl_cmp_key(key1, key2);
+#else
+ (void) key1;
+ (void) key2;
return 0;
-
- fail_tail_alloc:
- shm_du_buff_head_release(sdb, IVSZ);
- fail_encrypt:
- EVP_CIPHER_CTX_cleanup(ctx);
- fail_encrypt_init:
- free(out);
- fail_iv:
- return -ECRYPT;
+#endif
}
-static int openssl_decrypt(void * ctx,
- uint8_t * key,
- struct shm_du_buff * sdb)
+void crypt_free_key(void * key)
{
- uint8_t * in;
- uint8_t * out;
- uint8_t iv[IVSZ];
- int ret;
- int out_sz;
- int in_sz;
- int tmp_sz;
+ if (key == NULL)
+ return;
- in_sz = shm_du_buff_len(sdb);
- if (in_sz < IVSZ)
- return -ECRYPT;
+#ifdef HAVE_OPENSSL
+ openssl_free_key(key);
+#endif
+}
- in = shm_du_buff_head_release(sdb, IVSZ);
+int crypt_load_crt_file(const char * path,
+ void ** crt)
+{
+ assert(crt != NULL);
- memcpy(iv, in, IVSZ);
+ *crt = NULL;
- in = shm_du_buff_head(sdb);
- in_sz = shm_du_buff_tail(sdb) - in;
+#ifdef HAVE_OPENSSL
+ return openssl_load_crt_file(path, crt);
+#else
+ (void) path;
- out = malloc(in_sz);
- if (out == NULL)
- goto fail_malloc;
+ return 0;
+#endif
+}
- EVP_CIPHER_CTX_reset(ctx);
+int crypt_load_crt_str(const char * str,
+ void ** crt)
+{
+ assert(crt != NULL);
- ret = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
- if (ret != 1)
- goto fail_decrypt_init;
+ *crt = NULL;
- ret = EVP_DecryptUpdate(ctx, out, &tmp_sz, in, in_sz);
- if (ret != 1)
- goto fail_decrypt;
+#ifdef HAVE_OPENSSL
+ return openssl_load_crt_str(str, crt);
+#else
+ (void) str;
- out_sz = tmp_sz;
+ return 0;
+#endif
+}
- ret = EVP_DecryptFinal_ex(ctx, out + tmp_sz, &tmp_sz);
- if (ret != 1)
- goto fail_decrypt;
+int crypt_load_crt_der(const buffer_t buf,
+ void ** crt)
+{
+ assert(crt != NULL);
+#ifdef HAVE_OPENSSL
+ return openssl_load_crt_der(buf, crt);
+#else
+ *crt = NULL;
- out_sz += tmp_sz;
+ (void) buf;
- assert(out_sz <= in_sz);
+ return 0;
+#endif
+}
- shm_du_buff_tail_release(sdb, in_sz - out_sz);
+int crypt_get_pubkey_crt(void * crt,
+ void ** pk)
+{
+ assert(crt != NULL);
+ assert(pk != NULL);
- memcpy(in, out, out_sz);
+#ifdef HAVE_OPENSSL
+ return openssl_get_pubkey_crt(crt, pk);
+#else
+ (void) crt;
- free(out);
+ clrbuf(*pk);
return 0;
+#endif
+}
- fail_decrypt:
- EVP_CIPHER_CTX_cleanup(ctx);
- fail_decrypt_init:
- free(out);
- fail_malloc:
- return -ECRYPT;
-
+void crypt_free_crt(void * crt)
+{
+ if (crt == NULL)
+ return;
+#ifdef HAVE_OPENSSL
+ openssl_free_crt(crt);
+#endif
}
-static int openssl_crypt_init(void ** ctx)
+int crypt_crt_str(const void * crt,
+ char * buf)
{
- *ctx = EVP_CIPHER_CTX_new();
- if (*ctx == NULL)
- return -ECRYPT;
+#ifdef HAVE_OPENSSL
+ return openssl_crt_str(crt, buf);
+#else
+ (void) crt;
+ (void) buf;
return 0;
+#endif
}
-static void openssl_crypt_fini(void * ctx)
+int crypt_crt_der(const void * crt,
+ buffer_t * buf)
{
- EVP_CIPHER_CTX_free(ctx);
-}
+ assert(crt != NULL);
+ assert(buf != NULL);
-#endif /* HAVE_OPENSSL */
-
-int crypt_dh_pkp_create(void ** pkp,
- uint8_t * pk)
-{
#ifdef HAVE_OPENSSL
- assert(pkp != NULL);
- *pkp = NULL;
- return openssl_ecdh_pkp_create(pkp, pk);
+ return openssl_crt_der(crt, buf);
#else
- (void) pkp;
- (void) pk;
+ (void) crt;
- *pkp = NULL;
+ clrbuf(*buf);
return 0;
#endif
}
-void crypt_dh_pkp_destroy(void * pkp)
+int crypt_check_crt_name(void * crt,
+ const char * name)
{
#ifdef HAVE_OPENSSL
- openssl_ecdh_pkp_destroy(pkp);
+ return openssl_check_crt_name(crt, name);
#else
- (void) pkp;
- return;
+ (void) crt;
+ (void) name;
+
+ return 0;
#endif
}
-int crypt_dh_derive(void * pkp,
- buffer_t pk,
- uint8_t * s)
+struct auth_ctx * auth_create_ctx(void)
{
-#ifdef HAVE_OPENSSL
- return openssl_ecdh_derive(pkp, pk, s);
-#else
- (void) pkp;
- (void) pk;
+ struct auth_ctx * ctx;
- memset(s, 0, SYMMKEYSZ);
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ goto fail_malloc;
- return -ECRYPT;
+ memset(ctx, 0, sizeof(*ctx));
+#ifdef HAVE_OPENSSL
+ ctx->store = openssl_auth_create_store();
+ if (ctx->store == NULL)
+ goto fail_store;
#endif
+ return ctx;
+#ifdef HAVE_OPENSSL
+ fail_store:
+ free(ctx);
+#endif
+ fail_malloc:
+ return NULL;
}
-int crypt_encrypt(struct crypt_info * info,
- struct shm_du_buff * sdb)
+void auth_destroy_ctx(struct auth_ctx * ctx)
{
- if (info->flags == 0)
- return 0;
+ if (ctx == NULL)
+ return;
+#ifdef HAVE_OPENSSL
+ openssl_auth_destroy_store(ctx->store);
+#endif
+ free(ctx);
+}
+
+int auth_add_crt_to_store(struct auth_ctx * ctx,
+ void * crt)
+{
+ assert(ctx != NULL);
+ assert(crt != NULL);
#ifdef HAVE_OPENSSL
- return openssl_encrypt(info->ctx, info->key, sdb);
+ return openssl_auth_add_crt_to_store(ctx->store, crt);
#else
- (void) sdb;
+ (void) ctx;
+ (void) crt;
return 0;
#endif
}
-int crypt_decrypt(struct crypt_info * info,
- struct shm_du_buff * sdb)
+int auth_verify_crt(struct auth_ctx * ctx,
+ void * crt)
{
- if (info->flags == 0)
- return 0;
-
#ifdef HAVE_OPENSSL
- return openssl_decrypt(info->ctx, info->key, sdb);
+ return openssl_verify_crt(ctx->store, crt);
#else
- (void) sdb;
+ (void) ctx;
+ (void) crt;
- return -ECRYPT;
+ return 0;
#endif
}
-int crypt_init(struct crypt_info * info)
+int auth_sign(void * pkp,
+ buffer_t msg,
+ buffer_t * sig)
{
#ifdef HAVE_OPENSSL
- return openssl_crypt_init(&info->ctx);
+ return openssl_sign(pkp, msg, sig);
#else
- info->ctx = NULL;
+ (void) pkp;
+ (void) msg;
+ (void) sig;
+
+ clrbuf(*sig);
+
return 0;
#endif
}
-void crypt_fini(struct crypt_info * info)
+int auth_verify_sig(void * pk,
+ buffer_t msg,
+ buffer_t sig)
{
#ifdef HAVE_OPENSSL
- openssl_crypt_fini(info->ctx);
+ return openssl_verify_sig(pk, msg, sig);
#else
- (void) info;
- assert(info->ctx == NULL);
+ (void) pk;
+ (void) msg;
+ (void) sig;
+
+ return 0;
#endif
}
diff --git a/src/lib/crypt/openssl.c b/src/lib/crypt/openssl.c
new file mode 100644
index 00000000..291a3418
--- /dev/null
+++ b/src/lib/crypt/openssl.c
@@ -0,0 +1,788 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * OpenSSL based cryptographic operations
+ * Elliptic curve Diffie-Hellman key exchange
+ * AES encryption
+ # Authentication
+ *
+ * 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/errno.h>
+#include <ouroboros/crypt.h>
+#include <ouroboros/hash.h>
+#include <ouroboros/random.h>
+#include <ouroboros/utils.h>
+
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/ec.h>
+#include <openssl/pem.h>
+#include <openssl/sha.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+
+#include <assert.h>
+
+/*
+ * Derive the common secret from
+ * - your public key pair (kp)
+ * - the remote public key (pub).
+ * Store it in a preallocated buffer (s).
+ */
+static int __openssl_ecdh_derive_secret(EVP_PKEY * kp,
+ EVP_PKEY * pub,
+ uint8_t * s)
+{
+ EVP_PKEY_CTX * ctx;
+ int ret;
+ uint8_t * secret;
+ size_t secret_len;
+
+ ctx = EVP_PKEY_CTX_new(kp, NULL);
+ if (ctx == NULL)
+ goto fail_new;
+
+ ret = EVP_PKEY_derive_init(ctx);
+ if (ret != 1)
+ goto fail_ctx;
+
+ ret = EVP_PKEY_derive_set_peer(ctx, pub);
+ if (ret != 1)
+ goto fail_ctx;
+
+ ret = EVP_PKEY_derive(ctx, NULL, &secret_len);
+ if (ret != 1)
+ goto fail_ctx;
+
+ if (secret_len < SYMMKEYSZ)
+ goto fail_ctx;
+
+ secret = OPENSSL_malloc(secret_len);
+ if (secret == NULL)
+ goto fail_ctx;
+
+ ret = EVP_PKEY_derive(ctx, secret, &secret_len);
+ if (ret != 1)
+ goto fail_derive;
+
+ /* Hash the secret for use as AES key. */
+ mem_hash(HASH_SHA3_256, s, secret, secret_len);
+
+ OPENSSL_free(secret);
+ EVP_PKEY_CTX_free(ctx);
+
+ return 0;
+ fail_derive:
+ OPENSSL_free(secret);
+ fail_ctx:
+ EVP_PKEY_CTX_free(ctx);
+ fail_new:
+ return -ECRYPT;
+}
+
+static int __openssl_ecdh_gen_key(void ** kp)
+{
+ EVP_PKEY_CTX * ctx = NULL;
+ EVP_PKEY_CTX * kctx = NULL;
+ EVP_PKEY * params = NULL;
+ int ret;
+
+ ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+ if (ctx == NULL)
+ goto fail_new_id;
+
+ ret = EVP_PKEY_paramgen_init(ctx);
+ if (ret != 1)
+ goto fail_paramgen;
+
+ ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1);
+ if (ret != 1)
+ goto fail_paramgen;
+
+ ret = EVP_PKEY_paramgen(ctx, &params);
+ if (ret != 1)
+ goto fail_paramgen;
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (kctx == NULL)
+ goto fail_keygen_init;
+
+ ret = EVP_PKEY_keygen_init(kctx);
+ if (ret != 1)
+ goto fail_keygen;
+
+ ret = EVP_PKEY_keygen(kctx, (EVP_PKEY **) kp);
+ if (ret != 1)
+ goto fail_keygen;
+
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+ EVP_PKEY_CTX_free(ctx);
+
+ return 0;
+ fail_keygen:
+ EVP_PKEY_CTX_free(kctx);
+ fail_keygen_init:
+ EVP_PKEY_free(params);
+ fail_paramgen:
+ EVP_PKEY_CTX_free(ctx);
+ fail_new_id:
+ return -ECRYPT;
+}
+
+ssize_t openssl_ecdh_pkp_create(void ** pkp,
+ uint8_t * pk)
+{
+ uint8_t * pos;
+ ssize_t len;
+
+ assert(pkp != NULL);
+ assert(*pkp == NULL);
+ assert(pk != NULL);
+
+ if (__openssl_ecdh_gen_key(pkp) < 0)
+ goto fail_key;
+
+ pos = pk; /* i2d_PUBKEY increments the pointer, don't use pk! */
+ len = i2d_PUBKEY(*pkp, &pos);
+ if (len < 0)
+ goto fail_pubkey;
+
+ return len;
+ fail_pubkey:
+ EVP_PKEY_free(*pkp);
+ fail_key:
+ return -ECRYPT;
+}
+
+void openssl_ecdh_pkp_destroy(void * pkp)
+{
+ EVP_PKEY_free((EVP_PKEY *) pkp);
+}
+
+int openssl_ecdh_derive(void * pkp,
+ buffer_t pk,
+ uint8_t * s)
+{
+ uint8_t * pos;
+ EVP_PKEY * pub;
+
+ pos = pk.data; /* d2i_PUBKEY increments pos, don't use key ptr! */
+ pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) pk.len);
+ if (pub == NULL)
+ goto fail_pubkey;
+
+ if (__openssl_ecdh_derive_secret(pkp, pub, s) < 0)
+ goto fail_key;
+
+ EVP_PKEY_free(pub);
+
+ return 0;
+ fail_pubkey:
+ EVP_PKEY_free(pub);
+ fail_key:
+ return -ECRYPT;
+}
+
+/*
+ * AES encryption calls. If FRCT is disabled, we should generate a
+ * 128-bit random IV and append it to the packet. If the flow is
+ * reliable, we could initialize the context once, and consider the
+ * stream a single encrypted message to avoid initializing the
+ * encryption context for each packet.
+ */
+
+int openssl_encrypt(void * ctx,
+ uint8_t * key,
+ buffer_t in,
+ buffer_t * out)
+{
+ uint8_t * ptr;
+ uint8_t * iv;
+ int in_sz;
+ int out_sz;
+ int tmp_sz;
+ int ret;
+
+ in_sz = (int) in.len;
+
+ out->data = malloc(in.len + EVP_MAX_BLOCK_LENGTH + IVSZ);
+ if (out->data == NULL)
+ goto fail_malloc;
+
+ iv = out->data;
+ ptr = out->data + IVSZ;
+
+ if (random_buffer(iv, IVSZ) < 0)
+ goto fail_iv;
+
+ EVP_CIPHER_CTX_reset(ctx);
+
+ ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
+ if (ret != 1)
+ goto fail_iv;
+
+ ret = EVP_EncryptUpdate(ctx, ptr, &tmp_sz, in.data, in_sz);
+ if (ret != 1)
+ goto fail_encrypt;
+
+ out_sz = tmp_sz;
+ ret = EVP_EncryptFinal_ex(ctx, ptr + tmp_sz, &tmp_sz);
+ if (ret != 1)
+ goto fail_encrypt;
+
+ out_sz += tmp_sz;
+
+ EVP_CIPHER_CTX_cleanup(ctx);
+
+ assert(out_sz >= in_sz);
+
+ out->len = (size_t) out_sz + IVSZ;
+
+ return 0;
+ fail_encrypt:
+ EVP_CIPHER_CTX_cleanup(ctx);
+ fail_iv:
+ free(out->data);
+ fail_malloc:
+ clrbuf(*out);
+ return -ECRYPT;
+}
+
+int openssl_decrypt(void * ctx,
+ uint8_t * key,
+ buffer_t in,
+ buffer_t * out)
+{
+ uint8_t * ptr;
+ uint8_t * iv;
+ uint8_t * input;
+ int ret;
+ int out_sz;
+ int in_sz;
+ int tmp_sz;
+
+ in_sz = (int) in.len - IVSZ;
+ if (in_sz < 0)
+ return -ECRYPT;
+
+ out->data = malloc(in_sz);
+ if (out->data == NULL)
+ goto fail_malloc;
+
+ iv = in.data;
+ ptr = out->data;
+ input = in.data + IVSZ;
+
+ EVP_CIPHER_CTX_reset(ctx);
+
+ ret = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
+ if (ret != 1)
+ goto fail_decrypt_init;
+
+ ret = EVP_DecryptUpdate(ctx, ptr, &tmp_sz, input, in_sz);
+ if (ret != 1)
+ goto fail_decrypt;
+
+ out_sz = tmp_sz;
+ ret = EVP_DecryptFinal_ex(ctx, ptr + tmp_sz, &tmp_sz);
+ if (ret != 1)
+ goto fail_decrypt;
+
+ out_sz += tmp_sz;
+
+ assert(out_sz <= in_sz);
+
+ out->len = (size_t) out_sz;
+
+ return 0;
+ fail_decrypt:
+ EVP_CIPHER_CTX_cleanup(ctx);
+ fail_decrypt_init:
+ free(out->data);
+ fail_malloc:
+ clrbuf(*out);
+ return -ECRYPT;
+}
+
+void * openssl_crypt_create_ctx(void)
+{
+ return (void *) EVP_CIPHER_CTX_new();
+}
+
+void openssl_crypt_destroy_ctx(void * ctx)
+{
+ EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *) ctx);
+}
+
+/* AUTHENTICATION */
+
+int openssl_load_crt_file(const char * path,
+ void ** crt)
+{
+ FILE * fp;
+ X509 * xcrt;
+
+ fp = fopen(path, "r");
+ if (fp == NULL)
+ goto fail_file;
+
+ xcrt = PEM_read_X509(fp, NULL, NULL, NULL);
+ if (xcrt == NULL)
+ goto fail_crt;
+
+ fclose(fp);
+
+ *crt = (void *) xcrt;
+
+ return 0;
+ fail_crt:
+ fclose(fp);
+ fail_file:
+ *crt = NULL;
+ return -1;
+}
+
+int openssl_load_crt_str(const char * str,
+ void ** crt)
+{
+ BIO * bio;
+ X509 * xcrt;
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ goto fail_bio;
+
+ if (BIO_write(bio, str, strlen(str)) < 0)
+ goto fail_crt;
+
+ xcrt = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (xcrt == NULL)
+ goto fail_crt;
+
+ BIO_free(bio);
+
+ *crt = (void *) xcrt;
+
+ return 0;
+ fail_crt:
+ BIO_free(bio);
+ fail_bio:
+ *crt = NULL;
+ return -1;
+}
+
+int openssl_load_crt_der(buffer_t buf,
+ void ** crt)
+{
+ const uint8_t * p;
+ X509 * xcrt;
+
+ assert(crt != NULL);
+
+ p = buf.data;
+
+ xcrt = d2i_X509(NULL, &p, buf.len);
+ if (xcrt == NULL)
+ goto fail_crt;
+
+ *crt = (void *) xcrt;
+
+ return 0;
+ fail_crt:
+ *crt = NULL;
+ return -1;
+}
+
+int openssl_get_pubkey_crt(void * crt,
+ void ** key)
+{
+ EVP_PKEY * pk;
+ X509 * xcrt;
+
+ assert(crt != NULL);
+ assert(key != NULL);
+
+ xcrt = (X509 *) crt;
+
+ pk = X509_get_pubkey(xcrt);
+ if (pk == NULL)
+ goto fail_key;
+
+ *key = (void *) pk;
+
+ return 0;
+ fail_key:
+ return -1;
+}
+
+void openssl_free_crt(void * crt)
+{
+ X509_free((X509 *) crt);
+}
+
+int openssl_load_privkey_file(const char * path,
+ void ** key)
+{
+ FILE * fp;
+ EVP_PKEY * pkey;
+
+ fp = fopen(path, "r");
+ if (fp == NULL)
+ goto fail_file;
+
+ pkey = PEM_read_PrivateKey(fp, NULL, NULL, "");
+ if (pkey == NULL)
+ goto fail_key;
+
+ fclose(fp);
+
+ *key = (void *) pkey;
+
+ return 0;
+ fail_key:
+ fclose(fp);
+ fail_file:
+ *key = NULL;
+ return -1;
+}
+
+int openssl_load_privkey_str(const char * str,
+ void ** key)
+{
+ BIO * bio;
+ EVP_PKEY * pkey;
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ goto fail_bio;
+
+ if (BIO_write(bio, str, strlen(str)) < 0)
+ goto fail_key;
+
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+ if (pkey == NULL)
+ goto fail_key;
+
+ BIO_free(bio);
+
+ *key = (void *) pkey;
+
+ return 0;
+ fail_key:
+ BIO_free(bio);
+ fail_bio:
+ *key = NULL;
+ return -1;
+}
+
+int openssl_load_pubkey_file(const char * path,
+ void ** key)
+{
+ FILE * fp;
+ EVP_PKEY * pkey;
+
+ fp = fopen(path, "r");
+ if (fp == NULL)
+ goto fail_file;
+
+ pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
+ if (pkey == NULL)
+ goto fail_key;
+
+ fclose(fp);
+
+ *key = (void *) pkey;
+
+ return 0;
+ fail_key:
+ fclose(fp);
+ fail_file:
+ *key = NULL;
+ return -1;
+}
+
+int openssl_load_pubkey_str(const char * str,
+ void ** key)
+{
+ BIO * bio;
+ EVP_PKEY * pkey;
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ goto fail_bio;
+
+ if (BIO_write(bio, str, strlen(str)) < 0)
+ goto fail_key;
+
+ pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+ if (pkey == NULL)
+ goto fail_key;
+
+ BIO_free(bio);
+
+ *key = (void *) pkey;
+
+ return 0;
+ fail_key:
+ BIO_free(bio);
+ fail_bio:
+ *key = NULL;
+ return -1;
+}
+
+int openssl_cmp_key(const void * key1,
+ const void * key2)
+{
+ EVP_PKEY * pkey1;
+ EVP_PKEY * pkey2;
+
+ assert(key1 != NULL);
+ assert(key2 != NULL);
+
+ pkey1 = (EVP_PKEY *) key1;
+ pkey2 = (EVP_PKEY *) key2;
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ return EVP_PKEY_eq(pkey1, pkey2) == 1 ? 0 : -1;
+#else
+ return EVP_PKEY_cmp(pkey1, pkey2) == 1 ? 0 : -1;
+#endif
+}
+
+void openssl_free_key(void * key)
+{
+ EVP_PKEY_free((EVP_PKEY *) key);
+}
+
+int openssl_check_crt_name(void * crt,
+ const char * name)
+{
+ char * subj;
+ char * cn;
+ X509 * xcrt;
+
+ xcrt = (X509 *) crt;
+
+ subj = X509_NAME_oneline(X509_get_subject_name(xcrt), NULL, 0);
+ if (subj == NULL)
+ goto fail_subj;
+
+ cn = strstr(subj, "CN=");
+ if (cn == NULL)
+ goto fail_cn;
+
+ if (strcmp(cn + 3, name) != 0)
+ goto fail_cn;
+
+ free(subj);
+
+ return 0;
+ fail_cn:
+ free(subj);
+ fail_subj:
+ return -1;
+}
+
+int openssl_crt_str(const void * crt,
+ char * str)
+{
+ BIO * bio;
+ X509 * xcrt;
+ char * p;
+
+ xcrt = (X509 *) crt;
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ goto fail_bio;
+
+ X509_print(bio, xcrt);
+
+ BIO_get_mem_data(bio, &p);
+ if (p == NULL)
+ goto fail_p;
+
+ sprintf(str, "%s", p);
+
+ BIO_free(bio);
+
+ return 0;
+ fail_p:
+ BIO_free(bio);
+ fail_bio:
+ return -1;
+}
+
+int openssl_crt_der(const void * crt,
+ buffer_t * buf)
+{
+ int len;
+
+ assert(crt != NULL);
+ assert(buf != NULL);
+
+ len = i2d_X509((X509 *) crt, &buf->data);
+ if (len < 0)
+ goto fail_der;
+
+ buf->len = (size_t) len;
+
+ return 0;
+
+ fail_der:
+ clrbuf(*buf);
+ return -1;
+}
+
+
+void * openssl_auth_create_store(void)
+{
+ return X509_STORE_new();
+}
+
+void openssl_auth_destroy_store(void * ctx)
+{
+ X509_STORE_free((X509_STORE *) ctx);
+}
+
+int openssl_auth_add_crt_to_store(void * store,
+ void * crt)
+{
+ int ret;
+
+ ret = X509_STORE_add_cert((X509_STORE *) store, (X509 *) crt);
+
+ return ret == 1 ? 0 : -1;
+}
+
+int openssl_verify_crt(void * store,
+ void * crt)
+{
+ X509_STORE_CTX * ctx;
+ X509_STORE * _store;
+ X509* _crt;
+ int ret;
+
+ _store = (X509_STORE *) store;
+ _crt = (X509 *) crt;
+
+ ctx = X509_STORE_CTX_new();
+ if (ctx == NULL)
+ goto fail_store_ctx;
+
+ ret = X509_STORE_CTX_init(ctx, _store, _crt, NULL);
+ if (ret != 1)
+ goto fail_ca;
+
+ ret = X509_verify_cert(ctx);
+ if (ret != 1)
+ goto fail_ca;
+
+ X509_STORE_CTX_free(ctx);
+
+ return 0;
+ fail_ca:
+ X509_STORE_CTX_free(ctx);
+ fail_store_ctx:
+ return -1;
+}
+
+int openssl_sign(void * pkp,
+ buffer_t msg,
+ buffer_t * sig)
+{
+ EVP_PKEY * pkey;
+ EVP_MD_CTX * mdctx;
+ size_t required;
+
+ assert(pkp != NULL);
+ assert(sig != NULL);
+
+ pkey = (EVP_PKEY *) pkp;
+
+ mdctx = EVP_MD_CTX_new();
+ if (!mdctx)
+ goto fail_ctx;
+
+ if (EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1)
+ goto fail_digest;
+
+ if (EVP_DigestSignUpdate(mdctx, msg.data, msg.len) != 1)
+ goto fail_digest;
+
+ if (EVP_DigestSignFinal(mdctx, NULL, &required) != 1)
+ goto fail_digest;
+
+ sig->data = malloc(required);
+ if (sig->data == NULL)
+ goto fail_digest;
+
+ if (EVP_DigestSignFinal(mdctx, sig->data, &required) != 1)
+ goto fail_sign;
+
+ sig->len = required;
+
+ EVP_MD_CTX_free(mdctx);
+
+ return 0;
+ fail_sign:
+ freebuf(*sig);
+ fail_digest:
+ EVP_MD_CTX_free(mdctx);
+ fail_ctx:
+ clrbuf(*sig);
+ return -1;
+}
+
+int openssl_verify_sig(void * pk,
+ buffer_t msg,
+ buffer_t sig)
+{
+ EVP_PKEY * pkey;
+ EVP_MD_CTX * mdctx;
+ int ret;
+
+ assert(pk != NULL);
+
+ pkey = (EVP_PKEY *) pk;
+
+ mdctx = EVP_MD_CTX_new();
+ if (!mdctx)
+ goto fail_ctx;
+
+ if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1)
+ goto fail_digest;
+
+ if (EVP_DigestVerifyUpdate(mdctx, msg.data, msg.len) != 1)
+ goto fail_digest;
+
+ ret = EVP_DigestVerifyFinal(mdctx, sig.data, sig.len);
+ if (ret != 1)
+ goto fail_digest;
+
+ EVP_MD_CTX_free(mdctx);
+
+ return 0;
+ fail_digest:
+ EVP_MD_CTX_free(mdctx);
+ fail_ctx:
+ clrbuf(sig);
+ return -1;
+}
diff --git a/src/lib/crypt/openssl.h b/src/lib/crypt/openssl.h
new file mode 100644
index 00000000..d4ee73b9
--- /dev/null
+++ b/src/lib/crypt/openssl.h
@@ -0,0 +1,112 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * OpenSSL based cryptographic operations
+ * Elliptic curve Diffie-Hellman key exchange
+ * AES encryption
+ # Authentication
+ *
+ * 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_OPENSSL_H
+#define OUROBOROS_LIB_CRYPT_OPENSSL_H
+
+ssize_t openssl_ecdh_pkp_create(void ** pkp,
+ uint8_t * pk);
+
+void openssl_ecdh_pkp_destroy(void * pkp);
+
+int openssl_ecdh_derive(void * pkp,
+ buffer_t pk,
+ uint8_t * s);
+
+int openssl_encrypt(void * ctx,
+ uint8_t * key,
+ buffer_t in,
+ buffer_t * out);
+
+int openssl_decrypt(void * ctx,
+ uint8_t * key,
+ buffer_t in,
+ buffer_t * out);
+
+void * openssl_crypt_create_ctx(void);
+
+void openssl_crypt_destroy_ctx(void * ctx);
+
+/* AUTHENTICATION */
+
+int openssl_load_crt_file(const char * path,
+ void ** crt);
+
+int openssl_load_crt_str(const char * str,
+ void ** crt);
+
+int openssl_load_crt_der(buffer_t buf,
+ void ** crt);
+
+int openssl_get_pubkey_crt(void * crt,
+ void ** pk);
+
+void openssl_free_crt(void * crt);
+
+int openssl_load_privkey_file(const char * path,
+ void ** key);
+
+int openssl_load_privkey_str(const char * str,
+ void ** key);
+
+int openssl_load_pubkey_file(const char * path,
+ void ** key);
+
+int openssl_load_pubkey_str(const char * str,
+ void ** key);
+
+int openssl_cmp_key(const void * key1,
+ const void * key2);
+
+void openssl_free_key(void * key);
+
+int openssl_check_crt_name(void * crt,
+ const char * name);
+
+int openssl_crt_str(const void * crt,
+ char * str);
+
+int openssl_crt_der(const void * crt,
+ buffer_t * buf);
+
+void * openssl_auth_create_store(void);
+
+void openssl_auth_destroy_store(void * store);
+
+int openssl_auth_add_crt_to_store(void * store,
+ void * crt);
+
+int openssl_verify_crt(void * store,
+ void * crt);
+
+int openssl_sign(void * pkp,
+ buffer_t msg,
+ buffer_t * sig);
+
+int openssl_verify_sig(void * pk,
+ buffer_t msg,
+ buffer_t sig);
+
+#endif /* OUROBOROS_LIB_CRYPT_OPENSSL_H */
diff --git a/src/lib/dev.c b/src/lib/dev.c
index 92310b9e..c0cd11a3 100644
--- a/src/lib/dev.c
+++ b/src/lib/dev.c
@@ -99,7 +99,7 @@ struct flow {
uint16_t oflags;
ssize_t part_idx;
- struct crypt_info crypt;
+ struct crypt_ctx * crypt;
struct timespec snd_act;
struct timespec rcv_act;
@@ -227,7 +227,7 @@ static enum flow_state flow_wait_assign(int flow_id)
static int proc_announce(const char * prog)
{
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
int err;
if (proc_announce__irm_req_ser(&msg, prog) < 0)
@@ -244,7 +244,7 @@ static int proc_announce(const char * prog)
static void proc_exit(void)
{
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
if (proc_exit__irm_req_ser(&msg) < 0)
return;
@@ -252,6 +252,69 @@ static void proc_exit(void)
send_recv_msg(&msg);
}
+static int sdb_encrypt(struct flow * flow,
+ struct shm_du_buff * sdb)
+{
+ buffer_t in;
+ buffer_t out;
+ uint8_t * head;
+ uint8_t * tail;
+
+ if (flow->crypt == NULL)
+ return 0; /* No encryption */
+
+ in.data = shm_du_buff_head(sdb);
+ in.len = shm_du_buff_len(sdb);
+
+ if (crypt_encrypt(flow->crypt, in, &out) < 0)
+ goto fail_encrypt;
+
+ head = shm_du_buff_head_alloc(sdb, IVSZ);
+ if (head == NULL)
+ goto fail_alloc;
+
+ tail = shm_du_buff_tail_alloc(sdb, (out.len - in.len) - IVSZ);
+ if (tail == NULL)
+ goto fail_alloc;
+
+ memcpy(head, out.data, out.len);
+
+ freebuf(out);
+
+ return 0;
+ fail_alloc:
+ freebuf(out);
+ fail_encrypt:
+ return -ECRYPT;
+}
+
+static int sdb_decrypt(struct flow * flow,
+ struct shm_du_buff * sdb)
+{
+ buffer_t in;
+ buffer_t out;
+ uint8_t * head;
+
+ if (flow->crypt == NULL)
+ return 0; /* No decryption */
+
+ in.data = shm_du_buff_head(sdb);
+ in.len = shm_du_buff_len(sdb);
+
+ if (crypt_decrypt(flow->crypt, in, &out) < 0)
+ return -ENOMEM;
+
+
+ head = shm_du_buff_head_release(sdb, IVSZ) + IVSZ;
+ shm_du_buff_tail_release(sdb, (in.len - out.len) - IVSZ);
+
+ memcpy(head, out.data, out.len);
+
+ freebuf(out);
+
+ return 0;
+}
+
#include "frct.c"
void * flow_tx(void * o)
@@ -309,18 +372,18 @@ static void _flow_keepalive(struct flow * flow)
timeo = flow->info.qs.timeout;
acl = shm_rbuff_get_acl(flow->rx_rb);
- if (timeo == 0 || acl & (ACL_FLOWPEER | ACL_FLOWDOWN))
+ 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) {
+ if (ts_diff_ns(&now, &r_act) > (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 (ts_diff_ns(&s_act, &now) > (int64_t) timeo * (MILLION >> 2)) {
+ if (ts_diff_ns(&now, &s_act) > (int64_t) timeo * (MILLION >> 2)) {
pthread_rwlock_unlock(&ai.lock);
flow_send_keepalive(flow, now);
@@ -423,7 +486,7 @@ static void __flow_fini(int fd)
shm_flow_set_close(ai.flows[fd].set);
}
- crypt_fini(&ai.flows[fd].crypt);
+ crypt_destroy_ctx(ai.flows[fd].crypt);
list_del(&ai.flows[fd].next);
@@ -477,16 +540,14 @@ static int flow_init(struct flow_info * info,
flow->part_idx = NO_PART;
flow->snd_act = now;
flow->rcv_act = now;
+ flow->crypt = NULL;
- flow->crypt.flags = info->qs.cypher_s; /* TODO: move cypher_s */
-
- memset(flow->crypt.key, 0, 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;
+ if (sk!= NULL && sk->data != NULL) {
+ assert(sk->len == SYMMKEYSZ);
+ flow->crypt = crypt_create_ctx(sk->data);
+ if (flow->crypt == NULL)
+ goto fail_crypt;
+ }
assert(flow->frcti == NULL);
@@ -519,7 +580,7 @@ static int flow_init(struct flow_info * info,
fail_flow_set_add:
frcti_destroy(flow->frcti);
fail_frcti:
- crypt_fini(&flow->crypt);
+ crypt_destroy_ctx(flow->crypt);
fail_crypt:
shm_flow_set_close(flow->set);
fail_set:
@@ -764,7 +825,7 @@ int flow_accept(qosspec_t * qs,
{
struct flow_info flow;
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
buffer_t sk;
int fd;
int err;
@@ -805,7 +866,7 @@ int flow_alloc(const char * dst,
{
struct flow_info flow;
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
buffer_t sk; /* symmetric key */
int fd;
int err;
@@ -824,8 +885,10 @@ int flow_alloc(const char * dst,
return -ENOMEM;
err = send_recv_msg(&msg);
- if (err < 0)
+ if (err < 0) {
+ printf("send_recv_msg error %d\n", err);
return err;
+ }
err = flow__irm_result_des(&msg, &flow, &sk);
if (err < 0)
@@ -847,7 +910,7 @@ int flow_join(const char * dst,
{
struct flow_info flow;
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
int fd;
int err;
@@ -855,9 +918,6 @@ int flow_join(const char * dst,
if (qs != NULL)
qs->ber = 1;
#endif
- if (qs != NULL && qs->cypher_s > 0)
- return -ENOTSUP; /* TODO: Encrypted broadcast */
-
memset(&flow, 0, sizeof(flow));
flow.n_pid = getpid();
@@ -888,7 +948,7 @@ 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};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
struct timespec tic = TIMESPEC_INIT_NS(TICTIME);
struct timespec timeo = TIMESPEC_INIT_S(0);
struct flow * flow;
@@ -962,7 +1022,7 @@ int ipcp_flow_dealloc(int fd)
{
struct flow_info info;
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
struct flow * flow;
int err;
@@ -1200,7 +1260,7 @@ static int flow_tx_sdb(struct flow * flow,
if (frcti_snd(flow->frcti, sdb) < 0)
goto enomem;
- if (crypt_encrypt(&flow->crypt, sdb) < 0)
+ if (sdb_encrypt(flow, sdb) < 0)
goto enomem;
if (flow->info.qs.ber == 0 && add_crc(sdb) != 0)
@@ -1302,7 +1362,7 @@ static bool invalid_pkt(struct flow * flow,
if (flow->info.qs.ber == 0 && chk_crc(sdb) != 0)
return true;
- if (crypt_decrypt(&flow->crypt, sdb) < 0)
+ if (sdb_decrypt(flow, sdb) < 0)
return true;
return false;
@@ -1330,6 +1390,7 @@ static ssize_t flow_rx_sdb(struct flow * flow,
pthread_rwlock_unlock(&ai.lock);
*sdb = shm_rdrbuff_get(ai.rdrb, idx);
+
if (invalid_pkt(flow, *sdb)) {
shm_rdrbuff_remove(ai.rdrb, idx);
return -EAGAIN;
@@ -1767,11 +1828,12 @@ int np1_flow_dealloc(int flow_id,
return fd;
}
-int np1_flow_resp(int flow_id)
+int np1_flow_resp(int flow_id,
+ int resp)
{
int fd;
- if (flow_wait_assign(flow_id) != FLOW_ALLOCATED)
+ if (resp == 0 && flow_wait_assign(flow_id) != FLOW_ALLOCATED)
return -1;
pthread_rwlock_rdlock(&ai.lock);
@@ -1786,7 +1848,7 @@ int np1_flow_resp(int flow_id)
int ipcp_create_r(const struct ipcp_info * info)
{
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
int err;
if (ipcp_create_r__irm_req_ser(&msg,info) < 0)
@@ -1806,7 +1868,7 @@ int ipcp_flow_req_arr(const buffer_t * dst,
{
struct flow_info flow;
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
int err;
memset(&flow, 0, sizeof(flow));
@@ -1832,6 +1894,7 @@ int ipcp_flow_req_arr(const buffer_t * dst,
flow.n_1_pid = flow.n_pid;
flow.n_pid = getpid();
flow.mpl = 0;
+ flow.qs = qos_np1;
return flow_init(&flow, NULL);
}
@@ -1843,7 +1906,7 @@ int ipcp_flow_alloc_reply(int fd,
{
struct flow_info flow;
uint8_t buf[SOCK_BUF_SIZE];
- buffer_t msg = {buf, SOCK_BUF_SIZE};
+ buffer_t msg = {SOCK_BUF_SIZE, buf};
int err;
assert(fd >= 0 && fd < SYS_MAX_FLOWS);
@@ -1943,7 +2006,7 @@ int np1_flow_read(int fd,
pthread_rwlock_rdlock(&ai.lock);
- idx = shm_rbuff_read(flow->rx_rb);;
+ idx = shm_rbuff_read(flow->rx_rb);
if (idx < 0) {
pthread_rwlock_unlock(&ai.lock);
return idx;
diff --git a/src/lib/frct.c b/src/lib/frct.c
index c6fef35c..08c5ea80 100644
--- a/src/lib/frct.c
+++ b/src/lib/frct.c
@@ -137,11 +137,11 @@ static int frct_rib_read(const char * path,
"Retransmit timeout RTO (ns): %20ld\n"
"Sender left window edge: %20u\n"
"Sender right window edge: %20u\n"
- "Sender inactive (ns): %20ld\n"
+ "Sender inactive (ns): %20lld\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 inactive (ns): %20lld\n"
"Receiver last ack: %20u\n"
"Number of pkt retransmissions: %20zu\n"
"Number of rtt probes: %20zu\n"
@@ -159,11 +159,11 @@ static int frct_rib_read(const char * path,
frcti->rto,
frcti->snd_cr.lwe,
frcti->snd_cr.rwe,
- ts_diff_ns(&frcti->snd_cr.act, &now),
+ ts_diff_ns(&now, &frcti->snd_cr.act),
frcti->snd_cr.seqno,
frcti->rcv_cr.lwe,
frcti->rcv_cr.rwe,
- ts_diff_ns(&frcti->rcv_cr.act, &now),
+ ts_diff_ns(&now, &frcti->rcv_cr.act),
frcti->rcv_cr.seqno,
frcti->n_rtx,
frcti->n_prb,
@@ -261,7 +261,7 @@ static void __send_frct_pkt(int fd,
f = &ai.flows[fd];
- if (crypt_encrypt(&f->crypt, sdb) < 0)
+ if (sdb_encrypt(f, sdb) < 0)
goto fail;
#ifdef RXM_BLOCKING
@@ -303,13 +303,13 @@ static void send_frct_pkt(struct frcti * frcti)
ackno = frcti->rcv_cr.lwe;
rwe = frcti->rcv_cr.rwe;
- diff = ts_diff_ns(&frcti->rcv_cr.act, &now);
+ diff = ts_diff_ns(&now, &frcti->rcv_cr.act);
if (diff > frcti->a) {
pthread_rwlock_unlock(&frcti->lock);
return;
}
- diff = ts_diff_ns(&frcti->snd_cr.act, &now);
+ diff = ts_diff_ns(&now, &frcti->snd_cr.act);
if (diff < TICTIME) {
pthread_rwlock_unlock(&frcti->lock);
return;
@@ -339,7 +339,7 @@ static struct frcti * frcti_create(int fd,
#ifdef PROC_FLOW_STATS
char frctstr[FRCT_NAME_STRLEN + 1];
#endif
- mpl *= BILLION;
+ mpl *= MILLION;
a *= BILLION;
r *= BILLION;
@@ -517,14 +517,14 @@ static bool __frcti_is_window_open(struct frcti * frcti)
frcti->t_rdvs = now;
} else {
time_t diff;
- diff = ts_diff_ns(&frcti->t_wnd, &now);
+ diff = ts_diff_ns(&now, &frcti->t_wnd);
if (diff > MAX_RDV) {
pthread_mutex_unlock(&frcti->mtx);
pthread_rwlock_unlock(&frcti->lock);
return false;
}
- diff = ts_diff_ns(&frcti->t_rdvs, &now);
+ diff = ts_diff_ns(&now, &frcti->t_rdvs);
if (diff > frcti->rdv) {
frcti->t_rdvs = now;
__send_rdv(frcti->fd);
@@ -580,13 +580,13 @@ static int __frcti_window_wait(struct frcti * frcti,
clock_gettime(PTHREAD_COND_CLOCK, &now);
- diff = ts_diff_ns(&frcti->t_wnd, &now);
+ diff = ts_diff_ns(&now, &frcti->t_wnd);
if (diff > MAX_RDV) {
pthread_mutex_unlock(&frcti->mtx);
return -ECONNRESET; /* write fails! */
}
- diff = ts_diff_ns(&frcti->t_rdvs, &now);
+ diff = ts_diff_ns(&now, &frcti->t_rdvs);
if (diff > frcti->rdv) {
frcti->t_rdvs = now;
__send_rdv(frcti->fd);
@@ -855,7 +855,7 @@ static void __frcti_rcv(struct frcti * frcti,
if (!(pci->flags & FRCT_DATA))
frcti->n_dak++;
#endif
- rtt_estimator(frcti, ts_diff_ns(&frcti->t_probe, &now));
+ rtt_estimator(frcti, ts_diff_ns(&now, &frcti->t_probe));
frcti->probe = false;
}
}
diff --git a/src/lib/irm.c b/src/lib/irm.c
index d25101f3..8333d0d3 100644
--- a/src/lib/irm.c
+++ b/src/lib/irm.c
@@ -523,32 +523,23 @@ int irm_unbind_process(pid_t pid,
return ret;
}
-int irm_create_name(const char * name,
- enum pol_balance pol)
+int irm_create_name(struct name_info * info)
{
irm_msg_t msg = IRM_MSG__INIT;
- name_info_msg_t ni_msg = NAME_INFO_MSG__INIT;
irm_msg_t * recv_msg;
int ret;
- if (name == NULL)
+ if (info == NULL)
return -EINVAL;
- msg.code = IRM_MSG_CODE__IRM_CREATE_NAME;
- ni_msg.name = (char *) name;
- ni_msg.pol_lb = pol;
- msg.n_names = 1;
-
- msg.names = malloc(sizeof(*msg.names));
- if (msg.names == NULL) {
- return -ENOMEM;
- }
-
- msg.names[0] = &ni_msg;
+ msg.code = IRM_MSG_CODE__IRM_CREATE_NAME;
+ msg.name_info = name_info_s_to_msg(info);
+ if (msg.name_info == NULL)
+ goto fail_info_msg;
recv_msg = send_recv_irm_msg(&msg);
- free(msg.names);
+ name_info_msg__free_unpacked(msg.name_info, NULL);
if (recv_msg == NULL)
return -EIRMD;
@@ -562,6 +553,9 @@ int irm_create_name(const char * name,
irm_msg__free_unpacked(recv_msg, NULL);
return ret;
+
+ fail_info_msg:
+ return -ENOMEM;
}
int irm_destroy_name(const char * name)
diff --git a/src/lib/notifier.c b/src/lib/notifier.c
index 45745b9a..4fccd371 100644
--- a/src/lib/notifier.c
+++ b/src/lib/notifier.c
@@ -95,18 +95,14 @@ int notifier_reg(notifier_fn_t callback,
pthread_rwlock_wrlock(&notifier.lock);
list_for_each(p, &notifier.listeners) {
- struct listener * l = list_entry(p, struct listener, next);
- if (l->callback == callback) {
- pthread_rwlock_unlock(&notifier.lock);
- return -EPERM;
- }
+ l = list_entry(p, struct listener, next);
+ if (l->callback == callback)
+ goto fail;
}
l = malloc(sizeof(*l));
- if (l == NULL) {
- pthread_rwlock_unlock(&notifier.lock);
- return -ENOMEM;
- }
+ if (l == NULL)
+ goto fail;
l->callback = callback;
l->obj = obj;
@@ -116,6 +112,10 @@ int notifier_reg(notifier_fn_t callback,
pthread_rwlock_unlock(&notifier.lock);
return 0;
+ fail:
+ pthread_rwlock_unlock(&notifier.lock);
+ return -1;
+
}
void notifier_unreg(notifier_fn_t callback)
diff --git a/src/lib/pb/enroll.proto b/src/lib/pb/enroll.proto
index 7fe612a8..60e964c6 100644
--- a/src/lib/pb/enroll.proto
+++ b/src/lib/pb/enroll.proto
@@ -24,7 +24,6 @@ syntax = "proto2";
import "ipcp_config.proto";
message enroll_req_msg {
- /* TODO authentication */
required bytes id = 1;
}
diff --git a/src/lib/pb/ipcp_config.proto b/src/lib/pb/ipcp_config.proto
index 28528b0c..1308c6d1 100644
--- a/src/lib/pb/ipcp_config.proto
+++ b/src/lib/pb/ipcp_config.proto
@@ -24,17 +24,45 @@ syntax = "proto2";
import "model.proto";
+
+message ls_config_msg {
+ required uint32 pol = 1;
+ required uint32 t_recalc = 2;
+ required uint32 t_update = 3;
+ required uint32 t_timeo = 4;
+}
+
+message routing_config_msg {
+ required uint32 pol = 1;
+ optional ls_config_msg ls = 2;
+}
+
message dt_config_msg {
- required uint32 addr_size = 1;
- required uint32 eid_size = 2;
- required uint32 max_ttl = 3;
- required uint32 routing_type = 4;
+ required uint32 addr_size = 1;
+ required uint32 eid_size = 2;
+ required uint32 max_ttl = 3;
+ required routing_config_msg routing = 4;
+}
+
+message dir_dht_config_msg {
+ required uint32 alpha = 1;
+ required uint32 k = 2;
+ required uint32 t_expire = 3;
+ required uint32 t_refresh = 4;
+ required uint32 t_replicate = 5;
+ required uint64 peer = 6;
+}
+
+message dir_config_msg {
+ required uint32 pol = 1;
+ optional dir_dht_config_msg dht = 2;
}
message uni_config_msg {
required dt_config_msg dt = 1;
- required uint32 addr_auth_type = 2;
- required uint32 cong_avoid = 3;
+ required dir_config_msg dir = 2;
+ required uint32 addr_auth_type = 3;
+ required uint32 cong_avoid = 4;
}
message eth_config_msg {
@@ -42,16 +70,24 @@ message eth_config_msg {
required uint32 ethertype = 2;
}
-message udp_config_msg {
+message udp4_config_msg {
required uint32 ip_addr = 1;
required uint32 port = 2;
required uint32 dns_addr = 3; /* set to 0 if unused */
}
+message udp6_config_msg {
+ required bytes ip_addr = 1;
+ required uint32 port = 2;
+ required bytes dns_addr = 3; /* set to NULL 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;
+ optional udp4_config_msg udp4 = 4;
+ optional udp6_config_msg udp6 = 5;
+ optional eth_config_msg eth = 6;
}
diff --git a/src/lib/pb/irm.proto b/src/lib/pb/irm.proto
index da3bd982..75f5f350 100644
--- a/src/lib/pb/irm.proto
+++ b/src/lib/pb/irm.proto
@@ -75,18 +75,19 @@ message irm_msg {
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 name_info_msg name_info = 7;
+ optional string layer = 8;
+ repeated string exec = 9;
+ optional sint32 response = 10;
+ optional string dst = 11;
+ optional bytes hash = 12;
+ optional sint32 flow_id = 13;
+ optional qosspec_msg qosspec = 14;
+ optional ipcp_config_msg conf = 15;
+ optional uint32 opts = 16;
+ repeated ipcp_list_msg ipcps = 17;
+ repeated name_info_msg names = 18;
+ optional timespec_msg timeo = 19;
optional sint32 mpl = 20;
optional string comp = 21;
optional bytes pk = 22; /* piggyback */
diff --git a/src/lib/pb/model.proto b/src/lib/pb/model.proto
index f1e401f9..7b06e434 100644
--- a/src/lib/pb/model.proto
+++ b/src/lib/pb/model.proto
@@ -30,8 +30,7 @@ message qosspec_msg {
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. */
+ required uint32 timeout = 8; /* Timeout in ms. */
}
message flow_info_msg {
@@ -44,8 +43,12 @@ message flow_info_msg {
}
message name_info_msg {
- required string name = 1;
- required uint32 pol_lb = 2;
+ required string name = 1;
+ required uint32 pol_lb = 2;
+ required string skey = 3;
+ required string scrt = 4;
+ required string ckey = 5;
+ required string ccrt = 6;
}
message layer_info_msg {
diff --git a/src/lib/protobuf.c b/src/lib/protobuf.c
index b586168c..6df4e810 100644
--- a/src/lib/protobuf.c
+++ b/src/lib/protobuf.c
@@ -106,6 +106,66 @@ struct flow_info flow_info_msg_to_s(const flow_info_msg_t * msg)
return s;
}
+name_info_msg_t * name_info_s_to_msg(const struct name_info * info)
+{
+ name_info_msg_t * msg;
+
+ assert(info != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ name_info_msg__init(msg);
+
+ msg->name = strdup(info->name);
+ if (msg->name == NULL)
+ goto fail_msg;
+
+ msg->skey = strdup(info->s.key);
+ if (msg->skey == NULL)
+ goto fail_msg;
+
+ msg->scrt = strdup(info->s.crt);
+ if (msg->scrt == NULL)
+ goto fail_msg;
+
+ msg->ckey = strdup(info->c.key);
+ if (msg->skey == NULL)
+ goto fail_msg;
+
+ msg->ccrt = strdup(info->c.crt);
+ if (msg->ccrt == NULL)
+ goto fail_msg;
+
+ msg->pol_lb = info->pol_lb;
+
+ return msg;
+
+ fail_msg:
+ name_info_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct name_info name_info_msg_to_s(const name_info_msg_t * msg)
+{
+ struct name_info s;
+
+ assert(msg != NULL);
+ assert(strlen(msg->name) <= NAME_SIZE);
+
+ strcpy(s.name, msg->name);
+ strcpy(s.s.key, msg->skey);
+ strcpy(s.s.crt, msg->scrt);
+ strcpy(s.c.key, msg->ckey);
+ strcpy(s.c.crt, msg->ccrt);
+
+ s.pol_lb = msg->pol_lb;
+
+ return s;
+}
+
layer_info_msg_t * layer_info_s_to_msg(const struct layer_info * s)
{
layer_info_msg_t * msg;
@@ -188,6 +248,95 @@ struct ipcp_info ipcp_info_msg_to_s(const ipcp_info_msg_t * msg)
return s;
}
+ls_config_msg_t * ls_config_s_to_msg(const struct ls_config * s)
+{
+ ls_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ ls_config_msg__init(msg);
+
+ msg->pol = s->pol;
+ msg->t_recalc = s->t_recalc;
+ msg->t_update = s->t_update;
+ msg->t_timeo = s->t_timeo;
+
+ return msg;
+
+ fail_malloc:
+ return NULL;
+}
+
+struct ls_config ls_config_msg_to_s(const ls_config_msg_t * msg)
+{
+ struct ls_config s;
+
+ assert(msg != NULL);
+
+ s.pol = msg->pol;
+ s.t_recalc = msg->t_recalc;
+ s.t_update = msg->t_update;
+ s.t_timeo = msg->t_timeo;
+
+ return s;
+}
+
+routing_config_msg_t * routing_config_s_to_msg(const struct routing_config * s)
+{
+ routing_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+
+ routing_config_msg__init(msg);
+
+ switch (s->pol) {
+ case ROUTING_LINK_STATE:
+ msg->ls = ls_config_s_to_msg(&s->ls);
+ if (msg->ls == NULL)
+ goto fail_ls;
+ break;
+ default:
+ /* No checks here */
+ break;
+ }
+
+ msg->pol = s->pol;
+
+ return msg;
+
+ fail_ls:
+ routing_config_msg__free_unpacked(msg, NULL);
+ return NULL;
+}
+
+struct routing_config routing_config_msg_to_s(const routing_config_msg_t * msg)
+{
+ struct routing_config s;
+
+ assert(msg != NULL);
+
+ switch (msg->pol) {
+ case ROUTING_LINK_STATE:
+ s.ls = ls_config_msg_to_s(msg->ls);
+ break;
+ default:
+ /* No checks here */
+ break;
+ }
+
+ s.pol = msg->pol;
+
+ return s;
+}
+
dt_config_msg_t * dt_config_s_to_msg(const struct dt_config * s)
{
dt_config_msg_t * msg;
@@ -203,9 +352,14 @@ dt_config_msg_t * dt_config_s_to_msg(const struct dt_config * s)
msg->addr_size = s->addr_size;
msg->eid_size = s->eid_size;
msg->max_ttl = s->max_ttl;
- msg->routing_type = s->routing_type;
+ msg->routing = routing_config_s_to_msg(&s->routing);
+ if (msg->routing == NULL)
+ goto fail_routing;
return msg;
+ fail_routing:
+ dt_config_msg__free_unpacked(msg, NULL);
+ return NULL;
}
struct dt_config dt_config_msg_to_s(const dt_config_msg_t * msg)
@@ -217,11 +371,102 @@ struct dt_config dt_config_msg_to_s(const dt_config_msg_t * msg)
s.addr_size = msg->addr_size;
s.eid_size = msg->eid_size;
s.max_ttl = msg->max_ttl;
- s.routing_type = msg->routing_type;
+ s.routing = routing_config_msg_to_s(msg->routing);
return s;
}
+struct dir_dht_config dir_dht_config_msg_to_s(const dir_dht_config_msg_t * msg)
+{
+ struct dir_dht_config s;
+
+ assert(msg != NULL);
+
+ s.params.alpha = msg->alpha;
+ s.params.k = msg->k;
+ s.params.t_expire = msg->t_expire;
+ s.params.t_refresh = msg->t_refresh;
+ s.params.t_replicate = msg->t_replicate;
+ s.peer = msg->peer;
+
+ return s;
+}
+
+dir_dht_config_msg_t * dir_dht_config_s_to_msg(const struct dir_dht_config * s)
+{
+ dir_dht_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+
+ dir_dht_config_msg__init(msg);
+
+ msg->alpha = s->params.alpha;
+ msg->k = s->params.k;
+ msg->t_expire = s->params.t_expire;
+ msg->t_refresh = s->params.t_refresh;
+ msg->t_replicate = s->params.t_replicate;
+ msg->peer = s->peer;
+
+ return msg;
+}
+
+struct dir_config dir_config_msg_to_s(const dir_config_msg_t * msg)
+{
+ struct dir_config s;
+
+ assert(msg != NULL);
+
+ switch (msg->pol) {
+ case DIR_DHT:
+ s.dht = dir_dht_config_msg_to_s(msg->dht);
+ break;
+ default:
+ /* No checks here */
+ break;
+ }
+
+ s.pol = msg->pol;
+
+ return s;
+}
+
+dir_config_msg_t * dir_config_s_to_msg(const struct dir_config * s)
+{
+ dir_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+
+ dir_config_msg__init(msg);
+
+ switch (s->pol) {
+ case DIR_DHT:
+ msg->dht = dir_dht_config_s_to_msg(&s->dht);
+ if (msg->dht == NULL)
+ goto fail_msg;
+ break;
+ default:
+ /* No checks here */
+ break;
+ }
+
+ msg->pol = s->pol;
+
+ return msg;
+
+ fail_msg:
+ dir_config_msg__free_unpacked(msg, NULL);
+ return NULL;
+}
+
+
uni_config_msg_t * uni_config_s_to_msg(const struct uni_config * s)
{
uni_config_msg_t * msg;
@@ -238,6 +483,11 @@ uni_config_msg_t * uni_config_s_to_msg(const struct uni_config * s)
if (msg->dt == NULL)
goto fail_msg;
+ msg->dir = dir_config_s_to_msg(&s->dir);
+ if (msg->dir == NULL)
+ goto fail_msg;
+
+
msg->addr_auth_type = s->addr_auth_type;
msg->cong_avoid = s->cong_avoid;
@@ -254,6 +504,7 @@ 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.dir = dir_config_msg_to_s(msg->dir);
s.addr_auth_type = msg->addr_auth_type;
s.cong_avoid = msg->cong_avoid;
@@ -261,9 +512,9 @@ struct uni_config uni_config_msg_to_s(const uni_config_msg_t * msg)
return s;
}
-udp_config_msg_t * udp_config_s_to_msg(const struct udp_config * s)
+udp4_config_msg_t * udp4_config_s_to_msg(const struct udp4_config * s)
{
- udp_config_msg_t * msg;
+ udp4_config_msg_t * msg;
assert(s != NULL);
@@ -271,24 +522,77 @@ udp_config_msg_t * udp_config_s_to_msg(const struct udp_config * s)
if (msg == NULL)
return NULL;
- udp_config_msg__init(msg);
+ udp4_config_msg__init(msg);
- msg->ip_addr = s->ip_addr;
- msg->dns_addr = s->dns_addr;
+ msg->ip_addr = s->ip_addr.s_addr;
+ msg->dns_addr = s->dns_addr.s_addr;
msg->port = s->port;
return msg;
}
-struct udp_config udp_config_msg_to_s(const udp_config_msg_t * msg)
+struct udp4_config udp4_config_msg_to_s(const udp4_config_msg_t * msg)
+{
+ struct udp4_config s;
+
+ assert(msg != NULL);
+
+ s.ip_addr.s_addr = msg->ip_addr;
+ s.dns_addr.s_addr = msg->dns_addr;
+ s.port = msg->port;
+
+ return s;
+}
+
+#define IN6_LEN sizeof(struct in6_addr)
+udp6_config_msg_t * udp6_config_s_to_msg(const struct udp6_config * s)
+{
+ udp6_config_msg_t * msg;
+
+ assert(s != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ udp6_config_msg__init(msg);
+
+ msg->ip_addr.data = malloc(IN6_LEN);
+ if (msg->ip_addr.data == NULL)
+ goto fail_msg;
+
+ msg->ip_addr.len = IN6_LEN;
+ memcpy(msg->ip_addr.data, &s->ip_addr.s6_addr, IN6_LEN);
+
+ msg->dns_addr.data = malloc(IN6_LEN);
+ if (msg->dns_addr.data == NULL)
+ goto fail_msg;
+
+ msg->dns_addr.len = IN6_LEN;
+ memcpy(msg->dns_addr.data, &s->dns_addr.s6_addr, IN6_LEN);
+
+ msg->port = s->port;
+
+ return msg;
+
+ fail_msg:
+ udp6_config_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct udp6_config udp6_config_msg_to_s(const udp6_config_msg_t * msg)
{
- struct udp_config s;
+ struct udp6_config s;
assert(msg != NULL);
- s.ip_addr = msg->ip_addr;
- s.dns_addr = msg->dns_addr;
- s.port = msg->port;
+ assert(msg->ip_addr.len == IN6_LEN);
+ assert(msg->dns_addr.len == IN6_LEN);
+
+ memcpy(&s.ip_addr.s6_addr, msg->ip_addr.data, IN6_LEN);
+ memcpy(&s.dns_addr.s6_addr, msg->dns_addr.data, IN6_LEN);
+ s.port = msg->port;
return s;
}
@@ -362,9 +666,14 @@ ipcp_config_msg_t * ipcp_config_s_to_msg(const struct ipcp_config * s)
if (msg->eth == NULL)
goto fail_msg;
break;
- case IPCP_UDP:
- msg->udp = udp_config_s_to_msg(&s->udp);
- if (msg->udp == NULL)
+ case IPCP_UDP4:
+ msg->udp4 = udp4_config_s_to_msg(&s->udp4);
+ if (msg->udp4 == NULL)
+ goto fail_msg;
+ break;
+ case IPCP_UDP6:
+ msg->udp6 = udp6_config_s_to_msg(&s->udp6);
+ if (msg->udp6 == NULL)
goto fail_msg;
break;
default:
@@ -407,8 +716,11 @@ struct ipcp_config ipcp_config_msg_to_s(const ipcp_config_msg_t * msg)
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);
+ case IPCP_UDP4:
+ s.udp4 = udp4_config_msg_to_s(msg->udp4);
+ break;
+ case IPCP_UDP6:
+ s.udp6 = udp6_config_msg_to_s(msg->udp6);
break;
case IPCP_BROADCAST:
break;
@@ -439,7 +751,6 @@ qosspec_msg_t * qos_spec_s_to_msg(const struct qos_spec * s)
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;
@@ -458,7 +769,6 @@ struct qos_spec qos_spec_msg_to_s(const qosspec_msg_t * msg)
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;
diff --git a/src/lib/random.c b/src/lib/random.c
index 09e0b844..2dc5f02f 100644
--- a/src/lib/random.c
+++ b/src/lib/random.c
@@ -24,22 +24,12 @@
#include <ouroboros/random.h>
-#if defined(__APPLE__) /* Barf */
-#undef __OSX_AVAILABLE
-#define __OSX_AVAILABLE(arg)
-#undef __IOS_AVAILABLE
-#define __IOS_AVAILABLE(arg)
-#undef __TVOS_AVAILABLE
-#define __TVOS_AVAILABLE(arg)
-#undef __WATCHOS_AVAILABLE
-#define __WATCHOS_AVAILABLE(arg)
-#include <sys/random.h>
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <stdlib.h>
#elif defined(HAVE_SYS_RANDOM)
#include <sys/random.h>
#elif defined(HAVE_LIBGCRYPT)
#include <gcrypt.h>
-#elif defined(__FreeBSD__)
-#include <stdlib.h>
#elif defined(HAVE_OPENSSL_RNG)
#include <openssl/rand.h>
#include <limits.h>
@@ -48,13 +38,11 @@
int random_buffer(void * buf,
size_t len)
{
-#if defined(__APPLE__)
- return getentropy(buf, len);
-#elif defined(__FreeBSD__)
+#if defined(__APPLE__) || defined(__FreeBSD__)
arc4random_buf(buf, len);
return 0;
#elif defined(HAVE_SYS_RANDOM)
- return getrandom(buf, len, GRND_NONBLOCK); /* glibc 2.25 */
+ return getrandom(buf, len, GRND_NONBLOCK);
#elif defined(HAVE_LIBGCRYPT)
gcry_randomize(buf, len, GCRY_STRONG_RANDOM);
return 0;
diff --git a/src/lib/serdes-irm.c b/src/lib/serdes-irm.c
index c4ba3053..3aea0617 100644
--- a/src/lib/serdes-irm.c
+++ b/src/lib/serdes-irm.c
@@ -166,12 +166,7 @@ int flow__irm_result_des(buffer_t * buf,
*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;
- }
-
+ if (sk != NULL) {
sk->len = msg->symmkey.len;
sk->data = msg->symmkey.data;
diff --git a/src/lib/sockets.c b/src/lib/sockets.c
index 13219db0..5dfbcb5c 100644
--- a/src/lib/sockets.c
+++ b/src/lib/sockets.c
@@ -154,12 +154,13 @@ int send_recv_msg(buffer_t * msg)
return len < 0 ? -1 : 0;
}
-char * ipcp_sock_path(pid_t pid)
+static char * __sock_path(pid_t pid,
+ const char * prefix,
+ const char * suffix)
{
char * full_name = NULL;
char * pid_string = NULL;
size_t len = 0;
- char * delim = "_";
len = n_digits(pid);
pid_string = malloc(len + 1);
@@ -168,9 +169,9 @@ char * ipcp_sock_path(pid_t pid)
sprintf(pid_string, "%d", pid);
- len += strlen(IPCP_SOCK_PATH_PREFIX);
- len += strlen(delim);
- len += strlen(SOCK_PATH_SUFFIX);
+ len += strlen(prefix);
+ len += strlen(pid_string);
+ len += strlen(suffix);
full_name = malloc(len + 1);
if (full_name == NULL) {
@@ -178,12 +179,17 @@ char * ipcp_sock_path(pid_t pid)
return NULL;
}
- strcpy(full_name, IPCP_SOCK_PATH_PREFIX);
- strcat(full_name, delim);
+ strcpy(full_name, prefix);
strcat(full_name, pid_string);
- strcat(full_name, SOCK_PATH_SUFFIX);
+ strcat(full_name, suffix);
free(pid_string);
return full_name;
}
+
+char * sock_path(pid_t pid,
+ const char * prefix)
+{
+ return __sock_path(pid, prefix, SOCK_PATH_SUFFIX);
+}
diff --git a/src/lib/tests/CMakeLists.txt b/src/lib/tests/CMakeLists.txt
index 0e114548..2791dd0d 100644
--- a/src/lib/tests/CMakeLists.txt
+++ b/src/lib/tests/CMakeLists.txt
@@ -3,14 +3,18 @@ get_filename_component(PARENT_DIR ${PARENT_PATH} NAME)
create_test_sourcelist(${PARENT_DIR}_tests test_suite.c
# Add new tests here
+ auth_test.c
bitmap_test.c
btree_test.c
crc32_test.c
+ crypt_test.c
hash_test.c
md5_test.c
sha3_test.c
shm_rbuff_test.c
+ sockets_test.c
time_test.c
+ tpm_test.c
)
add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests})
@@ -20,9 +24,16 @@ 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)
add_test(${test_name} ${C_TEST_PATH}/${PARENT_DIR}_test ${test_name})
endforeach (test)
+
+set_property(TEST auth_test PROPERTY SKIP_RETURN_CODE 1)
+set_property(TEST crypt_test PROPERTY SKIP_RETURN_CODE 1)
diff --git a/src/lib/tests/auth_test.c b/src/lib/tests/auth_test.c
new file mode 100644
index 00000000..ede294b8
--- /dev/null
+++ b/src/lib/tests/auth_test.c
@@ -0,0 +1,643 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Test of the authentication 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 "config.h"
+
+#include <ouroboros/test.h>
+#include <ouroboros/crypt.h>
+#include <ouroboros/random.h>
+#include <ouroboros/utils.h>
+
+#define TEST_MSG_SIZE 1500
+
+/*
+* Certificates created following the guide
+* Building an openssl certificate authority
+* on
+* https://community.f5.com/kb/technicalarticles/
+*/
+
+/* Root certificate for CA ca.unittest.o7s */
+static const char * root_ca_crt = \
+"-----BEGIN CERTIFICATE-----\n"
+"MIICXTCCAgOgAwIBAgIURlENlCOy1OsA/AXFscPUQ2li8OYwCgYIKoZIzj0EAwIw\n"
+"fDELMAkGA1UEBhMCQkUxDDAKBgNVBAgMA09WTDEOMAwGA1UEBwwFR2hlbnQxDDAK\n"
+"BgNVBAoMA283czEVMBMGA1UECwwMdW5pdHRlc3QubzdzMRgwFgYDVQQDDA9jYS51\n"
+"bml0dGVzdC5vN3MxEDAOBgkqhkiG9w0BCQEWASAwHhcNMjUwODAzMTg1MzE1WhcN\n"
+"NDUwNzI5MTg1MzE1WjB8MQswCQYDVQQGEwJCRTEMMAoGA1UECAwDT1ZMMQ4wDAYD\n"
+"VQQHDAVHaGVudDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3Mx\n"
+"GDAWBgNVBAMMD2NhLnVuaXR0ZXN0Lm83czEQMA4GCSqGSIb3DQEJARYBIDBZMBMG\n"
+"ByqGSM49AgEGCCqGSM49AwEHA0IABEPMseCScbd/d5TlHmyYVszn/YGVeNdUCnFR\n"
+"naOr95WlTNo3MyKKBuoiEFwHhjPASgXr/VDVjJLSyM3JUPebAcGjYzBhMB0GA1Ud\n"
+"DgQWBBQkxjMILHH6lZ+rnCMnD/63GO3y1zAfBgNVHSMEGDAWgBQkxjMILHH6lZ+r\n"
+"nCMnD/63GO3y1zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAKBggq\n"
+"hkjOPQQDAgNIADBFAiEA1jVJWW4idkCgAYv0m2LT9C33Dq42aLyRkJ+9YdzDqLwC\n"
+"IHT6MS4I0k52YP/hxoqWVBbpOW79PKYMRLyXTk1r7+Fa\n"
+"-----END CERTIFICATE-----\n";
+
+
+/* Certificate for intermediary im.unittest.o7s used for signing */
+static const char * intermediate_ca_crt = \
+"-----BEGIN CERTIFICATE-----\n"
+"MIICbTCCAhOgAwIBAgICEAMwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCQkUxDDAK\n"
+"BgNVBAgMA09WTDEOMAwGA1UEBwwFR2hlbnQxDDAKBgNVBAoMA283czEVMBMGA1UE\n"
+"CwwMdW5pdHRlc3QubzdzMRgwFgYDVQQDDA9jYS51bml0dGVzdC5vN3MxEDAOBgkq\n"
+"hkiG9w0BCQEWASAwHhcNMjUwODAzMTkwMjU3WhcNNDUwNzI5MTkwMjU3WjBaMQsw\n"
+"CQYDVQQGEwJCRTEMMAoGA1UECAwDT1ZMMQwwCgYDVQQKDANvN3MxFTATBgNVBAsM\n"
+"DHVuaXR0ZXN0Lm83czEYMBYGA1UEAwwPaW0udW5pdHRlc3QubzdzMFkwEwYHKoZI\n"
+"zj0CAQYIKoZIzj0DAQcDQgAEdlra08XItIPtVl5veaq4UF6LIcBXj2mZFqKNEXFh\n"
+"l9uAz6UAbIc+FUPNfom6dwKbg/AjQ82a100eh6K/jCY7eKOBpjCBozAdBgNVHQ4E\n"
+"FgQUy8Go8BIO6i0lJ+mgBr9lvh2L0eswHwYDVR0jBBgwFoAUJMYzCCxx+pWfq5wj\n"
+"Jw/+txjt8tcwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEQYD\n"
+"VR0fBAowCDAGoASgAoYAMCoGCCsGAQUFBwEBBB4wHDAMBggrBgEFBQcwAoYAMAwG\n"
+"CCsGAQUFBzABhgAwCgYIKoZIzj0EAwIDSAAwRQIhAN3ZYhqu6mVLGidmONsbANk5\n"
+"rzT6aHJcmvj19OxMusaXAiBKy0gBFCri/GLizi4wZo09wf31yZMqfr8IrApvPaLw\n"
+"qA==\n"
+"-----END CERTIFICATE-----\n";
+
+/* Server test-1.unittest.o7s private-public key pair */
+static const char * server_ec_pkp = \
+"-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEIA4/bcmquVvGrY4+TtfnFSy1SpXs896r5xJjGuD6NmGRoAoGCCqGSM49\n"
+"AwEHoUQDQgAE4BSOhv36q4bCMLSkJaCvzwZ3pPy2M0YzRKFKeV48tG5eD+MBaTrT\n"
+"eoHUcRfpz0EO/inq3FVDzEoAQ2NWpnz0kA==\n"
+"-----END EC PRIVATE KEY-----\n";
+
+/* Public key for the Private key */
+static const char * server_ec_pk = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4BSOhv36q4bCMLSkJaCvzwZ3pPy2\n"
+"M0YzRKFKeV48tG5eD+MBaTrTeoHUcRfpz0EO/inq3FVDzEoAQ2NWpnz0kA==\n"
+"-----END PUBLIC KEY-----\n";
+
+/* Valid signed server certificate for test-1.unittest.o7s */
+static const char * signed_server_crt = \
+"-----BEGIN CERTIFICATE-----\n"
+"MIIDiTCCAy+gAwIBAgICEAUwCgYIKoZIzj0EAwIwWjELMAkGA1UEBhMCQkUxDDAK\n"
+"BgNVBAgMA09WTDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3Mx\n"
+"GDAWBgNVBAMMD2ltLnVuaXR0ZXN0Lm83czAeFw0yNTA4MDgxODQ4NTNaFw00NTA4\n"
+"MDMxODQ4NTNaMG4xCzAJBgNVBAYTAkJFMQwwCgYDVQQIDANPVkwxDjAMBgNVBAcM\n"
+"BUdoZW50MQwwCgYDVQQKDANvN3MxFTATBgNVBAsMDHVuaXR0ZXN0Lm83czEcMBoG\n"
+"A1UEAwwTdGVzdC0xLnVuaXR0ZXN0Lm83czBZMBMGByqGSM49AgEGCCqGSM49AwEH\n"
+"A0IABOAUjob9+quGwjC0pCWgr88Gd6T8tjNGM0ShSnlePLRuXg/jAWk603qB1HEX\n"
+"6c9BDv4p6txVQ8xKAENjVqZ89JCjggHPMIIByzAJBgNVHRMEAjAAMBEGCWCGSAGG\n"
+"+EIBAQQEAwIGQDA4BglghkgBhvhCAQ0EKxYpbzdzIHVuaXR0ZXN0IEdlbmVyYXRl\n"
+"ZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFI+htsK0xxy6e1CqCyxn7mqi\n"
+"wRrpMIGoBgNVHSMEgaAwgZ2AFMvBqPASDuotJSfpoAa/Zb4di9HroYGApH4wfDEL\n"
+"MAkGA1UEBhMCQkUxDDAKBgNVBAgMA09WTDEOMAwGA1UEBwwFR2hlbnQxDDAKBgNV\n"
+"BAoMA283czEVMBMGA1UECwwMdW5pdHRlc3QubzdzMRgwFgYDVQQDDA9jYS51bml0\n"
+"dGVzdC5vN3MxEDAOBgkqhkiG9w0BCQEWASCCAhADMA4GA1UdDwEB/wQEAwIFoDAT\n"
+"BgNVHSUEDDAKBggrBgEFBQcDATAoBgNVHR8EITAfMB2gG6AZhhdodHRwczovL291\n"
+"cm9ib3Jvcy5yb2NrczBYBggrBgEFBQcBAQRMMEowIwYIKwYBBQUHMAKGF2h0dHBz\n"
+"Oi8vb3Vyb2Jvcm9zLnJvY2tzMCMGCCsGAQUFBzABhhdodHRwczovL291cm9ib3Jv\n"
+"cy5yb2NrczAKBggqhkjOPQQDAgNIADBFAiBZuw/Yb2pq925H7pEiOXr4fMo0wknz\n"
+"ktkxoHAFbjQEPQIhAMInHI7lvRmS0IMw1wBF/WlUZWKvhyU/TeMIZfk/JGCS\n"
+"-----END CERTIFICATE-----\n";
+
+/* Self-signed by server test-1.unittest.o7s using its key */
+static const char * server_crt = \
+"-----BEGIN CERTIFICATE-----\n"
+"MIIBfjCCASWgAwIBAgIUB5VYxp7i+sgYjvLiwfpf0W5NfqQwCgYIKoZIzj0EAwIw\n"
+"HjEcMBoGA1UEAwwTdGVzdC0xLnVuaXR0ZXN0Lm83czAeFw0yNTA4MDMxOTI4MzVa\n"
+"Fw00NTA3MjkxOTI4MzVaMB4xHDAaBgNVBAMME3Rlc3QtMS51bml0dGVzdC5vN3Mw\n"
+"WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATgFI6G/fqrhsIwtKQloK/PBnek/LYz\n"
+"RjNEoUp5Xjy0bl4P4wFpOtN6gdRxF+nPQQ7+KercVUPMSgBDY1amfPSQo0EwPzAe\n"
+"BgNVHREEFzAVghN0ZXN0LTEudW5pdHRlc3QubzdzMB0GA1UdDgQWBBSPobbCtMcc\n"
+"untQqgssZ+5qosEa6TAKBggqhkjOPQQDAgNHADBEAiAoFC/rqgrRXmMUx4y5cPbv\n"
+"jOKpoL3FpehRgGkPatmL/QIgMRHc2TSGo6q1SG22Xt1dHAIBsaN2AlSfhjKULMH5\n"
+"gRo=\n"
+"-----END CERTIFICATE-----\n";
+
+static int test_auth_create_destroy_ctx(void)
+{
+ struct auth_ctx * ctx;
+
+ TEST_START();
+
+ ctx = auth_create_ctx();
+ if (ctx == NULL) {
+ printf("Failed to create auth context.\n");
+ goto fail_create;
+ }
+
+ auth_destroy_ctx(ctx);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_create:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_load_free_crt(void)
+{
+ void * crt;
+
+ TEST_START();
+
+ if (crypt_load_crt_str(root_ca_crt, &crt) < 0) {
+ printf("Failed to load certificate string.\n");
+ goto fail_load;
+ }
+
+ crypt_free_crt(crt);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_load:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_crypt_get_pubkey_crt(void)
+{
+ void * pk;
+ void * crt;
+
+ TEST_START();
+
+ if (crypt_load_crt_str(signed_server_crt, &crt) < 0) {
+ printf("Failed to load server certificate from string.\n");
+ goto fail_load;
+ }
+
+ if (crypt_get_pubkey_crt(crt, &pk) < 0) {
+ printf("Failed to get public key from certificate.\n");
+ goto fail_get_pubkey;
+ }
+
+ crypt_free_key(pk);
+ crypt_free_crt(crt);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_get_pubkey:
+ crypt_free_crt(crt);
+ fail_load:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_check_crt_name(void)
+{
+ void * crt;
+
+ TEST_START();
+
+ if (crypt_load_crt_str(signed_server_crt, &crt) < 0) {
+ printf("Failed to load certificate from string.\n");
+ goto fail_load;
+ }
+
+ if (crypt_check_crt_name(crt, "test-1.unittest.o7s") < 0) {
+ printf("Failed to verify correct name.\n");
+ goto fail_check;
+ }
+
+ if (crypt_check_crt_name(crt, "bogus.name") == 0) {
+ printf("Failed to detect incorrect name.\n");
+ goto fail_check;
+ }
+
+ crypt_free_crt(crt);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_check:
+ crypt_free_crt(crt);
+ fail_load:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_load_free_privkey(void)
+{
+ void * key;
+
+ TEST_START();
+
+ if (crypt_load_privkey_str(server_ec_pkp, &key) < 0) {
+ printf("Failed to load server key pair from string.\n");
+ goto fail_load;
+ }
+
+ crypt_free_key(key);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_load:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_load_free_pubkey(void)
+{
+ void * key;
+
+ TEST_START();
+
+ if (crypt_load_pubkey_str(server_ec_pk, &key) < 0) {
+ printf("Failed to load server public key from string.\n");
+ goto fail_load;
+ }
+
+ crypt_free_key(key);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_load:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_crypt_check_pubkey_crt(void)
+{
+ void * pk;
+ void * crt_pk;
+ void * crt;
+
+ TEST_START();
+
+ if (crypt_load_crt_str(signed_server_crt, &crt) < 0) {
+ printf("Failed to load public certificate from string.\n");
+ goto fail_crt;
+ }
+
+ if (crypt_load_pubkey_str(server_ec_pk, &pk) < 0) {
+ printf("Failed to load public key from string.\n");
+ goto fail_pubkey;
+ }
+
+ if (crypt_get_pubkey_crt(crt, &crt_pk) < 0) {
+ printf("Failed to get public key from certificate.\n");
+ goto fail_get_pubkey;
+ }
+
+ if (crypt_cmp_key(pk, crt_pk) != 0) {
+ printf("Public keys do not match .\n");
+ goto fail_check;
+ }
+
+
+ crypt_free_key(crt_pk);
+ crypt_free_key(pk);
+ crypt_free_crt(crt);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_check:
+ crypt_free_key(crt_pk);
+ fail_get_pubkey:
+ crypt_free_key(pk);
+ fail_pubkey:
+ crypt_free_crt(crt);
+ fail_crt:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_store_add(void)
+{
+ struct auth_ctx * ctx;
+ void * _root_ca_crt;
+
+ TEST_START();
+
+ ctx = auth_create_ctx();
+ if (ctx == NULL) {
+ printf("Failed to create auth context.\n");
+ goto fail_create;
+ }
+
+ if (crypt_load_crt_str(root_ca_crt, &_root_ca_crt) < 0) {
+ printf("Failed to load root crt from string.\n");
+ goto fail_load;
+ }
+
+ if (auth_add_crt_to_store(ctx, _root_ca_crt) < 0) {
+ printf("Failed to add root crt to auth store.\n");
+ goto fail_add;
+ }
+
+ crypt_free_crt(_root_ca_crt);
+ auth_destroy_ctx(ctx);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_add:
+ crypt_free_crt(_root_ca_crt);
+ fail_load:
+ crypt_free_crt(_root_ca_crt);
+ fail_create:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_verify_crt(void)
+{
+ struct auth_ctx * auth;
+ void * _server_crt;
+ void * _signed_server_crt;
+ void * _root_ca_crt;
+ void * _intermediate_ca_crt;
+
+ TEST_START();
+
+ auth = auth_create_ctx();
+ if (auth == NULL) {
+ printf("Failed to create auth context.\n");
+ goto fail_create_ctx;
+ }
+
+ if (crypt_load_crt_str(server_crt, &_server_crt) < 0) {
+ printf("Failed to load self-signed crt from string.\n");
+ goto fail_load_server_crt;
+ }
+
+ if (crypt_load_crt_str(signed_server_crt, &_signed_server_crt) < 0) {
+ printf("Failed to load signed crt from string.\n");
+ goto fail_load_signed_server_crt;
+ }
+
+ if (crypt_load_crt_str(root_ca_crt, &_root_ca_crt) < 0) {
+ printf("Failed to load root crt from string.\n");
+ goto fail_load_root_ca_crt;
+ }
+
+ if (crypt_load_crt_str(intermediate_ca_crt, &_intermediate_ca_crt) < 0) {
+ printf("Failed to load intermediate crt from string.\n");
+ goto fail_load_intermediate_ca_crt;
+ }
+
+ if (auth_add_crt_to_store(auth, _root_ca_crt) < 0) {
+ printf("Failed to add root ca crt to auth store.\n");
+ goto fail_verify;
+ }
+
+ if (auth_add_crt_to_store(auth, _intermediate_ca_crt) < 0) {
+ printf("Failed to add intermediate ca crt to auth store.\n");
+ goto fail_verify;
+ }
+
+ if (auth_verify_crt(auth, _signed_server_crt) < 0) {
+ printf("Failed to verify signed crt with ca crt.\n");
+ goto fail_verify;
+ }
+
+ if (auth_verify_crt(auth, _server_crt) == 0) {
+ printf("Failed to detect untrusted crt.\n");
+ goto fail_verify;
+ }
+
+ crypt_free_crt(_intermediate_ca_crt);
+ crypt_free_crt(_root_ca_crt);
+ crypt_free_crt(_signed_server_crt);
+ crypt_free_crt(_server_crt);
+
+ auth_destroy_ctx(auth);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_verify:
+ crypt_free_crt(_intermediate_ca_crt);
+ fail_load_intermediate_ca_crt:
+ crypt_free_crt(_root_ca_crt);
+ fail_load_root_ca_crt:
+ crypt_free_crt(_signed_server_crt);
+ fail_load_signed_server_crt:
+ crypt_free_crt(_server_crt);
+ fail_load_server_crt:
+ auth_destroy_ctx(auth);
+ fail_create_ctx:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int test_auth_sign(void)
+{
+ uint8_t buf[TEST_MSG_SIZE];
+ void * pkp;
+ void * pk;
+ buffer_t msg;
+ buffer_t sig;
+
+ TEST_START();
+
+ msg.data = buf;
+ msg.len = sizeof(buf);
+
+ if (random_buffer(msg.data, msg.len) < 0) {
+ printf("Failed to generate random message.\n");
+ goto fail_init;
+ }
+
+ if (crypt_load_privkey_str(server_ec_pkp, &pkp) < 0) {
+ printf("Failed to load server key pair from string.\n");
+ goto fail_init;
+ }
+
+ if (crypt_load_pubkey_str(server_ec_pk, &pk) < 0) {
+ printf("Failed to load public key.\n");
+ goto fail_pubkey;
+ }
+
+ if (auth_sign(pkp, msg, &sig) < 0) {
+ printf("Failed to sign message.\n");
+ goto fail_sign;
+ }
+
+ if (auth_verify_sig(pk, msg, sig) < 0) {
+ printf("Failed to verify signature.\n");
+ goto fail_verify;
+ }
+
+ freebuf(sig);
+
+ crypt_free_key(pk);
+ crypt_free_key(pkp);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_verify:
+ freebuf(sig);
+ fail_sign:
+ crypt_free_key(pk);
+ fail_pubkey:
+ crypt_free_key(pkp);
+ fail_init:
+ return TEST_RC_FAIL;
+}
+
+int test_auth_bad_signature(void)
+{
+ uint8_t buf[TEST_MSG_SIZE];
+ void * pkp;
+ void * pk;
+ buffer_t msg;
+ buffer_t sig;
+ buffer_t fake_sig;
+
+ TEST_START();
+
+ msg.data = buf;
+ msg.len = sizeof(buf);
+
+ if (random_buffer(msg.data, msg.len) < 0) {
+ printf("Failed to generate random message.\n");
+ goto fail_init;
+ }
+
+ if (crypt_load_privkey_str(server_ec_pkp, &pkp) < 0) {
+ printf("Failed to load server key pair from string.\n");
+ goto fail_init;
+ }
+
+ if (crypt_load_pubkey_str(server_ec_pk, &pk) < 0) {
+ printf("Failed to load public key.\n");
+ goto fail_pubkey;
+ }
+
+ if (auth_sign(pkp, msg, &sig) < 0) {
+ printf("Failed to sign message.\n");
+ goto fail_sign;
+ }
+
+ fake_sig.data = malloc(sig.len);
+ if (fake_sig.data == NULL) {
+ printf("Failed to allocate memory for fake signature.\n");
+ goto fail_malloc;
+ }
+
+ fake_sig.len = sig.len;
+ if (random_buffer(fake_sig.data, fake_sig.len) < 0) {
+ printf("Failed to generate random fake signature.\n");
+ goto fail_malloc;
+ }
+
+ if (auth_verify_sig(pk, msg, fake_sig) == 0) {
+ printf("Failed to detect bad signature.\n");
+ goto fail_verify;
+ }
+
+ freebuf(fake_sig);
+ freebuf(sig);
+
+ crypt_free_key(pk);
+ crypt_free_key(pkp);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_verify:
+ freebuf(fake_sig);
+ fail_malloc:
+ freebuf(sig);
+ fail_sign:
+ crypt_free_key(pk);
+ fail_pubkey:
+ crypt_free_key(pkp);
+ fail_init:
+ return TEST_RC_FAIL;
+}
+
+int test_crt_str(void)
+{
+ char str[2295];
+ void * crt;
+
+ TEST_START();
+
+ if (crypt_load_crt_str(signed_server_crt, &crt) < 0) {
+ printf("Failed to load certificate from string.\n");
+ goto fail_load;
+ }
+
+ if (crypt_crt_str(crt, str) < 0) {
+ printf("Failed to convert certificate to string.\n");
+ goto fail_to_str;
+ }
+
+ printf("Certificate string:\n%s\n", str);
+
+ crypt_free_crt(crt);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_to_str:
+ crypt_free_crt(crt);
+ fail_load:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int auth_test(int argc,
+ char ** argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_auth_create_destroy_ctx();
+#ifdef HAVE_OPENSSL
+ ret |= test_load_free_crt();
+ ret |= test_check_crt_name();
+ ret |= test_crypt_get_pubkey_crt();
+ ret |= test_load_free_privkey();
+ ret |= test_load_free_pubkey();
+ ret |= test_crypt_check_pubkey_crt();
+ ret |= test_store_add();
+ ret |= test_verify_crt();
+ ret |= test_auth_sign();
+ ret |= test_auth_bad_signature();
+ ret |= test_crt_str();
+#else
+ (void) test_load_free_crt;
+ (void) test_check_crt_name;
+ (void) test_crypt_get_pubkey_crt;
+ (void) test_load_free_privkey;
+ (void) test_load_free_pubkey;
+ (void) test_crypt_check_pubkey_crt;
+ (void) test_store_add;
+ (void) test_verify_crt;
+ (void) test_auth_sign;
+ (void) test_auth_bad_signature;
+ (void) test_crt_str;
+
+ ret = TEST_RC_SKIP;
+#endif
+ return ret;
+}
diff --git a/src/lib/tests/crypt_test.c b/src/lib/tests/crypt_test.c
new file mode 100644
index 00000000..e7a09e8f
--- /dev/null
+++ b/src/lib/tests/crypt_test.c
@@ -0,0 +1,258 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Test of the cryptography 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 "config.h"
+
+#include <ouroboros/test.h>
+#include <ouroboros/crypt.h>
+#include <ouroboros/random.h>
+#include <ouroboros/utils.h>
+
+#define TEST_PACKET_SIZE 1500
+
+static int test_crypt_create_destroy(void)
+{
+ struct crypt_ctx * ctx;
+
+ TEST_START();
+
+ ctx = crypt_create_ctx(NULL);
+ if (ctx == NULL) {
+ printf("Failed to initialize cryptography.\n");
+ goto fail;
+ }
+
+ crypt_destroy_ctx(ctx);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_crypt_create_destroy_with_key(void)
+{
+ struct crypt_ctx * ctx;
+ uint8_t key[SYMMKEYSZ];
+
+ TEST_START();
+
+ memset(key, 0, sizeof(key));
+
+ ctx = crypt_create_ctx(key);
+ if (ctx == NULL) {
+ printf("Failed to initialize cryptography.\n");
+ goto fail;
+ }
+
+ crypt_destroy_ctx(ctx);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_crypt_dh_pkp_create_destroy(void)
+{
+ void * pkp;
+ uint8_t buf[MSGBUFSZ];
+
+ TEST_START();
+
+ if (crypt_dh_pkp_create(&pkp, buf) < 0) {
+ printf("Failed to create DH PKP.");
+ goto fail;
+ }
+
+ crypt_dh_pkp_destroy(pkp);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_crypt_dh_derive(void)
+{
+ void * pkp1;
+ void * pkp2;
+ buffer_t pk1;
+ buffer_t pk2;
+ ssize_t len;
+ uint8_t buf1[MSGBUFSZ];
+ uint8_t buf2[MSGBUFSZ];
+ uint8_t s1[SYMMKEYSZ];
+ uint8_t s2[SYMMKEYSZ];
+
+ TEST_START();
+
+ len = crypt_dh_pkp_create(&pkp1, buf1);
+ if (len < 0) {
+ printf("Failed to create first key pair.");
+ goto fail_pkp1;
+ }
+
+ pk1.len = (size_t) len;
+ pk1.data = buf1;
+
+ len = crypt_dh_pkp_create(&pkp2, buf2);
+ if (len < 0) {
+ printf("Failed to create second key pair.");
+ goto fail_pkp2;
+ }
+
+ pk2.len = (size_t) len;
+ pk2.data = buf2;
+
+ if (crypt_dh_derive(pkp1, pk2, s1) < 0) {
+ printf("Failed to derive first key.");
+ goto fail;
+ }
+
+ if (crypt_dh_derive(pkp2, pk1, s2) < 0) {
+ printf("Failed to derive second key.");
+ goto fail;
+ }
+
+ if (memcmp(s1, s2, SYMMKEYSZ) != 0) {
+ printf("Derived keys do not match.");
+ goto fail;
+ }
+
+ crypt_dh_pkp_destroy(pkp2);
+ crypt_dh_pkp_destroy(pkp1);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ crypt_dh_pkp_destroy(pkp2);
+ fail_pkp2:
+ crypt_dh_pkp_destroy(pkp1);
+ fail_pkp1:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int test_crypt_encrypt_decrypt(void)
+{
+ uint8_t pkt[TEST_PACKET_SIZE];
+ uint8_t key[SYMMKEYSZ];
+ struct crypt_ctx * ctx;
+ buffer_t in;
+ buffer_t out;
+ buffer_t out2;
+
+ TEST_START();
+
+ if (random_buffer(key, sizeof(key)) < 0) {
+ printf("Failed to generate random key.\n");
+ goto fail_init;
+ }
+
+ if (random_buffer(pkt, sizeof(pkt)) < 0) {
+ printf("Failed to generate random data.\n");
+ goto fail_init;
+ }
+
+ ctx = crypt_create_ctx(key);
+ if (ctx == NULL) {
+ printf("Failed to initialize cryptography.\n");
+ goto fail_init;
+ }
+
+ in.len = sizeof(pkt);
+ in.data = pkt;
+
+ if (crypt_encrypt(ctx, in, &out) < 0) {
+ printf("Encryption failed.\n");
+ goto fail_encrypt;
+ }
+
+ if (out.len < in.len) {
+ printf("Encryption returned too little data.\n");
+ goto fail_encrypt;
+ }
+
+ if (crypt_decrypt(ctx, out, &out2) < 0) {
+ printf("Decryption failed.\n");
+ goto fail_decrypt;
+ }
+
+ if (out2.len != in.len) {
+ printf("Decrypted data length does not match original.\n");
+ goto fail_chk;
+ }
+
+ if (memcmp(in.data, out2.data, in.len) != 0) {
+ printf("Decrypted data does not match original.\n");
+ goto fail_chk;
+ }
+
+ crypt_destroy_ctx(ctx);
+ freebuf(out2);
+ freebuf(out);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_chk:
+ freebuf(out2);
+ fail_decrypt:
+ freebuf(out);
+ fail_encrypt:
+ crypt_destroy_ctx(ctx);
+ fail_init:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int crypt_test(int argc,
+ char ** argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_crypt_create_destroy();
+ ret |= test_crypt_create_destroy_with_key();
+#ifdef HAVE_OPENSSL
+ ret |= test_crypt_dh_pkp_create_destroy();
+ ret |= test_crypt_dh_derive();
+ ret |= test_crypt_encrypt_decrypt();
+#else
+ (void) test_crypt_dh_pkp_create_destroy;
+ (void) test_crypt_dh_derive;
+ (void) test_crypt_encrypt_decrypt;
+
+ ret = TEST_RC_SKIP;
+#endif
+ return ret;
+}
diff --git a/src/lib/tests/sockets_test.c b/src/lib/tests/sockets_test.c
new file mode 100644
index 00000000..bbf2323b
--- /dev/null
+++ b/src/lib/tests/sockets_test.c
@@ -0,0 +1,98 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Tests for socket.c
+ *
+ * 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/sockets.h>
+#include <ouroboros/test.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define TEST_PID 1234
+#define TEST_PID_STR "1234"
+#define TEST_SERVER_PATH "/tmp/test.sock"
+#define TEST_SERVER_PREFIX "/tmp/ouroboros/test."
+#define TEST_SOCK_PATH_PREFIX "var/run/ouroboros/test."
+
+static int test_sock_path(void)
+{
+ char * path;
+ char * exp = TEST_SOCK_PATH_PREFIX TEST_PID_STR SOCK_PATH_SUFFIX;
+
+ TEST_START();
+
+ path = sock_path(TEST_PID, TEST_SOCK_PATH_PREFIX);
+ if (path == NULL) {
+ printf("Path is NULL.\n");
+ goto fail_path;
+ }
+
+ if (strcmp(path, exp) != 0) {
+ printf("Expected path '%s', got '%s'.\n", exp, path);
+ goto fail_cmp;
+ }
+
+ free(path);
+
+ TEST_SUCCESS();
+ return TEST_RC_SUCCESS;
+ fail_cmp:
+ free(path);
+ fail_path:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_server_socket_open(void)
+{
+ int sockfd;
+
+ TEST_START();
+
+ sockfd = server_socket_open(TEST_SERVER_PATH);
+ if (sockfd < 0) {
+ printf("Failed to open server socket.\n");
+ goto fail_sock;
+ }
+
+ close(sockfd);
+
+ unlink(TEST_SERVER_PATH);
+
+ TEST_SUCCESS();
+ return TEST_RC_SUCCESS;
+ fail_sock:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int sockets_test(void)
+{
+ int ret = 0;
+
+ ret |= test_sock_path();
+ ret |= test_server_socket_open();
+
+ return ret;
+}
diff --git a/src/lib/tests/time_test.c b/src/lib/tests/time_test.c
index 65f896bb..2b75b873 100644
--- a/src/lib/tests/time_test.c
+++ b/src/lib/tests/time_test.c
@@ -22,143 +22,508 @@
#define _POSIX_C_SOURCE 200809L
+#include <ouroboros/test.h>
#include <ouroboros/time.h>
#include <stdio.h>
-static void ts_print(struct timespec * s)
+static int ts_check(struct timespec * s,
+ time_t sec,
+ time_t nsec)
{
- printf("timespec is %zd:%ld.\n", (ssize_t) s->tv_sec, s->tv_nsec);
+ return s->tv_sec == sec && s->tv_nsec == nsec;
}
-static void tv_print(struct timeval * v)
+static int tv_check(struct timeval * v,
+ time_t sec,
+ time_t usec)
{
- printf("timeval is %zd:%zu.\n", (ssize_t) v->tv_sec, (size_t) v->tv_usec);
+ return v->tv_sec == sec && v->tv_usec == usec;
}
-static void ts_init(struct timespec * s,
- time_t sec,
- time_t nsec)
+
+static int test_time_ts_init(void)
{
- s->tv_sec = sec;
- s->tv_nsec = nsec;
+ struct timespec s = TIMESPEC_INIT_S (100);
+ struct timespec ms = TIMESPEC_INIT_MS(100);
+ struct timespec us = TIMESPEC_INIT_US(100);
+ struct timespec ns = TIMESPEC_INIT_NS(100);
+
+ TEST_START();
+
+ if (!ts_check(&s, 100, 0)) {
+ printf("timespec_init_s failed.\n");
+ goto fail;
+ }
+
+ if (!ts_check(&ms, 0, 100 * MILLION)) {
+ printf("timespec_init_ms failed.\n");
+ goto fail;
+ }
+
+ if (!ts_check(&us, 0, 100* 1000L)) {
+ printf("timespec_init_us failed.\n");
+ goto fail;
+ }
+
+ if (!ts_check(&ns, 0, 100)) {
+ printf("timespec_init_ns failed.\n");
+ goto fail;
+ }
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
-static void tv_init(struct timeval * v,
- time_t sec,
- time_t usec)
+static int test_time_tv_init(void)
{
- v->tv_sec = sec;
- v->tv_usec = usec;
+ struct timeval s = TIMEVAL_INIT_S (100);
+ struct timeval ms = TIMEVAL_INIT_MS(100);
+ struct timeval us = TIMEVAL_INIT_US(100);
+
+ TEST_START();
+
+ if (!tv_check(&s, 100, 0)) {
+ printf("timeval_init_s failed.\n");
+ goto fail;
+ }
+
+ if (!tv_check(&ms, 0, 100 * 1000L)) {
+ printf("timeval_init_ms failed.\n");
+ goto fail;
+ }
+
+ if (!tv_check(&us, 0, 100)) {
+ printf("timeval_init_us failed.\n");
+ goto fail;
+ }
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
-static int ts_check(struct timespec * s,
- time_t sec,
- time_t nsec)
+static int test_ts_diff(void)
{
- return s->tv_sec == sec && s->tv_nsec == nsec;
+ struct timespec s0 = TIMESPEC_INIT_S (100);
+ struct timespec s1 = TIMESPEC_INIT_S (200);
+ struct timespec ms0 = TIMESPEC_INIT_MS(100);
+ struct timespec ms1 = TIMESPEC_INIT_MS(200);
+ struct timespec us0 = TIMESPEC_INIT_US(100);
+ struct timespec us1 = TIMESPEC_INIT_US(200);
+ struct timespec ns0 = TIMESPEC_INIT_NS(100);
+ struct timespec ns1 = TIMESPEC_INIT_NS(200);
+ struct timespec res;
+
+ TEST_START();
+
+ ts_diff(&s0, &s1, &res);
+ if (!ts_check(&res, -100, 0)) {
+ printf("timespec_diff failed at s0 - s1.\n");
+ goto fail;
+ }
+
+ ts_diff(&s1, &s0, &res);
+ if (!ts_check(&res, 100, 0)) {
+ printf("timespec_diff failed at s1 - s0.\n");
+ goto fail;
+ }
+
+ ts_diff(&ms0, &ms1, &res);
+ if (!ts_check(&res, -1, 900 * MILLION)) {
+ printf("timespec_diff failed at ms0 - ms1.\n");
+ goto fail;
+ }
+
+ ts_diff(&ms1, &ms0, &res);
+ if (!ts_check(&res, 0, 100 * MILLION)) {
+ printf("timespec_diff failed at ms1 - ms0.\n");
+ goto fail;
+ }
+
+ ts_diff(&us0, &us1, &res);
+ if (!ts_check(&res, -1, 999900 * 1000L)) {
+ printf("timespec_diff failed at us0 - us1.\n");
+ goto fail;
+ }
+
+ ts_diff(&us1, &us0, &res);
+ if (!ts_check(&res, 0, 100 * 1000L)) {
+ printf("timespec_diff failed at us1 - us0.\n");
+ goto fail;
+ }
+
+ ts_diff(&ns0, &ns1, &res);
+ if (!ts_check(&res, -1, 999999900)) {
+ printf("timespec_diff failed at ns0 - ns1.\n");
+ goto fail;
+ }
+
+ ts_diff(&ns1, &ns0, &res);
+ if (!ts_check(&res, 0, 100)) {
+ printf("timespec_diff failed at ns1 - ns0.\n");
+ goto fail;
+ }
+
+ ts_diff(&s0, &ms0, &res);
+ if (!ts_check(&res, 99, 900 * MILLION)) {
+ printf("timespec_diff failed at s0 - ms0.\n");
+ goto fail;
+ }
+
+ ts_diff(&s0, &us0, &res);
+ if (!ts_check(&res, 99, 999900 * 1000L)) {
+ printf("timespec_diff failed at s0 - us0.\n");
+ goto fail;
+ }
+
+ ts_diff(&s0, &ns0, &res);
+ if (!ts_check(&res, 99, 999999900)) {
+ printf("timespec_diff failed at s0 - ns0.\n");
+ goto fail;
+ }
+
+ ts_diff(&ms0, &us0, &res);
+ if (!ts_check(&res, 0, 99900 * 1000L)) {
+ printf("timespec_diff failed at ms0 - us0.\n");
+ goto fail;
+ }
+
+ ts_diff(&ms0, &ns0, &res);
+ if (!ts_check(&res, 0, 99999900)) {
+ printf("timespec_diff failed at ms0 - ns0.\n");
+ goto fail;
+ }
+
+ ts_diff(&us0, &ns0, &res);
+ if (!ts_check(&res, 0, 99900)) {
+ printf("timespec_diff failed at us0 - ns0.\n");
+ goto fail;
+ }
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
-static int tv_check(struct timeval * v,
- time_t sec,
- time_t usec)
+static int test_tv_diff(void)
{
- return v->tv_sec == sec && v->tv_usec == usec;
+ struct timeval s0 = TIMEVAL_INIT_S (100);
+ struct timeval s1 = TIMEVAL_INIT_S (200);
+ struct timeval ms0 = TIMEVAL_INIT_MS(100);
+ struct timeval ms1 = TIMEVAL_INIT_MS(200);
+ struct timeval us0 = TIMEVAL_INIT_US(100);
+ struct timeval us1 = TIMEVAL_INIT_US(200);
+ struct timeval res;
+
+ TEST_START();
+
+ tv_diff(&s0, &s1, &res);
+ if (!tv_check(&res, -100, 0)) {
+ printf("timeval_diff failed at s0 - s1.\n");
+ goto fail;
+ }
+
+ tv_diff(&s1, &s0, &res);
+ if (!tv_check(&res, 100, 0)) {
+ printf("timeval_diff failed at s1 - s0.\n");
+ goto fail;
+ }
+
+ tv_diff(&ms0, &ms1, &res);
+ if (!tv_check(&res, -1, 900 * 1000L)) {
+ printf("timeval_diff failed at ms0 - ms1.\n");
+ goto fail;
+ }
+
+ tv_diff(&ms1, &ms0, &res);
+ if (!tv_check(&res, 0, 100 * 1000L)) {
+ printf("timeval_diff failed at ms1 - ms0.\n");
+ goto fail;
+ }
+
+ tv_diff(&us0, &us1, &res);
+ if (!tv_check(&res, -1, 999900)) {
+ printf("timeval_diff failed at us0 - us1.\n");
+ goto fail;
+ }
+
+ tv_diff(&us1, &us0, &res);
+ if (!tv_check(&res, 0, 100)) {
+ printf("timeval_diff failed at us1 - us0.\n");
+ goto fail;
+ }
+
+ tv_diff(&s0, &ms0, &res);
+ if (!tv_check(&res, 99, 900 * 1000L)) {
+ printf("timeval_diff failed at s0 - ms0.\n");
+ goto fail;
+ }
+
+ tv_diff(&s0, &us0, &res);
+ if (!tv_check(&res, 99, 999900)) {
+ printf("timeval_diff failed at s0 - us0.\n");
+ goto fail;
+ }
+
+ tv_diff(&ms0, &us0, &res);
+ if (!tv_check(&res, 0, 99900)) {
+ printf("timeval_diff failed at ms0 - us0.\n");
+ goto fail;
+ }
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
-int time_test(int argc,
- char ** argv)
+static int test_ts_diff_time(void)
{
- struct timespec s0;
- struct timespec s1;
- struct timespec s2;
+ struct timespec s0 = TIMESPEC_INIT_S (100);
+ struct timespec s1 = TIMESPEC_INIT_S (200);
+ struct timespec ms0 = TIMESPEC_INIT_MS(100);
+ struct timespec ms1 = TIMESPEC_INIT_MS(200);
+ struct timespec us0 = TIMESPEC_INIT_US(100);
+ struct timespec us1 = TIMESPEC_INIT_US(200);
+ struct timespec ns0 = TIMESPEC_INIT_NS(100);
+ struct timespec ns1 = TIMESPEC_INIT_NS(200);
- struct timeval v0;
- struct timeval v1;
- struct timeval v2;
+ TEST_START();
- (void) argc;
- (void) argv;
+ if (ts_diff_ms(&s0, &s1) != -100 * 1000L) {
+ printf("timespec_diff_ms failed at s0 - s1.\n");
+ goto fail;
+ }
+
+ if (ts_diff_ms(&s1, &s0) != 100 * 1000L) {
+ printf("timespec_diff_ms failed at s1 - s0.\n");
+ goto fail;
+ }
+
+ if (ts_diff_us(&s0, &s1) != -100 * MILLION) {
+ printf("timespec_diff_us failed at s1 - s0.\n");
+ goto fail;
+ }
+
+ if (ts_diff_us(&s1, &s0) != 100 * MILLION) {
+ printf("timespec_diff_us failed at s0 - s1.\n");
+ goto fail;
+ }
+
+ if (ts_diff_ns(&s0, &s1) != -100 * BILLION) {
+ printf("timespec_diff_ns failed at s0 - s1.\n");
+ goto fail;
+ }
+
+ if (ts_diff_ns(&s1, &s0) != 100 * BILLION) {
+ printf("timespec_diff_ns failed at s1 - s0.\n");
+ goto fail;
+ }
+
+ if (ts_diff_ms(&ms0, &ms1) != -100) {
+ printf("timespec_diff_ms failed at ms0 - ms1.\n");
+ goto fail;
+ }
+
+ if (ts_diff_ms(&ms1, &ms0) != 100) {
+ printf("timespec_diff_ms failed at ms1 - ms0.\n");
+ goto fail;
+ }
- ts_init(&s0, 0, 0);
- ts_init(&s1, 5, 0);
+ if (ts_diff_us(&ms0, &ms1) != -100 * 1000L) {
+ printf("timespec_diff_us failed at ms0 - ms1.\n");
+ goto fail;
+ }
- ts_add(&s0, &s1, &s2);
- if (!ts_check(&s2, 5, 0)) {
- printf("ts_add failed.\n");
- ts_print(&s2);
- return -1;
+ if (ts_diff_us(&ms1, &ms0) != 100 * 1000L) {
+ printf("timespec_diff_us failed at ms1 - ms0.\n");
+ goto fail;
}
- tv_init(&v0, 0, 0);
- tv_init(&v1, 5, 0);
+ if (ts_diff_ns(&ms0, &ms1) != -100 * MILLION) {
+ printf("timespec_diff_ns failed at ms0 - ms1.\n");
+ goto fail;
+ }
- tv_add(&v0, &v1, &v2);
- if (!tv_check(&v2, 5, 0)) {
- printf("tv_add failed.\n");
- tv_print(&v2);
- return -1;
+ if (ts_diff_ns(&ms1, &ms0) != 100 * MILLION) {
+ printf("timespec_diff_ns failed at ms1 - ms0.\n");
+ goto fail;
}
- ts_init(&s0, 0, 500 * MILLION);
- ts_init(&s1, 0, 600 * MILLION);
+ if (ts_diff_ms(&us0, &us1) != 0) {
+ printf("timespec_diff_ms failed at us0 - us1.\n");
+ goto fail;
+ }
- ts_add(&s0, &s1, &s2);
- if (!ts_check(&s2, 1, 100 * MILLION)) {
- printf("ts_add with nano overflow failed.\n");
- ts_print(&s2);
- return -1;
+ if (ts_diff_ms(&us1, &us0) != 0) {
+ printf("timespec_diff_ms failed at us1 - us0.\n");
+ goto fail;
}
- tv_init(&v0, 0, 500 * 1000);
- tv_init(&v1, 0, 600 * 1000);
+ if (ts_diff_us(&us0, &us1) != -100) {
+ printf("timespec_diff_us failed at us0 - us1.\n");
+ goto fail;
+ }
- tv_add(&v0, &v1, &v2);
- if (!tv_check(&v2, 1, 100 * 1000)) {
- printf("tv_add with nano overflow failed.\n");
- tv_print(&v2);
- return -1;
+ if (ts_diff_us(&us1, &us0) != 100) {
+ printf("timespec_diff_us failed at us1 - us0.\n");
+ goto fail;
}
- ts_init(&s0, 0, 0);
- ts_init(&s1, 5, 0);
+ if (ts_diff_ns(&us0, &us1) != -100 * 1000L) {
+ printf("timespec_diff_ns failed at us0 - us1.\n");
+ goto fail;
+ }
- ts_diff(&s0, &s1, &s2);
- if (!ts_check(&s2, -5, 0)) {
- printf("ts_diff failed.\n");
- ts_print(&s2);
- return -1;
+ if (ts_diff_ns(&us1, &us0) != 100 * 1000L) {
+ printf("timespec_diff_ns failed at us1 - us0.\n");
+ goto fail;
}
- tv_init(&v0, 0, 0);
- tv_init(&v1, 5, 0);
+ if (ts_diff_ms(&ns0, &ns1) != 0) {
+ printf("timespec_diff_ms failed at ns0 - ns1.\n");
+ goto fail;
+ }
- tv_diff(&v0, &v1, &v2);
- if (!tv_check(&v2, -5, 0)) {
- printf("tv_diff failed.\n");
- tv_print(&v2);
- return -1;
+ if (ts_diff_ms(&ns1, &ns0) != 0) {
+ printf("timespec_diff_ms failed at ns1 - ns0.\n");
+ goto fail;
}
- ts_init(&s0, 0, 500 * MILLION);
- ts_init(&s1, 0, 600 * MILLION);
+ if (ts_diff_us(&ns0, &ns1) != 0) {
+ printf("timespec_diff_us failed at ns0 - ns1.\n");
+ goto fail;
+ }
- ts_diff(&s0, &s1, &s2);
- if (!ts_check(&s2, -1, 900 * MILLION)) {
- printf("ts_diff with nano underflow failed.\n");
- ts_print(&s2);
- return -1;
+ if (ts_diff_us(&ns1, &ns0) != 0) {
+ printf("timespec_diff_us failed at ns1 - ns0.\n");
+ goto fail;
}
- tv_init(&v0, 0, 500 * 1000);
- tv_init(&v1, 0, 600 * 1000);
+ if (ts_diff_ns(&ns0, &ns1) != -100) {
+ printf("timespec_diff_ns failed at ns0 - ns1.\n");
+ goto fail;
+ }
- tv_diff(&v0, &v1, &v2);
- if (!tv_check(&v2, -1, 900 * 1000)) {
- printf("tv_diff with nano underflow failed.\n");
- tv_print(&v2);
- return -1;
+ if (ts_diff_ns(&ns1, &ns0) != 100) {
+ printf("timespec_diff_ns failed at ns1 - ns0.\n");
+ goto fail;
}
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_tv_diff_time(void)
+{
+ struct timeval s0 = TIMEVAL_INIT_S (100);
+ struct timeval s1 = TIMEVAL_INIT_S (200);
+ struct timeval ms0 = TIMEVAL_INIT_MS(100);
+ struct timeval ms1 = TIMEVAL_INIT_MS(200);
+ struct timeval us0 = TIMEVAL_INIT_US(100);
+ struct timeval us1 = TIMEVAL_INIT_US(200);
+
+ TEST_START();
+
+ if (tv_diff_ms(&s0, &s1) != -100 * 1000L) {
+ printf("timeval_diff_ms failed at s0 - s1.\n");
+ goto fail;
+ }
+
+ if (tv_diff_ms(&s1, &s0) != 100 * 1000L) {
+ printf("timeval_diff_ms failed at s1 - s0.\n");
+ goto fail;
+ }
+
+ if (tv_diff_us(&s0, &s1) != -100 * MILLION) {
+ printf("timeval_diff_us failed at s0 - s1.\n");
+ goto fail;
+ }
+
+ if (tv_diff_us(&s1, &s0) != 100 * MILLION) {
+ printf("timeval_diff_us failed at s1 - s0.\n");
+ goto fail;
+ }
+
+ if (tv_diff_ms(&ms0, &ms1) != -100) {
+ printf("timeval_diff_ms failed at ms0 - ms1.\n");
+ goto fail;
+ }
+
+ if (tv_diff_ms(&ms1, &ms0) != 100) {
+ printf("timeval_diff_ms failed at ms1 - ms0.\n");
+ goto fail;
+ }
+
+ if (tv_diff_us(&ms0, &ms1) != -100 * 1000L) {
+ printf("timeval_diff_us failed at ms0 - ms1.\n");
+ goto fail;
+ }
+
+ if (tv_diff_us(&ms1, &ms0) != 100 * 1000L) {
+ printf("timeval_diff_us failed at ms1 - ms0.\n");
+ goto fail;
+ }
+
+ if (tv_diff_ms(&us0, &us1) != 0) {
+ printf("timeval_diff_ms failed at us0 - us1.\n");
+ goto fail;
+ }
+
+ if (tv_diff_ms(&us1, &us0) != 0) {
+ printf("timeval_diff_ms failed at us1 - us0.\n");
+ goto fail;
+ }
+
+ if (tv_diff_us(&us0, &us1) != -100) {
+ printf("timeval_diff_us failed at us0 - us1.\n");
+ goto fail;
+ }
+
+ if (tv_diff_us(&us1, &us0) != 100) {
+ printf("timeval_diff_us failed at us1 - us0.\n");
+ goto fail;
+ }
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int time_test(int argc,
+ char ** argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_time_ts_init();
+ ret |= test_time_tv_init();
+ ret |= test_ts_diff();
+ ret |= test_tv_diff();
+ ret |= test_ts_diff_time();
+ ret |= test_tv_diff_time();
+
+ return ret;
}
diff --git a/src/lib/tests/tpm_test.c b/src/lib/tests/tpm_test.c
new file mode 100644
index 00000000..98d4fab3
--- /dev/null
+++ b/src/lib/tests/tpm_test.c
@@ -0,0 +1,104 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Tests for the threadpool 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/.
+ */
+
+
+#include "tpm.c"
+
+#include <ouroboros/test.h>
+
+static void * test_func(void * o)
+{
+ (void) o;
+
+ while(1)
+ sleep(1);
+
+ return NULL;
+}
+
+static int test_tpm_create_destroy(void)
+{
+ struct tpm *tpm;
+
+ TEST_START();
+
+ tpm = tpm_create(2, 2, &test_func, NULL);
+ if (tpm == NULL) {
+ printf("Failed to initialize TPM.\n");
+ goto fail;
+ }
+
+ tpm_destroy(tpm);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_tpm_start_stop(void * (* fn)(void *),
+ void * o)
+{
+ struct tpm *tpm;
+
+ TEST_START();
+
+ tpm = tpm_create(2, 2, fn, o);
+ if (tpm == NULL) {
+ printf("Failed to initialize TPM.\n");
+ goto fail_create;
+ }
+
+ if (tpm_start(tpm) < 0) {
+ printf("Failed to start TPM.\n");
+ goto fail_start;
+ }
+
+ tpm_stop(tpm);
+
+ tpm_destroy(tpm);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_start:
+ tpm_destroy(tpm);
+ fail_create:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int tpm_test(int argc,
+ char ** argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_tpm_create_destroy();
+ ret |= test_tpm_start_stop(&test_func, NULL);
+
+ return ret;
+}
diff --git a/src/lib/tpm.c b/src/lib/tpm.c
index 0ef1fda8..7a17ef6b 100644
--- a/src/lib/tpm.c
+++ b/src/lib/tpm.c
@@ -26,21 +26,32 @@
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
+#include <ouroboros/pthread.h>
#include <ouroboros/time.h>
#include <ouroboros/tpm.h>
+#ifdef CONFIG_OUROBOROS_DEBUG
+#define OUROBOROS_PREFIX "tpm"
+#include <ouroboros/logs.h>
+#endif
+
#include <assert.h>
-#include <pthread.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
-#define TPM_TIMEOUT 1000
+#define TPM_TIMEOUT 1000
struct pthr_el {
struct list_head next;
bool kill;
bool busy;
-
+ bool wait;
+#ifdef CONFIG_OUROBOROS_DEBUG
+ struct timespec start;
+ struct timespec last;
+#endif
pthread_t thr;
};
@@ -63,16 +74,45 @@ struct tpm {
enum tpm_state state;
pthread_cond_t cond;
- pthread_mutex_t lock;
+ pthread_mutex_t mtx;
pthread_t mgr;
};
+#ifdef CONFIG_OUROBOROS_DEBUG
+#define BETWEEN(a, x, y) ((a) > (x) && (a) <= (y))
+static void tpm_debug_thread(struct pthr_el * e)
+{
+ struct timespec now;
+ time_t diff;
+ time_t intv;
+
+ if (e->wait || !e->busy)
+ return;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ diff = ts_diff_ms(&now, &e->start) / 1000;
+ intv = ts_diff_ms(&now, &e->last) / 1000;
+
+ (void) diff; /* Never read if both build options off (0) */
+ (void) intv; /* Never read if report option off (0) */
+
+ if (BETWEEN(TPM_DEBUG_REPORT_INTERVAL, 0, intv)) {
+ log_dbg("Thread %d:%lx running for %ld s.\n",
+ getpid(),e->thr, diff);
+ e->last = now;
+ }
+
+ if (BETWEEN(TPM_DEBUG_ABORT_TIMEOUT, 0, diff))
+ assert(false); /* TODO: Grab a coffee and fire up GDB */
+}
+#endif
+
static void tpm_join(struct tpm * tpm)
{
struct list_head * p;
struct list_head * h;
-
list_for_each_safe(p, h, &tpm->pool) {
struct pthr_el * e = list_entry(p, struct pthr_el, next);
if (tpm->state != TPM_RUNNING) {
@@ -86,15 +126,18 @@ static void tpm_join(struct tpm * tpm)
list_for_each_safe(p, h, &tpm->pool) {
struct pthr_el * e = list_entry(p, struct pthr_el, next);
+#ifdef CONFIG_OUROBOROS_DEBUG
+ tpm_debug_thread(e);
+#endif
if (e->kill) {
pthread_t thr = e->thr;
list_del(&e->next);
free(e);
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
pthread_join(thr, NULL);
- pthread_mutex_lock(&tpm->lock);
+ pthread_mutex_lock(&tpm->mtx);
}
}
}
@@ -114,56 +157,59 @@ static void tpm_kill(struct tpm * tpm)
}
}
-static void * tpmgr(void * o)
+static int __tpm(struct tpm * tpm)
{
struct timespec dl;
struct timespec to = TIMESPEC_INIT_MS(TPM_TIMEOUT);
- struct tpm * tpm = (struct tpm *) o;
-
- while (true) {
- clock_gettime(PTHREAD_COND_CLOCK, &dl);
- ts_add(&dl, &to, &dl);
- pthread_mutex_lock(&tpm->lock);
+ clock_gettime(PTHREAD_COND_CLOCK, &dl);
+ ts_add(&dl, &to, &dl);
- if (tpm->state != TPM_RUNNING) {
- tpm_join(tpm);
- pthread_mutex_unlock(&tpm->lock);
- break;
- }
+ pthread_mutex_lock(&tpm->mtx);
+ if (tpm->state != TPM_RUNNING) {
tpm_join(tpm);
+ pthread_mutex_unlock(&tpm->mtx);
+ return -1;
+ }
- if (tpm->cur - tpm->wrk < tpm->min) {
- size_t i;
- for (i = 0; i < tpm->inc; ++i) {
- struct pthr_el * e = malloc(sizeof(*e));
- if (e == NULL)
- break;
+ tpm_join(tpm);
- e->kill = false;
- e->busy = false;
+ if (tpm->cur - tpm->wrk < tpm->min) {
+ size_t i;
+ for (i = 0; i < tpm->inc; ++i) {
+ struct pthr_el * e = malloc(sizeof(*e));
+ if (e == NULL)
+ break;
- if (pthread_create(&e->thr, NULL,
- tpm->func, tpm->o)) {
- free(e);
- break;
- }
+ memset(e, 0, sizeof(*e));
- list_add(&e->next, &tpm->pool);
+ if (pthread_create(&e->thr, NULL, tpm->func, tpm->o)) {
+ free(e);
+ break;
}
- tpm->cur += i;
+ list_add(&e->next, &tpm->pool);
}
- if (pthread_cond_timedwait(&tpm->cond, &tpm->lock, &dl)
- == ETIMEDOUT)
- if (tpm->cur - tpm->wrk > tpm->min)
- tpm_kill(tpm);
-
- pthread_mutex_unlock(&tpm->lock);
+ tpm->cur += i;
}
+ pthread_cleanup_push(__cleanup_mutex_unlock, &tpm->mtx);
+
+ if (pthread_cond_timedwait(&tpm->cond, &tpm->mtx, &dl) == ETIMEDOUT)
+ if (tpm->cur - tpm->wrk > tpm->min)
+ tpm_kill(tpm);
+
+ pthread_cleanup_pop(true);
+
+ return 0;
+}
+
+static void * tpmgr(void * o)
+{
+ while (__tpm((struct tpm *) o) == 0);
+
return (void *) 0;
}
@@ -175,11 +221,14 @@ struct tpm * tpm_create(size_t min,
struct tpm * tpm;
pthread_condattr_t cattr;
+ assert(func != NULL);
+ assert(inc > 0);
+
tpm = malloc(sizeof(*tpm));
if (tpm == NULL)
goto fail_malloc;
- if (pthread_mutex_init(&tpm->lock, NULL))
+ if (pthread_mutex_init(&tpm->mtx, NULL))
goto fail_lock;
if (pthread_condattr_init(&cattr))
@@ -208,7 +257,7 @@ struct tpm * tpm_create(size_t min,
fail_cond:
pthread_condattr_destroy(&cattr);
fail_cattr:
- pthread_mutex_destroy(&tpm->lock);
+ pthread_mutex_destroy(&tpm->mtx);
fail_lock:
free(tpm);
fail_malloc:
@@ -217,34 +266,39 @@ struct tpm * tpm_create(size_t min,
int tpm_start(struct tpm * tpm)
{
- pthread_mutex_lock(&tpm->lock);
+ pthread_mutex_lock(&tpm->mtx);
if (pthread_create(&tpm->mgr, NULL, tpmgr, tpm)) {
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
return -1;
}
tpm->state = TPM_RUNNING;
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
return 0;
}
void tpm_stop(struct tpm * tpm)
{
- pthread_mutex_lock(&tpm->lock);
+ pthread_mutex_lock(&tpm->mtx);
+
+ if (tpm->state != TPM_RUNNING) {
+ pthread_mutex_unlock(&tpm->mtx);
+ return;
+ }
tpm->state = TPM_NULL;
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
pthread_join(tpm->mgr, NULL);
}
void tpm_destroy(struct tpm * tpm)
{
- pthread_mutex_destroy(&tpm->lock);
+ pthread_mutex_destroy(&tpm->mtx);
pthread_cond_destroy(&tpm->cond);
free(tpm);
@@ -260,40 +314,61 @@ static struct pthr_el * tpm_pthr_el(struct tpm * tpm,
e = list_entry(p, struct pthr_el, next);
if (e->thr == thr)
return e;
-
}
return NULL;
}
-void tpm_inc(struct tpm * tpm)
+void tpm_begin_work(struct tpm * tpm)
{
struct pthr_el * e;
- pthread_mutex_lock(&tpm->lock);
+#ifdef CONFIG_OUROBOROS_DEBUG
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+#endif
+
+ pthread_mutex_lock(&tpm->mtx);
e = tpm_pthr_el(tpm, pthread_self());
if (e != NULL) {
- e->busy = false;
- --tpm->wrk;
+ e->busy = true;
+ ++tpm->wrk;
+#ifdef CONFIG_OUROBOROS_DEBUG
+ e->start = now;
+ e->last = now;
+#endif
}
- pthread_mutex_unlock(&tpm->lock);
+ pthread_cond_signal(&tpm->cond);
+
+ pthread_mutex_unlock(&tpm->mtx);
}
-void tpm_dec(struct tpm * tpm)
+void tpm_wait_work(struct tpm * tpm)
{
struct pthr_el * e;
- pthread_mutex_lock(&tpm->lock);
+ pthread_mutex_lock(&tpm->mtx);
+
+ e = tpm_pthr_el(tpm, pthread_self());
+ if (e != NULL)
+ e->wait = true;
+
+ pthread_mutex_unlock(&tpm->mtx);
+}
+
+void tpm_end_work(struct tpm * tpm)
+{
+ struct pthr_el * e;
+
+ pthread_mutex_lock(&tpm->mtx);
e = tpm_pthr_el(tpm, pthread_self());
if (e != NULL) {
- e->busy = true;
- ++tpm->wrk;
+ e->busy = false;
+ --tpm->wrk;
}
- pthread_cond_signal(&tpm->cond);
-
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
}
diff --git a/src/lib/utils.c b/src/lib/utils.c
index fdbcd9d9..fd275f63 100644
--- a/src/lib/utils.c
+++ b/src/lib/utils.c
@@ -27,16 +27,26 @@
#include <stdlib.h>
#include <string.h>
+int bufcmp(const buffer_t * a,
+ const buffer_t * b)
+{
+ if (a->len != b->len)
+ return a->len < b->len ? -1 : 1;
+
+ return memcmp(a->data, b->data, a->len);
+}
+
+
int n_digits(unsigned i)
{
- int n = 1;
+ int n = 1;
- while (i > 9) {
- ++n;
- i /= 10;
- }
+ while (i > 9) {
+ ++n;
+ i /= 10;
+ }
- return n;
+ return n;
}
char * path_strip(const char * src)
diff --git a/src/tools/irm/CMakeLists.txt b/src/tools/irm/CMakeLists.txt
index e5e5c466..7acd5396 100644
--- a/src/tools/irm/CMakeLists.txt
+++ b/src/tools/irm/CMakeLists.txt
@@ -4,7 +4,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
-set(SOURCE_FILES
+set(TOOLS_IRM_SOURCE_FILES
# Add source files here
irm.c
irm_bind_program.c
@@ -32,8 +32,11 @@ set(SOURCE_FILES
irm_utils.c
)
-add_executable(irm ${SOURCE_FILES})
+add_executable(irm ${TOOLS_IRM_SOURCE_FILES})
target_link_libraries(irm LINK_PUBLIC ouroboros-irm)
install(TARGETS irm RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
+
+# enable when we have tests
+# add_subdirectory(tests)
diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c
index b8e5c54d..3fabc3cc 100644
--- a/src/tools/irm/irm_ipcp_bootstrap.c
+++ b/src/tools/irm/irm_ipcp_bootstrap.c
@@ -46,90 +46,131 @@
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
+#include <netinet/in.h>
#ifdef __FreeBSD__
#include <sys/socket.h>
#endif
-#define UNICAST "unicast"
-#define BROADCAST "broadcast"
-#define UDP "udp"
-#define ETH_LLC "eth-llc"
-#define ETH_DIX "eth-dix"
-#define LOCAL "local"
-
-#define MD5 "MD5"
-#define SHA3_224 "SHA3_224"
-#define SHA3_256 "SHA3_256"
-#define SHA3_384 "SHA3_384"
-#define SHA3_512 "SHA3_512"
-
-#define DEFAULT_ADDR_SIZE 4
-#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_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"
+#define UNICAST "unicast"
+#define BROADCAST "broadcast"
+#define IP_UDP4 "udp4"
+#define IP_UDP6 "udp6"
+#define ETH_LLC "eth-llc"
+#define ETH_DIX "eth-dix"
+#define LOCAL "local"
+
+#define MD5 "MD5"
+#define SHA3_224 "SHA3_224"
+#define SHA3_256 "SHA3_256"
+#define SHA3_384 "SHA3_384"
+#define SHA3_512 "SHA3_512"
+
+#define FLAT_RANDOM "flat"
+#define DHT_DIR "DHT"
+#define LINK_STATE "link_state"
+#define LINK_STATE_LFA "lfa"
+#define LINK_STATE_ECM "ecmp"
+#define NONE_CA "none"
+#define MB_ECN_CA "mb-ecn"
+
+#define DT(x) default_dt_config.x
+#define DHT(x) default_dht_config.params.x
+#define UNI(x) default_uni_config.x
+#define DIX(x) eth_dix_default_conf.eth.x
+#define LLC(x) eth_llc_default_conf.eth.x
+#define UD4(x) udp4_default_conf.udp4.x
+#define UD6(x) udp6_default_conf.udp6.x
+
+static char * usage_str = \
+ "Usage: irm ipcp bootstrap\n"
+ " name <ipcp name>\n"
+ " layer <layer name>\n"
+ " [type [TYPE]]\n"
+ "where TYPE in {" UNICAST " " BROADCAST " " LOCAL " "
+ IP_UDP4 " " IP_UDP6 " " ETH_LLC " " ETH_DIX "},\n\n"
+ "if TYPE == " UNICAST "\n"
+ " [addr_auth <ADDRESS_POLICY> (default: %s)]\n"
+ " [directory <DIRECTORY_POLICY> (default: %s)]\n"
+ " [hash [ALGORITHM] (default: %s)]\n"
+ " [routing <ROUTING_POLICY> (default: %s)]\n"
+ " [congestion <CONG_POLICY> (default: %s)]\n"
+ " [autobind]\n\n"
+ "where ADDRESS_POLICY in {" FLAT_RANDOM "}\n"
+ " DIRECTORY_POLICY in {" DHT_DIR "}\n"
+ " ALGORITHM in {" SHA3_224 " " SHA3_256 " "
+ SHA3_384 " " SHA3_512 "}\n"
+ " ROUTING_POLICY in {" LINK_STATE " "
+ LINK_STATE_LFA " " LINK_STATE_ECM "}\n"
+ " CONG_POLICY in {" NONE_CA " " MB_ECN_CA "}\n"
+ " [Data Transfer Constants]\n"
+ " [addr <address size> (default: %d)]\n"
+ " [eid <eid size> (default: %d)]\n"
+ " [ttl <max time-to-live>, default: %d)]\n\n"
+ "if DIRECTORY_POLICY == " DHT_DIR "\n"
+ " [dht_alpha <search factor> (default: %u)]\n"
+ " [dht_k <replication factor> (default: %u)]\n"
+ " [dht_t_expire <expiration (s)> (default: %u)]\n"
+ " [dht_t_refresh <contact refresh (s)> (default: %u)]\n"
+ " [dht_t_replicate <replication (s)> (default: %u)]\n\n"
+ "if ROUTING_POLICY == " LINK_STATE "\n"
+ " [ls_t_recalc <pff recalc interval (s)> (default: %ld)]\n"
+ " [ls_t_update <LSA update interval (s)> (default: %ld)]\n"
+ " [ls_t_timeo <link timeout (s)> (default: %ld)]\n\n"
+ "if TYPE == " IP_UDP4 "\n"
+ " ip <IP address in dotted notation>\n"
+ " [port <UDP port> (default: %d)]\n"
+ " [dns <DDNS IPv4 address in dotted notation>"
+ " (default: none)]\n\n"
+ "if TYPE == " IP_UDP6 "\n"
+ " ip <IPv6 address>\n"
+ " [port <UDP port> (default: %d)]\n"
+ " [dns <DDNS IPv6 address>"
+ " (default: none)]\n\n"
+
+ "if TYPE == " ETH_LLC "\n"
+ " dev <interface name>\n"
+ " [hash [ALGORITHM] (default: %s)]\n"
+ "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 in {" SHA3_224 " " SHA3_256 " "
+ SHA3_384 " " SHA3_512 "}\n\n"
+ "if TYPE == " LOCAL "\n"
+ " [hash [ALGORITHM] (default: %s)]\n"
+ "where ALGORITHM in {" SHA3_224 " " SHA3_256 " "
+ SHA3_384 " " SHA3_512 "}\n\n"
+ "if TYPE == " BROADCAST "\n"
+ " [autobind]\n\n";
static void usage(void)
{
/* FIXME: Add ipcp_config stuff. */
- printf("Usage: irm ipcp bootstrap\n"
- " name <ipcp name>\n"
- " layer <layer name>\n"
- " [type [TYPE]]\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 in {" FLAT_RANDOM_ADDR_AUTH "}\n"
- " ROUTING_POLICY in {" LINK_STATE_ROUTING " "
- LINK_STATE_LFA_ROUTING " " LINK_STATE_ECM_ROUTING "}\n"
- " 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"
- " [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 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 in {" SHA3_224 " " SHA3_256 " "
- SHA3_384 " " SHA3_512 "}\n\n"
- "if TYPE == " LOCAL "\n"
- " [hash [ALGORITHM] (default: %s)]\n"
- "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, MB_ECN_CA,
- SHA3_256, DEFAULT_UDP_PORT, SHA3_256, 0xA000, SHA3_256,
+ printf(usage_str,
+ /* unicast */
+ FLAT_RANDOM, DHT_DIR, SHA3_256, LINK_STATE, MB_ECN_CA,
+ /* dt */
+ DT(addr_size), DT(eid_size), DT(max_ttl),
+ /* dht */
+ DHT(alpha), DHT(k), DHT(t_expire),
+ DHT(t_refresh), DHT(t_replicate),
+ /* ls */
+ default_ls_config.t_recalc, default_ls_config.t_update,
+ default_ls_config.t_timeo,
+ /* udp4 */
+ UD4(port),
+ /* udp6 */
+ UD6(port),
+ /* eth_llc */
+ SHA3_256,
+ /* eth_dix */
+ DIX(ethertype),
+ SHA3_256,
+ /* local */
+ SHA3_256,
+ /* broadcast */
SHA3_256);
}
@@ -139,26 +180,32 @@ int do_bootstrap_ipcp(int argc,
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;
+ struct dir_config dir_config = default_dir_config;
+ uint8_t addr_size = DT(addr_size);
+ uint8_t eid_size = DT(eid_size);
+ uint8_t max_ttl = DT(max_ttl);
+ struct routing_config routing = default_routing_config;
+ enum pol_addr_auth addr_auth_type = UNI(addr_auth_type);
+ enum pol_cong_avoid cong_avoid = UNI(cong_avoid);
+ enum pol_dir_hash hash_algo = DIR_HASH_SHA3_256;
+ char * ipstr = NULL;
+ char * dnsstr = NULL;
+ struct in_addr ip4_addr = {.s_addr = INADDR_ANY};
+ struct in_addr dns4_addr = UD4(dns_addr);
+ int port4 = UD4(port);
+ struct in6_addr ip6_addr = IN6ADDR_ANY_INIT;
+ struct in6_addr dns6_addr = UD6(dns_addr);
+ int port6 = UD6(port);
char * ipcp_type = NULL;
enum ipcp_type type = IPCP_INVALID;
char * layer = NULL;
char * dev = NULL;
- uint16_t ethertype = DEFAULT_ETHERTYPE;
+ uint16_t ethertype = DIX(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;
@@ -180,11 +227,9 @@ int do_bootstrap_ipcp(int argc,
else
goto unknown_param;
} else if (matches(*argv, "ip") == 0) {
- if (inet_pton (AF_INET, *(argv + 1), &ip_addr) != 1)
- goto unknown_param;
+ ipstr = *(argv + 1);
} else if (matches(*argv, "dns") == 0) {
- if (inet_pton(AF_INET, *(argv + 1), &dns_addr) != 1)
- goto unknown_param;
+ dnsstr = *(argv + 1);
} else if (matches(*argv, "device") == 0) {
dev = *(argv + 1);
} else if (matches(*argv, "ethertype") == 0) {
@@ -206,26 +251,50 @@ int do_bootstrap_ipcp(int argc,
} else if (matches(*argv, "ttl") == 0) {
max_ttl = atoi(*(argv + 1));
} else if (matches(*argv, "port") == 0) {
- port = atoi(*(argv + 1));
+ port4 = atoi(*(argv + 1));
+ port6 = port4;
} else if (matches(*argv, "autobind") == 0) {
autobind = true;
cargs = 1;
} else if (matches(*argv, "addr_auth") == 0) {
- if (strcmp(FLAT_RANDOM_ADDR_AUTH, *(argv + 1)) == 0)
+ if (strcmp(FLAT_RANDOM, *(argv + 1)) == 0)
addr_auth_type = ADDR_AUTH_FLAT_RANDOM;
else
goto unknown_param;
- } else if (matches(*argv, "routing") == 0) {
- if (strcmp(LINK_STATE_ROUTING, *(argv + 1)) == 0)
- routing_type = ROUTING_LINK_STATE;
- else if (strcmp(LINK_STATE_LFA_ROUTING,
- *(argv + 1)) == 0)
- routing_type = ROUTING_LINK_STATE_LFA;
- else if (strcmp(LINK_STATE_ECM_ROUTING,
- *(argv + 1)) == 0)
- routing_type = ROUTING_LINK_STATE_ECMP;
+ } else if (matches(*argv, "directory") == 0) {
+ if (strcmp(DHT_DIR, *(argv + 1)) == 0)
+ dir_config.pol = DIR_DHT;
else
goto unknown_param;
+ } else if (matches(*argv, "dht_alpha") == 0) {
+ dir_config.dht.params.alpha = atoi(*(argv + 1));
+ } else if (matches(*argv, "dht_k") == 0) {
+ dir_config.dht.params.k = atoi(*(argv + 1));
+ } else if (matches(*argv, "dht_t_expire") == 0) {
+ dir_config.dht.params.t_expire = atoi(*(argv + 1));
+ } else if (matches(*argv, "dht_t_refresh") == 0) {
+ dir_config.dht.params.t_refresh = atoi(*(argv + 1));
+ } else if (matches(*argv, "dht_t_replicate") == 0) {
+ dir_config.dht.params.t_replicate = atoi(*(argv + 1));
+ } else if (matches(*argv, "routing") == 0) {
+ if (strcmp(LINK_STATE, *(argv + 1)) == 0) {
+ routing.pol = ROUTING_LINK_STATE;
+ routing.ls.pol = LS_SIMPLE;
+ } else if (strcmp(LINK_STATE_LFA, *(argv + 1)) == 0) {
+ routing.pol = ROUTING_LINK_STATE;
+ routing.ls.pol = LS_LFA;
+ } else if (strcmp(LINK_STATE_ECM, *(argv + 1)) == 0) {
+ routing.pol = ROUTING_LINK_STATE;
+ routing.ls.pol = LS_ECMP;
+ } else {
+ goto unknown_param;
+ }
+ } else if (matches(*argv, "ls_t_timeo") == 0) {
+ routing.ls.t_timeo = atoi(*(argv + 1));
+ } else if (matches(*argv, "ls_t_update") == 0) {
+ routing.ls.t_update = atoi(*(argv + 1));
+ } else if (matches(*argv, "ls_t_recalc") == 0) {
+ routing.ls.t_recalc = atoi(*(argv + 1));
} else if (matches(*argv, "congestion") == 0) {
if (strcmp(NONE_CA, *(argv + 1)) == 0)
cong_avoid = CA_NONE;
@@ -257,21 +326,59 @@ int do_bootstrap_ipcp(int argc,
}
if (ipcp_type != NULL) {
- if (strcmp(ipcp_type, UNICAST) == 0)
+ if (matches(ipcp_type, UNICAST) == 0)
type = IPCP_UNICAST;
- else if (strcmp(ipcp_type, BROADCAST) == 0)
+ else if (matches(ipcp_type, BROADCAST) == 0)
type = IPCP_BROADCAST;
- else if (strcmp(ipcp_type, UDP) == 0)
- type = IPCP_UDP;
- else if (strcmp(ipcp_type, ETH_LLC) == 0)
- type = IPCP_ETH_LLC;
- else if (strcmp(ipcp_type, ETH_DIX) == 0)
+ else if (matches(ipcp_type, IP_UDP4) == 0)
+ type = IPCP_UDP4;
+ else if (matches(ipcp_type, IP_UDP6) == 0)
+ type = IPCP_UDP6;
+ else if (matches(ipcp_type, ETH_DIX) == 0)
type = IPCP_ETH_DIX;
- else if (strcmp(ipcp_type, LOCAL) == 0)
+ else if (matches(ipcp_type, ETH_LLC) == 0)
+ type = IPCP_ETH_LLC;
+ else if (matches(ipcp_type, LOCAL) == 0)
type = IPCP_LOCAL;
else goto fail_usage;
}
+ if (type == IPCP_UDP4) {
+ if (inet_pton (AF_INET, ipstr, &ip4_addr) != 1) {
+ printf("Invalid IPv4 address: \"%s\".\n", ipstr);
+ goto fail_usage;
+ }
+
+ if (ip4_addr.s_addr == INADDR_ANY) {
+ printf("Cannot use IPv4 address: \"%s\".\n", ipstr);
+ goto fail_usage;
+ }
+
+ if (dnsstr != NULL &&
+ inet_pton(AF_INET, dnsstr, &dns4_addr) != 1) {
+ printf("Invalid DNS IPv4 address: \"%s\".\n", dnsstr);
+ goto fail_usage;
+ }
+ }
+
+ if (type == IPCP_UDP6) {
+ if (inet_pton(AF_INET6, ipstr, &ip6_addr) != 1) {
+ printf("Invalid IPv6 address: \"%s\".\n", ipstr);
+ goto fail_usage;
+ }
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&ip6_addr)) {
+ printf("Cannot use IPv6 address: \"%s\".\n", ipstr);
+ goto fail_usage;
+ }
+
+ if (dnsstr != NULL &&
+ inet_pton(AF_INET6, dnsstr, &dns6_addr) != 1) {
+ printf("Invalid DNS IPv6 address: \"%s\".\n", dnsstr);
+ goto fail_usage;
+ }
+ }
+
if (pid == -1) {
if (ipcp_type == NULL) {
printf("No IPCPs matching %s found.\n\n", ipcp);
@@ -315,16 +422,20 @@ int do_bootstrap_ipcp(int argc,
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.dt.routing = routing;
conf.unicast.addr_auth_type = addr_auth_type;
conf.unicast.cong_avoid = cong_avoid;
+ conf.unicast.dir = dir_config;
break;
- case IPCP_UDP:
- if (ip_addr == 0)
- goto fail_usage;
- conf.udp.ip_addr = ip_addr;
- conf.udp.dns_addr = dns_addr;
- conf.udp.port = port;
+ case IPCP_UDP4:
+ conf.udp4.ip_addr = ip4_addr;
+ conf.udp4.dns_addr = dns4_addr;
+ conf.udp4.port = port4;
+ break;
+ case IPCP_UDP6:
+ conf.udp6.ip_addr = ip6_addr;
+ conf.udp6.dns_addr = dns6_addr;
+ conf.udp6.port = port6;
break;
case IPCP_ETH_DIX:
conf.eth.ethertype = ethertype;
diff --git a/src/tools/irm/irm_ipcp_create.c b/src/tools/irm/irm_ipcp_create.c
index 35d33782..e2a5c488 100644
--- a/src/tools/irm/irm_ipcp_create.c
+++ b/src/tools/irm/irm_ipcp_create.c
@@ -46,7 +46,8 @@
#define UNICAST "unicast"
#define BROADCAST "broadcast"
-#define UDP "udp"
+#define UDP4 "udp4"
+#define UDP6 "udp6"
#define ETH_LLC "eth-llc"
#define ETH_DIX "eth-dix"
#define LOCAL "local"
@@ -57,7 +58,7 @@ static void usage(void)
" name <ipcp name>\n"
" type [TYPE]\n\n"
"where TYPE in {" UNICAST " " BROADCAST " " LOCAL " "
- UDP " " ETH_LLC " " ETH_DIX "}\n");
+ UDP4 " " UDP6 " " ETH_LLC " " ETH_DIX "}\n");
}
int do_create_ipcp(int argc,
@@ -92,8 +93,10 @@ int do_create_ipcp(int argc,
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, UDP4) == 0)
+ type = IPCP_UDP4;
+ else if (strcmp(ipcp_type, UDP6) == 0)
+ type = IPCP_UDP6;
else if (strcmp(ipcp_type, LOCAL) == 0)
type = IPCP_LOCAL;
else if (strcmp(ipcp_type, ETH_LLC) == 0)
diff --git a/src/tools/irm/irm_ipcp_list.c b/src/tools/irm/irm_ipcp_list.c
index dfa3099f..54985eb4 100644
--- a/src/tools/irm/irm_ipcp_list.c
+++ b/src/tools/irm/irm_ipcp_list.c
@@ -48,7 +48,8 @@
#define UNICAST "unicast"
#define BROADCAST "broadcast"
-#define UDP "udp"
+#define UDP4 "udp4"
+#define UDP6 "udp6"
#define ETH_LLC "eth-llc"
#define ETH_DIX "eth-dix"
#define LOCAL "local"
@@ -60,7 +61,7 @@ static void usage(void)
" [layer <layer_name>]\n\n"
" [type [TYPE]]\n\n"
"where TYPE = {" UNICAST " " LOCAL " "
- UDP " " ETH_LLC " " ETH_DIX "}\n");
+ UDP4 " " UDP6 " " ETH_LLC " " ETH_DIX "}\n");
}
static char * str_type(enum ipcp_type type)
@@ -74,8 +75,10 @@ static char * str_type(enum ipcp_type type)
return ETH_LLC;
case IPCP_ETH_DIX:
return ETH_DIX;
- case IPCP_UDP:
- return UDP;
+ case IPCP_UDP4:
+ return UDP4;
+ case IPCP_UDP6:
+ return UDP6;
case IPCP_LOCAL:
return LOCAL;
default:
@@ -113,8 +116,10 @@ int do_list_ipcp(int argc,
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, UDP4) == 0)
+ type = IPCP_UDP4;
+ else if (strcmp(ipcp_type, UDP6) == 0)
+ type = IPCP_UDP6;
else if (strcmp(ipcp_type, LOCAL) == 0)
type = IPCP_LOCAL;
else if (strcmp(ipcp_type, ETH_LLC) == 0)
diff --git a/src/tools/irm/irm_name_create.c b/src/tools/irm/irm_name_create.c
index a0079cad..22341d2e 100644
--- a/src/tools/irm/irm_name_create.c
+++ b/src/tools/irm/irm_name_create.c
@@ -36,31 +36,82 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define _POSIX_C_SOURCE 200809L
+#define _XOPEN_SOURCE 500
+
+#include <ouroboros/errno.h>
#include <ouroboros/irm.h>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include "irm_ops.h"
#include "irm_utils.h"
#define RR "round-robin"
#define SPILL "spillover"
+#define SENC "<security_dir>/server/<name>/enc.cfg"
+#define SCRT "<security_dir>/server/<name>/crt.pem"
+#define SKEY "<security_dir>/server/<name>/key.pem"
+#define CENC "<security_dir>/client/<name>/enc.cfg"
+#define CCRT "<security_dir>/client/<name>/crt.pem"
+#define CKEY "<security_dir>/client/<name>/key.pem"
static void usage(void)
{
printf("Usage: irm name create\n"
- " <name>\n"
- " lb [LB_POLICY], default: %s\n\n"
- "where LB_POLICY in {" RR " " SPILL "}\n", RR);
+ " <name>. max %d chars.\n"
+ " [lb LB_POLICY], default: %s\n"
+ " [sencpath <path>, default: " SENC "]\n"
+ " [scrtpath <path>, default: " SCRT "]\n"
+ " [skeypath <path>, default: " SKEY "]\n"
+ " [cencpath <path>, default: " CENC "]\n"
+ " [ccrtpath <path>, default: " CCRT "]\n"
+ " [ckeypath <path>, default: " CKEY "]\n"
+ "\n"
+ "where LB_POLICY in {" RR " " SPILL "}\n",
+ NAME_SIZE, RR);
+}
+
+static int cp_chk_path(char * buf,
+ const char * path)
+{
+ char * rp = realpath(path, NULL);
+ if (rp == NULL) {
+ printf("Failed to check path %s: %s\n.",
+ path, strerror(errno));
+ goto fail_rp;
+ }
+
+ if (strlen(rp) > NAME_PATH_SIZE) {
+ printf("File path too long: %s.\n", rp);
+ goto fail_len;
+ }
+
+ strcpy(buf, rp);
+ free(rp);
+
+ return 0;
+
+ fail_len:
+ free(rp);
+ fail_rp:
+ return -1;
}
int do_create_name(int argc,
char ** argv)
{
- char * name = NULL;
- char * lb_pol = RR;
- enum pol_balance pol_lb = LB_RR;
+ struct name_info info = {};
+ char * name = NULL;
+ char * sencpath = NULL;
+ char * scrtpath = NULL;
+ char * skeypath = NULL;
+ char * cencpath = NULL;
+ char * ccrtpath = NULL;
+ char * ckeypath = NULL;
+ char * lb_pol = RR;
name = *(argv++);
--argc;
@@ -68,6 +119,18 @@ int do_create_name(int argc,
while (argc > 0) {
if (matches(*argv, "lb") == 0) {
lb_pol = *(argv + 1);
+ } else if (matches(*argv, "sencpath") == 0) {
+ sencpath = *(argv + 1);
+ } else if (matches(*argv, "scrtpath") == 0) {
+ scrtpath = *(argv + 1);
+ } else if (matches(*argv, "skeypath") == 0) {
+ skeypath = *(argv + 1);
+ } else if (matches(*argv, "cencpath") == 0) {
+ cencpath = *(argv + 1);
+ } else if (matches(*argv, "ccrtpath") == 0) {
+ ccrtpath = *(argv + 1);
+ } else if (matches(*argv, "ckeypath") == 0) {
+ ckeypath = *(argv + 1);
} else {
printf("\"%s\" is unknown, try \"irm "
"name create\".\n", *argv);
@@ -78,19 +141,45 @@ int do_create_name(int argc,
argv += 2;
}
- if (name == NULL) {
- usage();
- return -1;
+ if (name == NULL)
+ goto fail;
+
+ if (strlen(name) > NAME_SIZE) {
+ printf("Name too long.\n");
+ goto fail;
}
+ strcpy(info.name, name);
+
+ if (sencpath != NULL && cp_chk_path(info.s.enc, sencpath) < 0)
+ goto fail;
+
+ if (scrtpath != NULL && cp_chk_path(info.s.crt, scrtpath) < 0)
+ goto fail;
+
+ if (skeypath != NULL && cp_chk_path(info.s.key, skeypath) < 0)
+ goto fail;
+
+ if (cencpath != NULL && cp_chk_path(info.c.enc, cencpath) < 0)
+ goto fail;
+
+ if (ccrtpath != NULL && cp_chk_path(info.c.crt, ccrtpath) < 0)
+ goto fail;
+
+ if (ckeypath != NULL && cp_chk_path(info.c.key, ckeypath) < 0)
+ goto fail;
+
if (strcmp(lb_pol, RR) == 0)
- pol_lb = LB_RR;
+ info.pol_lb = LB_RR;
else if (strcmp(lb_pol, SPILL) == 0)
- pol_lb = LB_SPILL;
+ info.pol_lb = LB_SPILL;
else {
usage();
return -1;
}
- return irm_create_name(name, pol_lb);
+ return irm_create_name(&info);
+ fail:
+ usage();
+ return -1;
}
diff --git a/src/tools/irm/irm_name_reg.c b/src/tools/irm/irm_name_reg.c
index 061ed8be..7689119a 100644
--- a/src/tools/irm/irm_name_reg.c
+++ b/src/tools/irm/irm_name_reg.c
@@ -107,14 +107,23 @@ int do_reg_name(int argc,
return -1;
}
+ if (strlen(name) > NAME_SIZE) {
+ printf("Name too long.\n");
+ usage();
+ return -1;
+ }
+
ipcps_len = irm_list_ipcps(&ipcps);
- if (ipcps_len < 0)
- return ipcps_len;
+ if (ipcps_len <= 0) {
+ printf("Failed to list IPCPs.\n");
+ return -1;
+ }
names_len = irm_list_names(&names);
if (names_len < 0) {
+ printf("Failed to list names.\n");
free(ipcps);
- return names_len;
+ return -1;
}
for (i = 0; i < names_len; ++i) {
@@ -124,11 +133,19 @@ int do_reg_name(int argc,
}
}
- if (name_create && irm_create_name(name, LB_SPILL)) {
- printf("Error creating name.");
- free(ipcps);
- free(name);
- return -1;
+ if (name_create) {
+ struct name_info info = {
+ .pol_lb = LB_SPILL
+ };
+
+ strcpy(info.name, name);
+
+ if (irm_create_name(&info) < 0) {
+ printf("Error creating name.");
+ free(ipcps);
+ free(names);
+ return -1;
+ }
}
for (i = 0; i < ipcps_len; ++i) {
@@ -136,6 +153,8 @@ int do_reg_name(int argc,
for (j = 0; j < layers_len; j++) {
if (wildcard_match(layers[j], ipcps[i].layer) == 0) {
if (irm_reg_name(name, ipcps[i].pid)) {
+ printf("Failed to register with %s",
+ ipcps[i].layer);
free(ipcps);
free(names);
return -1;
@@ -145,6 +164,8 @@ int do_reg_name(int argc,
for (j = 0; j < ipcp_len; j++) {
if (wildcard_match(ipcp[j], ipcps[i].name) == 0) {
if (irm_reg_name(name, ipcps[i].pid)) {
+ printf("Failed to register with %s",
+ ipcps[i].name);
free(ipcps);
free(names);
return -1;
diff --git a/src/tools/ocbr/ocbr_client.c b/src/tools/ocbr/ocbr_client.c
index ba7b41f4..eada6e60 100644
--- a/src/tools/ocbr/ocbr_client.c
+++ b/src/tools/ocbr/ocbr_client.c
@@ -129,7 +129,7 @@ int client_main(char * server,
++seqnr;
- if (ts_diff_us(&start, &end) / MILLION >= duration)
+ if (ts_diff_us(&end, &start) / MILLION >= duration)
stop = true;
}
} else { /* flood */
@@ -142,7 +142,7 @@ int client_main(char * server,
++seqnr;
- if (ts_diff_us(&start, &end) / MILLION
+ if (ts_diff_us(&end, &start) / MILLION
>= (long) duration)
stop = true;
}
@@ -151,7 +151,7 @@ int client_main(char * server,
clock_gettime(CLOCK_REALTIME, &end);
- ms = ts_diff_ms(&start, &end);
+ ms = ts_diff_ms(&end, &start);
printf("sent statistics: "
"%9ld packets, %12ld bytes in %9d ms, %4.4f Mb/s\n",
diff --git a/src/tools/ocbr/ocbr_server.c b/src/tools/ocbr/ocbr_server.c
index a4bbadd4..34c4fa94 100644
--- a/src/tools/ocbr/ocbr_server.c
+++ b/src/tools/ocbr/ocbr_server.c
@@ -114,14 +114,14 @@ static void handle_flow(int fd)
bytes_read += count;
}
- if (ts_diff_us(&alive, &now)
+ if (ts_diff_us(&now, &alive)
> server_settings.timeout * MILLION) {
printf("Test on flow %d timed out\n", fd);
stop = true;
}
- if (stop || ts_diff_ms(&now, &iv_end) < 0) {
- long us = ts_diff_us(&iv_start, &now);
+ if (stop || ts_diff_ms(&now, &iv_end) > 0) {
+ long us = ts_diff_us(&now, &iv_start);
printf("Flow %4d: %9ld packets (%12ld bytes) in %9ld ms"
" => %9.4f pps, %9.4f Mbps\n",
fd,
diff --git a/src/tools/operf/operf_client.c b/src/tools/operf/operf_client.c
index 63f98299..7060ce5b 100644
--- a/src/tools/operf/operf_client.c
+++ b/src/tools/operf/operf_client.c
@@ -133,7 +133,7 @@ void * writer(void * o)
clock_gettime(CLOCK_REALTIME, &start);
clock_gettime(CLOCK_REALTIME, &now);
- while (!stop && ts_diff_ms(&start, &now) < client.duration) {
+ while (!stop && ts_diff_ms(&now, &start) > client.duration) {
if (!client.flood) {
clock_gettime(CLOCK_REALTIME, &now);
ts_add(&now, &intv, &end);
@@ -230,10 +230,10 @@ int client_main(void)
printf("%ld received, ", client.rcvd);
printf("%ld%% packet loss, ", client.sent == 0 ? 0 :
100 - ((100 * client.rcvd) / client.sent));
- printf("time: %.3f ms, ", ts_diff_us(&tic, &toc) / 1000.0);
+ printf("time: %.3f ms, ", ts_diff_us(&toc, &tic) / 1000.0);
printf("bandwidth: %.3lf Mb/s.\n",
(client.rcvd * client.size * 8)
- / (double) ts_diff_us(&tic, &toc));
+ / (double) ts_diff_us(&toc, &tic));
}
flow_dealloc(fd);
diff --git a/src/tools/operf/operf_server.c b/src/tools/operf/operf_server.c
index d11f3486..a611f79c 100644
--- a/src/tools/operf/operf_server.c
+++ b/src/tools/operf/operf_server.c
@@ -66,7 +66,7 @@ void * cleaner_thread(void * o)
pthread_mutex_lock(&server.lock);
for (i = 0; i < OPERF_MAX_FLOWS; ++i)
if (fset_has(server.flows, i) &&
- ts_diff_ms(&server.times[i], &now)
+ ts_diff_ms(&now, &server.times[i])
> server.timeout) {
printf("Flow %d timed out.\n", i);
fset_del(server.flows, i);
diff --git a/src/tools/oping/oping.c b/src/tools/oping/oping.c
index ed3529e5..87c1ee18 100644
--- a/src/tools/oping/oping.c
+++ b/src/tools/oping/oping.c
@@ -77,7 +77,7 @@
" -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" \
+" -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" \
@@ -244,8 +244,6 @@ int main(int argc,
client.qs = qos_voice;
else if (strcmp(qos, "data") == 0)
client.qs = qos_data;
- else if (strcmp(qos, "raw_crypt") == 0)
- client.qs = qos_raw_crypt;
else
printf("Unknown QoS cube, defaulting to raw.\n");
}
diff --git a/src/tools/oping/oping_client.c b/src/tools/oping/oping_client.c
index 7b03c83d..5a9e03dc 100644
--- a/src/tools/oping/oping_client.c
+++ b/src/tools/oping/oping_client.c
@@ -100,7 +100,7 @@ void * reader(void * o)
sent.tv_sec = msg->tv_sec;
sent.tv_nsec = msg->tv_nsec;
- ms = ts_diff_us(&sent, &now) / 1000.0;
+ ms = ts_diff_us(&now, &sent) / 1000.0;
if (id < exp_id)
++client.ooo;
@@ -256,7 +256,7 @@ static int client_main(void)
printf("%zd out-of-order, ", client.ooo);
printf("%.0lf%% packet loss, ", client.sent == 0 ? 0 :
ceil(100 - (100 * (client.rcvd / (float) client.sent))));
- printf("time: %.3f ms\n", ts_diff_us(&tic, &toc) / 1000.0);
+ printf("time: %.3f ms\n", ts_diff_us(&toc, &tic) / 1000.0);
if (client.rcvd > 0) {
printf("rtt min/avg/max/mdev = %.3f/%.3f/%.3f/",
diff --git a/src/tools/oping/oping_server.c b/src/tools/oping/oping_server.c
index 6f76869c..c1d5e6e5 100644
--- a/src/tools/oping/oping_server.c
+++ b/src/tools/oping/oping_server.c
@@ -36,6 +36,8 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+ #include <ouroboros/hash.h>
+
void shutdown_server(int signo, siginfo_t * info, void * c)
{
(void) info;
@@ -67,7 +69,7 @@ void * cleaner_thread(void * o)
time_t diff;
pthread_mutex_lock(&server.lock);
- diff = ts_diff_ms(&server.times[i], &now);
+ diff = ts_diff_ms(&now, &server.times[i]);
pthread_mutex_unlock(&server.lock);
if (diff > deadline_ms) {
@@ -100,14 +102,15 @@ void * server_thread(void *o)
if (msg_len < 0)
continue;
+ if (!server.quiet)
+ printf("Received %d bytes on fd %d.\n",
+ msg_len, fd);
+
if (ntohl(msg->type) != ECHO_REQUEST) {
printf("Invalid message on fd %d.\n", fd);
continue;
}
- if (!server.quiet)
- printf("Received %d bytes on fd %d.\n", msg_len, fd);
-
clock_gettime(CLOCK_REALTIME, &now);
pthread_mutex_lock(&server.lock);
@@ -137,8 +140,8 @@ void * accept_thread(void * o)
while (true) {
fd = flow_accept(&qs, NULL);
if (fd < 0) {
- printf("Failed to accept flow.\n");
- break;
+ printf("Failed to accept flow: %d \n", fd);
+ continue;
}
printf("New flow %d.\n", fd);
diff --git a/src/tools/ovpn/ovpn.c b/src/tools/ovpn/ovpn.c
index 5333ff40..b25e3ea2 100644
--- a/src/tools/ovpn/ovpn.c
+++ b/src/tools/ovpn/ovpn.c
@@ -68,7 +68,6 @@ static void usage(void)
"server to connect to\n"
" -i, --ip IP address to give to TUN device\n"
" -m, --mask Subnet mask to give to TUN device\n"
- " -C, --crypt AES encryption (default: off)\n"
"\n"
" --help Display this help text and exit\n");
}
@@ -194,7 +193,6 @@ int main(int argc,
{{"ip", required_argument, NULL, 'i'},
{"mask", required_argument, NULL, 'm'},
{"name", required_argument, NULL, 'n'},
- {"crypt", no_argument, NULL, 'C'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
@@ -231,9 +229,6 @@ int main(int argc,
case 'n':
name = optarg;
break;
- case 'C':
- qs = qos_raw_crypt;
- break;
case 'h':
usage();
exit(EXIT_SUCCESS);
diff --git a/src/tools/time_utils.h b/src/tools/time_utils.h
index c17282dc..a4117f44 100644
--- a/src/tools/time_utils.h
+++ b/src/tools/time_utils.h
@@ -53,17 +53,17 @@
#include <sys/time.h>
/* functions for timespecs */
-#define ts_diff_ns(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * BILLION \
+#define ts_diff_ns(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * BILLION \
+ ((tx)->tv_nsec - (t0)->tv_nsec))
-#define ts_diff_us(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * MILLION \
+#define ts_diff_us(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * MILLION \
+ ((tx)->tv_nsec - (t0)->tv_nsec) / 1000L)
-#define ts_diff_ms(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * 1000L \
+#define ts_diff_ms(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * 1000L \
+ ((tx)->tv_nsec - (t0)->tv_nsec) / MILLION)
/* functions for timevals are the same */
-#define tv_diff_us(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * MILLION \
+#define tv_diff_us(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * MILLION \
+ ((tx)->tv_usec - (t0)->tv_usec) / 1000L)
-#define tv_diff_ms(t0, tx) (((tx)->tv_sec - (t0)->tv_sec) * 1000L \
+#define tv_diff_ms(tx, t0) (((tx)->tv_sec - (t0)->tv_sec) * 1000L \
+ ((tx)->tv_usec - (t0)->tv_usec) / MILLION)
/* functions for timespecs */