diff options
Diffstat (limited to 'src/lib')
57 files changed, 6925 insertions, 2233 deletions
diff --git a/src/lib/.gitignore b/src/lib/.gitignore index 8704469b..3ecaf66d 100644 --- a/src/lib/.gitignore +++ b/src/lib/.gitignore @@ -1 +1 @@ -*.pb-c.[ch]
\ No newline at end of file +*.pb-c.[ch] diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 022c5cca..04a8f089 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -4,13 +4,18 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})  include_directories(${CMAKE_SOURCE_DIR}/include)  include_directories(${CMAKE_BINARY_DIR}/include) -protobuf_generate_c(IRM_PROTO_SRCS IRM_PROTO_HDRS irmd_messages.proto) -protobuf_generate_c(IPCP_PROTO_SRCS IPCP_PROTO_HDRS ipcpd_messages.proto) -protobuf_generate_c(QOSSPEC_PROTO_SRCS QOSSPEC_PROTO_HDRS -  qosspec.proto) -protobuf_generate_c(LAYER_CONFIG_PROTO_SRCS LAYER_CONFIG_PROTO_HDRS -  ipcp_config.proto) -protobuf_generate_c(CACEP_PROTO_SRCS CACEP_PROTO_HDRS cacep.proto) +protobuf_generate_c(MODEL_PROTO_SRCS MODEL_PROTO_HDRS +  pb/model.proto) +protobuf_generate_c(IPCP_CONFIG_PROTO_SRCS IPCP_CONFIG_PROTO_HDRS +  pb/ipcp_config.proto) +protobuf_generate_c(ENROLL_PROTO_SRCS ENROLL_PROTO_HDRS +  pb/enroll.proto) +protobuf_generate_c(CEP_PROTO_SRCS CEP_PROTO_HDRS +  pb/cep.proto) +protobuf_generate_c(IRM_PROTO_SRCS IRM_PROTO_HDRS +  pb/irm.proto) +protobuf_generate_c(IPCP_PROTO_SRCS IPCP_PROTO_HDRS +  pb/ipcp.proto)  if (NOT APPLE)    find_library(LIBRT_LIBRARIES rt) @@ -41,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) @@ -107,17 +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") @@ -140,10 +152,10 @@ if (NOT ((CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") OR APPLE OR  endif ()  mark_as_advanced(LIBRT_LIBRARIES LIBPTHREAD_LIBRARIES -  LIBGCRYPT_LIBRARIES OPENSSL_LIBRARIES SYS_RND_INCLUDE_DIR -  LIBGCRYPT_INCLUDE_DIR SYS_RND_HDR) +  LIBGCRYPT_LIBRARIES OPENSSL_LIBRARIES OPENSSL_CRYPTO_LIBRARY +  SYS_RND_INCLUDE_DIR LIBGCRYPT_INCLUDE_DIR SYS_RND_HDR) -set(SHM_BUFFER_SIZE 4096 CACHE STRING +set(SHM_BUFFER_SIZE 16384 CACHE STRING      "Number of blocks in packet buffer, must be a power of 2")  set(SHM_RBUFF_SIZE 1024 CACHE STRING      "Number of blocks in rbuff buffer, must be a power of 2") @@ -166,7 +178,7 @@ else ()    set(PTHREAD_COND_CLOCK "CLOCK_REALTIME" CACHE INTERNAL      "Clock to use for condition variable timing")  endif () -set(SOCKET_TIMEOUT 1000 CACHE STRING +set(SOCKET_TIMEOUT 500 CACHE STRING    "Default timeout for responses from IPCPs (ms)")  set(SHM_PREFIX "ouroboros" CACHE STRING    "String to prepend to POSIX shared memory filenames") @@ -192,12 +204,16 @@ set(DELTA_T_ACK 10 CACHE STRING    "Maximum time to acknowledge a packet (s)")  set(DELTA_T_RTX 120 CACHE STRING    "Maximum time to retransmit a packet (s)") -set(DELTA_T_ACK_DELAY 10 CACHE STRING -  "Maximum time to wait before acknowledging a packet (ms)")  set(FRCT_REORDER_QUEUE_SIZE 256 CACHE STRING    "Size of the reordering queue, must be a power of 2")  set(FRCT_START_WINDOW 64 CACHE STRING    "Start window, must be a power of 2") +set(FRCT_LINUX_RTT_ESTIMATOR TRUE CACHE BOOL +  "Use Linux RTT estimator formula instead of the TCP RFC formula") +set(FRCT_RTO_MDEV_MULTIPLIER 2 CACHE STRING +  "Multiplier for deviation term in the RTO: RTO = sRTT + (mdev << X)") +set(FRCT_RTO_INC_FACTOR 0 CACHE STRING +  "Divisor for RTO increase after timeout: RTO += RTX >> X, 0: Karn/Partridge")  set(FRCT_RTO_MIN 250 CACHE STRING    "Minimum Retransmission Timeout (RTO) for FRCT (us)")  set(FRCT_TICK_TIME 5000 CACHE STRING @@ -214,10 +230,14 @@ set(RXM_WHEEL_LEVELS 3 CACHE STRING    "Number of levels in the retransmission wheel")  set(RXM_WHEEL_SLOTS_PER_LEVEL 256 CACHE STRING    "Number of slots per level in the retransmission wheel, must be a power of 2") -set(ACK_WHEEL_SLOTS 128 CACHE STRING +set(ACK_WHEEL_SLOTS 256 CACHE STRING    "Number of slots in the acknowledgment wheel, must be a power of 2") -set(ACK_WHEEL_RESOLUTION 20 CACHE STRING +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 @@ -231,7 +251,7 @@ endif ()  set(SOURCE_FILES_DEV    # Add source files here -  cacep.c +  cep.c    dev.c    ) @@ -243,15 +263,19 @@ set(SOURCE_FILES_COMMON    bitmap.c    btree.c    crc32.c +  crypt.c    hash.c    list.c    lockfile.c    logs.c    md5.c    notifier.c +  protobuf.c    qoscube.c    random.c    rib.c +  serdes-irm.c +  serdes-oep.c    sha3.c    shm_flow_set.c    shm_rbuff.c @@ -265,12 +289,23 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"    "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)  add_library(ouroboros-common SHARED ${SOURCE_FILES_COMMON} ${IRM_PROTO_SRCS} -  ${IPCP_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS} ${QOSSPEC_PROTO_SRCS}) +  ${IPCP_PROTO_SRCS} ${IPCP_CONFIG_PROTO_SRCS} ${MODEL_PROTO_SRCS} +  ${ENROLL_PROTO_SRCS} ${OPENSSL_SOURCES}) -add_library(ouroboros-dev SHARED ${SOURCE_FILES_DEV} ${CACEP_PROTO_SRCS}) +add_library(ouroboros-dev SHARED ${SOURCE_FILES_DEV} ${CEP_PROTO_SRCS})  add_library(ouroboros-irm SHARED ${SOURCE_FILES_IRM}) +set_target_properties(ouroboros-common PROPERTIES +  VERSION ${PACKAGE_VERSION} +  SOVERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}) +set_target_properties(ouroboros-dev PROPERTIES +  VERSION ${PACKAGE_VERSION} +  SOVERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}) +set_target_properties(ouroboros-irm PROPERTIES +  VERSION ${PACKAGE_VERSION} +  SOVERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}) +  include(AddCompileFlags)  if (CMAKE_BUILD_TYPE MATCHES "Debug*")    add_compile_flags(ouroboros-common -DCONFIG_OUROBOROS_DEBUG) @@ -279,7 +314,7 @@ if (CMAKE_BUILD_TYPE MATCHES "Debug*")  endif ()  target_link_libraries(ouroboros-common ${LIBRT_LIBRARIES} -  ${LIBPTHREAD_LIBRARIES} ${PROTOBUF_C_LIBRARY} ${OPENSSL_LIBRARIES} +  ${LIBPTHREAD_LIBRARIES} ${PROTOBUF_C_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}    ${LIBGCRYPT_LIBRARIES} ${FUSE_LIBRARIES})  target_link_libraries(ouroboros-dev ouroboros-common) diff --git a/src/lib/bitmap.c b/src/lib/bitmap.c index 0c551960..b0840c44 100644 --- a/src/lib/bitmap.c +++ b/src/lib/bitmap.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Bitmap implementation   * diff --git a/src/lib/btree.c b/src/lib/btree.c index 64b8689e..1af94b73 100644 --- a/src/lib/btree.c +++ b/src/lib/btree.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * B-trees   * diff --git a/src/lib/cacep.c b/src/lib/cep.c index e8d21d8e..ba238023 100644 --- a/src/lib/cacep.c +++ b/src/lib/cep.c @@ -1,7 +1,7 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   * - * The Common Application Connection Establishment Protocol + * The Ouroboros Connection Establishment Protocol   *   *    Dimitri Staessens <dimitri@ouroboros.rocks>   *    Sander Vrijders   <sander@ouroboros.rocks> @@ -22,35 +22,35 @@  #define _POSIX_C_SOURCE 199309L -#include <ouroboros/cacep.h> +#include <ouroboros/cep.h>  #include <ouroboros/dev.h>  #include <ouroboros/errno.h>  #include <stdlib.h>  #include <string.h> -#include "cacep.pb-c.h" -typedef CacepMsg cacep_msg_t; +#include "cep.pb-c.h" +typedef CepMsg cep_msg_t;  #define BUF_SIZE 128  static int read_msg(int                fd,                      struct conn_info * info)  { -        uint8_t                      buf[BUF_SIZE]; -        cacep_msg_t *                msg; -        ssize_t                      len; +        uint8_t     buf[BUF_SIZE]; +        cep_msg_t * msg; +        ssize_t     len;          len = flow_read(fd, buf, BUF_SIZE);          if (len < 0) -                return -1; +                return (int) len; -        msg = cacep_msg__unpack(NULL, len, buf); +        msg = cep_msg__unpack(NULL, len, buf);          if (msg == NULL)                  return -1; -        if (strlen(msg->comp_name) > CACEP_BUF_STRLEN) { -                cacep_msg__free_unpacked(msg, NULL); +        if (strlen(msg->comp_name) > OCEP_BUF_STRLEN) { +                cep_msg__free_unpacked(msg, NULL);                  return -1;          } @@ -61,7 +61,7 @@ static int read_msg(int                fd,          info->pref_syntax  = msg->pref_syntax;          info->addr         = msg->address; -        cacep_msg__free_unpacked(msg, NULL); +        cep_msg__free_unpacked(msg, NULL);          return 0;  } @@ -69,9 +69,9 @@ static int read_msg(int                fd,  static int send_msg(int                      fd,                      const struct conn_info * info)  { -        cacep_msg_t msg = CACEP_MSG__INIT; -        uint8_t *   data = NULL; -        size_t      len  = 0; +        cep_msg_t msg = CEP_MSG__INIT; +        uint8_t * data = NULL; +        size_t    len  = 0;          msg.comp_name    = (char *) info->comp_name;          msg.protocol     = (char *) info->protocol; @@ -81,7 +81,7 @@ static int send_msg(int                      fd,          if (msg.pref_syntax < 0)                  return -1; -        len = cacep_msg__get_packed_size(&msg); +        len = cep_msg__get_packed_size(&msg);          if (len == 0)                  return -1; @@ -89,7 +89,7 @@ static int send_msg(int                      fd,          if (data == NULL)                  return -ENOMEM; -        cacep_msg__pack(&msg, data); +        cep_msg__pack(&msg, data);          if (flow_write(fd, data, len) < 0) {                  free(data); @@ -101,26 +101,20 @@ static int send_msg(int                      fd,          return 0;  } -int cacep_snd(int                      fd, -              const struct conn_info * in) +int cep_snd(int                      fd, +            const struct conn_info * in)  {          if (in == NULL)                  return -EINVAL; -        if (send_msg(fd, in)) -                return -1; - -        return 0; +        return send_msg(fd, in);  } -int cacep_rcv(int                fd, -              struct conn_info * out) +int cep_rcv(int                fd, +            struct conn_info * out)  {          if (out == NULL)                  return -EINVAL; -        if (read_msg(fd, out)) -                return -1; - -        return 0; +        return read_msg(fd, out);  } diff --git a/src/lib/config.h.in b/src/lib/config.h.in index 5c5b6caf..8326a332 100644 --- a/src/lib/config.h.in +++ b/src/lib/config.h.in @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Ouroboros library configuration   * @@ -28,20 +28,24 @@  #define HAVE_ENCRYPTION  #endif -#define SYS_MAX_FLOWS       @SYS_MAX_FLOWS@ +#define SYS_MAX_FLOWS            @SYS_MAX_FLOWS@ -#cmakedefine                SHM_RBUFF_LOCKLESS -#cmakedefine                SHM_RDRB_MULTI_BLOCK -#cmakedefine                QOS_DISABLE_CRC -#cmakedefine                HAVE_OPENSSL_RNG +#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 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 */ @@ -69,15 +73,15 @@  #define DU_BUFF_TAILSPACE   @DU_BUFF_TAILSPACE@  /* Default Delta-t parameters */ -#define DELT_MPL            (@DELTA_T_MPL@ * BILLION)        /* ns */ -#define DELT_A              (@DELTA_T_ACK@ * BILLION)        /* ns */ -#define DELT_R              (@DELTA_T_RTX@ * BILLION)        /* ns */ - -#define DELT_ACK            (@DELTA_T_ACK_DELAY@ * MILLION)  /* ns */ +#cmakedefine                FRCT_LINUX_RTT_ESTIMATOR +#define DELT_A              (@DELTA_T_ACK@)                  /* ns */ +#define DELT_R              (@DELTA_T_RTX@)                  /* ns */  #define RQ_SIZE             (@FRCT_REORDER_QUEUE_SIZE@)  #define START_WINDOW        (@FRCT_START_WINDOW@)  #define RTO_MIN             (@FRCT_RTO_MIN@ * 1000) +#define RTO_DIV             (@FRCT_RTO_INC_FACTOR@) +#define MDEV_MUL            (@FRCT_RTO_MDEV_MULTIPLIER@)  #define TICTIME             (@FRCT_TICK_TIME@ * 1000)        /* ns */ diff --git a/src/lib/crc32.c b/src/lib/crc32.c index cd267faf..f369ad20 100644 --- a/src/lib/crc32.c +++ b/src/lib/crc32.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * 32-bit Cyclic Redundancy Check   * diff --git a/src/lib/crypt.c b/src/lib/crypt.c index 070f5113..8b18140e 100644 --- a/src/lib/crypt.c +++ b/src/lib/crypt.c @@ -1,8 +1,7 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * 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> @@ -21,428 +20,419 @@   * 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 <openssl/evp.h> -#include <openssl/ec.h> -#include <openssl/pem.h> +#include <assert.h> +#include <string.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, ¶ms); -        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; - -        assert(pkp != NULL); -        assert(*pkp == NULL); -        assert(pk != NULL); - -        if (__openssl_ecdh_gen_key(pkp) < 0) -                return -ECRYPT; +        struct crypt_ctx * crypt; -        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, -                               uint8_t * pk, -                               size_t    len, -                               uint8_t * s) +int crypt_load_privkey_file(const char * path, +                            void **      key)  { -        uint8_t *  pos; -        EVP_PKEY * pub; - -        pos = pk; /* d2i_PUBKEY increments the pointer, don't use key ptr! */ -        pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) len); -        if (pub == NULL) -                return -ECRYPT; - -        if (__openssl_ecdh_derive_secret(pkp, pub, s) < 0) { -                EVP_PKEY_free(pub); -                return -ECRYPT; -        } +        *key = NULL; -        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(struct flow *        f, -                           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; +        *key = NULL; -        in = shm_du_buff_head(sdb); -        in_sz = shm_du_buff_tail(sdb) - in; - -        if (random_buffer(iv, IVSZ) < 0) -                goto fail_iv; - -        out = malloc(in_sz + EVP_MAX_BLOCK_LENGTH); -        if (out == NULL) -                goto fail_iv; - -        EVP_CIPHER_CTX_reset(f->ctx); - -        ret = EVP_EncryptInit_ex(f->ctx, -                                 EVP_aes_256_cbc(), -                                 NULL, -                                 f->key, -                                 iv); -        if (ret != 1) -                goto fail_encrypt_init; - -        ret = EVP_EncryptUpdate(f->ctx, out, &tmp_sz, in, in_sz); -        if (ret != 1) -                goto fail_encrypt; - -        out_sz = tmp_sz; -        ret =  EVP_EncryptFinal_ex(f->ctx, out + tmp_sz, &tmp_sz); -        if (ret != 1) -                goto fail_encrypt; - -        out_sz += tmp_sz; - -        EVP_CIPHER_CTX_cleanup(f->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(f->ctx); - fail_encrypt_init: -        free(out); - fail_iv: -        return -ECRYPT; +#endif  } -static int openssl_decrypt(struct flow *        f, -                           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 = shm_du_buff_head_release(sdb, IVSZ); +#ifdef HAVE_OPENSSL +        openssl_free_key(key); +#endif +} -        memcpy(iv, in, IVSZ); +int crypt_load_crt_file(const char * path, +                        void **      crt) +{ +        assert(crt != NULL); -        in = shm_du_buff_head(sdb); +        *crt = NULL; -        in_sz = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); +#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(f->ctx); +int crypt_load_crt_str(const char * str, +                       void **      crt) +{ +        assert(crt != NULL); -        ret = EVP_DecryptInit_ex(f->ctx, -                                 EVP_aes_256_cbc(), -                                 NULL, -                                 f->key, -                                 iv); -        if (ret != 1) -                goto fail_decrypt_init; +        *crt = NULL; -        ret = EVP_DecryptUpdate(f->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(f->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(f->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 */ - -static 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; -        memset(pk, 0, MSGBUFSZ); -        *pkp = NULL; +        clrbuf(*buf);          return 0;  #endif  } -static 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  } -static int crypt_dh_derive(void *    pkp, -                           uint8_t * pk, -                           size_t    len, -                           uint8_t * s) +struct auth_ctx * auth_create_ctx(void)  { -#ifdef HAVE_OPENSSL -        return openssl_ecdh_derive(pkp, pk, len, s); -#else -        (void) pkp; -        (void) pk; -        (void) len; +        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; +} + +void auth_destroy_ctx(struct auth_ctx * ctx) +{ +        if (ctx == NULL) +                return; +#ifdef HAVE_OPENSSL +        openssl_auth_destroy_store(ctx->store);  #endif +        free(ctx);  } -static int crypt_encrypt(struct flow *        f, -                         struct shm_du_buff * sdb) +int auth_add_crt_to_store(struct auth_ctx * ctx, +                          void *            crt)  { +        assert(ctx != NULL); +        assert(crt != NULL); +  #ifdef HAVE_OPENSSL -        return openssl_encrypt(f, sdb); +        return openssl_auth_add_crt_to_store(ctx->store, crt);  #else -        (void) f; -        (void) sdb; +        (void) ctx; +        (void) crt;          return 0;  #endif  } -static int crypt_decrypt(struct flow *        f, -                         struct shm_du_buff * sdb) +int auth_verify_crt(struct auth_ctx * ctx, +                    void *            crt)  {  #ifdef HAVE_OPENSSL -        return openssl_decrypt(f, sdb); +        return openssl_verify_crt(ctx->store, crt);  #else -        (void) f; -        (void) sdb; +        (void) ctx; +        (void) crt; -        return -ECRYPT; +        return 0;  #endif  } -static int crypt_init(void ** ctx) +int auth_sign(void *     pkp, +              buffer_t   msg, +              buffer_t * sig)  {  #ifdef HAVE_OPENSSL -        return openssl_crypt_init(ctx); +        return openssl_sign(pkp, msg, sig);  #else -        assert(ctx != NULL); -        *ctx = NULL; +        (void) pkp; +        (void) msg; +        (void) sig; + +        clrbuf(*sig);          return 0;  #endif  } -static void crypt_fini(void * ctx) +int auth_verify_sig(void *   pk, +                    buffer_t msg, +                    buffer_t sig)  {  #ifdef HAVE_OPENSSL -        openssl_crypt_fini(ctx); +        return openssl_verify_sig(pk, msg, sig);  #else -        assert(ctx == NULL); -        (void) ctx; +        (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, ¶ms); +        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 723e3350..cb483aca 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * API for applications   * @@ -28,26 +28,36 @@  #include "config.h" -#include <ouroboros/hash.h> -#include <ouroboros/cacep.h> -#include <ouroboros/errno.h> +#include <ouroboros/bitmap.h> +#include <ouroboros/cep.h> +#include <ouroboros/crypt.h>  #include <ouroboros/dev.h> +#include <ouroboros/errno.h> +#include <ouroboros/fccntl.h> +#include <ouroboros/flow.h> +#include <ouroboros/fqueue.h> +#include <ouroboros/hash.h> +#include <ouroboros/ipcp.h>  #include <ouroboros/ipcp-dev.h> +#include <ouroboros/list.h>  #include <ouroboros/local-dev.h> -#include <ouroboros/sockets.h> -#include <ouroboros/fccntl.h> -#include <ouroboros/bitmap.h> +#include <ouroboros/np1_flow.h>  #include <ouroboros/pthread.h>  #include <ouroboros/random.h> +#include <ouroboros/serdes-irm.h>  #include <ouroboros/shm_flow_set.h>  #include <ouroboros/shm_rdrbuff.h>  #include <ouroboros/shm_rbuff.h> +#include <ouroboros/sockets.h>  #include <ouroboros/utils.h> -#include <ouroboros/fqueue.h>  #ifdef PROC_FLOW_STATS  #include <ouroboros/rib.h>  #endif +#ifdef HAVE_LIBGCRYPT +#include <gcrypt.h> +#endif +#include <assert.h>  #include <stdlib.h>  #include <string.h>  #include <stdio.h> @@ -65,51 +75,34 @@  #define CRCLEN    (sizeof(uint32_t))  #define SECMEMSZ  16384 -#define SYMMKEYSZ 32  #define MSGBUFSZ  2048 -struct flow_set { -        size_t idx; -}; - -struct fqueue { -        int    fqueue[2 * SHM_BUFFER_SIZE]; /* Safe copy from shm. */ -        size_t fqsize; -        size_t next; -}; - -enum port_state { -        PORT_NULL = 0, -        PORT_INIT, -        PORT_ID_PENDING, -        PORT_ID_ASSIGNED, -        PORT_DESTROY -}; - -struct port { +/* map flow_ids to flow descriptors; track state of the flow */ +struct fmap {          int             fd; - -        enum port_state state; -        pthread_mutex_t state_lock; -        pthread_cond_t  state_cond; +        /* TODO: use actual flow state */ +        enum flow_state state;  };  #define frcti_to_flow(frcti) \          ((struct flow *)((uint8_t *) frcti - offsetof(struct flow, frcti)))  struct flow { +        struct list_head      next; + +        struct flow_info      info; +          struct shm_rbuff *    rx_rb;          struct shm_rbuff *    tx_rb;          struct shm_flow_set * set; -        int                   flow_id; -        int                   oflags; -        qosspec_t             qs; + +        uint16_t              oflags;          ssize_t               part_idx; -        void *                ctx; -        uint8_t               key[SYMMKEYSZ]; +        struct crypt_ctx *    crypt; -        pid_t                 pid; +        struct timespec       snd_act; +        struct timespec       rcv_act;          bool                  snd_timesout;          bool                  rcv_timesout; @@ -119,148 +112,362 @@ struct flow {          struct frcti *        frcti;  }; -struct { -        char *                prog; -        pid_t                 pid; +struct flow_set { +        size_t           idx; +        pthread_rwlock_t lock; +}; +struct fqueue { +        struct flowevent fqueue[SHM_BUFFER_SIZE]; /* Safe copy from shm. */ +        size_t           fqsize; +        size_t           next; +}; + +struct {          struct shm_rdrbuff *  rdrb;          struct shm_flow_set * fqset; -        struct timerwheel *   tw; -          struct bmp *          fds;          struct bmp *          fqueues;          struct flow *         flows; -        struct port *         ports; +        struct fmap *         id_to_fd; +        struct list_head      flow_list; + +        pthread_mutex_t       mtx; +        pthread_cond_t        cond; + +        pthread_t             tx; +        pthread_t             rx; +        size_t                n_frcti; +        fset_t *              frct_set;          pthread_rwlock_t      lock;  } ai; -#include "frct.c" - -static void port_destroy(struct port * p) +static void flow_destroy(struct fmap * p)  { -        pthread_mutex_lock(&p->state_lock); +        pthread_mutex_lock(&ai.mtx); -        if (p->state == PORT_DESTROY) { -                pthread_mutex_unlock(&p->state_lock); +        if (p->state == FLOW_DESTROY) { +                pthread_mutex_unlock(&ai.mtx);                  return;          } -        if (p->state == PORT_ID_PENDING) -                p->state = PORT_DESTROY; +        if (p->state == FLOW_ALLOC_PENDING) +                p->state = FLOW_DESTROY;          else -                p->state = PORT_NULL; +                p->state = FLOW_NULL; -        pthread_cond_signal(&p->state_cond); +        pthread_cond_signal(&ai.cond); -        while (p->state != PORT_NULL) -                pthread_cond_wait(&p->state_cond, &p->state_lock); +        pthread_cleanup_push(__cleanup_mutex_unlock, &ai.mtx); -        p->fd = -1; -        p->state = PORT_INIT; +        while (p->state != FLOW_NULL) +                pthread_cond_wait(&ai.cond, &ai.mtx); -        pthread_mutex_unlock(&p->state_lock); +        p->fd    = -1; +        p->state = FLOW_INIT; + +        pthread_cleanup_pop(true);  } -static void port_set_state(struct port *   p, -                           enum port_state state) +static void flow_set_state(struct fmap *   p, +                           enum flow_state state)  { -        pthread_mutex_lock(&p->state_lock); +        pthread_mutex_lock(&ai.mtx); -        if (p->state == PORT_DESTROY) { -                pthread_mutex_unlock(&p->state_lock); +        if (p->state == FLOW_DESTROY) { +                pthread_mutex_unlock(&ai.mtx);                  return;          }          p->state = state; -        pthread_cond_broadcast(&p->state_cond); +        pthread_cond_broadcast(&ai.cond); -        pthread_mutex_unlock(&p->state_lock); +        pthread_mutex_unlock(&ai.mtx);  } -static enum port_state port_wait_assign(int flow_id) +static enum flow_state flow_wait_assign(int flow_id)  { -        enum port_state state; -        struct port *   p; +        enum flow_state state; +        struct fmap *   p; -        p = &ai.ports[flow_id]; +        p = &ai.id_to_fd[flow_id]; -        pthread_mutex_lock(&p->state_lock); +        pthread_mutex_lock(&ai.mtx); -        if (p->state == PORT_ID_ASSIGNED) { -                pthread_mutex_unlock(&p->state_lock); -                return PORT_ID_ASSIGNED; +        if (p->state == FLOW_ALLOCATED) { +                pthread_mutex_unlock(&ai.mtx); +                return FLOW_ALLOCATED;          } -        if (p->state == PORT_INIT) -                p->state = PORT_ID_PENDING; +        if (p->state == FLOW_INIT) +                p->state = FLOW_ALLOC_PENDING; + +        pthread_cleanup_push(__cleanup_mutex_unlock, &ai.mtx); -        while (p->state == PORT_ID_PENDING) -                pthread_cond_wait(&p->state_cond, &p->state_lock); +        while (p->state == FLOW_ALLOC_PENDING) +                pthread_cond_wait(&ai.cond, &ai.mtx); -        if (p->state == PORT_DESTROY) { -                p->state = PORT_NULL; -                pthread_cond_broadcast(&p->state_cond); +        if (p->state == FLOW_DESTROY) { +                p->state = FLOW_NULL; +                pthread_cond_broadcast(&ai.cond);          }          state = p->state; -        assert(state != PORT_INIT); +        pthread_cleanup_pop(true); -        pthread_mutex_unlock(&p->state_lock); +        assert(state != FLOW_INIT);          return state;  } -static int proc_announce(char * prog) +static int proc_announce(const char * prog) +{ +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; +        int              err; + +        if (proc_announce__irm_req_ser(&msg, prog) < 0) +                return -ENOMEM; + +        err = send_recv_msg(&msg); +        if (err < 0) +                return err; + +        return irm__irm_result_des(&msg); +} + +/* IRMd will clean up the mess if this fails */ +static void proc_exit(void) +{ +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; + +        if (proc_exit__irm_req_ser(&msg) < 0) +                return; + +        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)  { -        irm_msg_t   msg = IRM_MSG__INIT; -        irm_msg_t * recv_msg; -        int         ret = -1; - -        msg.code    = IRM_MSG_CODE__IRM_PROC_ANNOUNCE; -        msg.has_pid = true; -        msg.pid     = ai.pid; -        msg.prog    = prog; - -        recv_msg = send_recv_irm_msg(&msg); -        if (recv_msg == NULL) { -                return -EIRMD; +        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) +{ +        struct timespec tic = TIMESPEC_INIT_NS(TICTIME); + +        (void) o; + +        while (true) { +                timerwheel_move(); + +                nanosleep(&tic, NULL);          } -        if (!recv_msg->has_result || (ret = recv_msg->result)) { -                irm_msg__free_unpacked(recv_msg, NULL); -                return ret; +        return (void *) 0; +} + +static void flow_send_keepalive(struct flow * flow, +                                struct timespec now) +{ +        struct shm_du_buff * sdb; +        ssize_t              idx; +        uint8_t *            ptr; + +        idx = shm_rdrbuff_alloc(ai.rdrb, 0, &ptr, &sdb); +        if (idx < 0) +                return; + +        pthread_rwlock_wrlock(&ai.lock); + +        flow->snd_act = now; + +        if (shm_rbuff_write(flow->tx_rb, idx)) +                shm_rdrbuff_remove(ai.rdrb, idx); +        else +                shm_flow_set_notify(flow->set, flow->info.id, FLOW_PKT); + +        pthread_rwlock_unlock(&ai.lock); +} + +/* Needs rdlock on ai. */ +static void _flow_keepalive(struct flow * flow) +{ +        struct timespec    now; +        struct timespec    s_act; +        struct timespec    r_act; +        int                flow_id; +        time_t             timeo; +        uint32_t           acl; + +        s_act = flow->snd_act; +        r_act = flow->rcv_act; + +        flow_id = flow->info.id; +        timeo   = flow->info.qs.timeout; + +        acl = shm_rbuff_get_acl(flow->rx_rb); +        if (timeo == 0 || acl & (ACL_FLOWPEER | ACL_FLOWDOWN)) +                return; + +        clock_gettime(PTHREAD_COND_CLOCK, &now); + +        if (ts_diff_ns(&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;          } -        irm_msg__free_unpacked(recv_msg, NULL); +        if (ts_diff_ns(&now, &s_act) > (int64_t) timeo * (MILLION >> 2)) { +                pthread_rwlock_unlock(&ai.lock); + +                flow_send_keepalive(flow, now); -        return ret; +                pthread_rwlock_rdlock(&ai.lock); +        } +} + +static void handle_keepalives(void) +{ +        struct list_head * p; +        struct list_head * h; + +        pthread_rwlock_rdlock(&ai.lock); + +        list_for_each_safe(p, h, &ai.flow_list) { +                struct flow * flow; +                flow = list_entry(p, struct flow, next); +                _flow_keepalive(flow); +        } + +        pthread_rwlock_unlock(&ai.lock); +} + +static void __cleanup_fqueue_destroy(void * fq) +{ +        fqueue_destroy((fqueue_t *) fq); +} + +void * flow_rx(void * o) +{ +        struct timespec tic = TIMESPEC_INIT_NS(TICTIME); +        int             ret; +        struct fqueue * fq; + +        (void) o; + +        fq = fqueue_create(); + +        pthread_cleanup_push(__cleanup_fqueue_destroy, fq); + +        /* fevent will filter all FRCT packets for us */ +        while ((ret = fevent(ai.frct_set, fq, &tic)) != 0) { +                if (ret == -ETIMEDOUT) { +                        handle_keepalives(); +                        continue; +                } + +                while (fqueue_next(fq) >= 0) +                        ; /* no need to act */ +        } + +        pthread_cleanup_pop(true); + +        return (void *) 0;  }  static void flow_clear(int fd)  {          memset(&ai.flows[fd], 0, sizeof(ai.flows[fd])); -        ai.flows[fd].flow_id  = -1; -        ai.flows[fd].pid      = -1; +        ai.flows[fd].info.id  = -1;  } -#include "crypt.c" - -static void flow_fini(int fd) +static void __flow_fini(int fd)  {          assert(fd >= 0 && fd < SYS_MAX_FLOWS); -        if (ai.flows[fd].flow_id != -1) { -                port_destroy(&ai.ports[ai.flows[fd].flow_id]); -                bmp_release(ai.fds, fd); -        } +        if (ai.flows[fd].frcti != NULL) { +                ai.n_frcti--; +                if (ai.n_frcti == 0) { +                        pthread_cancel(ai.tx); +                        pthread_join(ai.tx, NULL); +                } + +                shm_flow_set_del(ai.fqset, 0, ai.flows[fd].info.id); -        if (ai.flows[fd].frcti != NULL)                  frcti_destroy(ai.flows[fd].frcti); +        } + +        if (ai.flows[fd].info.id != -1) { +                flow_destroy(&ai.id_to_fd[ai.flows[fd].info.id]); +                bmp_release(ai.fds, fd); +        }          if (ai.flows[fd].rx_rb != NULL) {                  shm_rbuff_set_acl(ai.flows[fd].rx_rb, ACL_FLOWDOWN); @@ -274,24 +481,36 @@ static void flow_fini(int fd)          if (ai.flows[fd].set != NULL) {                  shm_flow_set_notify(ai.flows[fd].set, -                                    ai.flows[fd].flow_id, +                                    ai.flows[fd].info.id,                                      FLOW_DEALLOC);                  shm_flow_set_close(ai.flows[fd].set);          } -        if (ai.flows[fd].ctx != NULL) -                crypt_fini(ai.flows[fd].ctx); +        crypt_destroy_ctx(ai.flows[fd].crypt); + +        list_del(&ai.flows[fd].next);          flow_clear(fd);  } -static int flow_init(int       flow_id, -                     pid_t     pid, -                     qosspec_t qs, -                     uint8_t * s) +static void flow_fini(int fd)  { -        int fd; -        int err = -ENOMEM; +        pthread_rwlock_wrlock(&ai.lock); + +        __flow_fini(fd); + +        pthread_rwlock_unlock(&ai.lock); +} + +static int flow_init(struct flow_info * info, +                     buffer_t *         sk) +{ +        struct timespec now; +        struct flow *   flow; +        int             fd; +        int             err = -ENOMEM; + +        clock_gettime(PTHREAD_COND_CLOCK, &now);          pthread_rwlock_wrlock(&ai.lock); @@ -301,46 +520,73 @@ static int flow_init(int       flow_id,                  goto fail_fds;          } -        ai.flows[fd].rx_rb = shm_rbuff_open(ai.pid, flow_id); -        if (ai.flows[fd].rx_rb == NULL) +        flow = &ai.flows[fd]; + +        flow->info = *info; + +        flow->rx_rb = shm_rbuff_open(info->n_pid, info->id); +        if (flow->rx_rb == NULL)                  goto fail_rx_rb; -        ai.flows[fd].tx_rb = shm_rbuff_open(pid, flow_id); -        if (ai.flows[fd].tx_rb == NULL) +        flow->tx_rb = shm_rbuff_open(info->n_1_pid, info->id); +        if (flow->tx_rb == NULL)                  goto fail_tx_rb; -        ai.flows[fd].set = shm_flow_set_open(pid); -        if (ai.flows[fd].set == NULL) +        flow->set = shm_flow_set_open(info->n_1_pid); +        if (flow->set == NULL)                  goto fail_set; -        ai.flows[fd].flow_id  = flow_id; -        ai.flows[fd].oflags   = FLOWFDEFAULT; -        ai.flows[fd].pid      = pid; -        ai.flows[fd].part_idx = NO_PART; -        ai.flows[fd].qs       = qs; +        flow->oflags   = FLOWFDEFAULT; +        flow->part_idx = NO_PART; +        flow->snd_act  = now; +        flow->rcv_act  = now; +        flow->crypt    = NULL; + +        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); + +        if (info->qs.in_order != 0) { +                flow->frcti = frcti_create(fd, DELT_A, DELT_R, info->mpl); +                if (flow->frcti == NULL) +                        goto fail_frcti; -        if (qs.cypher_s > 0) { -                assert(s != NULL); -                if (crypt_init(&ai.flows[fd].ctx) < 0) -                        goto fail_ctx; +                if (shm_flow_set_add(ai.fqset, 0, info->id)) +                        goto fail_flow_set_add; -                memcpy(ai.flows[fd].key, s, SYMMKEYSZ); +                ++ai.n_frcti; +                if (ai.n_frcti == 1 && +                    pthread_create(&ai.tx, NULL, flow_tx, NULL) < 0) +                        goto fail_tx_thread;          } -        ai.ports[flow_id].fd = fd; +        list_add_tail(&flow->next, &ai.flow_list); + +        ai.id_to_fd[info->id].fd = fd; -        port_set_state(&ai.ports[flow_id], PORT_ID_ASSIGNED); +        flow_set_state(&ai.id_to_fd[info->id], FLOW_ALLOCATED);          pthread_rwlock_unlock(&ai.lock);          return fd; - fail_ctx: -        shm_flow_set_close(ai.flows[fd].set); + fail_tx_thread: +        shm_flow_set_del(ai.fqset, 0, info->id); + fail_flow_set_add: +        frcti_destroy(flow->frcti); + fail_frcti: +        crypt_destroy_ctx(flow->crypt); + fail_crypt: +        shm_flow_set_close(flow->set);   fail_set: -        shm_rbuff_close(ai.flows[fd].tx_rb); +        shm_rbuff_close(flow->tx_rb);   fail_tx_rb: -        shm_rbuff_close(ai.flows[fd].rx_rb); +        shm_rbuff_close(flow->rx_rb);   fail_rx_rb:          bmp_release(ai.fds, fd);   fail_fds: @@ -362,110 +608,143 @@ static void init(int     argc,                   char ** argv,                   char ** envp)  { -        const char * prog = argv[0]; -        int          i; +        char * prog = argv[0]; +        int    i;  #ifdef PROC_FLOW_STATS -        char         procstr[32]; +        char   procstr[32];  #endif          (void) argc;          (void) envp; -        assert(ai.prog == NULL); -          if (check_python(argv[0]))                  prog = argv[1]; -        ai.pid = getpid(); +        prog = path_strip(prog); +        if (prog == NULL) { +                fprintf(stderr, "FATAL: Could not determine program name.\n"); +                goto fail_prog; +        } + +        if (proc_announce(prog)) { +                fprintf(stderr, "FATAL: Could not announce to IRMd.\n"); +                goto fail_prog; +        } +  #ifdef HAVE_LIBGCRYPT          if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { -                if (!gcry_check_version(GCRYPT_VERSION)) -                        goto fail_fds; +                if (!gcry_check_version(GCRYPT_VERSION)) { +                        fprintf(stderr, "FATAL: Could not get gcry version.\n"); +                        goto fail_prog; +                }                  gcry_control(GCRYCTL_DISABLE_SECMEM, 0);                  gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);          }  #endif          ai.fds = bmp_create(PROG_MAX_FLOWS - PROG_RES_FDS, PROG_RES_FDS); -        if (ai.fds == NULL) +        if (ai.fds == NULL) { +                fprintf(stderr, "FATAL: Could not create fd bitmap.\n");                  goto fail_fds; +        }          ai.fqueues = bmp_create(PROG_MAX_FQUEUES, 0); -        if (ai.fqueues == NULL) +        if (ai.fqueues == NULL) { +                fprintf(stderr, "FATAL: Could not create fqueue bitmap.\n");                  goto fail_fqueues; +        }          ai.rdrb = shm_rdrbuff_open(); -        if (ai.rdrb == NULL) +        if (ai.rdrb == NULL) { +                fprintf(stderr, "FATAL: Could not open packet buffer.\n");                  goto fail_rdrb; +        }          ai.flows = malloc(sizeof(*ai.flows) * PROG_MAX_FLOWS); -        if (ai.flows == NULL) +        if (ai.flows == NULL) { +                fprintf(stderr, "FATAL: Could not malloc flows.\n");                  goto fail_flows; +        }          for (i = 0; i < PROG_MAX_FLOWS; ++i)                  flow_clear(i); -        ai.ports = malloc(sizeof(*ai.ports) * SYS_MAX_FLOWS); -        if (ai.ports == NULL) -                goto fail_ports; +        ai.id_to_fd = malloc(sizeof(*ai.id_to_fd) * SYS_MAX_FLOWS); +        if (ai.id_to_fd == NULL) { +                fprintf(stderr, "FATAL: Could not malloc id_to_fd.\n"); +                goto fail_id_to_fd; +        } -        if (prog != NULL) { -                ai.prog = strdup(path_strip((char *) prog)); -                if (ai.prog == NULL) -                        goto fail_prog; +        for (i = 0; i < SYS_MAX_FLOWS; ++i) +                ai.id_to_fd[i].state = FLOW_INIT; -                if (proc_announce((char *) ai.prog)) -                        goto fail_announce; +        if (pthread_mutex_init(&ai.mtx, NULL)) { +                fprintf(stderr, "FATAL: Could not init mutex.\n"); +                goto fail_mtx;          } -        for (i = 0; i < SYS_MAX_FLOWS; ++i) { -                ai.ports[i].state = PORT_INIT; -                if (pthread_mutex_init(&ai.ports[i].state_lock, NULL)) { -                        int j; -                        for (j = 0; j < i; ++j) -                                pthread_mutex_destroy(&ai.ports[j].state_lock); -                        goto fail_announce; -                } -                if (pthread_cond_init(&ai.ports[i].state_cond, NULL)) { -                        int j; -                        for (j = 0; j < i; ++j) -                                pthread_cond_destroy(&ai.ports[j].state_cond); -                        goto fail_state_cond; -                } +        if (pthread_cond_init(&ai.cond, NULL) < 0) { +                fprintf(stderr, "FATAL: Could not init condvar.\n"); +                goto fail_cond;          } -        if (pthread_rwlock_init(&ai.lock, NULL)) -                goto fail_lock; +        if (pthread_rwlock_init(&ai.lock, NULL) < 0) { +                fprintf(stderr, "FATAL: Could not initialize flow lock.\n"); +                goto fail_flow_lock; +        }          ai.fqset = shm_flow_set_open(getpid()); -        if (ai.fqset == NULL) +        if (ai.fqset == NULL) { +                fprintf(stderr, "FATAL: Could not open flow set.\n");                  goto fail_fqset; +        } -        if (timerwheel_init() < 0) +        ai.frct_set = fset_create(); +        if (ai.frct_set == NULL || ai.frct_set->idx != 0) { +                fprintf(stderr, "FATAL: Could not create FRCT set.\n"); +                goto fail_frct_set; +        } + +        if (timerwheel_init() < 0) { +                fprintf(stderr, "FATAL: Could not initialize timerwheel.\n");                  goto fail_timerwheel; +        }  #if defined PROC_FLOW_STATS          if (strstr(argv[0], "ipcpd") == NULL) {                  sprintf(procstr, "proc.%d", getpid()); -                /* Don't bail on fail, it just won't show metrics */ -                rib_init(procstr); +                if (rib_init(procstr) < 0) { +                        fprintf(stderr, "FATAL: Could not initialize RIB.\n"); +                        goto fail_rib_init; +                }          }  #endif +        if (pthread_create(&ai.rx, NULL, flow_rx, NULL) < 0) { +                fprintf(stderr, "FATAL: Could not start monitor thread.\n"); +                goto fail_monitor; +        } + +        list_head_init(&ai.flow_list); +          return; + fail_monitor: +#if defined PROC_FLOW_STATS +        rib_fini(); + fail_rib_init: +#endif +        timerwheel_fini();   fail_timerwheel: +        fset_destroy(ai.frct_set); + fail_frct_set:          shm_flow_set_close(ai.fqset);   fail_fqset:          pthread_rwlock_destroy(&ai.lock); - fail_lock: -        for (i = 0; i < SYS_MAX_FLOWS; ++i) -                pthread_cond_destroy(&ai.ports[i].state_cond); - fail_state_cond: -        for (i = 0; i < SYS_MAX_FLOWS; ++i) -                pthread_mutex_destroy(&ai.ports[i].state_lock); - fail_announce: -        free(ai.prog); - fail_prog: -        free(ai.ports); - fail_ports: + fail_flow_lock: +        pthread_cond_destroy(&ai.cond); + fail_cond: +        pthread_mutex_destroy(&ai.mtx); + fail_mtx: +        free(ai.id_to_fd); + fail_id_to_fd:          free(ai.flows);   fail_flows:          shm_rdrbuff_close(ai.rdrb); @@ -474,60 +753,60 @@ static void init(int     argc,   fail_fqueues:          bmp_destroy(ai.fds);   fail_fds: -        fprintf(stderr, "FATAL: ouroboros-dev init failed. " -                        "Make sure an IRMd is running.\n\n");          memset(&ai, 0, sizeof(ai)); + fail_prog:          exit(EXIT_FAILURE);  }  static void fini(void)  { -        int  i = 0; -#ifdef PROC_FLOW_STATS -        char procstr[32]; - -        sprintf(procstr, "proc.%d", getpid()); -        rib_fini(); -#endif +        int  i;          if (ai.fds == NULL)                  return; -        if (ai.prog != NULL) -                free(ai.prog); +        pthread_cancel(ai.rx); +        pthread_join(ai.rx, NULL);          pthread_rwlock_wrlock(&ai.lock);          for (i = 0; i < PROG_MAX_FLOWS; ++i) { -                if (ai.flows[i].flow_id != -1) { +                if (ai.flows[i].info.id != -1) {                          ssize_t idx;                          shm_rbuff_set_acl(ai.flows[i].rx_rb, ACL_FLOWDOWN);                          while ((idx = shm_rbuff_read(ai.flows[i].rx_rb)) >= 0)                                  shm_rdrbuff_remove(ai.rdrb, idx); -                        flow_fini(i); +                        __flow_fini(i);                  }          } -        shm_flow_set_close(ai.fqset); +        pthread_cond_destroy(&ai.cond); +        pthread_mutex_destroy(&ai.mtx); -        for (i = 0; i < SYS_MAX_FLOWS; ++i) { -                pthread_mutex_destroy(&ai.ports[i].state_lock); -                pthread_cond_destroy(&ai.ports[i].state_cond); -        } +        pthread_rwlock_unlock(&ai.lock); +#ifdef PROC_FLOW_STATS +        rib_fini(); +#endif          timerwheel_fini(); -        shm_rdrbuff_close(ai.rdrb); +        fset_destroy(ai.frct_set); + +        shm_flow_set_close(ai.fqset); + +        pthread_rwlock_destroy(&ai.lock);          free(ai.flows); -        free(ai.ports); +        free(ai.id_to_fd); + +        shm_rdrbuff_close(ai.rdrb);          bmp_destroy(ai.fds);          bmp_destroy(ai.fqueues); -        pthread_rwlock_unlock(&ai.lock); +        proc_exit(); -        pthread_rwlock_destroy(&ai.lock); +        memset(&ai, 0, sizeof(ai));  }  #if defined(__MACH__) && defined(__APPLE__) @@ -544,310 +823,232 @@ __attribute__((section(FINI_SECTION))) __typeof__(fini) * __fini = fini;  int flow_accept(qosspec_t *             qs,                  const struct timespec * timeo)  { -        irm_msg_t   msg = IRM_MSG__INIT; -        irm_msg_t * recv_msg; -        int         fd; -        void *      pkp;          /* public key pair     */ -        uint8_t     s[SYMMKEYSZ]; /* secret key for flow */ -        uint8_t     buf[MSGBUFSZ]; -        int         err = -EIRMD; -        ssize_t     key_len; +        struct flow_info flow; +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; +        buffer_t         sk; +        int              fd; +        int              err; -        memset(s, 0, SYMMKEYSZ); - -        msg.code    = IRM_MSG_CODE__IRM_FLOW_ACCEPT; -        msg.has_pid = true; -        msg.pid     = ai.pid; - -        if (timeo != NULL) { -                msg.has_timeo_sec = true; -                msg.has_timeo_nsec = true; -                msg.timeo_sec  = timeo->tv_sec; -                msg.timeo_nsec = timeo->tv_nsec; -        } - -        key_len = crypt_dh_pkp_create(&pkp, buf); -        if (key_len < 0) { -                err = -ECRYPT; -                goto fail_crypt_pkp; -        } -        if (key_len > 0) { -                msg.has_pk  = true; -                msg.pk.data = buf; -                msg.pk.len  = (uint32_t) key_len; -        } - -        pthread_cleanup_push(crypt_dh_pkp_destroy, pkp); - -        recv_msg = send_recv_irm_msg(&msg); - -        pthread_cleanup_pop(false); - -        if (recv_msg == NULL) -                goto fail_recv; - -        if (!recv_msg->has_result) -                goto fail_result; - -        if (recv_msg->result !=  0) { -                err = recv_msg->result; -                goto fail_result; -        } - -        if (!recv_msg->has_pid || !recv_msg->has_flow_id || -            recv_msg->qosspec == NULL) -                goto fail_result; - -        if (recv_msg->pk.len != 0 && -            crypt_dh_derive(pkp, recv_msg->pk.data, -                            recv_msg->pk.len, s) < 0) { -                err = -ECRYPT; -                goto fail_result; -        } - -        crypt_dh_pkp_destroy(pkp); +#ifdef QOS_DISABLE_CRC +        if (qs != NULL) +                qs->ber = 1; +#endif +        memset(&flow, 0, sizeof(flow)); -        fd = flow_init(recv_msg->flow_id, recv_msg->pid, -                       msg_to_spec(recv_msg->qosspec), s); +        flow.n_pid = getpid(); +        flow.qs    = qs == NULL ? qos_raw : *qs; -        irm_msg__free_unpacked(recv_msg, NULL); +        if (flow_accept__irm_req_ser(&msg, &flow, timeo)) +                return -ENOMEM; -        if (fd < 0) -                return fd; +        err = send_recv_msg(&msg); +        if (err < 0) +                return err; -        pthread_rwlock_wrlock(&ai.lock); +        err = flow__irm_result_des(&msg, &flow, &sk); +        if (err < 0) +                return err; -        assert(ai.flows[fd].frcti == NULL); +        fd = flow_init(&flow, &sk); -        if (ai.flows[fd].qs.in_order != 0) { -                ai.flows[fd].frcti = frcti_create(fd); -                if (ai.flows[fd].frcti == NULL) { -                        pthread_rwlock_unlock(&ai.lock); -                        flow_dealloc(fd); -                        return -ENOMEM; -                } -        } +        freebuf(sk);          if (qs != NULL) -                *qs = ai.flows[fd].qs; - -        pthread_rwlock_unlock(&ai.lock); +                *qs = flow.qs;          return fd; - - fail_result: -        irm_msg__free_unpacked(recv_msg, NULL); - fail_recv: -        crypt_dh_pkp_destroy(pkp); - fail_crypt_pkp: -        return err;  } -static int __flow_alloc(const char *            dst, -                        qosspec_t *             qs, -                        const struct timespec * timeo, -                        bool join) +int flow_alloc(const char *            dst, +               qosspec_t *             qs, +               const struct timespec * timeo)  { -        irm_msg_t     msg    = IRM_MSG__INIT; -        qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT; -        irm_msg_t *   recv_msg; -        int           fd; -        void *        pkp = NULL;     /* public key pair     */ -        uint8_t       s[SYMMKEYSZ];   /* secret key for flow */ -        uint8_t       buf[MSGBUFSZ]; -        int           err = -EIRMD; - -        memset(s, 0, SYMMKEYSZ); +        struct flow_info flow; +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; +        buffer_t         sk; /* symmetric key */ +        int              fd; +        int              err;  #ifdef QOS_DISABLE_CRC          if (qs != NULL)                  qs->ber = 1;  #endif -        msg.code    = join ? IRM_MSG_CODE__IRM_FLOW_JOIN -                           : IRM_MSG_CODE__IRM_FLOW_ALLOC; -        msg.dst     = (char *) dst; -        msg.has_pid = true; -        msg.pid     = ai.pid; -        qs_msg      = spec_to_msg(qs); -        msg.qosspec = &qs_msg; -        if (timeo != NULL) { -                msg.has_timeo_sec = true; -                msg.has_timeo_nsec = true; -                msg.timeo_sec  = timeo->tv_sec; -                msg.timeo_nsec = timeo->tv_nsec; -        } +        memset(&flow, 0, sizeof(flow)); -        if (!join && qs != NULL && qs->cypher_s != 0) { -                ssize_t key_len; +        flow.n_pid = getpid(); +        flow.qs    = qs == NULL ? qos_raw : *qs; -                key_len = crypt_dh_pkp_create(&pkp, buf); -                if (key_len < 0) { -                        err = -ECRYPT; -                        goto fail_crypt_pkp; -                } +        if (flow_alloc__irm_req_ser(&msg, &flow, dst, timeo)) +                return -ENOMEM; -                msg.has_pk  = true; -                msg.pk.data = buf; -                msg.pk.len  = (uint32_t) key_len; +        err = send_recv_msg(&msg); +        if (err < 0) { +                printf("send_recv_msg error %d\n", err); +                return err;          } -        recv_msg = send_recv_irm_msg(&msg); -        if (recv_msg == NULL) -                goto fail_send; - -        if (!recv_msg->has_result) -                goto fail_result; +        err = flow__irm_result_des(&msg, &flow, &sk); +        if (err < 0) +                return err; -        if (recv_msg->result != 0) { -                err = recv_msg->result; -                goto fail_result; -        } +        fd = flow_init(&flow, &sk); -        if (!recv_msg->has_pid || !recv_msg->has_flow_id) -                goto fail_result; - -        if (!join && qs != NULL && qs->cypher_s != 0) { -                if (!recv_msg->has_pk || recv_msg->pk.len == 0) { -                        err = -ECRYPT; -                        goto fail_result; -                } +        freebuf(sk); -                if (crypt_dh_derive(pkp, recv_msg->pk.data, -                                    recv_msg->pk.len, s) < 0) { -                        err = -ECRYPT; -                        goto fail_result; -                } +        if (qs != NULL) +                *qs = flow.qs; -                crypt_dh_pkp_destroy(pkp); -        } +        return fd; +} -        fd = flow_init(recv_msg->flow_id, recv_msg->pid, -                       qs == NULL ? qos_raw : *qs, s); +int flow_join(const char *            dst, +              const struct timespec * timeo) +{ +        struct flow_info flow; +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; +        int              fd; +        int              err; -        irm_msg__free_unpacked(recv_msg, NULL); +        memset(&flow, 0, sizeof(flow)); -        if (fd < 0) -                return fd; +        flow.n_pid = getpid(); +        flow.qs    = qos_np1; -        pthread_rwlock_wrlock(&ai.lock); +        if (flow_join__irm_req_ser(&msg, &flow, dst, timeo)) +                return -ENOMEM; -        assert(ai.flows[fd].frcti == NULL); +        err = send_recv_msg(&msg); +        if (err < 0) +                return err; -        if (ai.flows[fd].qs.in_order != 0) { -                ai.flows[fd].frcti = frcti_create(fd); -                if (ai.flows[fd].frcti == NULL) { -                        pthread_rwlock_unlock(&ai.lock); -                        flow_dealloc(fd); -                        return -ENOMEM; -                } -        } +        err = flow__irm_result_des(&msg, &flow, NULL); +        if (err < 0) +                return err; -        pthread_rwlock_unlock(&ai.lock); +        fd = flow_init(&flow, NULL);          return fd; - - fail_result: -        irm_msg__free_unpacked(recv_msg, NULL); - fail_send: -        crypt_dh_pkp_destroy(pkp); - fail_crypt_pkp: -        return err; -} - -int flow_alloc(const char *            dst, -               qosspec_t *             qs, -               const struct timespec * timeo) -{ -        return __flow_alloc(dst, qs, timeo, false); -} - -int flow_join(const char *            dst, -              qosspec_t *             qs, -              const struct timespec * timeo) -{ -        if (qs != NULL && qs->cypher_s != 0) -                return -ECRYPT; - -        return __flow_alloc(dst, qs, timeo, true);  } +#define PKT_BUF_LEN 2048  int flow_dealloc(int fd)  { -        irm_msg_t     msg = IRM_MSG__INIT; -        irm_msg_t *   recv_msg; -        struct flow * f; -        time_t        timeo; +        struct flow_info info; +        uint8_t          pkt[PKT_BUF_LEN]; +        uint8_t          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; +        int              err;          if (fd < 0 || fd >= SYS_MAX_FLOWS )                  return -EINVAL; -        msg.code           = IRM_MSG_CODE__IRM_FLOW_DEALLOC; -        msg.has_flow_id    = true; -        msg.has_pid        = true; -        msg.pid            = ai.pid; -        msg.has_timeo_sec  = true; -        msg.has_timeo_nsec = true; -        msg.timeo_nsec     = 0; +        memset(&info, 0, sizeof(flow)); -        f = &ai.flows[fd]; +        flow = &ai.flows[fd];          pthread_rwlock_rdlock(&ai.lock); -        if (f->flow_id < 0) { +        if (flow->info.id < 0) {                  pthread_rwlock_unlock(&ai.lock);                  return -ENOTALLOC;          } -        msg.flow_id = f->flow_id; +        flow->oflags = FLOWFDEFAULT | FLOWFRNOPART; + +        flow->rcv_timesout = true; +        flow->rcv_timeo = tic; + +        pthread_rwlock_unlock(&ai.lock); -        timeo = frcti_dealloc(f->frcti); -        while (timeo < 0) { /* keep the flow active for rtx */ -                ssize_t ret; -                uint8_t buf[128]; +        flow_read(fd, buf, SOCK_BUF_SIZE); -                f->oflags = FLOWFDEFAULT | FLOWFRNOPART; +        pthread_rwlock_rdlock(&ai.lock); -                f->rcv_timesout = true; -                f->rcv_timeo.tv_sec = -timeo; -                f->rcv_timeo.tv_nsec = 0; +        timeo.tv_sec = frcti_dealloc(flow->frcti); +        while (timeo.tv_sec < 0) { /* keep the flow active for rtx */ +                ssize_t         ret;                  pthread_rwlock_unlock(&ai.lock); -                ret = flow_read(fd, buf, 128); +                ret = flow_read(fd, pkt, PKT_BUF_LEN);                  pthread_rwlock_rdlock(&ai.lock); -                timeo = frcti_dealloc(f->frcti); +                timeo.tv_sec = frcti_dealloc(flow->frcti); -                if ((ret == -ETIMEDOUT || ret == -EFLOWDOWN) && timeo < 0) -                        timeo = -timeo; +                if (ret == -EFLOWDOWN && timeo.tv_sec < 0) +                        timeo.tv_sec = -timeo.tv_sec;          } -        msg.timeo_sec = timeo; +        pthread_cleanup_push(__cleanup_rwlock_unlock, &ai.lock); -        shm_rbuff_fini(ai.flows[fd].tx_rb); +        shm_rbuff_fini(flow->tx_rb); -        pthread_rwlock_unlock(&ai.lock); +        pthread_cleanup_pop(true); -        recv_msg = send_recv_irm_msg(&msg); -        if (recv_msg == NULL) -                return -EIRMD; +        info.id  = flow->info.id; +        info.n_pid = getpid(); -        if (!recv_msg->has_result) { -                irm_msg__free_unpacked(recv_msg, NULL); -                return -EIRMD; -        } +        if (flow_dealloc__irm_req_ser(&msg, &info, &timeo) < 0) +                return -ENOMEM; -        irm_msg__free_unpacked(recv_msg, NULL); +        err = send_recv_msg(&msg); +        if (err < 0) +                return err; -        pthread_rwlock_wrlock(&ai.lock); +        err = irm__irm_result_des(&msg);          flow_fini(fd); +        return err; +} + +int ipcp_flow_dealloc(int fd) +{ +        struct flow_info info; +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; +        struct flow *    flow; +        int              err; + +        if (fd < 0 || fd >= SYS_MAX_FLOWS ) +                return -EINVAL; + +        flow = &ai.flows[fd]; + +        memset(&info, 0, sizeof(flow)); + +        pthread_rwlock_rdlock(&ai.lock); + +        if (flow->info.id < 0) { +                pthread_rwlock_unlock(&ai.lock); +                return -ENOTALLOC; +        } + +        info.id      = flow->info.id; +        info.n_1_pid = flow->info.n_1_pid; +          pthread_rwlock_unlock(&ai.lock); -        return 0; +        if (ipcp_flow_dealloc__irm_req_ser(&msg, &info) < 0) +                return -ENOMEM; + +        err = send_recv_msg(&msg); +        if (err < 0) +                return err; + +        err = irm__irm_result_des(&msg); + +        flow_fini(fd); + +        return err;  }  int fccntl(int fd, @@ -856,6 +1057,7 @@ int fccntl(int fd,  {          uint32_t *        fflags;          uint16_t *        cflags; +        uint16_t          csflags;          va_list           l;          struct timespec * timeo;          qosspec_t *       qs; @@ -873,7 +1075,7 @@ int fccntl(int fd,          pthread_rwlock_wrlock(&ai.lock); -        if (flow->flow_id < 0) { +        if (flow->info.id < 0) {                  pthread_rwlock_unlock(&ai.lock);                  va_end(l);                  return -ENOTALLOC; @@ -912,13 +1114,13 @@ int fccntl(int fd,                          goto einval;                  if (!flow->rcv_timesout)                          goto eperm; -                *timeo = flow->snd_timeo; +                *timeo = flow->rcv_timeo;                  break;          case FLOWGQOSSPEC:                  qs = va_arg(l, qosspec_t *);                  if (qs == NULL)                          goto einval; -                *qs = flow->qs; +                *qs = flow->info.qs;                  break;          case FLOWGRXQLEN:                  qlen  = va_arg(l, size_t *); @@ -945,13 +1147,13 @@ int fccntl(int fd,                          rx_acl |= ACL_FLOWDOWN;                          tx_acl |= ACL_FLOWDOWN;                          shm_flow_set_notify(flow->set, -                                            flow->flow_id, +                                            flow->info.id,                                              FLOW_DOWN);                  } else {                          rx_acl &= ~ACL_FLOWDOWN;                          tx_acl &= ~ACL_FLOWDOWN;                          shm_flow_set_notify(flow->set, -                                            flow->flow_id, +                                            flow->info.id,                                              FLOW_UP);                  } @@ -966,15 +1168,13 @@ int fccntl(int fd,                  *fflags = flow->oflags;                  break;          case FRCTSFLAGS: -                cflags = va_arg(l, uint16_t *); -                if (cflags == NULL) -                        goto einval; +                csflags = (uint16_t) va_arg(l, uint32_t);                  if (flow->frcti == NULL)                          goto eperm; -                frcti_setflags(flow->frcti, *cflags); +                frcti_setflags(flow->frcti, csflags);                  break;          case FRCTGFLAGS: -                cflags = (uint16_t *) va_arg(l, int *); +                cflags = (uint16_t *) va_arg(l, uint32_t *);                  if (cflags == NULL)                          goto einval;                  if (flow->frcti == NULL) @@ -1027,6 +1227,60 @@ static int add_crc(struct shm_du_buff * sdb)          return 0;  } +static int flow_tx_sdb(struct flow *        flow, +                       struct shm_du_buff * sdb, +                       bool                 block, +                       struct timespec *    abstime) +{ +        struct timespec now; +        ssize_t         idx; +        int             ret; + +        clock_gettime(PTHREAD_COND_CLOCK, &now); + +        pthread_rwlock_wrlock(&ai.lock); + +        flow->snd_act = now; + +        pthread_rwlock_unlock(&ai.lock); + +        idx = shm_du_buff_get_idx(sdb); + +        pthread_rwlock_rdlock(&ai.lock); + +        if (shm_du_buff_len(sdb) > 0) { +                if (frcti_snd(flow->frcti, sdb) < 0) +                        goto enomem; + +                if (sdb_encrypt(flow, sdb) < 0) +                        goto enomem; + +                if (flow->info.qs.ber == 0 && add_crc(sdb) != 0) +                        goto enomem; +        } + +        pthread_cleanup_push(__cleanup_rwlock_unlock, &ai.lock); + +        if (!block) +                ret = shm_rbuff_write(flow->tx_rb, idx); +        else +                ret = shm_rbuff_write_b(flow->tx_rb, idx, abstime); + +        if (ret < 0) +                shm_rdrbuff_remove(ai.rdrb, idx); +        else +                shm_flow_set_notify(flow->set, flow->info.id, FLOW_PKT); + +        pthread_cleanup_pop(true); + +        return 0; + +enomem: +        pthread_rwlock_unlock(&ai.lock); +        shm_rdrbuff_remove(ai.rdrb, idx); +        return -ENOMEM; +} +  ssize_t flow_write(int          fd,                     const void * buf,                     size_t       count) @@ -1037,31 +1291,27 @@ ssize_t flow_write(int          fd,          int                  flags;          struct timespec      abs;          struct timespec *    abstime = NULL; -        struct timespec      tic = {0, TICTIME}; -        struct timespec      tictime;          struct shm_du_buff * sdb;          uint8_t *            ptr; -        if (buf == NULL) -                return 0; +        if (buf == NULL && count != 0) +                return -EINVAL; -        if (fd < 0 || fd > PROG_MAX_FLOWS) +        if (fd < 0 || fd >= PROG_MAX_FLOWS)                  return -EBADF;          flow = &ai.flows[fd];          clock_gettime(PTHREAD_COND_CLOCK, &abs); -        pthread_rwlock_rdlock(&ai.lock); +        pthread_rwlock_wrlock(&ai.lock); -        if (flow->flow_id < 0) { +        if (flow->info.id < 0) {                  pthread_rwlock_unlock(&ai.lock);                  return -ENOTALLOC;          } -        ts_add(&tic, &abs, &tictime); - -        if (ai.flows[fd].snd_timesout) { +        if (flow->snd_timesout) {                  ts_add(&abs, &flow->snd_timeo, &abs);                  abstime = &abs;          } @@ -1078,54 +1328,67 @@ ssize_t flow_write(int          fd,                          return -EAGAIN;                  idx = shm_rdrbuff_alloc(ai.rdrb, count, &ptr, &sdb);          } else { -                while ((ret = frcti_window_wait(flow->frcti, &tictime)) < 0) { -                        if (ret != -ETIMEDOUT) -                                return ret; - -                        if (abstime != NULL && ts_diff_ns(&tictime, &abs) <= 0) -                                return -ETIMEDOUT; - -                        frcti_tick(flow->frcti); - -                        ts_add(&tictime, &tic, &tictime); -                } +                ret = frcti_window_wait(flow->frcti, abstime); +                if (ret < 0) +                        return ret;                  idx = shm_rdrbuff_alloc_b(ai.rdrb, count, &ptr, &sdb, abstime);          }          if (idx < 0)                  return idx; -        memcpy(ptr, buf, count); +        if (count > 0) +                memcpy(ptr, buf, count); -        pthread_rwlock_rdlock(&ai.lock); +        ret = flow_tx_sdb(flow, sdb, !(flags & FLOWFWNOBLOCK), abstime); -        if (frcti_snd(flow->frcti, sdb) < 0) -                goto enomem; +        return ret < 0 ? (ssize_t) ret : (ssize_t) count; +} -        if (flow->qs.cypher_s > 0 && crypt_encrypt(flow, sdb) < 0) -                goto enomem; +static bool invalid_pkt(struct flow *        flow, +                        struct shm_du_buff * sdb) +{ +        if (shm_du_buff_len(sdb) == 0) +                return true; -        if (flow->qs.ber == 0 && add_crc(sdb) != 0) -                goto enomem; +        if (flow->info.qs.ber == 0 && chk_crc(sdb) != 0) +                return true; -        if (flags & FLOWFWNOBLOCK) -                ret = shm_rbuff_write(flow->tx_rb, idx); -        else -                ret = shm_rbuff_write_b(flow->tx_rb, idx, abstime); +        if (sdb_decrypt(flow, sdb) < 0) +                return true; -        if (ret < 0) -                shm_rdrbuff_remove(ai.rdrb, idx); -        else -                shm_flow_set_notify(flow->set, flow->flow_id, FLOW_PKT); +        return false; +} -        pthread_rwlock_unlock(&ai.lock); +static ssize_t flow_rx_sdb(struct flow *         flow, +                           struct shm_du_buff ** sdb, +                           bool                  block, +                           struct timespec *     abstime) +{ +        ssize_t         idx; +        struct timespec now; -        return ret < 0 ? (ssize_t) ret : (ssize_t) count; +        idx = block ? shm_rbuff_read_b(flow->rx_rb, abstime) : +                shm_rbuff_read(flow->rx_rb); +        if (idx < 0) +                return idx; + +        clock_gettime(PTHREAD_COND_CLOCK, &now); + +        pthread_rwlock_wrlock(&ai.lock); + +        flow->rcv_act = now; - enomem:          pthread_rwlock_unlock(&ai.lock); -        shm_rdrbuff_remove(ai.rdrb, idx); -        return -ENOMEM; + +        *sdb = shm_rdrbuff_get(ai.rdrb, idx); + +        if (invalid_pkt(flow, *sdb)) { +                shm_rdrbuff_remove(ai.rdrb, idx); +                return -EAGAIN; +        } + +        return idx;  }  ssize_t flow_read(int    fd, @@ -1135,120 +1398,100 @@ ssize_t flow_read(int    fd,          ssize_t              idx;          ssize_t              n;          uint8_t *            packet; -        struct shm_rbuff *   rb;          struct shm_du_buff * sdb;          struct timespec      abs; -        struct timespec      tic = {0, TICTIME}; -        struct timespec      tictime; +        struct timespec      now;          struct timespec *    abstime = NULL;          struct flow *        flow; -        bool                 noblock; +        bool                 block;          bool                 partrd; -        if (fd < 0 || fd > PROG_MAX_FLOWS) +        if (fd < 0 || fd >= PROG_MAX_FLOWS)                  return -EBADF;          flow = &ai.flows[fd]; -        clock_gettime(PTHREAD_COND_CLOCK, &abs); +        clock_gettime(PTHREAD_COND_CLOCK, &now);          pthread_rwlock_rdlock(&ai.lock); -        if (flow->part_idx == DONE_PART) { +        if (flow->info.id < 0) {                  pthread_rwlock_unlock(&ai.lock); -                flow->part_idx = NO_PART; -                return 0; +                return -ENOTALLOC;          } -        if (flow->flow_id < 0) { +        if (flow->part_idx == DONE_PART) {                  pthread_rwlock_unlock(&ai.lock); -                return -ENOTALLOC; +                flow->part_idx = NO_PART; +                return 0;          } -        rb   = flow->rx_rb; -        noblock = flow->oflags & FLOWFRNOBLOCK; +        block  = !(flow->oflags & FLOWFRNOBLOCK);          partrd = !(flow->oflags & FLOWFRNOPART); -        ts_add(&tic, &abs, &tictime); - -        if (ai.flows[fd].rcv_timesout) { -                ts_add(&abs, &flow->rcv_timeo, &abs); +        if (flow->rcv_timesout) { +                ts_add(&now, &flow->rcv_timeo, &abs);                  abstime = &abs;          }          idx = flow->part_idx; -          if (idx < 0) {                  while ((idx = frcti_queued_pdu(flow->frcti)) < 0) {                          pthread_rwlock_unlock(&ai.lock); -                        idx = noblock ? shm_rbuff_read(rb) : -                                shm_rbuff_read_b(rb, &tictime); +                        idx = flow_rx_sdb(flow, &sdb, block, abstime);                          if (idx < 0) { -                                frcti_tick(flow->frcti); - -                                if (idx != -ETIMEDOUT) +                                if (block && idx != -EAGAIN) +                                        return idx; +                                if (!block)                                          return idx; -                                if (abstime != NULL -                                    && ts_diff_ns(&tictime, &abs) <= 0) -                                        return -ETIMEDOUT; - -                                ts_add(&tictime, &tic, &tictime); -                                pthread_rwlock_rdlock(&ai.lock); -                                continue; -                        } - -                        sdb = shm_rdrbuff_get(ai.rdrb, idx); -                        if (flow->qs.ber == 0 && chk_crc(sdb) != 0) {                                  pthread_rwlock_rdlock(&ai.lock); -                                shm_rdrbuff_remove(ai.rdrb, idx);                                  continue;                          }                          pthread_rwlock_rdlock(&ai.lock); -                        if (flow->qs.cypher_s > 0 -                            && crypt_decrypt(flow, sdb) < 0) { -                                pthread_rwlock_unlock(&ai.lock); -                                shm_rdrbuff_remove(ai.rdrb, idx); -                                return -ENOMEM; -                        } -                          frcti_rcv(flow->frcti, sdb);                  }          } -        frcti_tick(flow->frcti); +        sdb = shm_rdrbuff_get(ai.rdrb, idx);          pthread_rwlock_unlock(&ai.lock); -        n = shm_rdrbuff_read(&packet, ai.rdrb, idx); +        packet = shm_du_buff_head(sdb); + +        n = shm_du_buff_len(sdb);          assert(n >= 0);          if (n <= (ssize_t) count) {                  memcpy(buf, packet, n); -                shm_rdrbuff_remove(ai.rdrb, idx); +                ipcp_sdb_release(sdb);                  pthread_rwlock_wrlock(&ai.lock);                  flow->part_idx = (partrd && n == (ssize_t) count) ?                          DONE_PART : NO_PART; +                flow->rcv_act = now; +                  pthread_rwlock_unlock(&ai.lock);                  return n;          } else {                  if (partrd) {                          memcpy(buf, packet, count); -                        sdb = shm_rdrbuff_get(ai.rdrb, idx);                          shm_du_buff_head_release(sdb, n);                          pthread_rwlock_wrlock(&ai.lock);                          flow->part_idx = idx; + +                        flow->rcv_act = now; +                          pthread_rwlock_unlock(&ai.lock);                          return count;                  } else { -                        shm_rdrbuff_remove(ai.rdrb, idx); +                        ipcp_sdb_release(sdb);                          return -EMSGSIZE;                  }          } @@ -1256,26 +1499,31 @@ ssize_t flow_read(int    fd,  /* fqueue functions. */ -struct flow_set * fset_create() +struct flow_set * fset_create(void)  { -        struct flow_set * set = malloc(sizeof(*set)); +        struct flow_set * set; + +        set = malloc(sizeof(*set));          if (set == NULL) -                return NULL; +                goto fail_malloc;          assert(ai.fqueues);          pthread_rwlock_wrlock(&ai.lock);          set->idx = bmp_allocate(ai.fqueues); -        if (!bmp_is_id_valid(ai.fqueues, set->idx)) { -                pthread_rwlock_unlock(&ai.lock); -                free(set); -                return NULL; -        } +        if (!bmp_is_id_valid(ai.fqueues, set->idx)) +                goto fail_bmp_alloc;          pthread_rwlock_unlock(&ai.lock);          return set; + + fail_bmp_alloc: +        pthread_rwlock_unlock(&ai.lock); +        free(set); + fail_malloc: +        return NULL;  }  void fset_destroy(struct flow_set * set) @@ -1294,13 +1542,13 @@ void fset_destroy(struct flow_set * set)          free(set);  } -struct fqueue * fqueue_create() +struct fqueue * fqueue_create(void)  {          struct fqueue * fq = malloc(sizeof(*fq));          if (fq == NULL)                  return NULL; -        memset(fq->fqueue, -1, (SHM_BUFFER_SIZE) * sizeof(*fq->fqueue)); +        memset(fq->fqueue, -1, SHM_BUFFER_SIZE * sizeof(*fq->fqueue));          fq->fqsize = 0;          fq->next   = 0; @@ -1323,41 +1571,57 @@ void fset_zero(struct flow_set * set)  int fset_add(struct flow_set * set,               int               fd)  { -        int    ret; -        size_t packets; -        size_t i; +        struct flow *           flow; +        int                     ret; -        if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS) +        if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)                  return -EINVAL; -        pthread_rwlock_wrlock(&ai.lock); +        flow = &ai.flows[fd]; -        if (ai.flows[fd].flow_id < 0) { -                pthread_rwlock_unlock(&ai.lock); -                return -EINVAL; +        pthread_rwlock_rdlock(&ai.lock); + +        if (flow->info.id < 0) { +                ret = -EINVAL; +                goto fail;          } -        ret = shm_flow_set_add(ai.fqset, set->idx, ai.flows[fd].flow_id); +        if (flow->frcti != NULL) +                shm_flow_set_del(ai.fqset, 0, ai.flows[fd].info.id); + +        ret = shm_flow_set_add(ai.fqset, set->idx, ai.flows[fd].info.id); +        if (ret < 0) +                goto fail; -        packets = shm_rbuff_queued(ai.flows[fd].rx_rb); -        for (i = 0; i < packets; i++) -                shm_flow_set_notify(ai.fqset, ai.flows[fd].flow_id, FLOW_PKT); +        if (shm_rbuff_queued(ai.flows[fd].rx_rb)) +                shm_flow_set_notify(ai.fqset, ai.flows[fd].info.id, FLOW_PKT);          pthread_rwlock_unlock(&ai.lock);          return ret; + + fail: +        pthread_rwlock_unlock(&ai.lock); +        return ret;  }  void fset_del(struct flow_set * set,                int               fd)  { -        if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS) +        struct flow * flow; + +        if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)                  return; +        flow = &ai.flows[fd]; +          pthread_rwlock_rdlock(&ai.lock); -        if (ai.flows[fd].flow_id >= 0) -                shm_flow_set_del(ai.fqset, set->idx, ai.flows[fd].flow_id); +        if (flow->info.id >= 0) +                shm_flow_set_del(ai.fqset, set->idx, flow->info.id); + +        if (flow->frcti != NULL) +                shm_flow_set_add(ai.fqset, 0, ai.flows[fd].info.id);          pthread_rwlock_unlock(&ai.lock);  } @@ -1365,28 +1629,86 @@ void fset_del(struct flow_set * set,  bool fset_has(const struct flow_set * set,                int                     fd)  { -        bool ret = false; +        bool ret; -        if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS) +        if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)                  return false;          pthread_rwlock_rdlock(&ai.lock); -        if (ai.flows[fd].flow_id < 0) { +        if (ai.flows[fd].info.id < 0) {                  pthread_rwlock_unlock(&ai.lock);                  return false;          } -        ret = (shm_flow_set_has(ai.fqset, set->idx, ai.flows[fd].flow_id) == 1); +        ret = (shm_flow_set_has(ai.fqset, set->idx, ai.flows[fd].info.id) == 1);          pthread_rwlock_unlock(&ai.lock);          return ret;  } +/* Filter fqueue events for non-data packets */ +static int fqueue_filter(struct fqueue * fq) +{ +        struct shm_du_buff * sdb; +        int                  fd; +        ssize_t              idx; +        struct frcti *       frcti; + +        while (fq->next < fq->fqsize) { +                if (fq->fqueue[fq->next].event != FLOW_PKT) +                        return 1; + +                pthread_rwlock_rdlock(&ai.lock); + +                fd = ai.id_to_fd[fq->fqueue[fq->next].flow_id].fd; +                if (fd < 0) { +                        ++fq->next; +                        pthread_rwlock_unlock(&ai.lock); +                        continue; +                } + +                frcti = ai.flows[fd].frcti; +                if (frcti == NULL) { +                        pthread_rwlock_unlock(&ai.lock); +                        return 1; +                } + +                if (__frcti_pdu_ready(frcti) >= 0) { +                        pthread_rwlock_unlock(&ai.lock); +                        return 1; +                } + +                pthread_rwlock_unlock(&ai.lock); + +                idx = flow_rx_sdb(&ai.flows[fd], &sdb, false, NULL); +                if (idx < 0) +                        return 0; + +                pthread_rwlock_rdlock(&ai.lock); + +                sdb = shm_rdrbuff_get(ai.rdrb, idx); + +                __frcti_rcv(frcti, sdb); + +                if (__frcti_pdu_ready(frcti) >= 0) { +                        pthread_rwlock_unlock(&ai.lock); +                        return 1; +                } + +                pthread_rwlock_unlock(&ai.lock); + +                ++fq->next; +        } + +        return 0; +} +  int fqueue_next(struct fqueue * fq)  { -        int fd; +        int                fd; +        struct flowevent * e;          if (fq == NULL)                  return -EINVAL; @@ -1394,16 +1716,16 @@ int fqueue_next(struct fqueue * fq)          if (fq->fqsize == 0 || fq->next == fq->fqsize)                  return -EPERM; +        if (fq->next != 0 && fqueue_filter(fq) == 0) +                return -EPERM; +          pthread_rwlock_rdlock(&ai.lock); -        if (fq->next != 0 && frcti_filter(fq) == 0) { -                pthread_rwlock_unlock(&ai.lock); -                return -EPERM; -        } +        e = fq->fqueue + fq->next; -        fd = ai.ports[fq->fqueue[fq->next]].fd; +        fd = ai.id_to_fd[e->flow_id].fd; -        fq->next += 2; +        ++fq->next;          pthread_rwlock_unlock(&ai.lock); @@ -1418,7 +1740,7 @@ enum fqtype fqueue_type(struct fqueue * fq)          if (fq->fqsize == 0 || fq->next == 0)                  return -EPERM; -        return fq->fqueue[fq->next - 1]; +        return fq->fqueue[(fq->next - 1)].event;  }  ssize_t fevent(struct flow_set *       set, @@ -1426,8 +1748,6 @@ ssize_t fevent(struct flow_set *       set,                 const struct timespec * timeo)  {          ssize_t           ret = 0; -        struct timespec   tic = {0, TICTIME}; -        struct timespec   tictime;          struct timespec   abs;          struct timespec * t = NULL; @@ -1435,50 +1755,47 @@ ssize_t fevent(struct flow_set *       set,                  return -EINVAL;          if (fq->fqsize > 0 && fq->next != fq->fqsize) -                return fq->fqsize; +                return 1;          clock_gettime(PTHREAD_COND_CLOCK, &abs); -        ts_add(&tic, &abs, &tictime); -        t = &tictime; - -        if (timeo != NULL) +        if (timeo != NULL) {                  ts_add(&abs, timeo, &abs); +                t = &abs; +        }          while (ret == 0) {                  ret = shm_flow_set_wait(ai.fqset, set->idx, fq->fqueue, t); -                if (ret == -ETIMEDOUT) { -                        if (timeo != NULL && ts_diff_ns(t, &abs) < 0) { -                                fq->fqsize = 0; -                                return -ETIMEDOUT; -                        } -                        ret = 0; -                        ts_add(t, &tic, t); -                        pthread_rwlock_rdlock(&ai.lock); -                        timerwheel_move(); -                        pthread_rwlock_unlock(&ai.lock); -                        continue; -                } +                if (ret == -ETIMEDOUT) +                        return -ETIMEDOUT; -                fq->fqsize = ret << 1; +                fq->fqsize = ret;                  fq->next   = 0; -                ret = frcti_filter(fq); +                ret = fqueue_filter(fq);          } -        assert(ret); +        assert(ret != 0);          return 1;  }  /* ipcp-dev functions. */ -int np1_flow_alloc(pid_t     n_pid, -                   int       flow_id, -                   qosspec_t qs) +int np1_flow_alloc(pid_t n_pid, +                   int   flow_id)  { -        qs.cypher_s = 0; /* No encryption ctx for np1 */ -        return flow_init(flow_id, n_pid, qs, NULL); +        struct flow_info flow; + +        memset(&flow, 0, sizeof(flow)); + +        flow.id      = flow_id; +        flow.n_pid   = getpid(); +        flow.qs      = qos_np1; +        flow.mpl     = 0; +        flow.n_1_pid = n_pid; /* This "flow" is upside-down! */ + +        return flow_init(&flow, NULL);  }  int np1_flow_dealloc(int    flow_id, @@ -1496,151 +1813,119 @@ int np1_flow_dealloc(int    flow_id,          pthread_rwlock_rdlock(&ai.lock); -        fd = ai.ports[flow_id].fd; +        fd = ai.id_to_fd[flow_id].fd;          pthread_rwlock_unlock(&ai.lock);          return fd;  } -int np1_flow_resp(int flow_id) +int np1_flow_resp(int flow_id, +                  int resp)  {          int fd; -        if (port_wait_assign(flow_id) != PORT_ID_ASSIGNED) +        if (resp == 0 && flow_wait_assign(flow_id) != FLOW_ALLOCATED)                  return -1;          pthread_rwlock_rdlock(&ai.lock); -        fd = ai.ports[flow_id].fd; +        fd = ai.id_to_fd[flow_id].fd;          pthread_rwlock_unlock(&ai.lock);          return fd;  } -int ipcp_create_r(int result) +int ipcp_create_r(const struct ipcp_info * info)  { -        irm_msg_t   msg = IRM_MSG__INIT; -        irm_msg_t * recv_msg; -        int         ret; - -        msg.code       = IRM_MSG_CODE__IPCP_CREATE_R; -        msg.has_pid    = true; -        msg.pid        = getpid(); -        msg.has_result = true; -        msg.result     = result; - -        recv_msg = send_recv_irm_msg(&msg); -        if (recv_msg == NULL) -                return -EIRMD; - -        if (!recv_msg->has_result) { -                irm_msg__free_unpacked(recv_msg, NULL); -                return -1; -        } +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; +        int              err; + +        if (ipcp_create_r__irm_req_ser(&msg,info) < 0) +                return -ENOMEM; -        ret = recv_msg->result; -        irm_msg__free_unpacked(recv_msg, NULL); +        err = send_recv_msg(&msg); +        if (err < 0) +                return err; -        return ret; +        return irm__irm_result_des(&msg);  } -int ipcp_flow_req_arr(const uint8_t * dst, -                      size_t          len, -                      qosspec_t       qs, -                      const void *    data, -                      size_t          dlen) +int ipcp_flow_req_arr(const buffer_t * dst, +                      qosspec_t        qs, +                      time_t           mpl, +                      const buffer_t * data)  { -        irm_msg_t     msg = IRM_MSG__INIT; -        irm_msg_t *   recv_msg; -        qosspec_msg_t qs_msg; -        int           fd; - -        assert(dst != NULL); - -        msg.code      = IRM_MSG_CODE__IPCP_FLOW_REQ_ARR; -        msg.has_pid   = true; -        msg.pid       = getpid(); -        msg.has_hash  = true; -        msg.hash.len  = len; -        msg.hash.data = (uint8_t *) dst; -        qs_msg        = spec_to_msg(&qs); -        msg.qosspec   = &qs_msg; -        msg.has_pk    = true; -        msg.pk.data   = (uint8_t *) data; -        msg.pk.len    = dlen; - -        recv_msg = send_recv_irm_msg(&msg); -        if (recv_msg == NULL) -                return -EIRMD; - -        if (!recv_msg->has_flow_id || !recv_msg->has_pid) { -                irm_msg__free_unpacked(recv_msg, NULL); -                return -1; -        } +        struct flow_info flow; +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; +        int              err; -        if (recv_msg->has_result && recv_msg->result) { -                irm_msg__free_unpacked(recv_msg, NULL); -                return -1; -        } +        memset(&flow, 0, sizeof(flow)); -        qs.cypher_s = 0; /* No encryption ctx for np1 */ -        fd = flow_init(recv_msg->flow_id, recv_msg->pid, qs, NULL); +        assert(dst != NULL && dst->len != 0 && dst->data != NULL); -        irm_msg__free_unpacked(recv_msg, NULL); +        flow.n_1_pid = getpid(); +        flow.qs      = qs; +        flow.mpl     = mpl; -        return fd; +        if (ipcp_flow_req_arr__irm_req_ser(&msg, dst, &flow, data) < 0) +                return -ENOMEM; + +        err = send_recv_msg(&msg); +        if (err < 0) +                return err; + +        err = flow__irm_result_des(&msg, &flow, NULL); +        if (err < 0) +                return err; + +        /* inverted for np1_flow */ +        flow.n_1_pid = flow.n_pid; +        flow.n_pid   = getpid(); +        flow.mpl     = 0; +        flow.qs      = qos_np1; + +        return flow_init(&flow, NULL);  } -int ipcp_flow_alloc_reply(int          fd, -                          int          response, -                          const void * data, -                          size_t       len) +int ipcp_flow_alloc_reply(int              fd, +                          int              response, +                          time_t           mpl, +                          const buffer_t * data)  { -        irm_msg_t   msg = IRM_MSG__INIT; -        irm_msg_t * recv_msg; -        int         ret; +        struct flow_info flow; +        uint8_t          buf[SOCK_BUF_SIZE]; +        buffer_t         msg = {SOCK_BUF_SIZE, buf}; +        int              err;          assert(fd >= 0 && fd < SYS_MAX_FLOWS); -        msg.code         = IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY; -        msg.has_flow_id  = true; -        msg.has_pk       = true; -        msg.pk.data      = (uint8_t *) data; -        msg.pk.len       = (uint32_t) len; -          pthread_rwlock_rdlock(&ai.lock); -        msg.flow_id = ai.flows[fd].flow_id; +        flow.id = ai.flows[fd].info.id;          pthread_rwlock_unlock(&ai.lock); -        msg.has_response = true; -        msg.response     = response; - -        recv_msg = send_recv_irm_msg(&msg); -        if (recv_msg == NULL) -                return -EIRMD; - -        if (!recv_msg->has_result) { -                irm_msg__free_unpacked(recv_msg, NULL); -                return -1; -        } +        flow.mpl         = mpl; -        ret = recv_msg->result; +        if (ipcp_flow_alloc_reply__irm_msg_ser(&msg, &flow, response, data) < 0) +                return -ENOMEM; -        irm_msg__free_unpacked(recv_msg, NULL); +        err = send_recv_msg(&msg); +        if (err < 0) +                return err; -        return ret; +        return irm__irm_result_des(&msg);  }  int ipcp_flow_read(int                   fd,                     struct shm_du_buff ** sdb)  { -        struct flow *      flow; -        struct shm_rbuff * rb; -        ssize_t            idx = -1; +        struct flow * flow; +        ssize_t       idx = -1;          assert(fd >= 0 && fd < SYS_MAX_FLOWS);          assert(sdb); @@ -1649,50 +1934,39 @@ int ipcp_flow_read(int                   fd,          pthread_rwlock_rdlock(&ai.lock); -        assert(flow->flow_id >= 0); - -        rb = flow->rx_rb; +        assert(flow->info.id >= 0); -        while ((idx = frcti_queued_pdu(flow->frcti)) < 0) { +        while (frcti_queued_pdu(flow->frcti) < 0) {                  pthread_rwlock_unlock(&ai.lock); -                idx = shm_rbuff_read(rb); +                idx = flow_rx_sdb(flow, sdb, false, NULL);                  if (idx < 0)                          return idx;                  pthread_rwlock_rdlock(&ai.lock); -                *sdb = shm_rdrbuff_get(ai.rdrb, idx); -                if (flow->qs.ber == 0 && chk_crc(*sdb) != 0) -                        continue; -                  frcti_rcv(flow->frcti, *sdb);          } -        frcti_tick(flow->frcti); -          pthread_rwlock_unlock(&ai.lock); -        *sdb = shm_rdrbuff_get(ai.rdrb, idx); -          return 0;  }  int ipcp_flow_write(int                  fd,                      struct shm_du_buff * sdb)  { -        struct flow * flow; -        int           ret; -        ssize_t       idx; +        struct flow *   flow; +        int             ret;          assert(fd >= 0 && fd < SYS_MAX_FLOWS);          assert(sdb);          flow = &ai.flows[fd]; -        pthread_rwlock_rdlock(&ai.lock); +        pthread_rwlock_wrlock(&ai.lock); -        if (flow->flow_id < 0) { +        if (flow->info.id < 0) {                  pthread_rwlock_unlock(&ai.lock);                  return -ENOTALLOC;          } @@ -1702,30 +1976,74 @@ int ipcp_flow_write(int                  fd,                  return -EPERM;          } -        assert(flow->tx_rb); +        pthread_rwlock_unlock(&ai.lock); -        idx = shm_du_buff_get_idx(sdb); +        ret = flow_tx_sdb(flow, sdb, true, NULL); + +        return ret; +} + +int np1_flow_read(int                   fd, +                  struct shm_du_buff ** sdb) +{ +        struct flow *    flow; +        ssize_t          idx = -1; -        if (frcti_snd(flow->frcti, sdb) < 0) { +        assert(fd >= 0 && fd < SYS_MAX_FLOWS); +        assert(sdb); + +        flow = &ai.flows[fd]; + +        assert(flow->info.id >= 0); + +        pthread_rwlock_rdlock(&ai.lock); + +        idx = shm_rbuff_read(flow->rx_rb); +        if (idx < 0) {                  pthread_rwlock_unlock(&ai.lock); -                return -ENOMEM; +                return idx;          } -        if (flow->qs.ber == 0 && add_crc(sdb) != 0) { +        pthread_rwlock_unlock(&ai.lock); + +        *sdb = shm_rdrbuff_get(ai.rdrb, idx); + +        return 0; +} + +int np1_flow_write(int                  fd, +                   struct shm_du_buff * sdb) +{ +        struct flow * flow; +        int           ret; +        ssize_t       idx; + +        assert(fd >= 0 && fd < SYS_MAX_FLOWS); +        assert(sdb); + +        flow = &ai.flows[fd]; + +        pthread_rwlock_rdlock(&ai.lock); + +        if (flow->info.id < 0) {                  pthread_rwlock_unlock(&ai.lock); -                shm_rdrbuff_remove(ai.rdrb, idx); -                return -ENOMEM; +                return -ENOTALLOC;          } -        ret = shm_rbuff_write_b(flow->tx_rb, idx, NULL); -        if (ret == 0) -                shm_flow_set_notify(flow->set, flow->flow_id, FLOW_PKT); -        else -                shm_rdrbuff_remove(ai.rdrb, idx); +        if ((flow->oflags & FLOWFACCMODE) == FLOWFRDONLY) { +                pthread_rwlock_unlock(&ai.lock); +                return -EPERM; +        }          pthread_rwlock_unlock(&ai.lock); -        assert(ret <= 0); +        idx = shm_du_buff_get_idx(sdb); + +        ret = shm_rbuff_write_b(flow->tx_rb, idx, NULL); +        if (ret < 0) +                shm_rdrbuff_remove(ai.rdrb, idx); +        else +                shm_flow_set_notify(flow->set, flow->info.id, FLOW_PKT);          return ret;  } @@ -1749,7 +2067,7 @@ int ipcp_flow_fini(int fd)          pthread_rwlock_rdlock(&ai.lock); -        if (ai.flows[fd].flow_id < 0) { +        if (ai.flows[fd].info.id < 0) {                  pthread_rwlock_unlock(&ai.lock);                  return -1;          } @@ -1758,7 +2076,7 @@ int ipcp_flow_fini(int fd)          shm_rbuff_set_acl(ai.flows[fd].tx_rb, ACL_FLOWDOWN);          shm_flow_set_notify(ai.flows[fd].set, -                            ai.flows[fd].flow_id, +                            ai.flows[fd].info.id,                              FLOW_DEALLOC);          rx_rb = ai.flows[fd].rx_rb; @@ -1779,9 +2097,9 @@ int ipcp_flow_get_qoscube(int         fd,          pthread_rwlock_rdlock(&ai.lock); -        assert(ai.flows[fd].flow_id >= 0); +        assert(ai.flows[fd].info.id >= 0); -        *cube = qos_spec_to_cube(ai.flows[fd].qs); +        *cube = qos_spec_to_cube(ai.flows[fd].info.qs);          pthread_rwlock_unlock(&ai.lock); @@ -1794,7 +2112,7 @@ size_t ipcp_flow_queued(int fd)          pthread_rwlock_rdlock(&ai.lock); -        assert(ai.flows[fd].flow_id >= 0); +        assert(ai.flows[fd].info.id >= 0);          q = shm_rbuff_queued(ai.flows[fd].tx_rb); @@ -1830,13 +2148,14 @@ int local_flow_write(int    fd,          pthread_rwlock_rdlock(&ai.lock); -        if (flow->flow_id < 0) { +        if (flow->info.id < 0) {                  pthread_rwlock_unlock(&ai.lock);                  return -ENOTALLOC;          } +          ret = shm_rbuff_write_b(flow->tx_rb, idx, NULL);          if (ret == 0) -                shm_flow_set_notify(flow->set, flow->flow_id, FLOW_PKT); +                shm_flow_set_notify(flow->set, flow->info.id, FLOW_PKT);          else                  shm_rdrbuff_remove(ai.rdrb, idx); diff --git a/src/lib/frct.c b/src/lib/frct.c index 5313e4da..08c5ea80 100644 --- a/src/lib/frct.c +++ b/src/lib/frct.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Flow and Retransmission Control   * @@ -20,6 +20,8 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ +#include <ouroboros/endian.h> +  #define DELT_RDV         (100 * MILLION) /* ns */  #define MAX_RDV            (1 * BILLION) /* ns */ @@ -52,10 +54,20 @@ struct frcti {          uint32_t          rttseq;          struct timespec   t_probe;     /* Probe time             */          bool              probe;       /* Probe active           */ - +#ifdef PROC_FLOW_STATS +        size_t            n_rtx;       /* Number of rxm packets  */ +        size_t            n_prb;       /* Number of rtt probes   */ +        size_t            n_rtt;       /* Number of estimates    */ +        size_t            n_dup;       /* Duplicates received    */ +        size_t            n_dak;       /* Delayed ACKs received  */ +        size_t            n_rdv;       /* Number of rdv packets  */ +        size_t            n_out;       /* Packets out of window  */ +        size_t            n_rqo;       /* Packets out of rqueue  */ +#endif          struct frct_cr    snd_cr;          struct frct_cr    rcv_cr; +          ssize_t           rq[RQ_SIZE];          pthread_rwlock_t  lock; @@ -125,12 +137,20 @@ 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 last ack:               %20u\n", +                "Receiver inactive (ns):          %20lld\n" +                "Receiver last ack:               %20u\n" +                "Number of pkt retransmissions:   %20zu\n" +                "Number of rtt probes:            %20zu\n" +                "Number of rtt estimates:         %20zu\n" +                "Number of duplicates received:   %20zu\n" +                "Number of delayed acks received: %20zu\n" +                "Number of rendez-vous sent:      %20zu\n" +                "Number of packets out of window: %20zu\n" +                "Number of packets out of rqueue: %20zu\n",                  frcti->mpl,                  frcti->a,                  frcti->r, @@ -139,12 +159,20 @@ 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), -                frcti->rcv_cr.seqno); +                ts_diff_ns(&now, &frcti->rcv_cr.act), +                frcti->rcv_cr.seqno, +                frcti->n_rtx, +                frcti->n_prb, +                frcti->n_rtt, +                frcti->n_dup, +                frcti->n_dak, +                frcti->n_rdv, +                frcti->n_out, +                frcti->n_rqo);          pthread_rwlock_unlock(&flow->frcti->lock); @@ -156,10 +184,19 @@ static int frct_rib_read(const char * path,  static int frct_rib_readdir(char *** buf)  {          *buf = malloc(sizeof(**buf)); +        if (*buf == NULL) +                goto fail_malloc;          (*buf)[0] = strdup("frct"); +        if ((*buf)[0] == NULL) +                goto fail_strdup;          return 1; + + fail_strdup: +        free(*buf); + fail_malloc: +        return -ENOMEM;  }  static int frct_rib_getattr(const char *      path, @@ -168,7 +205,7 @@ static int frct_rib_getattr(const char *      path,          (void) path;          (void) attr; -        attr->size  = 1024; +        attr->size  = 1189;          attr->mtime = 0;          return 0; @@ -223,16 +260,24 @@ static void __send_frct_pkt(int      fd,          pci->ackno = hton32(ackno);          f = &ai.flows[fd]; + +        if (sdb_encrypt(f, sdb) < 0) +                goto fail; +  #ifdef RXM_BLOCKING -        if (shm_rbuff_write_b(f->tx_rb, idx, NULL)) { +        if (shm_rbuff_write_b(f->tx_rb, idx, NULL))  #else -        if (shm_rbuff_write(f->tx_rb, idx)) { +        if (shm_rbuff_write(f->tx_rb, idx))  #endif -                ipcp_sdb_release(sdb); -                return; -        } +                goto fail; -        shm_flow_set_notify(f->set, f->flow_id, FLOW_PKT); +        shm_flow_set_notify(f->set, f->info.id, FLOW_PKT); + +        return; + + fail: +        ipcp_sdb_release(sdb); +        return;  }  static void send_frct_pkt(struct frcti * frcti) @@ -245,9 +290,11 @@ static void send_frct_pkt(struct frcti * frcti)          assert(frcti); -        pthread_rwlock_rdlock(&frcti->lock); +        clock_gettime(PTHREAD_COND_CLOCK, &now); + +        pthread_rwlock_wrlock(&frcti->lock); -        if (frcti->rcv_cr.lwe == frcti->rcv_cr.seqno) { +        if (!after(frcti->rcv_cr.lwe, frcti->rcv_cr.seqno)) {                  pthread_rwlock_unlock(&frcti->lock);                  return;          } @@ -256,64 +303,46 @@ static void send_frct_pkt(struct frcti * frcti)          ackno = frcti->rcv_cr.lwe;          rwe   = frcti->rcv_cr.rwe; -        clock_gettime(PTHREAD_COND_CLOCK, &now); - -        diff = ts_diff_ns(&frcti->rcv_cr.act, &now); - -        pthread_rwlock_unlock(&frcti->lock); - -        if (diff > frcti->a || diff < DELT_ACK) +        diff = ts_diff_ns(&now, &frcti->rcv_cr.act); +        if (diff > frcti->a) { +                pthread_rwlock_unlock(&frcti->lock);                  return; +        } -        __send_frct_pkt(fd, FRCT_ACK | FRCT_FC, ackno, rwe); - -        pthread_rwlock_wrlock(&frcti->lock); +        diff = ts_diff_ns(&now, &frcti->snd_cr.act); +        if (diff < TICTIME) { +                pthread_rwlock_unlock(&frcti->lock); +                return; +        } -        if (after(frcti->rcv_cr.lwe, frcti->rcv_cr.seqno)) -                frcti->rcv_cr.seqno = frcti->rcv_cr.lwe; +        frcti->rcv_cr.seqno = frcti->rcv_cr.lwe;          pthread_rwlock_unlock(&frcti->lock); + +        __send_frct_pkt(fd, FRCT_ACK | FRCT_FC, ackno, rwe);  }  static void __send_rdv(int fd)  { -        struct shm_du_buff * sdb; -        struct frct_pci *    pci; -        ssize_t              idx; -        struct flow *        f; - -        /* Raw calls needed to bypass frcti. */ -        idx = shm_rdrbuff_alloc_b(ai.rdrb, sizeof(*pci), NULL, &sdb, NULL); -        if (idx < 0) -                return; - -        pci = (struct frct_pci *) shm_du_buff_head(sdb); -        memset(pci, 0, sizeof(*pci)); - -        pci->flags = FRCT_RDVS; - -        f = &ai.flows[fd]; - -        if (shm_rbuff_write_b(f->tx_rb, idx, NULL)) { -                ipcp_sdb_release(sdb); -                return; -        } - -        shm_flow_set_notify(f->set, f->flow_id, FLOW_PKT); +        __send_frct_pkt(fd, FRCT_RDVS, 0, 0);  } -static struct frcti * frcti_create(int fd) +static struct frcti * frcti_create(int    fd, +                                   time_t a, +                                   time_t r, +                                   time_t mpl)  {          struct frcti *      frcti;          ssize_t             idx;          struct timespec     now; -        time_t              mpl; -        time_t              a; -        time_t              r;          pthread_condattr_t  cattr;  #ifdef PROC_FLOW_STATS          char                frctstr[FRCT_NAME_STRLEN + 1];  #endif +        mpl *= MILLION; +        a   *= BILLION; +        r   *= BILLION; +          frcti = malloc(sizeof(*frcti));          if (frcti == NULL)                  goto fail_malloc; @@ -346,9 +375,9 @@ static struct frcti * frcti_create(int fd)          clock_gettime(PTHREAD_COND_CLOCK, &now); -        frcti->mpl = mpl = DELT_MPL; -        frcti->a   = a   = DELT_A; -        frcti->r   = r   = DELT_R; +        frcti->mpl = mpl; +        frcti->a   = a; +        frcti->r   = r;          frcti->rdv = DELT_RDV;          frcti->fd  = fd; @@ -357,10 +386,19 @@ static struct frcti * frcti_create(int fd)          frcti->probe  = false;          frcti->srtt = 0;            /* Updated on first ACK */ -        frcti->mdev = 10 * MILLION; /* Initial rxm will be after 20 ms */ -        frcti->rto  = 20 * MILLION; /* Initial rxm will be after 20 ms */ - -        if (ai.flows[fd].qs.loss == 0) { +        frcti->mdev = 10 * MILLION; /* Updated on first ACK */ +        frcti->rto  = BILLION;      /* Initial rxm will be after 1 s   */ +#ifdef PROC_FLOW_STATS +        frcti->n_rtx = 0; +        frcti->n_prb = 0; +        frcti->n_rtt = 0; +        frcti->n_dup = 0; +        frcti->n_dak = 0; +        frcti->n_rdv = 0; +        frcti->n_out = 0; +        frcti->n_rqo = 0; +#endif +        if (ai.flows[fd].info.qs.loss == 0) {                  frcti->snd_cr.cflags |= FRCTFRTX | FRCTFLINGER;                  frcti->rcv_cr.cflags |= FRCTFRTX;          } @@ -447,9 +485,6 @@ static void frcti_setflags(struct frcti * frcti,  #define frcti_rcv(frcti, sdb)                           \          (frcti == NULL ? 0 : __frcti_rcv(frcti, sdb)) -#define frcti_tick(frcti)                               \ -        (frcti == NULL ? 0 : __frcti_tick()) -  #define frcti_dealloc(frcti)                            \          (frcti == NULL ? 0 : __frcti_dealloc(frcti)) @@ -463,7 +498,7 @@ static void frcti_setflags(struct frcti * frcti,  static bool __frcti_is_window_open(struct frcti * frcti)  {          struct frct_cr * snd_cr = &frcti->snd_cr; -        int ret                 = true; +        bool             ret    = true;          pthread_rwlock_rdlock(&frcti->lock); @@ -471,7 +506,7 @@ static bool __frcti_is_window_open(struct frcti * frcti)                  ret = before(snd_cr->seqno, snd_cr->rwe);          if (!ret) { -                 struct timespec now; +                struct timespec now;                  clock_gettime(PTHREAD_COND_CLOCK, &now); @@ -482,16 +517,21 @@ 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); +#ifdef PROC_FLOW_STATS +                                frcti->n_rdv++; +#endif +                          }                  } @@ -518,7 +558,6 @@ static int __frcti_window_wait(struct frcti *    frcti,          while (snd_cr->seqno == snd_cr->rwe && ret != -ETIMEDOUT) {                  struct timespec now; -                  pthread_rwlock_unlock(&frcti->lock);                  pthread_mutex_lock(&frcti->mtx); @@ -532,9 +571,7 @@ static int __frcti_window_wait(struct frcti *    frcti,                  pthread_cleanup_push(__cleanup_mutex_unlock, &frcti->mtx); -                ret = -pthread_cond_timedwait(&frcti->cond, -                                              &frcti->mtx, -                                              abstime); +                ret = -__timedwait(&frcti->cond, &frcti->mtx, abstime);                  pthread_cleanup_pop(false); @@ -543,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); @@ -631,6 +668,7 @@ static time_t __frcti_dealloc(struct frcti * frcti)          wait = MAX(frcti->rcv_cr.inact - now.tv_sec + frcti->rcv_cr.act.tv_sec,                     frcti->snd_cr.inact - now.tv_sec + frcti->snd_cr.act.tv_sec); +        wait = MAX(wait, 0);          if (frcti->snd_cr.cflags & FRCTFLINGER              && before(frcti->snd_cr.lwe, frcti->snd_cr.seqno)) @@ -655,6 +693,7 @@ static int __frcti_snd(struct frcti *       frcti,          bool              rtx;          assert(frcti); +        assert(shm_du_buff_len(sdb) != 0);          snd_cr = &frcti->snd_cr;          rcv_cr = &frcti->rcv_cr; @@ -684,7 +723,7 @@ static int __frcti_snd(struct frcti *       frcti,                  /* There are no unacknowledged packets. */                  assert(snd_cr->seqno == snd_cr->lwe);                  random_buffer(&snd_cr->seqno, sizeof(snd_cr->seqno)); -                snd_cr->lwe = snd_cr->seqno - 1; +                snd_cr->lwe = snd_cr->seqno;                  snd_cr->rwe = snd_cr->lwe + START_WINDOW;          } @@ -703,9 +742,11 @@ static int __frcti_snd(struct frcti *       frcti,                          frcti->rttseq  = snd_cr->seqno;                          frcti->t_probe = now;                          frcti->probe   = true; +#ifdef PROC_FLOW_STATS +                        frcti->n_prb++; +#endif                  } - -                if (now.tv_sec - rcv_cr->act.tv_sec <= frcti->a) { +                if ((now.tv_sec - rcv_cr->act.tv_sec) * BILLION <= frcti->a) {                          pci->flags |= FRCT_ACK;                          pci->ackno = hton32(rcv_cr->lwe);                          rcv_cr->seqno = rcv_cr->lwe; @@ -735,17 +776,19 @@ static void rtt_estimator(struct frcti * frcti,          } else {                  time_t delta = mrtt - srtt;                  srtt += (delta >> 3); -                rttvar += (ABS(delta) - rttvar) >> 2; +                delta = (ABS(delta) - rttvar) >> 2; +#ifdef FRCT_LINUX_RTT_ESTIMATOR +                if (delta < 0) +                        delta >>= 3; +#endif +                rttvar += delta;          } - -        frcti->srtt     = MAX(1000U, srtt); -        frcti->mdev     = MAX(100U, rttvar); -        frcti->rto      = MAX(RTO_MIN, frcti->srtt + (frcti->mdev << 1)); -} - -static void __frcti_tick(void) -{ -        timerwheel_move(); +#ifdef PROC_FLOW_STATS +        frcti->n_rtt++; +#endif +        frcti->srtt     = MAX(1000L, srtt); +        frcti->mdev     = MAX(100L, rttvar); +        frcti->rto      = MAX(RTO_MIN, frcti->srtt + (frcti->mdev << MDEV_MUL));  }  /* Always queues the next application packet on the RQ. */ @@ -782,11 +825,14 @@ static void __frcti_rcv(struct frcti *       frcti,                  if (pci->flags & FRCT_DRF)  { /* New run. */                          rcv_cr->lwe = seqno;                          rcv_cr->rwe = seqno + RQ_SIZE; -                } else { +                        rcv_cr->seqno = seqno; +                } else if (pci->flags & FRCT_DATA) {                          goto drop_packet;                  }          } +        rcv_cr->act = now; +          /* For now, just send an immediate window update. */          if (pci->flags & FRCT_RDVS) {                  fd = frcti->fd; @@ -805,7 +851,11 @@ static void __frcti_rcv(struct frcti *       frcti,                          frcti->snd_cr.lwe = ackno;                  if (frcti->probe && after(ackno, frcti->rttseq)) { -                        rtt_estimator(frcti, ts_diff_ns(&frcti->t_probe, &now)); +#ifdef PROC_FLOW_STATS +                        if (!(pci->flags & FRCT_DATA)) +                                frcti->n_dak++; +#endif +                        rtt_estimator(frcti, ts_diff_ns(&now, &frcti->t_probe));                          frcti->probe = false;                  }          } @@ -835,20 +885,33 @@ static void __frcti_rcv(struct frcti *       frcti,          if (before(seqno, rcv_cr->lwe)) {                  rcv_cr->seqno = seqno; /* Ensures we send a new ACK. */ +#ifdef PROC_FLOW_STATS +                frcti->n_dup++; +#endif                  goto drop_packet;          }          if (rcv_cr->cflags & FRCTFRTX) { -                if (!before(seqno, rcv_cr->rwe)) /* Out of window. */ +                if (!before(seqno, rcv_cr->rwe)) {  /* Out of window. */ +#ifdef PROC_FLOW_STATS +                        frcti->n_out++; +#endif                          goto drop_packet; +                } -                if (!before(seqno, rcv_cr->lwe + RQ_SIZE)) +                if (!before(seqno, rcv_cr->lwe + RQ_SIZE))  { +#ifdef PROC_FLOW_STATS +                        frcti->n_rqo++; +#endif                          goto drop_packet; /* Out of rq. */ - -                if (frcti->rq[pos] != -1) +                } +                if (frcti->rq[pos] != -1) { +#ifdef PROC_FLOW_STATS +                        frcti->n_dup++; +#endif                          goto drop_packet; /* Duplicate in rq. */ - +                }                  fd = frcti->fd;          } else {                  rcv_cr->lwe = seqno; @@ -856,72 +919,16 @@ static void __frcti_rcv(struct frcti *       frcti,          frcti->rq[pos] = idx; -        rcv_cr->act = now; -          pthread_rwlock_unlock(&frcti->lock);          if (fd != -1) -                timerwheel_ack(fd, frcti); +                timerwheel_delayed_ack(fd, frcti);          return;   drop_packet:          pthread_rwlock_unlock(&frcti->lock); - -        send_frct_pkt(frcti); -          shm_rdrbuff_remove(ai.rdrb, idx); +        send_frct_pkt(frcti);          return;  } - -/* Filter fqueue events for non-data packets */ -int frcti_filter(struct fqueue * fq) -{ -        struct shm_du_buff * sdb; -        int                  fd; -        ssize_t              idx; -        struct frcti *       frcti; -        struct shm_rbuff *   rb; - -        while (fq->next < fq->fqsize) { -                if (fq->fqueue[fq->next + 1] != FLOW_PKT) -                        return 1; - -                pthread_rwlock_rdlock(&ai.lock); - -                fd = ai.ports[fq->fqueue[fq->next]].fd; -                rb = ai.flows[fd].rx_rb; -                frcti = ai.flows[fd].frcti; - -                if (frcti == NULL) { -                        pthread_rwlock_unlock(&ai.lock); -                        return 1; -                } - -                if (__frcti_pdu_ready(frcti) >= 0) { -                        pthread_rwlock_unlock(&ai.lock); -                        return 1; -                } - -                idx = shm_rbuff_read(rb); -                if (idx < 0) { -                        pthread_rwlock_unlock(&ai.lock); -                        return 0; -                } - -                sdb = shm_rdrbuff_get(ai.rdrb, idx); - -                __frcti_rcv(frcti, sdb); - -                if (__frcti_pdu_ready(frcti) >= 0) { -                        pthread_rwlock_unlock(&ai.lock); -                        return 1; -                } - -                pthread_rwlock_unlock(&ai.lock); - -                fq->next += 2; -        } - -        return fq->next < fq->fqsize; -} diff --git a/src/lib/hash.c b/src/lib/hash.c index 4ce3f3b4..b465f894 100644 --- a/src/lib/hash.c +++ b/src/lib/hash.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Hashing   * @@ -29,43 +29,50 @@  #include "config.h" +#include <ouroboros/endian.h>  #include <ouroboros/hash.h> -#ifndef HAVE_LIBGCRYPT +#ifdef HAVE_LIBGCRYPT +#include <gcrypt.h> +#else  #include <ouroboros/crc32.h>  #include <ouroboros/md5.h>  #include <ouroboros/sha3.h> -#else -#include <gcrypt.h>  #endif  #include <string.h>  #include <assert.h>  #include <stdbool.h> +#ifdef HAVE_LIBGCRYPT +int gcry_algo_tbl [] = { +        /* DIR_HASH policies first */ +        GCRY_MD_SHA3_224, +        GCRY_MD_SHA3_256, +        GCRY_MD_SHA3_384, +        GCRY_MD_SHA3_512, +        /* Below for internal use only */ +        GCRY_MD_CRC32, +        GCRY_MD_MD5, +}; +#else +int hash_len_tbl [] = { +        /* DIR_HASH policies first */ +        SHA3_224_HASH_LEN, +        SHA3_256_HASH_LEN, +        SHA3_384_HASH_LEN, +        SHA3_512_HASH_LEN, +        /* Below for internal use only */ +        CRC32_HASH_LEN, +        MD5_HASH_LEN +}; +#endif +  uint16_t hash_len(enum hash_algo algo)  {  #ifdef HAVE_LIBGCRYPT -        return (uint16_t) gcry_md_get_algo_dlen(algo); +        return (uint16_t) gcry_md_get_algo_dlen(gcry_algo_tbl[algo]);  #else -        switch (algo) { -        case HASH_CRC32: -                return CRC32_HASH_LEN; -        case HASH_MD5: -                return MD5_HASH_LEN; -        case HASH_SHA3_224: -                return SHA3_224_HASH_LEN; -        case HASH_SHA3_256: -                return SHA3_256_HASH_LEN; -        case HASH_SHA3_384: -                return SHA3_384_HASH_LEN; -        case HASH_SHA3_512: -                return SHA3_512_HASH_LEN; -        default: -                assert(false); -                break; -        } - -        return 0; +        return hash_len_tbl[algo];  #endif  } @@ -75,7 +82,7 @@ void mem_hash(enum hash_algo  algo,                size_t          len)  {  #ifdef HAVE_LIBGCRYPT -        gcry_md_hash_buffer(algo, dst, buf, len); +        gcry_md_hash_buffer(gcry_algo_tbl[algo], dst, buf, len);  #else          struct sha3_ctx sha3_ctx;          struct md5_ctx md5_ctx; @@ -84,6 +91,7 @@ void mem_hash(enum hash_algo  algo,          case HASH_CRC32:                  memset(dst, 0, CRC32_HASH_LEN);                  crc32((uint32_t *) dst, buf, len); +                *(uint32_t *) dst = htobe32(*(uint32_t *) dst);                  break;          case HASH_MD5:                  rhash_md5_init(&md5_ctx); diff --git a/src/lib/ipcp_config.proto b/src/lib/ipcp_config.proto deleted file mode 100644 index 185d9af7..00000000 --- a/src/lib/ipcp_config.proto +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * Layer configuration message - * - *    Dimitri Staessens <dimitri@ouroboros.rocks> - *    Sander Vrijders   <sander@ouroboros.rocks> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -syntax = "proto2"; - -message layer_info_msg { -        required string layer_name    =  1; -        required uint32 dir_hash_algo =  2; -} - -message ipcp_config_msg { -        required layer_info_msg layer_info =  1; -        required int32 ipcp_type           =  2; -        // Config for unicast IPCP -        optional uint32 addr_size          =  3; -        optional uint32 eid_size           =  4; -        optional uint32 max_ttl            =  5; -        optional uint32 addr_auth_type     =  6; -        optional uint32 routing_type       =  7; -        optional uint32 cong_avoid         =  8; -        // Config for UDP -        optional uint32 ip_addr            =  9; -        optional uint32 dns_addr           = 10; -        optional uint32 port               = 11; -        // Config for the Ethernet -        optional string dev                = 12; -        // Config for DIX Ethernet -        optional uint32 ethertype          = 13; -} - -enum enroll_code { -        ENROLL_REQ  = 1; -        ENROLL_BOOT = 2; -        ENROLL_DONE = 4; -}; - -message enroll_msg { -        required enroll_code     code   = 1; -        optional ipcp_config_msg conf   = 2; -        optional int64           t_sec  = 3; -        optional uint32          t_nsec = 4; -        optional int32           result = 5; -};
\ No newline at end of file diff --git a/src/lib/irm.c b/src/lib/irm.c index 64353f45..8333d0d3 100644 --- a/src/lib/irm.c +++ b/src/lib/irm.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * The API to instruct the IRM   * @@ -31,28 +31,37 @@  #include <ouroboros/irm.h>  #include <ouroboros/utils.h>  #include <ouroboros/sockets.h> +#include <ouroboros/protobuf.h>  #include <stdbool.h>  #include <string.h>  #include <stdlib.h>  #include <sys/stat.h> -pid_t irm_create_ipcp(const char *   name, -                      enum ipcp_type type) +int irm_create_ipcp(const char *   name, +                    enum ipcp_type type)  { -        irm_msg_t   msg      = IRM_MSG__INIT; -        irm_msg_t * recv_msg = NULL; -        int         ret      = -1; +        irm_msg_t        msg      = IRM_MSG__INIT; +        irm_msg_t *      recv_msg; +        int              ret; +        struct ipcp_info info; -        if (name == NULL) +        if (name == NULL || strlen(name) > IPCP_NAME_SIZE)                  return -EINVAL; -        msg.code          = IRM_MSG_CODE__IRM_CREATE_IPCP; -        msg.name          = (char *) name; -        msg.has_ipcp_type = true; -        msg.ipcp_type     = type; +        memset(&info, 0, sizeof(info)); + +        info.type = type; +        strcpy(info.name, name); + +        msg.code      = IRM_MSG_CODE__IRM_CREATE_IPCP; +        msg.ipcp_info = ipcp_info_s_to_msg(&info); +        if (msg.ipcp_info == NULL) +                return -ENOMEM;          recv_msg = send_recv_irm_msg(&msg); +        ipcp_info_msg__free_unpacked(msg.ipcp_info, NULL); +          if (recv_msg == NULL)                  return -EIRMD; @@ -98,11 +107,9 @@ int irm_destroy_ipcp(pid_t pid)  int irm_bootstrap_ipcp(pid_t                      pid,                         const struct ipcp_config * conf)  { -        irm_msg_t         msg        = IRM_MSG__INIT; -        ipcp_config_msg_t config     = IPCP_CONFIG_MSG__INIT; -        layer_info_msg_t  layer_info = LAYER_INFO_MSG__INIT; -        irm_msg_t *       recv_msg   = NULL; -        int               ret        = -1; +        irm_msg_t   msg = IRM_MSG__INIT; +        irm_msg_t * recv_msg; +        int         ret;          if (pid == -1 || conf == NULL)                  return -EINVAL; @@ -110,56 +117,10 @@ int irm_bootstrap_ipcp(pid_t                      pid,          msg.code    = IRM_MSG_CODE__IRM_BOOTSTRAP_IPCP;          msg.has_pid = true;          msg.pid     = pid; - -        config.layer_info     = &layer_info; -        msg.conf              = &config; -        layer_info.layer_name = (char *) conf->layer_info.layer_name; - -        config.ipcp_type = conf->type; - -        if (conf->type != IPCP_UDP) -                layer_info.dir_hash_algo  = conf->layer_info.dir_hash_algo; - -        switch (conf->type) { -        case IPCP_UNICAST: -                config.has_addr_size      = true; -                config.addr_size          = conf->addr_size; -                config.has_eid_size       = true; -                config.eid_size           = conf->eid_size; -                config.has_max_ttl        = true; -                config.max_ttl            = conf->max_ttl; -                config.has_addr_auth_type = true; -                config.addr_auth_type     = conf->addr_auth_type; -                config.has_routing_type   = true; -                config.routing_type       = conf->routing_type; -                config.has_cong_avoid     = true; -                config.cong_avoid         = conf->cong_avoid; -                break; -        case IPCP_UDP: -                config.has_ip_addr  = true; -                config.ip_addr      = conf->ip_addr; -                config.has_dns_addr = true; -                config.dns_addr     = conf->dns_addr; -                config.has_port     = true; -                config.port         = conf->port; -                break; -        case IPCP_LOCAL: -                /* FALLTHRU */ -        case IPCP_BROADCAST: -                break; -        case IPCP_ETH_LLC: -                config.dev = conf->dev; -                break; -        case IPCP_ETH_DIX: -                config.dev = conf->dev; -                config.has_ethertype = true; -                config.ethertype = conf->ethertype; -                break; -        default: -                return -EIPCPTYPE; -        } +        msg.conf    = ipcp_config_s_to_msg(conf);          recv_msg = send_recv_irm_msg(&msg); +        ipcp_config_msg__free_unpacked(msg.conf, NULL);          if (recv_msg == NULL)                  return -EIRMD; @@ -179,8 +140,7 @@ int irm_connect_ipcp(pid_t        pid,                       const char * component,                       qosspec_t    qs)  { -        irm_msg_t     msg    = IRM_MSG__INIT; -        qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT; +        irm_msg_t     msg = IRM_MSG__INIT;          irm_msg_t *   recv_msg;          int           ret; @@ -190,10 +150,11 @@ int irm_connect_ipcp(pid_t        pid,          msg.comp      = (char *) component;          msg.has_pid   = true;          msg.pid       = pid; -        qs_msg        = spec_to_msg(&qs); -        msg.qosspec   = &qs_msg; +        msg.qosspec   = qos_spec_s_to_msg(&qs);          recv_msg = send_recv_irm_msg(&msg); +        qosspec_msg__free_unpacked(msg.qosspec, NULL); +          if (recv_msg == NULL)                  return -EIRMD; @@ -237,7 +198,7 @@ int irm_disconnect_ipcp(pid_t        pid,          return ret;  } -ssize_t irm_list_ipcps(struct ipcp_info ** ipcps) +ssize_t irm_list_ipcps(struct ipcp_list_info ** ipcps)  {          irm_msg_t   msg = IRM_MSG__INIT;          irm_msg_t * recv_msg; @@ -407,50 +368,69 @@ int irm_bind_program(const char * prog,                       int          argc,                       char **      argv)  { -        irm_msg_t   msg      = IRM_MSG__INIT; -        irm_msg_t * recv_msg = NULL; -        int         ret      = -1; -        char *      full_name; +        irm_msg_t   msg = IRM_MSG__INIT; +        irm_msg_t * recv_msg; +        char **     exec; +        int         ret; +        int         i;          if (prog == NULL || name == NULL)                  return -EINVAL; -        full_name = strdup(prog); -        if (full_name == NULL) -                return -ENOMEM; +        exec = malloc((argc + 2) * sizeof(*exec)); +        if (exec== NULL) { +                ret = -ENOMEM; +                goto fail_exec; +        } -        if ((ret = check_prog_path(&full_name)) < 0) { -                free(full_name); -                return ret; +        exec[0] = strdup(prog); +        if (exec[0] == NULL) { +                ret = -ENOMEM; +                goto fail_exec0;          } +        ret = check_prog_path(&exec[0]); +        if (ret < 0) +                goto fail; + +        for (i = 0; i < argc; i++) +                exec[i + 1] = argv[i]; + +        exec[argc + 1] = ""; +          msg.code = IRM_MSG_CODE__IRM_BIND_PROGRAM;          msg.name = (char *) name; -        msg.prog = full_name; -        if (argv != NULL) { -                msg.n_args = argc; -                msg.args = (char **) argv; -        } +        msg.n_exec = argc + 2; +        msg.exec = exec;          msg.has_opts = true;          msg.opts = opts;          recv_msg = send_recv_irm_msg(&msg); - -        free(full_name); - -        if (recv_msg == NULL) -                return -EIRMD; +        if (recv_msg == NULL) { +                ret = -EIRMD; +                goto fail; +        }          if (!recv_msg->has_result) {                  irm_msg__free_unpacked(recv_msg, NULL); -                return -1; +                ret = -EPERM; +                goto fail;          }          ret = recv_msg->result;          irm_msg__free_unpacked(recv_msg, NULL); +        free(exec[0]); +        free(exec); + +        return ret; + fail: +        free(exec[0]); + fail_exec0: +        free(exec); + fail_exec:          return ret;  } @@ -543,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; @@ -582,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/irmd_messages.proto b/src/lib/irmd_messages.proto deleted file mode 100644 index 515d486f..00000000 --- a/src/lib/irmd_messages.proto +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * IRMd message - * - *    Dimitri Staessens <dimitri@ouroboros.rocks> - *    Sander Vrijders   <sander@ouroboros.rocks> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -syntax = "proto2"; - -import "ipcp_config.proto"; -import "qosspec.proto"; - -enum irm_msg_code { -        IRM_CREATE_IPCP       =  1; -        IPCP_CREATE_R         =  2; -        IRM_DESTROY_IPCP      =  3; -        IRM_LIST_IPCPS        =  4; -        IRM_BOOTSTRAP_IPCP    =  5; -        IRM_ENROLL_IPCP       =  6; -        IRM_CONNECT_IPCP      =  7; -        IRM_DISCONNECT_IPCP   =  8; -        IRM_BIND_PROGRAM      =  9; -        IRM_UNBIND_PROGRAM    = 10; -        IRM_PROC_ANNOUNCE     = 11; -        IRM_BIND_PROCESS      = 12; -        IRM_UNBIND_PROCESS    = 13; -        IRM_CREATE_NAME       = 14; -        IRM_DESTROY_NAME      = 15; -        IRM_LIST_NAMES        = 16; -        IRM_REG_NAME          = 17; -        IRM_UNREG_NAME        = 18; -        IRM_FLOW_ALLOC        = 19; -        IRM_FLOW_ACCEPT       = 20; -        IRM_FLOW_JOIN         = 21; -        IRM_FLOW_DEALLOC      = 22; -        IPCP_FLOW_REQ_ARR     = 23; -        IPCP_FLOW_ALLOC_REPLY = 24; -        IRM_REPLY             = 25; -}; - -message ipcp_info_msg { -        required uint32 pid   = 1; -        required uint32 type  = 2; -        required string name  = 3; -        required string layer = 4; -}; - -message name_info_msg { -        required string name   = 1; -        required uint32 pol_lb = 2; -}; - -message irm_msg { -        required irm_msg_code code    =  1; -        optional string prog          =  2; -        optional sint32 pid           =  3; -        optional string name          =  4; -        optional uint32 ipcp_type     =  5; -        optional string layer         =  6; -        repeated string args          =  7; -        optional sint32 response      =  8; -        optional string dst           =  9; -        optional bytes  hash          = 10; -        optional sint32 flow_id       = 11; -        optional qosspec_msg qosspec  = 12; -        optional ipcp_config_msg conf = 13; -        optional uint32 opts          = 14; -        repeated ipcp_info_msg ipcps  = 15; -        repeated name_info_msg names  = 16; -        optional uint32 timeo_sec     = 17; -        optional uint32 timeo_nsec    = 18; -        optional string comp          = 19; -        optional bytes pk             = 20; /* piggyback */ -        optional sint32 result        = 21; -}; diff --git a/src/lib/list.c b/src/lib/list.c index 55c5d04a..62b2eb27 100644 --- a/src/lib/list.c +++ b/src/lib/list.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Simple doubly linked list implementation.   * @@ -62,10 +62,10 @@ void list_add_tail(struct list_head * n,  void list_del(struct list_head * e)  {          del_list(e->prv, e->nxt); -        e->nxt = e->prv = NULL; +        e->nxt = e->prv = e;  } -bool list_is_empty(struct list_head * h) +bool list_is_empty(const struct list_head * h)  {          return h->nxt == h;  } diff --git a/src/lib/lockfile.c b/src/lib/lockfile.c index b0e1115f..cf6d3c94 100644 --- a/src/lib/lockfile.c +++ b/src/lib/lockfile.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Lockfile for Ouroboros   * @@ -36,81 +36,69 @@  #include <sys/stat.h>  #define LF_SIZE (sizeof(pid_t)) +#define LF_PROT (PROT_READ | PROT_WRITE)  struct lockfile {          pid_t * pid;  }; -struct lockfile * lockfile_create() { -        int fd; -        mode_t mask; -        struct lockfile * lf = malloc(sizeof(*lf)); -        if (lf == NULL) -                return NULL; - -        mask = umask(0); +static struct lockfile * __lockfile_open(int oflag) +{ +        int    fd; +        struct lockfile * lf; -        fd = shm_open(SHM_LOCKFILE_NAME, O_CREAT | O_EXCL | O_RDWR, 0666); -        if (fd == -1) { -                free(lf); -                return NULL; -        } +        lf = malloc(sizeof(*lf)); +        if (lf == NULL) +                goto fail_lockfile; -        umask(mask); +        fd = shm_open(SHM_LOCKFILE_NAME, oflag, 0666); +        if (fd == -1) +                goto fail_shm_open; -        if (ftruncate(fd, LF_SIZE - 1) < 0) { -                free(lf); -                return NULL; -        } +        if ((oflag & O_CREAT) && ftruncate(fd, LF_SIZE) < 0) +                goto fail_truncate; -        lf->pid = mmap(NULL, -                       LF_SIZE, PROT_READ | PROT_WRITE, -                       MAP_SHARED, -                       fd, -                       0); +        lf->pid = mmap(NULL, LF_SIZE, LF_PROT, MAP_SHARED, fd, 0); +        if (lf->pid == MAP_FAILED) +                goto fail_mmap;          close (fd); -        if (lf->pid == MAP_FAILED) { -                shm_unlink(SHM_LOCKFILE_NAME); -                free(lf); -                return NULL; -        } - -        *lf->pid = getpid(); -          return lf; + + fail_mmap: +        shm_unlink(SHM_LOCKFILE_NAME); + fail_truncate: +        close(fd); + fail_shm_open: +        free(lf); + fail_lockfile: +        return NULL;  } -struct lockfile * lockfile_open() { -        int fd; -        struct lockfile * lf = malloc(sizeof(*lf)); -        if (lf == NULL) -                return NULL; +struct lockfile * lockfile_create(void) +{ +        struct lockfile * lf; +        mode_t            mask; -        fd = shm_open(SHM_LOCKFILE_NAME, O_RDWR, 0666); -        if (fd < 0) { -                free(lf); -                return NULL; -        } +        mask = umask(0); -        lf->pid = mmap(NULL, -                       LF_SIZE, PROT_READ | PROT_WRITE, -                       MAP_SHARED, -                       fd, -                       0); +        lf = __lockfile_open(O_CREAT | O_EXCL | O_RDWR); +        if (lf == NULL) +                return NULL; -        close(fd); +        umask(mask); -        if (lf->pid == MAP_FAILED) { -                shm_unlink(SHM_LOCKFILE_NAME); -                free(lf); -                return NULL; -        } +        *lf->pid = getpid();          return lf;  } +struct lockfile * lockfile_open(void) +{ +        return __lockfile_open(O_RDWR); +} +  void lockfile_close(struct lockfile * lf)  {          assert(lf); @@ -127,11 +115,9 @@ void lockfile_destroy(struct lockfile * lf)          if (getpid() != *lf->pid && kill(*lf->pid, 0) == 0)                  return; -        munmap(lf->pid, LF_SIZE); +        lockfile_close(lf);          shm_unlink(SHM_LOCKFILE_NAME); - -        free(lf);  }  pid_t lockfile_owner(struct lockfile * lf) diff --git a/src/lib/logs.c b/src/lib/logs.c index edfeac15..d90bcd63 100644 --- a/src/lib/logs.c +++ b/src/lib/logs.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Logging facilities   * diff --git a/src/lib/md5.c b/src/lib/md5.c index a9152ee2..ad0dd4d7 100644 --- a/src/lib/md5.c +++ b/src/lib/md5.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * MD5 algorithm   * diff --git a/src/lib/notifier.c b/src/lib/notifier.c index 1f600765..4fccd371 100644 --- a/src/lib/notifier.c +++ b/src/lib/notifier.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Notifier event system using callbacks   * @@ -95,18 +95,14 @@ int notifier_reg(notifier_fn_t callback,          pthread_rwlock_wrlock(¬ifier.lock);          list_for_each(p, ¬ifier.listeners) { -                struct listener * l = list_entry(p, struct listener, next); -                if (l->callback == callback) { -                        pthread_rwlock_unlock(¬ifier.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(¬ifier.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(¬ifier.lock);          return 0; + fail: +        pthread_rwlock_unlock(¬ifier.lock); +        return -1; +  }  void notifier_unreg(notifier_fn_t callback) diff --git a/src/lib/cacep.proto b/src/lib/pb/cep.proto index f0ef1e98..d31cf4f7 100644 --- a/src/lib/cacep.proto +++ b/src/lib/pb/cep.proto @@ -1,7 +1,7 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   * - * Message for Connection Information in CACEP + * Message for Connection Information in OCEP   *   *    Dimitri Staessens <dimitri@ouroboros.rocks>   *    Sander Vrijders   <sander@ouroboros.rocks> @@ -27,7 +27,7 @@ message fixed_conc_syntax_msg {          repeated uint32 lens = 2;  } -message cacep_msg { +message cep_msg {          required string comp_name                  = 1;          required string protocol                   = 2;          required int32 pref_version                = 3; @@ -36,4 +36,4 @@ message cacep_msg {          repeated int32 supp_syntax                 = 6;          optional fixed_conc_syntax_msg syntax_spec = 7;          required uint64 address                    = 8; -}
\ No newline at end of file +} diff --git a/src/lib/qosspec.proto b/src/lib/pb/enroll.proto index 8a355363..60e964c6 100644 --- a/src/lib/qosspec.proto +++ b/src/lib/pb/enroll.proto @@ -1,7 +1,7 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   * - * QoS specification message + * Enrollment protocol   *   *    Dimitri Staessens <dimitri@ouroboros.rocks>   *    Sander Vrijders   <sander@ouroboros.rocks> @@ -21,14 +21,21 @@   */  syntax = "proto2"; +import "ipcp_config.proto"; -message qosspec_msg { -        required uint32 delay        = 1; /* In ms */ -        required uint64 bandwidth    = 2; /* In bits/s */ -        required uint32 availability = 3; /* Class of 9s */ -        required uint32 loss         = 4; /* Packet loss */ -        required uint32 ber          = 5; /* Bit error rate, ppb */ -        required uint32 in_order     = 6; /* In-order delivery */ -        required uint32 max_gap      = 7; /* In ms */ -        required uint32 cypher_s     = 8; /* Crypto strength in bits */ -}; +message enroll_req_msg { +        required bytes id = 1; +} + +message enroll_resp_msg { +        required bytes           id       = 1; +        required int64           t_sec    = 2; +        required int32           t_nsec   = 3; +        required int32           response = 4; +        optional ipcp_config_msg conf     = 5; +} + +message enroll_ack_msg { +        required bytes id     = 1; +        required int32 result = 2; +} diff --git a/src/lib/ipcpd_messages.proto b/src/lib/pb/ipcp.proto index a8c3bfb4..c2c7f48b 100644 --- a/src/lib/ipcpd_messages.proto +++ b/src/lib/pb/ipcp.proto @@ -1,7 +1,7 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   * - * IPCPd message + * Messages sent to IPCPds   *   *    Dimitri Staessens <dimitri@ouroboros.rocks>   *    Sander Vrijders   <sander@ouroboros.rocks> @@ -23,7 +23,8 @@  syntax = "proto2";  import "ipcp_config.proto"; -import "qosspec.proto"; +import "model.proto"; +  enum ipcp_msg_code {          IPCP_BOOTSTRAP       =  1; @@ -38,7 +39,7 @@ enum ipcp_msg_code {          IPCP_CONNECT         = 10;          IPCP_DISCONNECT      = 11;          IPCP_REPLY           = 12; -}; +}  message ipcp_msg {          required ipcp_msg_code code        =  1; @@ -53,5 +54,6 @@ message ipcp_msg {          optional int32 response            = 10;          optional string comp               = 11;          optional uint32 timeo_sec          = 12; -        optional int32 result              = 13; -}; +        optional sint32 mpl                = 13; +        optional int32 result              = 14; +} diff --git a/src/lib/pb/ipcp_config.proto b/src/lib/pb/ipcp_config.proto new file mode 100644 index 00000000..1308c6d1 --- /dev/null +++ b/src/lib/pb/ipcp_config.proto @@ -0,0 +1,93 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Layer configuration message + * + *    Dimitri Staessens <dimitri@ouroboros.rocks> + *    Sander Vrijders   <sander@ouroboros.rocks> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +syntax = "proto2"; + +import "model.proto"; + + +message 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 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 dir_config_msg  dir   = 2; +        required uint32 addr_auth_type = 3; +        required uint32 cong_avoid     = 4; +} + +message eth_config_msg { +        required string dev       = 1; +        required uint32 ethertype = 2; +} + +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 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 new file mode 100644 index 00000000..75f5f350 --- /dev/null +++ b/src/lib/pb/irm.proto @@ -0,0 +1,98 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Messages sent to IRMd + * + *    Dimitri Staessens <dimitri@ouroboros.rocks> + *    Sander Vrijders   <sander@ouroboros.rocks> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +syntax = "proto2"; + +import "ipcp_config.proto"; +import "model.proto"; + +enum irm_msg_code { +        IRM_CREATE_IPCP       =  1; +        IPCP_CREATE_R         =  2; +        IRM_DESTROY_IPCP      =  3; +        IRM_LIST_IPCPS        =  4; +        IRM_BOOTSTRAP_IPCP    =  5; +        IRM_ENROLL_IPCP       =  6; +        IRM_CONNECT_IPCP      =  7; +        IRM_DISCONNECT_IPCP   =  8; +        IRM_BIND_PROGRAM      =  9; +        IRM_UNBIND_PROGRAM    = 10; +        IRM_PROC_ANNOUNCE     = 11; +        IRM_PROC_EXIT         = 12; +        IRM_BIND_PROCESS      = 13; +        IRM_UNBIND_PROCESS    = 14; +        IRM_CREATE_NAME       = 15; +        IRM_DESTROY_NAME      = 16; +        IRM_LIST_NAMES        = 17; +        IRM_REG_NAME          = 18; +        IRM_UNREG_NAME        = 19; +        IRM_FLOW_ALLOC        = 20; +        IRM_FLOW_ACCEPT       = 21; +        IRM_FLOW_JOIN         = 22; +        IRM_FLOW_DEALLOC      = 23; +        IPCP_FLOW_DEALLOC     = 24; +        IPCP_FLOW_REQ_ARR     = 25; +        IPCP_FLOW_ALLOC_REPLY = 26; +        IRM_REPLY             = 27; +} + +message timespec_msg { +        required uint64 tv_sec  = 1; +        required uint32 tv_nsec = 2; +} + +message ipcp_list_msg { +        required uint32 pid       = 1; +        required uint32 type      = 2; +        required string name      = 3; +        required string layer     = 4; +        required uint32 hash_algo = 5; +} + +message irm_msg { +        required irm_msg_code code       =  1; +        optional string prog             =  2; +        optional sint32 pid              =  3; +        optional string name             =  4; +        optional flow_info_msg flow_info =  5; +        optional ipcp_info_msg ipcp_info =  6; +        optional 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 */ +        optional bytes symmkey           = 23; +        optional uint32 timeo_sec        = 24; +        optional uint32 timeo_nsec       = 25; +        optional sint32 result           = 26; +} diff --git a/src/lib/pb/model.proto b/src/lib/pb/model.proto new file mode 100644 index 00000000..7b06e434 --- /dev/null +++ b/src/lib/pb/model.proto @@ -0,0 +1,64 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Model description messages + * + *    Dimitri Staessens <dimitri@ouroboros.rocks> + *    Sander Vrijders   <sander@ouroboros.rocks> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +syntax = "proto2"; + +message qosspec_msg { +        required uint32 delay        = 1; /* In ms.                   */ +        required uint64 bandwidth    = 2; /* In bits/s.               */ +        required uint32 availability = 3; /* Class of 9s.             */ +        required uint32 loss         = 4; /* Packet loss.             */ +        required uint32 ber          = 5; /* Bit error rate, ppb.     */ +        required uint32 in_order     = 6; /* In-order delivery.       */ +        required uint32 max_gap      = 7; /* In ms.                   */ +        required uint32 timeout      = 8; /* Timeout in ms.           */ +} + +message flow_info_msg { +        required uint32      id      = 1; +        required uint32      n_pid   = 2; +        required uint32      n_1_pid = 3; +        required uint32      mpl     = 4; +        required uint32      state   = 5; +        required qosspec_msg qos     = 6; +} + +message name_info_msg { +        required string name    = 1; +        required uint32 pol_lb  = 2; +        required string skey    = 3; +        required string scrt    = 4; +        required string ckey    = 5; +        required string ccrt    = 6; +} + +message layer_info_msg { +        required string name          = 1; +        required uint32 dir_hash_algo = 2; +} + +message ipcp_info_msg { +        required uint32 type  = 1; +        required string name  = 2; +        required uint32 pid   = 3; +        required uint32 state = 4; +} diff --git a/src/lib/protobuf.c b/src/lib/protobuf.c new file mode 100644 index 00000000..6df4e810 --- /dev/null +++ b/src/lib/protobuf.c @@ -0,0 +1,915 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Protobuf syntax conversion + * + *    Dimitri Staessens <dimitri@ouroboros.rocks> + *    Sander Vrijders   <sander@ouroboros.rocks> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _DEFAULT_SOURCE + +#include <ouroboros/protobuf.h> + +#include <stdlib.h> +#include <string.h> +#include <time.h> + +timespec_msg_t * timespec_s_to_msg(const struct timespec * s) +{ +        timespec_msg_t * msg; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        timespec_msg__init(msg); + +        msg->tv_sec  = s->tv_sec; +        msg->tv_nsec = s->tv_nsec; + +        return msg; + + fail_malloc: +        return NULL; +} + +struct timespec timespec_msg_to_s(timespec_msg_t * msg) +{ +        struct timespec s; + +        assert(msg != NULL); + +        s.tv_sec  = msg->tv_sec; +        s.tv_nsec = msg->tv_nsec; + +        return s; +} + +flow_info_msg_t * flow_info_s_to_msg(const struct flow_info * s) +{ +        flow_info_msg_t * msg; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        flow_info_msg__init(msg); + +        msg->id      = s->id; +        msg->n_pid   = s->n_pid; +        msg->n_1_pid = s->n_1_pid; +        msg->mpl     = s->mpl; +        msg->state   = s->state; +        msg->qos     = qos_spec_s_to_msg(&s->qs); +        if (msg->qos == NULL) +                goto fail_msg; + +        return msg; + + fail_msg: +        flow_info_msg__free_unpacked(msg, NULL); + fail_malloc: +        return NULL; +} + +struct flow_info flow_info_msg_to_s(const flow_info_msg_t * msg) +{ +        struct flow_info s; + +        assert(msg != NULL); + +        s.id      = msg->id; +        s.n_pid   = msg->n_pid; +        s.n_1_pid = msg->n_1_pid; +        s.mpl     = msg->mpl; +        s.state   = msg->state; +        s.qs      = qos_spec_msg_to_s(msg->qos); + +        return s; +} + +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; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        layer_info_msg__init(msg); + +        msg->name = strdup(s->name); +        if (msg->name == NULL) +                goto fail_msg; + +        msg->dir_hash_algo  = s->dir_hash_algo; + +        return msg; + + fail_msg: +        layer_info_msg__free_unpacked(msg, NULL); + fail_malloc: +        return NULL; +} + +struct layer_info layer_info_msg_to_s(const layer_info_msg_t * msg) +{ +        struct layer_info s; + +        assert(msg != NULL); +        assert(strlen(msg->name) <= LAYER_NAME_SIZE); + +        s.dir_hash_algo = msg->dir_hash_algo; +        strcpy(s.name, msg->name); + +        return s; +} + +ipcp_info_msg_t * ipcp_info_s_to_msg(const struct ipcp_info * s) +{ +        ipcp_info_msg_t * msg; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        ipcp_info_msg__init(msg); + +        msg->name = strdup(s->name); +        if (msg->name == NULL) +                goto fail_msg; + +        msg->type  = s->type; +        msg->pid   = s->pid; +        msg->state = s->state; + +        return msg; + fail_msg: +        ipcp_info_msg__free_unpacked(msg, NULL); + fail_malloc: +        return NULL; +} + +struct ipcp_info ipcp_info_msg_to_s(const ipcp_info_msg_t * msg) +{ +        struct ipcp_info s; + +        assert(msg != NULL); +        assert(msg->name != NULL); +        assert(strlen(msg->name) <= NAME_SIZE); + +        strcpy(s.name, msg->name); +        s.type  = msg->type; +        s.pid   = msg->pid; +        s.state = msg->state; + +        return s; +} + +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; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                return NULL; + +        dt_config_msg__init(msg); + +        msg->addr_size    = s->addr_size; +        msg->eid_size     = s->eid_size; +        msg->max_ttl      = s->max_ttl; +        msg->routing      = 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) +{ +        struct dt_config s; + +        assert(msg != NULL); + +        s.addr_size    = msg->addr_size; +        s.eid_size     = msg->eid_size; +        s.max_ttl      = msg->max_ttl; +        s.routing      = 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; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        uni_config_msg__init(msg); + +        msg->dt = dt_config_s_to_msg(&s->dt); +        if (msg->dt == NULL) +                goto fail_msg; + +        msg->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; + +        return msg; + + fail_msg: +        uni_config_msg__free_unpacked(msg, NULL); + fail_malloc: +        return NULL; +} + +struct uni_config uni_config_msg_to_s(const uni_config_msg_t * msg) +{ +        struct uni_config s; + +        s.dt = dt_config_msg_to_s(msg->dt); +        s.dir = dir_config_msg_to_s(msg->dir); + +        s.addr_auth_type  = msg->addr_auth_type; +        s.cong_avoid      = msg->cong_avoid; + +        return s; +} + +udp4_config_msg_t * udp4_config_s_to_msg(const struct udp4_config * s) +{ +        udp4_config_msg_t * msg; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                return NULL; + +        udp4_config_msg__init(msg); + +        msg->ip_addr  = s->ip_addr.s_addr; +        msg->dns_addr = s->dns_addr.s_addr; +        msg->port     = s->port; + +        return 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 udp6_config s; + +        assert(msg != NULL); + +        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; +} + +eth_config_msg_t * eth_config_s_to_msg(const struct eth_config * s) +{ +        eth_config_msg_t * msg; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        eth_config_msg__init(msg); + +        msg->dev = strdup(s->dev); +        if (msg->dev == NULL) +                goto fail_msg; + +        msg->ethertype = s->ethertype; + +        return msg; + + fail_msg: +        eth_config_msg__free_unpacked(msg, NULL); + fail_malloc: +        return NULL; +} + +struct eth_config eth_config_msg_to_s(const eth_config_msg_t * msg) +{ +        struct eth_config s; + +        assert(msg != NULL); +        assert(strlen(msg->dev) <= DEV_NAME_SIZE); + +        strcpy(s.dev, msg->dev); +        s.ethertype = msg->ethertype; + +        return s; +} + + +ipcp_config_msg_t * ipcp_config_s_to_msg(const struct ipcp_config * s) +{ +        ipcp_config_msg_t * msg; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        ipcp_config_msg__init(msg); + +        switch (s->type) { +        case IPCP_LOCAL: +                break; +        case IPCP_UNICAST: +                msg->unicast = uni_config_s_to_msg(&s->unicast); +                if (msg->unicast == NULL) +                        goto fail_msg; +                break; +        case IPCP_BROADCAST: +                break; +        case IPCP_ETH_LLC: +                /* FALLTHRU */ +        case IPCP_ETH_DIX: +                msg->eth = eth_config_s_to_msg(&s->eth); +                if (msg->eth == NULL) +                        goto fail_msg; +                break; +        case IPCP_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: +                /* No checks here */ +                break; +        } + +        msg->ipcp_type = s->type; + +        msg->layer_info = layer_info_s_to_msg(&s->layer_info); +        if (msg->layer_info == NULL) +                goto fail_msg; + +        return msg; + + fail_msg: +        ipcp_config_msg__free_unpacked(msg, NULL); + fail_malloc: +        return NULL; +} + +struct ipcp_config ipcp_config_msg_to_s(const ipcp_config_msg_t * msg) +{ +        struct ipcp_config s; + +        assert(msg != NULL); + +        s.type = msg->ipcp_type; + +        s.layer_info = layer_info_msg_to_s(msg->layer_info); + +        switch(msg->ipcp_type) { +        case IPCP_LOCAL: +                break; +        case IPCP_UNICAST: +                s.unicast = uni_config_msg_to_s(msg->unicast); +                break; +        case IPCP_ETH_LLC: +                /* FALLTHRU */ +        case IPCP_ETH_DIX: +                s.eth = eth_config_msg_to_s(msg->eth); +                break; +        case IPCP_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; +        default: +                /* No checks here */ +                break; +        } + +        return s; +} + +qosspec_msg_t * qos_spec_s_to_msg(const struct qos_spec * s) +{ +        qosspec_msg_t  * msg; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                return NULL; + +        qosspec_msg__init(msg); + +        msg->delay        = s->delay; +        msg->bandwidth    = s->bandwidth; +        msg->availability = s->availability; +        msg->loss         = s->loss; +        msg->ber          = s->ber; +        msg->in_order     = s->in_order; +        msg->max_gap      = s->max_gap; +        msg->timeout      = s->timeout; + +        return msg; +} + +struct qos_spec qos_spec_msg_to_s(const qosspec_msg_t * msg) +{ +        struct qos_spec s; + +        assert(msg != NULL); + +        s.delay        = msg->delay; +        s.bandwidth    = msg->bandwidth; +        s.availability = msg->availability; +        s.loss         = msg->loss; +        s.ber          = msg->ber; +        s.in_order     = msg->in_order; +        s.max_gap      = msg->max_gap; +        s.timeout      = msg->timeout; + +        return s; +} + +enroll_req_msg_t * enroll_req_s_to_msg(const struct enroll_req * s) +{ +        enroll_req_msg_t * msg; +        uint8_t *          id; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_msg; + +        id = malloc(ENROLL_ID_LEN); +        if (id == NULL) +                goto fail_id; + +        memcpy(id, s->id, ENROLL_ID_LEN); + +        enroll_req_msg__init(msg); + +        msg->id.len  = ENROLL_ID_LEN; +        msg->id.data = id; + +        return msg; + + fail_id: +        free(msg); + fail_msg: +        return NULL; +} + +struct enroll_req enroll_req_msg_to_s(const enroll_req_msg_t * msg) +{ +        struct enroll_req s; + +        assert(msg != NULL); + +        memcpy(s.id, msg->id.data, ENROLL_ID_LEN); + +        return s; +} + +enroll_resp_msg_t * enroll_resp_s_to_msg(const struct enroll_resp * s) +{ +        enroll_resp_msg_t * msg; +        uint8_t *           id; + +        assert(s != NULL); + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_msg; + +        id = malloc(ENROLL_ID_LEN); +        if (id == NULL) +                goto fail_id; + +        memcpy(id, s->id, ENROLL_ID_LEN); + +        enroll_resp_msg__init(msg); + +        msg->id.len   = ENROLL_ID_LEN; +        msg->id.data  = id; + +        msg->t_sec    = s->t.tv_sec; +        msg->t_nsec   = s->t.tv_nsec; +        msg->response = s->response; +        if (msg->response < 0) +                return msg; + +        msg->conf = ipcp_config_s_to_msg(&s->conf); +        if (msg->conf == NULL) +                goto fail_id; + +        return msg; + + fail_id: +        enroll_resp_msg__free_unpacked(msg, NULL); + fail_msg: +        return NULL; +} + +struct enroll_resp enroll_resp_msg_to_s(const enroll_resp_msg_t * msg) +{ +        struct enroll_resp s; + +        assert (msg != NULL); + +        s.response = msg->response; +        if (s.response >= 0) +                s.conf = ipcp_config_msg_to_s(msg->conf); + +        s.t.tv_sec  = msg->t_sec; +        s.t.tv_nsec = msg->t_nsec; + +        memcpy(s.id, msg->id.data, ENROLL_ID_LEN); + +        return s; +} + +enroll_ack_msg_t * enroll_ack_s_to_msg(const struct enroll_ack * s) +{ +        enroll_ack_msg_t * msg; +        uint8_t *          id; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_msg; + +        id = malloc(ENROLL_ID_LEN); +        if (id == NULL) +                goto fail_id; + +        memcpy(id, s->id, ENROLL_ID_LEN); + +        enroll_ack_msg__init(msg); + +        msg->id.len   = ENROLL_ID_LEN; +        msg->id.data  = id; + +        msg->result = s->result; + +        return msg; + + fail_id: +        enroll_ack_msg__free_unpacked(msg, NULL); + fail_msg: +        return NULL; +} + +struct enroll_ack enroll_ack_msg_to_s(const enroll_ack_msg_t * msg) +{ +        struct enroll_ack s; + +        assert(msg != NULL); + +        memcpy(s.id, msg->id.data, ENROLL_ID_LEN); + +        s.result = msg->result; + +        return s; +} diff --git a/src/lib/qoscube.c b/src/lib/qoscube.c index b9482263..267b3a87 100644 --- a/src/lib/qoscube.c +++ b/src/lib/qoscube.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Quality of Service cube   * diff --git a/src/lib/random.c b/src/lib/random.c index ee992fda..2dc5f02f 100644 --- a/src/lib/random.c +++ b/src/lib/random.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Pseudo random generator   * @@ -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/rib.c b/src/lib/rib.c index 27c66f2f..97a20f47 100644 --- a/src/lib/rib.c +++ b/src/lib/rib.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * RIB export using FUSE   * @@ -139,6 +139,10 @@ static int rib_readdir(const char *            path,          (void) offset;          (void) info; +        /* Fix ls calling readdir in an infinite loop on raspbian. */ +        if (info != NULL && info->nonseekable != 0) +                return -ENOENT; +          filler(buf, ".", NULL, 0);          filler(buf, "..", NULL, 0); @@ -203,12 +207,15 @@ static size_t __getattr(const char *  path,                  if (strcmp(comp, r->path) == 0) {                          size_t ret = r->ops->getattr(path + 1, &attr);                          pthread_rwlock_unlock(&rib.lock); -                        st->st_mode  = S_IFREG | 0755; -                        st->st_nlink = 1; -                        st->st_uid   = getuid(); -                        st->st_gid   = getgid(); -                        st->st_size  = attr.size; -                        st->st_mtime = attr.mtime; +                        st->st_mode   = S_IFREG | 0644; +                        st->st_blocks = 1; +                        st->st_nlink  = 1; +                        st->st_uid    = getuid(); +                        st->st_gid    = getgid(); +                        st->st_size   = attr.size; +                        st->st_atime  = attr.mtime; +                        st->st_mtime  = attr.mtime; +                        st->st_ctime  = attr.mtime;                          return ret;                  }          } @@ -252,6 +259,8 @@ static int rib_getattr(const char *  path,          st->st_uid   = getuid();          st->st_gid   = getgid();          st->st_mtime = now.tv_sec; +        st->st_atime = now.tv_sec; +        st->st_ctime = now.tv_sec;          return 0;  } @@ -338,7 +347,7 @@ int rib_init(const char * mountpt)          fuse_opt_free_args(&args);          rmdir(rib.mnt);   fail_mnt: -        memset(rib.mnt, 0, RIB_PATH_LEN + 1); +        memset(rib.mnt, 0, sizeof(rib.mnt));   fail:          return -1;  #else @@ -377,6 +386,18 @@ void rib_fini(void)          pthread_rwlock_unlock(&rib.lock);          pthread_rwlock_destroy(&rib.lock); + +        memset(rib.mnt, 0, sizeof(rib.mnt)); +#endif +} + +void rib_cleanup(const char * mnt) +{ +#ifdef HAVE_FUSE +        fuse_unmount(mnt, NULL); +        rmdir(mnt); +#else +        (void) mnt;  #endif  } diff --git a/src/lib/serdes-irm.c b/src/lib/serdes-irm.c new file mode 100644 index 00000000..3aea0617 --- /dev/null +++ b/src/lib/serdes-irm.c @@ -0,0 +1,473 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Ouroboros IRM Protocol - serialization/deserialization + * + *    Dimitri Staessens <dimitri@ouroboros.rocks> + *    Sander Vrijders   <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + +#include <ouroboros/errno.h> +#include <ouroboros/serdes-irm.h> +#include <ouroboros/protobuf.h> + +#include <stdlib.h> +#include <string.h> + +int flow_accept__irm_req_ser(buffer_t *               buf, +                             const struct flow_info * flow, +                             const struct timespec *  timeo) +{ +        irm_msg_t * msg; +        size_t      len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code    = IRM_MSG_CODE__IRM_FLOW_ACCEPT; +        msg->flow_info = flow_info_s_to_msg(flow); +        if (msg->flow_info == NULL) +                goto fail_msg; + +        msg->timeo = timeo == NULL ? NULL : timespec_s_to_msg(timeo); +        if (timeo != NULL && msg->timeo == NULL) +                goto fail_msg; + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + +static int __flow_alloc_ser(buffer_t *               buf, +                            const struct flow_info * flow, +                            const char *             dst, +                            const struct timespec *  timeo, +                            int                      msg_code) +{ +        irm_msg_t *     msg; +        size_t          len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code = msg_code; +        msg->flow_info = flow_info_s_to_msg(flow); +        if (msg->flow_info == NULL) +                goto fail_msg; + +        msg->dst = strdup(dst); +        if (msg->dst == NULL) +                goto fail_msg; + +        msg->timeo = timeo == NULL ? NULL : timespec_s_to_msg(timeo); +        if (timeo != NULL && msg->timeo == NULL) +                goto fail_msg; + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + +int flow_alloc__irm_req_ser(buffer_t *               buf, +                            const struct flow_info * flow, +                            const char *             dst, +                            const struct timespec *  timeo) +{ +        return __flow_alloc_ser(buf, flow, dst, timeo, +                                IRM_MSG_CODE__IRM_FLOW_ALLOC); +} + +int flow_join__irm_req_ser(buffer_t *               buf, +                           const struct flow_info * flow, +                           const char *             dst, +                           const struct timespec *  timeo) +{ +        return __flow_alloc_ser(buf, flow, dst, timeo, +                                IRM_MSG_CODE__IRM_FLOW_JOIN); +} + +int flow__irm_result_des(buffer_t *         buf, +                         struct flow_info * flow, +                         buffer_t  *        sk) +{ +        irm_msg_t * msg; +        int         err; + +        if (sk != NULL) +                sk->data = NULL; + +        msg = irm_msg__unpack(NULL, buf->len, buf->data); +        if (msg == NULL) { +                err = -EIRMD; +                goto fail_msg; +        } + +        if (!msg->has_result) { +                err = -EIRMD; +                goto fail; +        } + +        if (msg->result < 0) { +                err = msg->result; +                goto fail; +        } + +        if (msg->flow_info == NULL) { +                err = -EBADF; +                goto fail; +        } + +        *flow = flow_info_msg_to_s(msg->flow_info); + +        if (sk != NULL) { +                sk->len  = msg->symmkey.len; +                sk->data = msg->symmkey.data; + +                msg->symmkey.data = NULL; +                msg->symmkey.len  = 0; +        } + +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + fail: +        irm_msg__free_unpacked(msg, NULL); + fail_msg: +        return err; +} + +int flow_dealloc__irm_req_ser(buffer_t *               buf, +                              const struct flow_info * flow, +                              const struct timespec *  timeo) +{ +        irm_msg_t * msg; +        size_t      len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code = IRM_MSG_CODE__IRM_FLOW_DEALLOC; +        msg->flow_info = flow_info_s_to_msg(flow); +        if (msg->flow_info == NULL) +                goto fail_msg; + +        msg->timeo = timespec_s_to_msg(timeo); +        if (msg->timeo == NULL) +                goto fail_msg; + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + +int ipcp_flow_dealloc__irm_req_ser(buffer_t *               buf, +                                   const struct flow_info * flow) +{ +        irm_msg_t * msg; +        size_t      len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code = IRM_MSG_CODE__IPCP_FLOW_DEALLOC; +        msg->flow_info = flow_info_s_to_msg(flow); +        if (msg->flow_info == NULL) +                goto fail_msg; + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + + +int ipcp_create_r__irm_req_ser(buffer_t *               buf, +                               const struct ipcp_info * ipcp) +{ +        irm_msg_t * msg; +        size_t      len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code       = IRM_MSG_CODE__IPCP_CREATE_R; +        msg->ipcp_info  = ipcp_info_s_to_msg(ipcp); +        if (msg->ipcp_info == NULL) +                goto fail_msg; + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + +int proc_announce__irm_req_ser(buffer_t *   buf, +                               const char * prog) +{ +        irm_msg_t * msg; +        size_t      len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code    = IRM_MSG_CODE__IRM_PROC_ANNOUNCE; +        msg->has_pid = true; +        msg->pid     = getpid(); +        msg->prog    = strdup(prog); +        if (msg->prog == NULL) +                goto fail_msg; + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + +int proc_exit__irm_req_ser(buffer_t *   buf) +{ +        irm_msg_t * msg; +        size_t      len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code    = IRM_MSG_CODE__IRM_PROC_EXIT; +        msg->has_pid = true; +        msg->pid     = getpid(); + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + +int ipcp_flow_req_arr__irm_req_ser(buffer_t *               buf, +                                   const buffer_t *         dst, +                                   const struct flow_info * flow, +                                   const buffer_t *         data) +{ +        irm_msg_t * msg; +        size_t      len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code      = IRM_MSG_CODE__IPCP_FLOW_REQ_ARR; +        msg->flow_info = flow_info_s_to_msg(flow); +        if (msg->flow_info == NULL) +                goto fail_msg; + +        msg->has_hash  = true; +        msg->hash.len  = dst->len; +        msg->hash.data = dst->data; +        msg->has_pk    = true; +        msg->pk.len    = data->len; +        msg->pk.data   = data->data; + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); + +        /* Don't free * dst or data! */ +        msg->hash.len = 0; +        msg->hash.data = NULL; +        msg->pk.len = 0; +        msg->pk.data = NULL; +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + +int ipcp_flow_alloc_reply__irm_msg_ser(buffer_t *               buf, +                                       const struct flow_info * flow, +                                       int                      response, +                                       const buffer_t *         data) +{ +        irm_msg_t * msg; +        size_t      len; + +        msg = malloc(sizeof(*msg)); +        if (msg == NULL) +                goto fail_malloc; + +        irm_msg__init(msg); + +        msg->code      = IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY; +        msg->flow_info = flow_info_s_to_msg(flow); +        if (msg->flow_info == NULL) +                goto fail_msg; + +        msg->has_pk       = true; +        msg->pk.len       = data->len; +        msg->pk.data      = data->data; +        msg->has_response = true; +        msg->response     = response; + +        len = irm_msg__get_packed_size(msg); +        if (len == 0 || len > buf->len) +                goto fail_msg; + +        buf->len = len; + +        irm_msg__pack(msg, buf->data); + +        /* Don't free * data! */ +        msg->pk.len = 0; +        msg->pk.data = NULL; + +        irm_msg__free_unpacked(msg, NULL); + +        return 0; + fail_msg: +        irm_msg__free_unpacked(msg, NULL); + fail_malloc: +        return -ENOMEM; +} + +int irm__irm_result_des(buffer_t * buf) +{ +        irm_msg_t * msg; +        int         err; + +        msg = irm_msg__unpack(NULL, buf->len, buf->data); +        if (msg == NULL) { +                err = -EIRMD; +                goto fail_msg; +        } + +        if (!msg->has_result) { +                err = -EIRMD; +                goto fail; +        } + +        err = msg->result; + fail: +        irm_msg__free_unpacked(msg, NULL); + fail_msg: +        return err; +} diff --git a/src/lib/serdes-oep.c b/src/lib/serdes-oep.c new file mode 100644 index 00000000..8a836b3b --- /dev/null +++ b/src/lib/serdes-oep.c @@ -0,0 +1,161 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Ouroboros Enrollment Protocol - serialization/deserialization + * + *    Dimitri Staessens <dimitri@ouroboros.rocks> + *    Sander Vrijders   <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200112L + +#include <ouroboros/protobuf.h> +#include <ouroboros/serdes-oep.h> + +ssize_t enroll_req_ser(const struct enroll_req * req, +                       buffer_t                  buf) +{ +        enroll_req_msg_t * msg; +        ssize_t            sz; + +        msg = enroll_req_s_to_msg(req); +        if (msg == NULL) +                goto fail_msg; + +        sz = enroll_req_msg__get_packed_size(msg); +        if (sz < 0 || (size_t) sz > buf.len) +                goto fail_pack; + +        enroll_req_msg__pack(msg, buf.data); + +        enroll_req_msg__free_unpacked(msg, NULL); + +        return sz; + + fail_pack: +        enroll_req_msg__free_unpacked(msg, NULL); + fail_msg: +    return -1; +} + +int enroll_req_des(struct enroll_req * req, +                   const buffer_t      buf) +{ +        enroll_req_msg_t * msg; + +        msg = enroll_req_msg__unpack(NULL, buf.len, buf.data); +        if (msg == NULL) +                goto fail_unpack; + +        if (msg->id.len != ENROLL_ID_LEN) +                goto fail_id; + +        *req = enroll_req_msg_to_s(msg); + +        enroll_req_msg__free_unpacked(msg, NULL); + +        return 0; + + fail_id: +        enroll_req_msg__free_unpacked(msg, NULL); + fail_unpack: +        return -1; +} + +ssize_t enroll_resp_ser(const struct enroll_resp * resp, +                        buffer_t                   buf) +{ +        enroll_resp_msg_t * msg; +        ssize_t             sz; + +        msg = enroll_resp_s_to_msg(resp); +        if (msg == NULL) +                goto fail_msg; + +        sz = enroll_resp_msg__get_packed_size(msg); +        if (sz < 0 || (size_t) sz > buf.len) +                goto fail_pack; + +        enroll_resp_msg__pack(msg, buf.data); + +        enroll_resp_msg__free_unpacked(msg, NULL); + +        return sz; + + fail_pack: +        enroll_resp_msg__free_unpacked(msg, NULL); + fail_msg: +        return -1; +} + +int enroll_resp_des(struct enroll_resp * resp, +                    const buffer_t       buf) +{ +        enroll_resp_msg_t * msg; + +        msg = enroll_resp_msg__unpack(NULL, buf.len, buf.data); +        if (msg == NULL) +                return -1; + +        *resp = enroll_resp_msg_to_s(msg); + +        enroll_resp_msg__free_unpacked(msg, NULL); + +        return 0; +} + +ssize_t enroll_ack_ser(const struct enroll_ack * ack, +                       buffer_t                  buf) +{ +        enroll_ack_msg_t * msg; +        ssize_t            sz; + +        msg = enroll_ack_s_to_msg(ack); +        if (msg == NULL) +                goto fail_msg; + +        sz = enroll_ack_msg__get_packed_size(msg); +        if (sz < 0 || (size_t) sz > buf.len) +                goto fail_pack; + +        enroll_ack_msg__pack(msg, buf.data); + +        enroll_ack_msg__free_unpacked(msg, NULL); + +        return sz; + + fail_pack: +        enroll_ack_msg__free_unpacked(msg, NULL); + fail_msg: +        return -1; + +} + +int enroll_ack_des(struct enroll_ack * ack, +                   const buffer_t      buf) +{ +        enroll_ack_msg_t * msg; + +        msg = enroll_ack_msg__unpack(NULL, buf.len, buf.data); +        if (msg == NULL) +                return -1; + +        *ack = enroll_ack_msg_to_s(msg); + +        enroll_ack_msg__free_unpacked(msg, NULL); + +        return 0; +} diff --git a/src/lib/sha3.c b/src/lib/sha3.c index 74f971ab..b9d6b07f 100644 --- a/src/lib/sha3.c +++ b/src/lib/sha3.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * SHA3 algorithm   * @@ -52,8 +52,7 @@  #include <assert.h>  #include <string.h> -#define IS_ALIGNED_64(p) (0 == (7 & ((const uint8_t *) (p)      \ -                                     - (const uint8_t *) 0))) +#define IS_ALIGNED_64(p) (0 == (7 & ((uintptr_t) (p))))  #define I64(x) x##LL  #define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) diff --git a/src/lib/shm_flow_set.c b/src/lib/shm_flow_set.c index 5a9bee6c..39913fd1 100644 --- a/src/lib/shm_flow_set.c +++ b/src/lib/shm_flow_set.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Management of flow_sets for fqueue   * @@ -24,21 +24,21 @@  #include "config.h" -#include <ouroboros/lockfile.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/shm_flow_set.h>  #include <ouroboros/errno.h> +#include <ouroboros/lockfile.h>  #include <ouroboros/pthread.h> +#include <ouroboros/shm_flow_set.h> +#include <ouroboros/time.h> -#include <sys/mman.h> +#include <assert.h>  #include <fcntl.h> +#include <signal.h>  #include <stdlib.h>  #include <stdio.h> +#include <string.h>  #include <unistd.h> -#include <signal.h> +#include <sys/mman.h>  #include <sys/stat.h> -#include <string.h> -#include <assert.h>  /*   * pthread_cond_timedwait has a WONTFIX bug as of glibc 2.25 where it @@ -52,39 +52,35 @@  #endif  #define FN_MAX_CHARS 255 +#define FS_PROT      (PROT_READ | PROT_WRITE) -#define QUEUESIZE ((SHM_BUFFER_SIZE) * sizeof(struct portevent)) +#define QUEUESIZE ((SHM_BUFFER_SIZE) * sizeof(struct flowevent)) -#define SHM_FLOW_SET_FILE_SIZE (SYS_MAX_FLOWS * sizeof(ssize_t)             \ -                                + PROG_MAX_FQUEUES * sizeof(size_t)         \ -                                + PROG_MAX_FQUEUES * sizeof(pthread_cond_t) \ -                                + PROG_MAX_FQUEUES * QUEUESIZE              \ -                                + sizeof(pthread_mutex_t)) +#define SHM_FSET_FILE_SIZE (SYS_MAX_FLOWS * sizeof(ssize_t)             \ +                            + PROG_MAX_FQUEUES * sizeof(size_t)         \ +                            + PROG_MAX_FQUEUES * sizeof(pthread_cond_t) \ +                            + PROG_MAX_FQUEUES * QUEUESIZE              \ +                            + sizeof(pthread_mutex_t))  #define fqueue_ptr(fs, idx) (fs->fqueues + (SHM_BUFFER_SIZE) * idx) -struct portevent { -        int flow_id; -        int event; -}; -  struct shm_flow_set {          ssize_t *          mtable;          size_t *           heads;          pthread_cond_t *   conds; -        struct portevent * fqueues; +        struct flowevent * fqueues;          pthread_mutex_t *  lock;          pid_t pid;  };  static struct shm_flow_set * flow_set_create(pid_t pid, -                                             int   flags) +                                             int   oflags)  {          struct shm_flow_set * set;          ssize_t *             shm_base;          char                  fn[FN_MAX_CHARS]; -        int                   shm_fd; +        int                   fd;          sprintf(fn, SHM_FLOW_SET_PREFIX "%d", pid); @@ -92,39 +88,33 @@ static struct shm_flow_set * flow_set_create(pid_t pid,          if (set == NULL)                  goto fail_malloc; -        shm_fd = shm_open(fn, flags, 0666); -        if (shm_fd == -1) +        fd = shm_open(fn, oflags, 0666); +        if (fd == -1)                  goto fail_shm_open; -        if (ftruncate(shm_fd, SHM_FLOW_SET_FILE_SIZE - 1) < 0) { -                close(shm_fd); -                goto fail_shm_open; -        } - -        shm_base = mmap(NULL, -                        SHM_FLOW_SET_FILE_SIZE, -                        PROT_READ | PROT_WRITE, -                        MAP_SHARED, -                        shm_fd, -                        0); - -        close(shm_fd); +        if ((oflags & O_CREAT) && ftruncate(fd, SHM_FSET_FILE_SIZE) < 0) +                goto fail_truncate; +        shm_base = mmap(NULL, SHM_FSET_FILE_SIZE, FS_PROT, MAP_SHARED, fd, 0);          if (shm_base == MAP_FAILED)                  goto fail_mmap; +        close(fd); +          set->mtable  = shm_base;          set->heads   = (size_t *) (set->mtable + SYS_MAX_FLOWS);          set->conds   = (pthread_cond_t *)(set->heads + PROG_MAX_FQUEUES); -        set->fqueues = (struct portevent *) (set->conds + PROG_MAX_FQUEUES); +        set->fqueues = (struct flowevent *) (set->conds + PROG_MAX_FQUEUES);          set->lock    = (pthread_mutex_t *)                  (set->fqueues + PROG_MAX_FQUEUES * (SHM_BUFFER_SIZE));          return set;   fail_mmap: -        if (flags & O_CREAT) +        if (oflags & O_CREAT)                  shm_unlink(fn); + fail_truncate: +        close(fd);   fail_shm_open:          free(set);   fail_malloc: @@ -206,7 +196,7 @@ struct shm_flow_set * shm_flow_set_open(pid_t pid)  void shm_flow_set_destroy(struct shm_flow_set * set)  { -        char fn[25]; +        char fn[FN_MAX_CHARS];          assert(set); @@ -221,7 +211,7 @@ void shm_flow_set_close(struct shm_flow_set * set)  {          assert(set); -        munmap(set->mtable, SHM_FLOW_SET_FILE_SIZE); +        munmap(set->mtable, SHM_FSET_FILE_SIZE);          free(set);  } @@ -307,6 +297,8 @@ void shm_flow_set_notify(struct shm_flow_set * set,                           int                   flow_id,                           int                   event)  { +        struct flowevent * e; +          assert(set);          assert(!(flow_id < 0) && flow_id < SYS_MAX_FLOWS); @@ -317,10 +309,13 @@ void shm_flow_set_notify(struct shm_flow_set * set,                  return;          } -        (fqueue_ptr(set, set->mtable[flow_id]) + -         (set->heads[set->mtable[flow_id]]))->flow_id = flow_id; -        (fqueue_ptr(set, set->mtable[flow_id]) + -         (set->heads[set->mtable[flow_id]])++)->event = event; +        e = fqueue_ptr(set, set->mtable[flow_id]) + +                set->heads[set->mtable[flow_id]]; + +        e->flow_id = flow_id; +        e->event   = event; + +        ++set->heads[set->mtable[flow_id]];          pthread_cond_signal(&set->conds[set->mtable[flow_id]]); @@ -330,7 +325,7 @@ void shm_flow_set_notify(struct shm_flow_set * set,  ssize_t shm_flow_set_wait(const struct shm_flow_set * set,                            size_t                      idx, -                          int *                       fqueue, +                          struct flowevent *          fqueue,                            const struct timespec *     abstime)  {          ssize_t ret = 0; @@ -349,18 +344,11 @@ ssize_t shm_flow_set_wait(const struct shm_flow_set * set,          pthread_cleanup_push(__cleanup_mutex_unlock, set->lock);          while (set->heads[idx] == 0 && ret != -ETIMEDOUT) { -                if (abstime != NULL) { -                        ret = -pthread_cond_timedwait(set->conds + idx, -                                                      set->lock, -                                                      abstime); +                ret = -__timedwait(set->conds + idx, set->lock, abstime);  #ifdef HAVE_CANCEL_BUG -                        if (ret == -ETIMEDOUT) -                                pthread_testcancel(); +                if (ret == -ETIMEDOUT) +                        pthread_testcancel();  #endif -                } else { -                        ret = -pthread_cond_wait(set->conds + idx, -                                                 set->lock); -                }  #ifdef HAVE_ROBUST_MUTEX                  if (ret == -EOWNERDEAD)                          pthread_mutex_consistent(set->lock); @@ -370,7 +358,7 @@ ssize_t shm_flow_set_wait(const struct shm_flow_set * set,          if (ret != -ETIMEDOUT) {                  memcpy(fqueue,                         fqueue_ptr(set, idx), -                       set->heads[idx] * sizeof(struct portevent)); +                       set->heads[idx] * sizeof(*fqueue));                  ret = set->heads[idx];                  set->heads[idx] = 0;          } diff --git a/src/lib/shm_rbuff.c b/src/lib/shm_rbuff.c index 361d5bb0..22cff41c 100644 --- a/src/lib/shm_rbuff.c +++ b/src/lib/shm_rbuff.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Ring buffer implementations for incoming packets   * @@ -26,22 +26,22 @@  #include <ouroboros/shm_rbuff.h>  #include <ouroboros/lockfile.h> -#include <ouroboros/time_utils.h>  #include <ouroboros/errno.h>  #include <ouroboros/fccntl.h>  #include <ouroboros/pthread.h> +#include <ouroboros/time.h> -#include <sys/mman.h> +#include <assert.h>  #include <fcntl.h> +#include <signal.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h>  #include <stdlib.h>  #include <string.h> -#include <stdio.h> -#include <stdint.h>  #include <unistd.h> -#include <signal.h> +#include <sys/mman.h>  #include <sys/stat.h> -#include <assert.h> -#include <stdbool.h>  #define FN_MAX_CHARS 255 @@ -69,20 +69,11 @@ struct shm_rbuff {          int               flow_id;  /* flow_id of the flow           */  }; -void shm_rbuff_close(struct shm_rbuff * rb) -{ -        assert(rb); - -        munmap(rb->shm_base, SHM_RB_FILE_SIZE); - -        free(rb); -} -  #define MM_FLAGS (PROT_READ | PROT_WRITE) -struct shm_rbuff * rbuff_create(pid_t pid, -                                int   flow_id, -                                int   flags) +static struct shm_rbuff * rbuff_create(pid_t pid, +                                       int   flow_id, +                                       int   flags)  {          struct shm_rbuff * rb;          int                fd; @@ -99,7 +90,7 @@ struct shm_rbuff * rbuff_create(pid_t pid,          if (fd == -1)                  goto fail_open; -        if ((flags & O_CREAT) && ftruncate(fd, SHM_RB_FILE_SIZE - 1) < 0) +        if ((flags & O_CREAT) && ftruncate(fd, SHM_RB_FILE_SIZE) < 0)                  goto fail_truncate;          shm_base = mmap(NULL, SHM_RB_FILE_SIZE, MM_FLAGS, MAP_SHARED, fd, 0); @@ -130,6 +121,13 @@ struct shm_rbuff * rbuff_create(pid_t pid,          return NULL;  } +static void rbuff_destroy(struct shm_rbuff * rb) +{ +        munmap(rb->shm_base, SHM_RB_FILE_SIZE); + +        free(rb); +} +  struct shm_rbuff * shm_rbuff_create(pid_t pid,                                      int   flow_id)  { @@ -174,7 +172,7 @@ struct shm_rbuff * shm_rbuff_create(pid_t pid,          *rb->head = 0;          *rb->tail = 0; -        rb->pid = pid; +        rb->pid     = pid;          rb->flow_id = flow_id;          pthread_mutexattr_destroy(&mattr); @@ -202,6 +200,13 @@ struct shm_rbuff * shm_rbuff_open(pid_t pid,          return rbuff_create(pid, flow_id, O_RDWR);  } +void shm_rbuff_close(struct shm_rbuff * rb) +{ +        assert(rb); + +        rbuff_destroy(rb); +} +  #if (defined(SHM_RBUFF_LOCKLESS) &&                            \       (defined(__GNUC__) || defined (__clang__)))  #include "shm_rbuff_ll.c" diff --git a/src/lib/shm_rbuff_ll.c b/src/lib/shm_rbuff_ll.c index eef8a2fb..46a5314e 100644 --- a/src/lib/shm_rbuff_ll.c +++ b/src/lib/shm_rbuff_ll.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Lockless ring buffer for incoming packets   * @@ -31,6 +31,11 @@ void shm_rbuff_destroy(struct shm_rbuff * rb)          sprintf(fn, SHM_RBUFF_PREFIX "%d.%d", rb->pid, rb->flow_id); +        __sync_bool_compare_and_swap(rb->acl, *rb->acl, ACL_FLOWDOWN); + +        pthread_cond_broadcast(rb->del); +        pthread_cond_broadcast(rb->add); +          shm_rbuff_close(rb);          shm_unlink(fn); @@ -103,12 +108,7 @@ int shm_rbuff_write_b(struct shm_rbuff *      rb,          pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock);          while (!shm_rbuff_free(rb) && ret != -ETIMEDOUT) { -                if (abstime != NULL) -                        ret = -pthread_cond_timedwait(rb->add, -                                                      rb->lock, -                                                      abstime); -                else -                        ret = -pthread_cond_wait(rb->add, rb->lock); +                ret = -__timedwait(rb->add, rb->lock, abstime);  #ifdef HAVE_ROBUST_MUTEX                  if (ret == -EOWNERDEAD)                          pthread_mutex_consistent(rb->lock); @@ -138,9 +138,15 @@ ssize_t shm_rbuff_read(struct shm_rbuff * rb)          assert(rb); -        if (shm_rbuff_empty(rb)) -                return __sync_fetch_and_add(rb->acl, 0) & ACL_FLOWDOWN ? -                        -EFLOWDOWN : -EAGAIN; +        if (shm_rbuff_empty(rb)) { +                if (_sync_fetch_and_add(rb->acl, 0) & ACL_FLOWDOWN) +                        return -EFLOWDOWN; + +                if (_sync_fetch_and_add(rb->acl, 0) & ACL_FLOWPEER) +                        return -EFLOWPEER; + +                return -EAGAIN; +        }          ntail = RB_TAIL; @@ -176,12 +182,7 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff *      rb,          pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock);          while (shm_rbuff_empty(rb) && (idx != -ETIMEDOUT)) { -                if (abstime != NULL) -                        idx = -pthread_cond_timedwait(rb->add, -                                                      rb->lock, -                                                      abstime); -                else -                        idx = -pthread_cond_wait(rb->add, rb->lock); +                idx = -__timedwait(rb->add, rb->lock, abstime);  #ifdef HAVE_ROBUST_MUTEX                  if (idx == -EOWNERDEAD)                          pthread_mutex_consistent(rb->lock); diff --git a/src/lib/shm_rbuff_pthr.c b/src/lib/shm_rbuff_pthr.c index cedbc7b1..b543fb07 100644 --- a/src/lib/shm_rbuff_pthr.c +++ b/src/lib/shm_rbuff_pthr.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Ring buffer for incoming packets   * @@ -24,12 +24,15 @@ void shm_rbuff_destroy(struct shm_rbuff * rb)  {          char fn[FN_MAX_CHARS]; -        assert(rb); +        assert(rb != NULL);  #ifdef CONFIG_OUROBOROS_DEBUG          pthread_mutex_lock(rb->lock); -        assert(shm_rbuff_empty(rb)); +        *rb->acl = *rb->acl & ACL_FLOWDOWN; + +        pthread_cond_broadcast(rb->del); +        pthread_cond_broadcast(rb->add);          pthread_mutex_unlock(rb->lock);  #endif @@ -45,7 +48,7 @@ int shm_rbuff_write(struct shm_rbuff * rb,  {          int ret = 0; -        assert(rb); +        assert(rb != NULL);          assert(idx < SHM_BUFFER_SIZE);  #ifndef HAVE_ROBUST_MUTEX @@ -88,7 +91,7 @@ int shm_rbuff_write_b(struct shm_rbuff *      rb,  {          int ret = 0; -        assert(rb); +        assert(rb != NULL);          assert(idx < SHM_BUFFER_SIZE);  #ifndef HAVE_ROBUST_MUTEX @@ -111,12 +114,7 @@ int shm_rbuff_write_b(struct shm_rbuff *      rb,          while (!shm_rbuff_free(rb)                 && ret != -ETIMEDOUT                 && !(*rb->acl & ACL_FLOWDOWN)) { -                if (abstime != NULL) -                        ret = -pthread_cond_timedwait(rb->del, -                                                      rb->lock, -                                                      abstime); -                else -                        ret = -pthread_cond_wait(rb->del, rb->lock); +                ret = -__timedwait(rb->del, rb->lock, abstime);  #ifdef HAVE_ROBUST_MUTEX                  if (ret == -EOWNERDEAD)                          pthread_mutex_consistent(rb->lock); @@ -138,11 +136,24 @@ int shm_rbuff_write_b(struct shm_rbuff *      rb,          return ret;  } +static int check_rb_acl(struct shm_rbuff * rb) +{ +        assert(rb != NULL); + +        if (*rb->acl & ACL_FLOWDOWN) +                return -EFLOWDOWN; + +        if (*rb->acl & ACL_FLOWPEER) +                return -EFLOWPEER; + +        return -EAGAIN; +} +  ssize_t shm_rbuff_read(struct shm_rbuff * rb)  {          ssize_t ret = 0; -        assert(rb); +        assert(rb != NULL);  #ifndef HAVE_ROBUST_MUTEX          pthread_mutex_lock(rb->lock); @@ -152,7 +163,7 @@ ssize_t shm_rbuff_read(struct shm_rbuff * rb)  #endif          if (shm_rbuff_empty(rb)) { -                ret = *rb->acl & ACL_FLOWDOWN ? -EFLOWDOWN : -EAGAIN; +                ret = check_rb_acl(rb);                  pthread_mutex_unlock(rb->lock);                  return ret;          } @@ -171,7 +182,7 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff *      rb,  {          ssize_t idx = -1; -        assert(rb); +        assert(rb != NULL);  #ifndef HAVE_ROBUST_MUTEX          pthread_mutex_lock(rb->lock); @@ -187,36 +198,35 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff *      rb,          pthread_cleanup_push(__cleanup_mutex_unlock, rb->lock); -        while (shm_rbuff_empty(rb) -               && (idx != -ETIMEDOUT) -               && !(*rb->acl & ACL_FLOWDOWN)) { -                if (abstime != NULL) -                        idx = -pthread_cond_timedwait(rb->add, -                                                      rb->lock, -                                                      abstime); -                else -                        idx = -pthread_cond_wait(rb->add, rb->lock); +        while (shm_rbuff_empty(rb) && +               idx != -ETIMEDOUT && +               check_rb_acl(rb) == -EAGAIN) { +                idx = -__timedwait(rb->add, rb->lock, abstime);  #ifdef HAVE_ROBUST_MUTEX                  if (idx == -EOWNERDEAD)                          pthread_mutex_consistent(rb->lock);  #endif          } -        if (idx != -ETIMEDOUT) { +        if (!shm_rbuff_empty(rb)) {                  idx = *tail_el_ptr(rb);                  *rb->tail = (*rb->tail + 1) & ((SHM_RBUFF_SIZE) - 1);                  pthread_cond_broadcast(rb->del); +        } else if (idx != -ETIMEDOUT) { +                idx = check_rb_acl(rb);          }          pthread_cleanup_pop(true); +        assert(idx != -EAGAIN); +          return idx;  }  void shm_rbuff_set_acl(struct shm_rbuff * rb,                         uint32_t           flags)  { -        assert(rb); +        assert(rb != NULL);  #ifndef HAVE_ROBUST_MUTEX          pthread_mutex_lock(rb->lock); @@ -236,7 +246,7 @@ uint32_t shm_rbuff_get_acl(struct shm_rbuff * rb)  {          uint32_t flags; -        assert(rb); +        assert(rb != NULL);  #ifndef HAVE_ROBUST_MUTEX          pthread_mutex_lock(rb->lock); @@ -253,7 +263,7 @@ uint32_t shm_rbuff_get_acl(struct shm_rbuff * rb)  void shm_rbuff_fini(struct shm_rbuff * rb)  { -        assert(rb); +        assert(rb != NULL);  #ifndef HAVE_ROBUST_MUTEX          pthread_mutex_lock(rb->lock); @@ -277,7 +287,7 @@ size_t shm_rbuff_queued(struct shm_rbuff * rb)  {          size_t ret; -        assert(rb); +        assert(rb != NULL);  #ifndef HAVE_ROBUST_MUTEX          pthread_mutex_lock(rb->lock); diff --git a/src/lib/shm_rdrbuff.c b/src/lib/shm_rdrbuff.c index e3552100..7ad1bd2e 100644 --- a/src/lib/shm_rdrbuff.c +++ b/src/lib/shm_rdrbuff.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Random Deletion Ring Buffer for Data Units   * @@ -25,21 +25,19 @@  #include "config.h"  #include <ouroboros/errno.h> -#include <ouroboros/shm_rdrbuff.h> -#include <ouroboros/shm_du_buff.h> -#include <ouroboros/time_utils.h>  #include <ouroboros/pthread.h> +#include <ouroboros/shm_rdrbuff.h> -#include <sys/mman.h> +#include <assert.h>  #include <fcntl.h> -#include <unistd.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h>  #include <stdlib.h>  #include <string.h> -#include <stdio.h> -#include <signal.h> +#include <unistd.h> +#include <sys/mman.h>  #include <sys/stat.h> -#include <stdbool.h> -#include <assert.h>  #define SHM_BLOCKS_SIZE ((SHM_BUFFER_SIZE) * SHM_RDRB_BLOCK_SIZE)  #define SHM_FILE_SIZE (SHM_BLOCKS_SIZE + 2 * sizeof(size_t)                    \ @@ -173,7 +171,7 @@ static struct shm_rdrbuff * rdrb_create(int flags)          if (fd == -1)                  goto fail_open; -        if ((flags & O_CREAT) && ftruncate(fd, SHM_FILE_SIZE - 1) < 0) +        if ((flags & O_CREAT) && ftruncate(fd, SHM_FILE_SIZE) < 0)                  goto fail_truncate;          shm_base = mmap(NULL, SHM_FILE_SIZE, MM_FLAGS, MAP_SHARED, fd, 0); @@ -205,7 +203,7 @@ static struct shm_rdrbuff * rdrb_create(int flags)          return NULL;  } -struct shm_rdrbuff * shm_rdrbuff_create() +struct shm_rdrbuff * shm_rdrbuff_create(void)  {          struct shm_rdrbuff * rdrb;          mode_t               mask; @@ -263,7 +261,7 @@ struct shm_rdrbuff * shm_rdrbuff_create()          return NULL;  } -struct shm_rdrbuff * shm_rdrbuff_open() +struct shm_rdrbuff * shm_rdrbuff_open(void)  {          return rdrb_create(O_RDWR);  } @@ -402,13 +400,7 @@ ssize_t shm_rdrbuff_alloc_b(struct shm_rdrbuff *    rdrb,  #else          while (!shm_rdrb_free(rdrb, 1) && ret != ETIMEDOUT) {  #endif -                if (abstime != NULL) -                        ret = pthread_cond_timedwait(rdrb->healthy, -                                                     rdrb->lock, -                                                     abstime); -                else -                        ret = pthread_cond_wait(rdrb->healthy, rdrb->lock); - +                ret = __timedwait(rdrb->healthy, rdrb->lock, abstime);  #ifdef SHM_RDRB_MULTI_BLOCK                  if (blocks + *rdrb->head > (SHM_BUFFER_SIZE))                          padblocks = (SHM_BUFFER_SIZE) - *rdrb->head; @@ -532,6 +524,13 @@ uint8_t * shm_du_buff_tail(struct shm_du_buff * sdb)          return (uint8_t *) (sdb + 1) + sdb->du_tail;  } +size_t shm_du_buff_len(struct shm_du_buff * sdb) +{ +        assert(sdb); + +        return sdb->du_tail - sdb->du_head; +} +  uint8_t * shm_du_buff_head_alloc(struct shm_du_buff * sdb,                                   size_t               size)  { @@ -578,7 +577,7 @@ uint8_t * shm_du_buff_head_release(struct shm_du_buff * sdb,  }  uint8_t * shm_du_buff_tail_release(struct shm_du_buff * sdb, -                              size_t               size) +                                   size_t               size)  {          assert(sdb);          assert(!(size > sdb->du_tail - sdb->du_head)); diff --git a/src/lib/sockets.c b/src/lib/sockets.c index 8179d2b3..5dfbcb5c 100644 --- a/src/lib/sockets.c +++ b/src/lib/sockets.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * The sockets layer to communicate between daemons   * @@ -21,6 +21,7 @@   */  #include <ouroboros/errno.h> +#include <ouroboros/pthread.h>  #include <ouroboros/sockets.h>  #include <ouroboros/utils.h> @@ -29,9 +30,7 @@  #include <string.h>  #include <stdio.h>  #include <stdlib.h> -#include <pthread.h>  #include <stdbool.h> -#include <sys/time.h>  /* Apple doesn't support SEQPACKET. */  #ifdef __APPLE__ @@ -57,8 +56,7 @@ int client_socket_open(char * file_name)          serv_addr.sun_family = AF_UNIX;          sprintf(serv_addr.sun_path, "%s", file_name); -        if (connect(sockfd, -                    (struct sockaddr *) &serv_addr, +        if (connect(sockfd, (struct sockaddr *) &serv_addr,                      sizeof(serv_addr))) {                  close(sockfd);                  return -1; @@ -102,10 +100,9 @@ int server_socket_open(char * file_name)  irm_msg_t * send_recv_irm_msg(irm_msg_t * msg)  { -        int         sockfd; -        uint8_t     buf[SOCK_BUF_SIZE]; -        ssize_t     len; -        irm_msg_t * recv_msg = NULL; +        int            sockfd; +        uint8_t        buf[SOCK_BUF_SIZE]; +        ssize_t        len;          sockfd = client_socket_open(IRM_SOCK_PATH);          if (sockfd < 0) @@ -117,27 +114,53 @@ irm_msg_t * send_recv_irm_msg(irm_msg_t * msg)                  return NULL;          } -        pthread_cleanup_push(__cleanup_close_ptr, &sockfd); -          irm_msg__pack(msg, buf); -        if (write(sockfd, buf, len) != -1) +        pthread_cleanup_push(__cleanup_close_ptr, &sockfd); + +        len = write(sockfd, buf, len); +        if (len >= 0)                  len = read(sockfd, buf, SOCK_BUF_SIZE); -        if (len > 0) -                recv_msg = irm_msg__unpack(NULL, len, buf); +        pthread_cleanup_pop(true); + +        if (len < 0) +                goto fail; + +        return irm_msg__unpack(NULL, len, buf); + fail: +        return NULL; +} + +int send_recv_msg(buffer_t * msg) +{ +        int     sockfd; +        ssize_t len = 0; + +        sockfd = client_socket_open(IRM_SOCK_PATH); +        if (sockfd < 0) +                return -1; + +        pthread_cleanup_push(__cleanup_close_ptr, &sockfd); + +        len = write(sockfd, msg->data, msg->len); +        if (len >= 0) +                len = read(sockfd, msg->data, SOCK_BUF_SIZE);          pthread_cleanup_pop(true); -        return recv_msg; +        msg->len = (size_t) len; + +        return len < 0 ? -1 : 0;  } -char * ipcp_sock_path(pid_t pid) +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); @@ -146,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) { @@ -156,49 +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;  } -qosspec_msg_t spec_to_msg(const qosspec_t * qs) +char * sock_path(pid_t        pid, +                 const char * prefix)  { -        qosspec_t     spec; -        qosspec_msg_t msg = QOSSPEC_MSG__INIT; - -        spec = (qs == NULL ? qos_raw : *qs); - -        msg.delay        = spec.delay; -        msg.bandwidth    = spec.bandwidth; -        msg.availability = spec.availability; -        msg.loss         = spec.loss; -        msg.ber          = spec.ber; -        msg.in_order     = spec.in_order; -        msg.max_gap      = spec.max_gap; -        msg.cypher_s     = spec.cypher_s; - -        return msg; -} - -qosspec_t msg_to_spec(const qosspec_msg_t * msg) -{ -        qosspec_t     spec; - -        assert(msg); - -        spec.delay        = msg->delay; -        spec.bandwidth    = msg->bandwidth; -        spec.availability = msg->availability; -        spec.loss         = msg->loss; -        spec.ber          = msg->ber; -        spec.in_order     = msg->in_order; -        spec.max_gap      = msg->max_gap; -        spec.cypher_s     = msg->cypher_s; - -        return spec; +        return __sock_path(pid, prefix, SOCK_PATH_SUFFIX);  } diff --git a/src/lib/tests/CMakeLists.txt b/src/lib/tests/CMakeLists.txt index 9e23b0ee..2791dd0d 100644 --- a/src/lib/tests/CMakeLists.txt +++ b/src/lib/tests/CMakeLists.txt @@ -3,13 +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 -  time_utils_test.c +  sockets_test.c +  time_test.c +  tpm_test.c    )  add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}) @@ -19,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/bitmap_test.c b/src/lib/tests/bitmap_test.c index 0815ecff..4dbd6653 100644 --- a/src/lib/tests/bitmap_test.c +++ b/src/lib/tests/bitmap_test.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Test of the bitmap   * @@ -27,7 +27,8 @@  #define BITMAP_SIZE 200 -int bitmap_test(int argc, char ** argv) +int bitmap_test(int     argc, +                char ** argv)  {          struct bmp * bmp;          ssize_t bits = BITMAP_SIZE; @@ -60,27 +61,23 @@ int bitmap_test(int argc, char ** argv)                  if (!bmp_is_id_valid(bmp, id)) {                          if (i < BITMAP_SIZE + offset) {                                  printf("Failed valid ID %d (%zd).\n", i, id); -                                bmp_destroy(bmp); -                                return -1; +                                goto fail;                          }                          if (id >= offset && id < bits + offset) {                                  printf("Valid ID %zd returned invalid.\n", id); -                                bmp_destroy(bmp); -                                return -1; +                                goto fail;                          }                          continue;                  }                  if (!bmp_is_id_used(bmp, id)) {                          printf("ID not marked in use.\n"); -                        bmp_destroy(bmp); -                        return -1; +                        goto fail;                  }                  if (id != i) {                          printf("Wrong ID returned.\n"); -                        bmp_destroy(bmp); -                        return -1; +                        goto fail;                  }          } @@ -89,20 +86,24 @@ int bitmap_test(int argc, char ** argv)                  if (bmp_release(bmp, r)) {                          printf("Failed to release ID.\n"); -                        return -1; +                        goto fail;                  }                  id = bmp_allocate(bmp);                  if (!bmp_is_id_valid(bmp, id))                          continue; +                  if (id != r) {                          printf("Wrong prev ID returned.\n"); -                        bmp_destroy(bmp); -                        return -1; +                        goto fail;                  }          }          bmp_destroy(bmp);          return 0; + + fail: +        bmp_destroy(bmp); +        return -1;  } diff --git a/src/lib/tests/btree_test.c b/src/lib/tests/btree_test.c index 9dc59d32..8bd30370 100644 --- a/src/lib/tests/btree_test.c +++ b/src/lib/tests/btree_test.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Test of the B-tree implementation   * diff --git a/src/lib/tests/crc32_test.c b/src/lib/tests/crc32_test.c index a0f70423..a26c8220 100644 --- a/src/lib/tests/crc32_test.c +++ b/src/lib/tests/crc32_test.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Test of the CRC32 function   * 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/hash_test.c b/src/lib/tests/hash_test.c new file mode 100644 index 00000000..970d9185 --- /dev/null +++ b/src/lib/tests/hash_test.c @@ -0,0 +1,202 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the hashing functions + * + *    Dimitri Staessens <dimitri@ouroboros.rocks> + *    Sander Vrijders   <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include <ouroboros/hash.h> +#include <ouroboros/test.h> + +#include <stdlib.h> +#include <stdint.h> +#include <assert.h> +#include <string.h> +#include <stdio.h> + +/* + * Test vectors calculated at + * https://www.lammertbies.nl/comm/info/crc-calculation.html + */ + +struct vec_entry { +        char * in; +        char * out; +}; + +static int test_crc32(void) +{ +        int ret = 0; + +        struct vec_entry vec [] = { +                { "0",         "f4dbdf21" }, +                { "123456789", "cbf43926" }, +                { "987654321", "015f0201" }, +                { NULL,        NULL       } +        }; + +        struct vec_entry * cur = vec; + +        TEST_START(); + +        while (cur->in != NULL) { +                uint8_t crc[4]; +                char    res[9]; + +                str_hash(HASH_CRC32, crc, cur->in); + +                sprintf(res, HASH_FMT32, HASH_VAL32(crc)); +                if (strcmp(res, cur->out) != 0) { +                        printf("Hash failed %s != %s.\n", res, cur->out); +                        ret |= -1; +                } + +                ++cur; +        } + +        TEST_END(ret); + +        return ret; +} + +static int test_md5(void) +{ +        int ret = 0; + +        struct vec_entry vec [] = {{ +                "abc", +                "900150983cd24fb0d6963f7d28e17f72" +        }, { +                "The quick brown fox jumps over the lazy dog", +                "9e107d9d372bb6826bd81d3542a419d6" +        }, { +                "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", +                "8215ef0796a20bcaaae116d3876c664a" +        }, { +                NULL, +                NULL +        }}; + +        struct vec_entry * cur = vec; + +        TEST_START(); + + +        while (cur->in != NULL) { +                uint8_t md5[16]; +                char    res[33]; + +                str_hash(HASH_MD5, md5, cur->in); + +                sprintf(res, HASH_FMT128, HASH_VAL128(md5)); +                if (strcmp(res, cur->out) != 0) { +                        printf("Hash failed %s != %s.\n", res, cur->out); +                        ret |= -1; +                } + +                ++cur; +        } + +        TEST_END(ret); + +        return ret; +} + +static int test_sha3(void) +{ +        int ret = 0; + +        uint8_t sha3[64]; +        char    res[129]; + +        char * in = "abc"; + +        char * out = +                "e642824c3f8cf24ad09234ee7d3c766f" +                "c9a3a5168d0c94ad73b46fdf"; + +        TEST_START(); + +        str_hash(HASH_SHA3_224, sha3, in); + +        sprintf(res, HASH_FMT224, HASH_VAL224(sha3)); +        if (strcmp(res, out) != 0) { +                printf("SHA3-224 failed %s != %s", res, out); +                ret |= -1; +        } + +        out = +                "3a985da74fe225b2045c172d6bd390bd" +                "855f086e3e9d525b46bfe24511431532"; + +        str_hash(HASH_SHA3_256, sha3, in); + +        sprintf(res, HASH_FMT256, HASH_VAL256(sha3)); +        if (strcmp(res, out) != 0) { +                printf("SHA3-256 failed %s != %s.\n", res, out); +                ret |= -1; +        } + +        out = +                "ec01498288516fc926459f58e2c6ad8d" +                "f9b473cb0fc08c2596da7cf0e49be4b2" +                "98d88cea927ac7f539f1edf228376d25"; + +        str_hash(HASH_SHA3_384, sha3, in); + +        sprintf(res, HASH_FMT384, HASH_VAL384(sha3)); +        if (strcmp(res, out) != 0) { +                printf("SHA3-384failed %s != %s.'n", res, out); +                ret |= -1; +        } + +        out = +                "b751850b1a57168a5693cd924b6b096e" +                "08f621827444f70d884f5d0240d2712e" +                "10e116e9192af3c91a7ec57647e39340" +                "57340b4cf408d5a56592f8274eec53f0"; + +        str_hash(HASH_SHA3_512, sha3, in); + +        sprintf(res, HASH_FMT512, HASH_VAL512(sha3)); +        if (strcmp(res, out) != 0) { +                printf("SHA3-512 failed %s != %s.\n", res, out); +                ret |= -1; +        } + +        TEST_END(ret); + +        return ret; +} + +int hash_test(int     argc, +              char ** argv) +{ +        int ret = 0; + +        (void) argc; +        (void) argv; + +        ret |= test_crc32(); + +        ret |= test_md5(); + +        ret |= test_sha3(); + +        return ret; +} diff --git a/src/lib/tests/md5_test.c b/src/lib/tests/md5_test.c index b5ad127f..28e8f42f 100644 --- a/src/lib/tests/md5_test.c +++ b/src/lib/tests/md5_test.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Test of the MD5 function   * diff --git a/src/lib/tests/sha3_test.c b/src/lib/tests/sha3_test.c index 4860cd9b..82b4ef0d 100644 --- a/src/lib/tests/sha3_test.c +++ b/src/lib/tests/sha3_test.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Test of the SHA3 function   * diff --git a/src/lib/tests/shm_rbuff_test.c b/src/lib/tests/shm_rbuff_test.c index a3ed1449..e36c3229 100644 --- a/src/lib/tests/shm_rbuff_test.c +++ b/src/lib/tests/shm_rbuff_test.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Test of the shm_rbuff   * 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 new file mode 100644 index 00000000..2b75b873 --- /dev/null +++ b/src/lib/tests/time_test.c @@ -0,0 +1,529 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the time utilities + * + *    Dimitri Staessens <dimitri@ouroboros.rocks> + *    Sander Vrijders   <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200809L + +#include <ouroboros/test.h> +#include <ouroboros/time.h> + +#include <stdio.h> + +static int ts_check(struct timespec * s, +                    time_t            sec, +                    time_t            nsec) +{ +        return s->tv_sec == sec && s->tv_nsec == nsec; +} + +static int tv_check(struct timeval * v, +                    time_t           sec, +                    time_t           usec) +{ +        return v->tv_sec == sec && v->tv_usec == usec; +} + + +static int test_time_ts_init(void) +{ +        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 int test_time_tv_init(void) +{ +        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 test_ts_diff(void) +{ +        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 test_tv_diff(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); +        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; +} + +static int test_ts_diff_time(void) +{ +        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); + +        TEST_START(); + +        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; +        } + +        if (ts_diff_us(&ms0, &ms1) != -100 * 1000L) { +                printf("timespec_diff_us failed at ms0 - ms1.\n"); +                goto fail; +        } + +        if (ts_diff_us(&ms1, &ms0) != 100 * 1000L) { +                printf("timespec_diff_us failed at ms1 - ms0.\n"); +                goto fail; +        } + +        if (ts_diff_ns(&ms0, &ms1) != -100 * MILLION) { +                printf("timespec_diff_ns failed at ms0 - ms1.\n"); +                goto fail; +        } + +        if (ts_diff_ns(&ms1, &ms0) != 100 * MILLION) { +                printf("timespec_diff_ns failed at ms1 - ms0.\n"); +                goto fail; +        } + +        if (ts_diff_ms(&us0, &us1) != 0) { +                printf("timespec_diff_ms failed at us0 - us1.\n"); +                goto fail; +        } + +        if (ts_diff_ms(&us1, &us0) != 0) { +                printf("timespec_diff_ms failed at us1 - us0.\n"); +                goto fail; +        } + +        if (ts_diff_us(&us0, &us1) != -100) { +                printf("timespec_diff_us failed at us0 - us1.\n"); +                goto fail; +        } + +        if (ts_diff_us(&us1, &us0) != 100) { +                printf("timespec_diff_us failed at us1 - us0.\n"); +                goto fail; +        } + +        if (ts_diff_ns(&us0, &us1) != -100 * 1000L) { +                printf("timespec_diff_ns failed at us0 - us1.\n"); +                goto fail; +        } + +        if (ts_diff_ns(&us1, &us0) != 100 * 1000L) { +                printf("timespec_diff_ns failed at us1 - us0.\n"); +                goto fail; +        } + +        if (ts_diff_ms(&ns0, &ns1) != 0) { +                printf("timespec_diff_ms failed at ns0 - ns1.\n"); +                goto fail; +        } + +        if (ts_diff_ms(&ns1, &ns0) != 0) { +                printf("timespec_diff_ms failed at ns1 - ns0.\n"); +                goto fail; +        } + +        if (ts_diff_us(&ns0, &ns1) != 0) { +                printf("timespec_diff_us failed at ns0 - ns1.\n"); +                goto fail; +        } + +        if (ts_diff_us(&ns1, &ns0) != 0) { +                printf("timespec_diff_us failed at ns1 - ns0.\n"); +                goto fail; +        } + +        if (ts_diff_ns(&ns0, &ns1) != -100) { +                printf("timespec_diff_ns failed at ns0 - ns1.\n"); +                goto fail; +        } + +        if (ts_diff_ns(&ns1, &ns0) != 100) { +                printf("timespec_diff_ns failed at ns1 - ns0.\n"); +                goto fail; +        } + +        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/time_utils_test.c b/src/lib/tests/time_utils_test.c deleted file mode 100644 index fa65c4dc..00000000 --- a/src/lib/tests/time_utils_test.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * Test of the time utilities - * - *    Dimitri Staessens <dimitri@ouroboros.rocks> - *    Sander Vrijders   <sander@ouroboros.rocks> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., http://www.fsf.org/about/contact/. - */ - -#define _POSIX_C_SOURCE 200809L - -#include <ouroboros/time_utils.h> - -#include <stdio.h> - -static void ts_print(struct timespec * s) -{ -        printf("timespec is %zd:%ld.\n", (ssize_t) s->tv_sec, s->tv_nsec); -} - -static void tv_print(struct timeval * v) -{ -        printf("timeval is %zd:%zu.\n", (ssize_t) v->tv_sec, (size_t) v->tv_usec); -} - -static void ts_init(struct timespec * s, -                    time_t            sec, -                    time_t            nsec) -{ -        s->tv_sec  = sec; -        s->tv_nsec = nsec; -} - -static void tv_init(struct timeval * v, -                    time_t           sec, -                    time_t           usec) -{ -        v->tv_sec  = sec; -        v->tv_usec = usec; -} - -static int ts_check(struct timespec * s, -                    time_t            sec, -                    time_t            nsec) -{ -        return s->tv_sec == sec && s->tv_nsec == nsec; -} - -static int tv_check(struct timeval * v, -                    time_t           sec, -                    time_t           usec) -{ -        return v->tv_sec == sec && v->tv_usec == usec; -} - -int time_utils_test(int     argc, -                    char ** argv) -{ -        struct timespec s0; -        struct timespec s1; -        struct timespec s2; - -        struct timeval v0; -        struct timeval v1; -        struct timeval v2; - -        (void) argc; -        (void) argv; - -        ts_init(&s0, 0, 0); -        ts_init(&s1, 5, 0); - -        ts_add(&s0, &s1, &s2); -        if (!ts_check(&s2, 5, 0)) { -                printf("ts_add failed.\n"); -                ts_print(&s2); -                return -1; -        } - -        tv_init(&v0, 0, 0); -        tv_init(&v1, 5, 0); - -        tv_add(&v0, &v1, &v2); -        if (!tv_check(&v2, 5, 0)) { -                printf("tv_add failed.\n"); -                tv_print(&v2); -                return -1; -        } - -        ts_init(&s0, 0, 500 * MILLION); -        ts_init(&s1, 0, 600 * MILLION); - -        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; -        } - -        tv_init(&v0, 0, 500 * 1000); -        tv_init(&v1, 0, 600 * 1000); - -        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; -        } - -        ts_init(&s0, 0, 0); -        ts_init(&s1, 5, 0); - -        ts_diff(&s0, &s1, &s2); -        if (!ts_check(&s2, -5, 0)) { -                printf("ts_diff failed.\n"); -                ts_print(&s2); -                return -1; -        } - -        tv_init(&v0, 0, 0); -        tv_init(&v1, 5, 0); - -        tv_diff(&v0, &v1, &v2); -        if (!tv_check(&v2, -5, 0)) { -                printf("tv_diff failed.\n"); -                tv_print(&v2); -                return -1; -        } - -        ts_init(&s0, 0, 500 * MILLION); -        ts_init(&s1, 0, 600 * MILLION); - -        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; -        } - -        tv_init(&v0, 0, 500 * 1000); -        tv_init(&v1, 0, 600 * 1000); - -        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; -        } - -        return 0; -} 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/timerwheel.c b/src/lib/timerwheel.c index 3c1a44b4..96f4ac47 100644 --- a/src/lib/timerwheel.c +++ b/src/lib/timerwheel.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Timerwheel   * @@ -30,16 +30,12 @@  struct rxm {          struct list_head     next;          uint32_t             seqno; -#ifdef RXM_BUFFER_ON_HEAP -        uint8_t *            pkt; -        size_t               pkt_len; -#else +#ifndef RXM_BUFFER_ON_HEAP          struct shm_du_buff * sdb; -        uint8_t *            head; -        uint8_t *            tail;  #endif +        struct frct_pci *    pkt; +        size_t               len;          time_t               t0;      /* Time when original was sent (us). */ -        size_t               mul;     /* RTO multiplier.                   */          struct frcti *       frcti;          int                  fd;          int                  flow_id; /* Prevent rtx when fd reused.       */ @@ -62,11 +58,9 @@ struct {          struct list_head acks[ACKQ_SLOTS];          bool             map[ACKQ_SLOTS][PROG_MAX_FLOWS]; -        size_t           prv_rxm; /* Last processed rxm slot at lvl 0. */ -        size_t           prv_ack; /* Last processed ack slot.          */ +        size_t           prv_rxm[RXMQ_LVLS]; /* Last processed rxm slots. */ +        size_t           prv_ack;            /* Last processed ack slot.  */          pthread_mutex_t  lock; - -        bool             in_use;  } rw;  static void timerwheel_fini(void) @@ -119,8 +113,10 @@ static int timerwheel_init(void)          clock_gettime(PTHREAD_COND_CLOCK, &now); -        rw.prv_rxm = (ts_to_rxm_slot(now) - 1) & (RXMQ_SLOTS - 1);          for (i = 0; i < RXMQ_LVLS; ++i) { +                rw.prv_rxm[i] = (ts_to_rxm_slot(now) - 1); +                rw.prv_rxm[i] >>= (RXMQ_BUMP * i); +                rw.prv_rxm[i] &= (RXMQ_SLOTS - 1);                  for (j = 0; j < RXMQ_SLOTS; ++j)                          list_head_init(&rw.rxms[i][j]);          } @@ -142,38 +138,34 @@ static void timerwheel_move(void)          size_t             i;          size_t             j; -        if (!__sync_bool_compare_and_swap(&rw.in_use, true, true)) -                return; -          pthread_mutex_lock(&rw.lock);          pthread_cleanup_push(__cleanup_mutex_unlock, &rw.lock);          clock_gettime(PTHREAD_COND_CLOCK, &now); -        rxm_slot = ts_to_ns(now) >> RXMQ_RES; -        j = rw.prv_rxm; -        rw.prv_rxm = rxm_slot & (RXMQ_SLOTS - 1); +        rxm_slot = ts_to_rxm_slot(now);          for (i = 0; i < RXMQ_LVLS; ++i) {                  size_t j_max_slot = rxm_slot & (RXMQ_SLOTS - 1); +                j = rw.prv_rxm[i];                  if (j_max_slot < j)                          j_max_slot += RXMQ_SLOTS; -                  while (j++ < j_max_slot) {                          list_for_each_safe(p, h,                                             &rw.rxms[i][j & (RXMQ_SLOTS - 1)]) {                                  struct rxm *         r;                                  struct frct_cr *     snd_cr;                                  struct frct_cr *     rcv_cr; +                                size_t               slot;                                  size_t               rslot;                                  ssize_t              idx;                                  struct shm_du_buff * sdb; -                                uint8_t *            head; +                                struct frct_pci *    pci;                                  struct flow *        f;                                  uint32_t             snd_lwe;                                  uint32_t             rcv_lwe; -                                time_t               rto; +                                size_t               lvl = 0;                                  r = list_entry(p, struct rxm, next); @@ -186,84 +178,87 @@ static void timerwheel_move(void)                                  shm_du_buff_ack(r->sdb);  #endif                                  if (f->frcti == NULL -                                    || f->flow_id != r->flow_id) +                                    || f->info.id != r->flow_id)                                          goto cleanup; -                                pthread_rwlock_wrlock(&r->frcti->lock); +                                pthread_rwlock_rdlock(&r->frcti->lock);                                  snd_lwe = snd_cr->lwe;                                  rcv_lwe = rcv_cr->lwe; -                                rto     = r->frcti->rto;                                  pthread_rwlock_unlock(&r->frcti->lock);                                  /* Has been ack'd, remove. */ -                                if ((int) (r->seqno - snd_lwe) < 0) +                                if (before(r->seqno, snd_lwe))                                          goto cleanup;                                  /* Check for r-timer expiry. */                                  if (ts_to_ns(now) - r->t0 > r->frcti->r)                                          goto flow_down; -                                if (r->frcti->probe -                                    && (r->frcti->rttseq + 1) == r->seqno) +                                pthread_rwlock_wrlock(&r->frcti->lock); + +                                if (r->seqno == r->frcti->rttseq) { +                                        r->frcti->rto += +                                                r->frcti->rto >> RTO_DIV;                                          r->frcti->probe = false; +                                } +#ifdef PROC_FLOW_STATS +                                r->frcti->n_rtx++; +#endif +                                rslot = r->frcti->rto >> RXMQ_RES; + +                                pthread_rwlock_unlock(&r->frcti->lock); + +                                /* Schedule at least in the next time slot. */ +                                slot = ts_to_ns(now) >> RXMQ_RES; + +                                while (rslot >= RXMQ_SLOTS) { +                                        ++lvl; +                                        rslot >>= RXMQ_BUMP; +                                        slot >>= RXMQ_BUMP; +                                } + +                                if (lvl >= RXMQ_LVLS) /* Can't reschedule */ +                                        goto flow_down; + +                                rslot = (rslot + slot + 1) & (RXMQ_SLOTS - 1);  #ifdef RXM_BLOCKING -  #ifdef RXM_BUFFER_ON_HEAP -                                if (ipcp_sdb_reserve(&sdb, r->pkt_len)) -  #else -                                if (ipcp_sdb_reserve(&sdb, r->tail - r->head)) -  #endif +                                if (ipcp_sdb_reserve(&sdb, r->len) < 0)  #else -  #ifdef RXM_BUFFER_ON_HEAP -                                if (shm_rdrbuff_alloc(ai.rdrb, r->pkt_len, NULL, -                                                      &sdb)) -  #else -                                if (shm_rdrbuff_alloc(ai.rdrb, -                                                      r->tail - r->head, NULL, -                                                      &sdb)) -  #endif +                                if (shm_rdrbuff_alloc(ai.rdrb, r->len, NULL, +                                                      &sdb) < 0)  #endif -                                        goto reschedule; /* rbuff full */ -                                idx = shm_du_buff_get_idx(sdb); +                                        goto reschedule; /* rdrbuff full */ -                                head = shm_du_buff_head(sdb); -#ifdef RXM_BUFFER_ON_HEAP -                                memcpy(head, r->pkt, r->pkt_len); -#else -                                memcpy(head, r->head, r->tail - r->head); +                                pci = (struct frct_pci *) shm_du_buff_head(sdb); +                                memcpy(pci, r->pkt, r->len); +#ifndef RXM_BUFFER_ON_HEAP                                  ipcp_sdb_release(r->sdb); -                                r->sdb  = sdb; -                                r->head = head; -                                r->tail = shm_du_buff_tail(sdb); +                                r->sdb = sdb; +                                r->pkt = pci;                                  shm_du_buff_wait_ack(sdb);  #endif +                                idx = shm_du_buff_get_idx(sdb); +                                  /* Retransmit the copy. */ -                                ((struct frct_pci *) head)->ackno = -                                        hton32(rcv_lwe); +                                pci->ackno = hton32(rcv_lwe);  #ifdef RXM_BLOCKING -                                if (shm_rbuff_write_b(f->tx_rb, idx, NULL) == 0) +                                if (shm_rbuff_write_b(f->tx_rb, idx, NULL) < 0)  #else -                                if (shm_rbuff_write(f->tx_rb, idx) == 0) +                                if (shm_rbuff_write(f->tx_rb, idx) < 0)  #endif -                                        shm_flow_set_notify(f->set, f->flow_id, -                                                            FLOW_PKT); -                        reschedule: -                                r->mul++; - -                                /* Schedule at least in the next time slot. */ -                                rslot = (rxm_slot -                                         + MAX(((rto * r->mul) >> RXMQ_RES), 1)) -                                        & (RXMQ_SLOTS - 1); - -                                list_add_tail(&r->next, &rw.rxms[i][rslot]); - +                                        goto flow_down; +                                shm_flow_set_notify(f->set, f->info.id, +                                                    FLOW_PKT); +                         reschedule: +                                list_add(&r->next, &rw.rxms[lvl][rslot]);                                  continue; -                        flow_down: +                         flow_down:                                  shm_rbuff_set_acl(f->tx_rb, ACL_FLOWDOWN);                                  shm_rbuff_set_acl(f->rx_rb, ACL_FLOWDOWN); -                        cleanup: +                         cleanup:  #ifdef RXM_BUFFER_ON_HEAP                                  free(r->pkt);  #else @@ -272,9 +267,9 @@ static void timerwheel_move(void)                                  free(r);                          }                  } +                rw.prv_rxm[i] = rxm_slot & (RXMQ_SLOTS - 1);                  /* Move up a level in the wheel. */                  rxm_slot >>= RXMQ_BUMP; -                j >>= RXMQ_BUMP;          }          ack_slot = ts_to_ack_slot(now) & (ACKQ_SLOTS - 1) ; @@ -297,11 +292,10 @@ static void timerwheel_move(void)                          rw.map[j & (ACKQ_SLOTS - 1)][a->fd] = false; -                        if (f->flow_id == a->flow_id && f->frcti != NULL) +                        if (f->info.id == a->flow_id && f->frcti != NULL)                                  send_frct_pkt(a->frcti);                          free(a); -                  }          } @@ -327,21 +321,19 @@ static int timerwheel_rxm(struct frcti *       frcti,          clock_gettime(PTHREAD_COND_CLOCK, &now);          r->t0    = ts_to_ns(now); -        r->mul   = 0;          r->seqno = seqno;          r->frcti = frcti; +        r->len  = shm_du_buff_len(sdb);  #ifdef RXM_BUFFER_ON_HEAP -        r->pkt_len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); -        r->pkt = malloc(r->pkt_len); +        r->pkt = malloc(r->len);          if (r->pkt == NULL) {                  free(r);                  return -ENOMEM;          } -        memcpy(r->pkt, shm_du_buff_head(sdb), r->pkt_len); +        memcpy(r->pkt, shm_du_buff_head(sdb), r->len);  #else -        r->sdb   = sdb; -        r->head  = shm_du_buff_head(sdb); -        r->tail  = shm_du_buff_tail(sdb); +        r->sdb = sdb; +        r->pkt = (struct frct_pci *) shm_du_buff_head(sdb);  #endif          pthread_rwlock_rdlock(&r->frcti->lock); @@ -349,7 +341,7 @@ static int timerwheel_rxm(struct frcti *       frcti,          slot     = r->t0 >> RXMQ_RES;          r->fd      = frcti->fd; -        r->flow_id = ai.flows[r->fd].flow_id; +        r->flow_id = ai.flows[r->fd].info.id;          pthread_rwlock_unlock(&r->frcti->lock); @@ -367,7 +359,7 @@ static int timerwheel_rxm(struct frcti *       frcti,                  return -EPERM;          } -        slot = (slot + rto_slot) & (RXMQ_SLOTS - 1); +        slot = (slot + rto_slot + 1) & (RXMQ_SLOTS - 1);          pthread_mutex_lock(&rw.lock); @@ -377,13 +369,11 @@ static int timerwheel_rxm(struct frcti *       frcti,  #endif          pthread_mutex_unlock(&rw.lock); -        __sync_bool_compare_and_swap(&rw.in_use, false, true); -          return 0;  } -static int timerwheel_ack(int            fd, -                          struct frcti * frcti) +static int timerwheel_delayed_ack(int            fd, +                                  struct frcti * frcti)  {          struct timespec now;          struct ack *    a; @@ -395,18 +385,16 @@ static int timerwheel_ack(int            fd,          clock_gettime(PTHREAD_COND_CLOCK, &now); -        slot = DELT_ACK >> ACKQ_RES; -        if (slot >= ACKQ_SLOTS) { /* Out of timerwheel range. */ -                free(a); -                return -EPERM; -        } +        pthread_rwlock_rdlock(&frcti->lock); -        slot = (((ts_to_ns(now) + DELT_ACK) >> ACKQ_RES) + 1) +        slot = (((ts_to_ns(now) + (TICTIME << 1)) >> ACKQ_RES) + 1)                  & (ACKQ_SLOTS - 1); +        pthread_rwlock_unlock(&frcti->lock); +          a->fd    = fd;          a->frcti = frcti; -        a->flow_id = ai.flows[fd].flow_id; +        a->flow_id = ai.flows[fd].info.id;          pthread_mutex_lock(&rw.lock); @@ -422,7 +410,5 @@ static int timerwheel_ack(int            fd,          pthread_mutex_unlock(&rw.lock); -        __sync_bool_compare_and_swap(&rw.in_use, false, true); -          return 0;  } diff --git a/src/lib/tpm.c b/src/lib/tpm.c index dfba6492..7a17ef6b 100644 --- a/src/lib/tpm.c +++ b/src/lib/tpm.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Threadpool management   * @@ -26,21 +26,32 @@  #include <ouroboros/errno.h>  #include <ouroboros/list.h> -#include <ouroboros/time_utils.h> +#include <ouroboros/pthread.h> +#include <ouroboros/time.h>  #include <ouroboros/tpm.h> -#include <pthread.h> -#include <stdlib.h> +#ifdef CONFIG_OUROBOROS_DEBUG +#define OUROBOROS_PREFIX "tpm" +#include <ouroboros/logs.h> +#endif +  #include <assert.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,57 +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 = {(TPM_TIMEOUT / 1000), -                              (TPM_TIMEOUT % 1000) * MILLION}; -        struct tpm * tpm = (struct tpm *) o; - -        while (true) { -                clock_gettime(PTHREAD_COND_CLOCK, &dl); -                ts_add(&dl, &to, &dl); +        struct timespec to = TIMESPEC_INIT_MS(TPM_TIMEOUT); -                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;  } @@ -176,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)) @@ -209,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: @@ -218,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_join(tpm->mgr, NULL); - -        pthread_mutex_destroy(&tpm->lock); +        pthread_mutex_destroy(&tpm->mtx);          pthread_cond_destroy(&tpm->cond);          free(tpm); @@ -261,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_wait_work(struct tpm * tpm) +{ +        struct pthr_el * e; + +        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_dec(struct tpm * tpm) +void tpm_end_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->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 931ee449..fd275f63 100644 --- a/src/lib/utils.c +++ b/src/lib/utils.c @@ -1,5 +1,5 @@  /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024   *   * Handy utilities   * @@ -20,29 +20,43 @@   * Foundation, Inc., http://www.fsf.org/about/contact/.   */ +#define _POSIX_C_SOURCE 200809L + +#include <ouroboros/utils.h> +  #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(char * src) +char * path_strip(const char * src)  { -        char * dst = NULL; +        char * dst;          if (src == NULL)                  return NULL; -        dst = src + strlen(src); +        dst = (char *) src + strlen(src);          while (dst > src && *dst != '/')                  --dst; @@ -52,3 +66,58 @@ char * path_strip(char * src)          return dst;  } + +size_t argvlen(const char ** argv) +{ +        size_t argc   = 0; + +        if (argv == NULL) +                return 0; + +        while (*argv++ != NULL) +                argc++; + +        return argc; +} + +void argvfree(char ** argv) +{ +        char ** argv_dup; + +        if (argv == NULL) +                return; + +        argv_dup = argv; +        while (*argv_dup != NULL) +                free(*(argv_dup++)); + +        free(argv); +} + +char ** argvdup(char ** argv) +{ +        int     argc = 0; +        char ** argv_dup = argv; +        int     i; + +        if (argv == NULL) +                return NULL; + +        while (*(argv_dup++) != NULL) +                argc++; + +        argv_dup = malloc((argc + 1) * sizeof(*argv_dup)); +        if (argv_dup == NULL) +                return NULL; + +        for (i = 0; i < argc; ++i) { +                argv_dup[i] = strdup(argv[i]); +                if (argv_dup[i] == NULL) { +                        argvfree(argv_dup); +                        return NULL; +                } +        } + +        argv_dup[argc] = NULL; +        return argv_dup; +}  | 
