diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/CMakeLists.txt | 106 | ||||
-rw-r--r-- | src/lib/cacep.c | 3 | ||||
-rw-r--r-- | src/lib/cdap.c | 3 | ||||
-rw-r--r-- | src/lib/cdap_req.c | 5 | ||||
-rw-r--r-- | src/lib/cdap_req.h | 1 | ||||
-rw-r--r-- | src/lib/config.h.in | 57 | ||||
-rw-r--r-- | src/lib/dev.c | 478 | ||||
-rw-r--r-- | src/lib/frct_pci.c | 112 | ||||
-rw-r--r-- | src/lib/hash.c | 43 | ||||
-rw-r--r-- | src/lib/irm.c | 3 | ||||
-rw-r--r-- | src/lib/lockfile.c | 15 | ||||
-rw-r--r-- | src/lib/md5.c | 2 | ||||
-rw-r--r-- | src/lib/nsm.c | 55 | ||||
-rw-r--r-- | src/lib/random.c | 3 | ||||
-rw-r--r-- | src/lib/rib.c | 5 | ||||
-rw-r--r-- | src/lib/shm_flow_set.c | 52 | ||||
-rw-r--r-- | src/lib/shm_rbuff.c | 7 | ||||
-rw-r--r-- | src/lib/shm_rbuff_ll.c | 15 | ||||
-rw-r--r-- | src/lib/shm_rbuff_pthr.c | 15 | ||||
-rw-r--r-- | src/lib/shm_rdrbuff.c | 5 | ||||
-rw-r--r-- | src/lib/sockets.c | 31 | ||||
-rw-r--r-- | src/lib/tests/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/lib/tests/rib_test.c | 3 | ||||
-rw-r--r-- | src/lib/tests/timerwheel_test.c | 104 | ||||
-rw-r--r-- | src/lib/time_utils.c | 3 | ||||
-rw-r--r-- | src/lib/timerwheel.c | 232 | ||||
-rw-r--r-- | src/lib/tpm.c | 5 |
27 files changed, 1128 insertions, 242 deletions
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 550bbc08..9d8fbf9c 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -15,7 +15,7 @@ protobuf_generate_c(CACEP_PROTO_SRCS CACEP_PROTO_HDRS cacep.proto) if (NOT APPLE) find_library(LIBRT_LIBRARIES rt) if (NOT LIBRT_LIBRARIES) - message(FATAL_ERROR "Could not find librt.") + message(FATAL_ERROR "Could not find librt") endif () else () set(LIBRT_LIBRARIES "") @@ -23,7 +23,7 @@ endif () find_library(LIBPTHREAD_LIBRARIES pthread) if (NOT LIBPTHREAD_LIBRARIES) - message(FATAL_ERROR "Could not find libpthread.") + message(FATAL_ERROR "Could not find libpthread") endif () include(CheckSymbolExists) @@ -31,30 +31,60 @@ list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200809L) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__XSI_VISIBLE=500) list(APPEND CMAKE_REQUIRED_LIBRARIES pthread) check_symbol_exists(pthread_mutexattr_setrobust pthread.h HAVE_ROBUST_MUTEX) -set(HAVE_ROBUST_MUTEX CACHE STRING "Have robust mutexes") + +if (HAVE_ROBUST_MUTEX) + set(DISABLE_ROBUST_MUTEXES FALSE CACHE BOOL "Disable robust mutex support") + if (NOT DISABLE_ROBUST_MUTEXES) + message(STATUS "Robust mutex support enabled") + set(HAVE_ROBUST_MUTEX TRUE) + else () + message(STATUS "Robust mutex support disabled by user") + set(HAVE_ROBUST_MUTEX FALSE) + endif () +endif () find_library(LIBGCRYPT_LIBRARIES gcrypt) if (LIBGCRYPT_LIBRARIES) - find_path(LIBGCRYPT_INCLUDE_DIR gcrypt.h HINTS /usr/include /usr/local/include) - if (NOT LIBGCRYPT_INCLUDE_DIR STREQUAL "GRYPT_INCLUDE_DIR-NOTFOUND") + find_path(LIBGCRYPT_INCLUDE_DIR gcrypt.h + HINTS /usr/include /usr/local/include) + if (LIBGCRYPT_INCLUDE_DIR) file(STRINGS ${LIBGCRYPT_INCLUDE_DIR}/gcrypt.h GCSTR REGEX "^#define GCRYPT_VERSION ") string(REGEX REPLACE "^#define GCRYPT_VERSION \"(.*)\".*$" "\\1" GCVER "${GCSTR}") - message(STATUS "Found libgcrypt: ${LIBGCRYPT_LIBRARIES} (found version \"${GCVER}\")") + message(STATUS "Found libgcrypt: ${LIBGCRYPT_LIBRARIES}" + "(found version \"${GCVER}\")") if (NOT GCVER VERSION_LESS "1.7.0") - set(HAVE_LIBGCRYPT "1" CACHE STRING "Have libgcrypt") + set (DISABLE_LIBGCRYPT FALSE CACHE BOOL "Disable libgcrypt support") + if (NOT DISABLE_LIBGCRYPT) + message(STATUS "libgcrypt support enabled") + set(HAVE_LIBGCRYPT TRUE) + else () + message(STATUS "libgcrpyt support disabled by user") + endif() + else () + message(STATUS "Install version > \"1.7.0\" to enable libgcrypt support") endif() endif () -else () +endif () + +if (NOT HAVE_LIBGCRYPT) set(LIBGCRYPT_LIBRARIES "") set(LIBGCRYPT_INCLUDE_DIR "") endif () find_package(OpenSSL) if (OPENSSL_FOUND) - set(HAVE_OPENSSL "1" CACHE STRING "Have OpenSSL") -else () + set (DISABLE_OPENSSL FALSE CACHE BOOL "Disable OpenSSL support") + if (NOT DISABLE_OPENSSL) + message(STATUS "OpenSSL support enabled") + set(HAVE_OPENSSL TRUE) + else() + message(STATUS "OpenSSL support disabled by user") + endif() +endif () + +if (NOT HAVE_OPENSSL) set (OPENSSL_INCLUDE_DIR "") endif () @@ -62,9 +92,9 @@ if (APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") set(SYS_RND_HDR "") else () find_path(SYS_RND_HDR sys/random.h PATH /usr/include/ /usr/local/include/) - if (NOT SYS_RND_HDR STREQUAL "SYS_RND_HDR-NOTFOUND") + if (SYS_RND_HDR) message(STATUS "Found sys/random.h in ${SYS_RND_HDR}") - set(HAVE_SYS_RANDOM "1" CACHE STRING "Have random header") + set(HAVE_SYS_RANDOM TRUE) else () set(SYS_RND_HDR "") endif () @@ -73,10 +103,52 @@ endif() if (NOT ((CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") OR APPLE OR HAVE_SYS_RANDOM OR HAVE_OPENSSL OR HAVE_LIBGCRYPT)) message(FATAL_ERROR "No secure random generator found, " - "please install libgcrypt (> 1.7.0) or OpenSSL" - ) + "please install libgcrypt (> 1.7.0) or OpenSSL") endif () +mark_as_advanced(LIBRT_LIBRARIES LIBPTHREAD_LIBRARIES + LIBGCRYPT_LIBRARIES OPENSSL_LIBRARIES SYS_RND_INCLUDE_DIR + LIBGCRYPT_INCLUDE_DIR SYS_RND_HDR) + +math(EXPR SHM_BUFFER_EXPR "1 << 20") +set(SHM_BUFFER_SIZE ${SHM_BUFFER_EXPR} CACHE STRING + "Number of blocks in SDU buffer, must be a power of 2") +set(SYS_MAX_FLOWS 4096 CACHE STRING + "Maximum number of total flows for this system") +set(AP_MAX_FLOWS 1024 CACHE STRING + "Maximum number of flows in an application") +set(AP_RES_FDS 64 CACHE STRING + "Number of reserved flow descriptors per application") +set(AP_MAX_FQUEUES 32 CACHE STRING + "Maximum number of flow sets per application") +set(DU_BUFF_HEADSPACE 128 CACHE STRING + "Bytes of headspace to reserve for future headers") +set(DU_BUFF_TAILSPACE 16 CACHE STRING + "Bytes of tailspace to reserve for future tails") +if (NOT APPLE) + set(PTHREAD_COND_CLOCK "CLOCK_MONOTONIC" CACHE STRING + "Clock to use for condition variable timing") +else () + set (PTHREAD_COND_CLOCK "CLOCK_REALTIME" CACHE INTERNAL + "Clock to use for condition variable timing") +endif () +set(SOCKET_TIMEOUT 1000 CACHE STRING + "Default timeout for responses from IPCPs (ms)") +set(CDAP_REPLY_TIMEOUT 6000 CACHE STRING + "Timeout for CDAP to wait for reply") +set(SHM_PREFIX "ouroboros" CACHE STRING + "String to prepend to POSIX shared memory filenames") +set(SHM_RBUFF_PREFIX "/${SHM_PREFIX}.rbuff." CACHE INTERNAL + "Prefix for rbuff POSIX shared memory filenames") +set(SHM_LOCKFILE_NAME "/${SHM_PREFIX}.lockfile" CACHE INTERNAL + "Filename for the POSIX shared memory lockfile") +set(SHM_FLOW_SET_PREFIX "/${SHM_PREFIX}.set." CACHE INTERNAL + "Prefix for the POSIX shared memory flow set") +set(SHM_RDRB_NAME "/${SHM_PREFIX}.rdrb" CACHE INTERNAL + "Name for the main POSIX shared memory buffer") +set(SHM_RDRB_BLOCK_SIZE "sysconf(_SC_PAGESIZE)" CACHE STRING + "SDU buffer block size, multiple of pagesize for performance") + set(SOURCE_FILES # Add source files here bitmap.c @@ -86,6 +158,7 @@ set(SOURCE_FILES cdap_req.c crc32.c dev.c + frct_pci.c hash.c hashtable.c irm.c @@ -93,7 +166,6 @@ set(SOURCE_FILES lockfile.c logs.c md5.c - nsm.c qos.c qoscube.c random.c @@ -104,10 +176,14 @@ set(SOURCE_FILES shm_rdrbuff.c sockets.c time_utils.c + timerwheel.c tpm.c utils.c ) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) + add_library(ouroboros SHARED ${SOURCE_FILES} ${IRM_PROTO_SRCS} ${IPCP_PROTO_SRCS} ${DIF_CONFIG_PROTO_SRCS} ${CDAP_PROTO_SRCS} ${CACEP_PROTO_SRCS} ${RO_PROTO_SRCS}) diff --git a/src/lib/cacep.c b/src/lib/cacep.c index 55d11b0f..722adca1 100644 --- a/src/lib/cacep.c +++ b/src/lib/cacep.c @@ -20,7 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 199309L + #include <ouroboros/cacep.h> #include <ouroboros/dev.h> #include <ouroboros/errno.h> diff --git a/src/lib/cdap.c b/src/lib/cdap.c index bf8d5816..679771f5 100644 --- a/src/lib/cdap.c +++ b/src/lib/cdap.c @@ -20,7 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + #include <ouroboros/cdap.h> #include <ouroboros/bitmap.h> #include <ouroboros/dev.h> diff --git a/src/lib/cdap_req.c b/src/lib/cdap_req.c index 7aded62f..a9b85525 100644 --- a/src/lib/cdap_req.c +++ b/src/lib/cdap_req.c @@ -20,7 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + #include <ouroboros/time_utils.h> #include <ouroboros/errno.h> diff --git a/src/lib/cdap_req.h b/src/lib/cdap_req.h index 89f4145a..4c9cd15b 100644 --- a/src/lib/cdap_req.h +++ b/src/lib/cdap_req.h @@ -23,7 +23,6 @@ #ifndef OUROBOROS_CDAP_REQ_H #define OUROBOROS_CDAP_REQ_H -#include <ouroboros/config.h> #include <ouroboros/cdap.h> #include <ouroboros/list.h> #include <ouroboros/utils.h> diff --git a/src/lib/config.h.in b/src/lib/config.h.in new file mode 100644 index 00000000..e9c43389 --- /dev/null +++ b/src/lib/config.h.in @@ -0,0 +1,57 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Ouroboros library configuration + * + * Dimitri Staessens <[email protected]> + * Sander Vrijders <[email protected]> + * + * 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/. + */ + +#cmakedefine HAVE_SYS_RANDOM +#cmakedefine HAVE_LIBGCRYPT +#cmakedefine HAVE_OPENSSL + +#define SYS_MAX_FLOWS @SYS_MAX_FLOWS@ + +#cmakedefine SHM_RBUFF_LOCKLESS + +#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@ + +#if defined(__linux__) || (defined(__MACH__) && !defined(__APPLE__)) +/* Avoid a bug in robust mutex implementation of glibc 2.25 */ + #include <features.h> + #if !defined(__GLIBC__) || !(__GLIBC__ == 2 && __GLIBC_MINOR__ == 25) + #cmakedefine HAVE_ROBUST_MUTEX + #endif +#else +#cmakedefine HAVE_ROBUST_MUTEX +#endif + +#define PTHREAD_COND_CLOCK @PTHREAD_COND_CLOCK@ + +#define AP_MAX_FLOWS @AP_MAX_FLOWS@ +#define AP_RES_FDS @AP_RES_FDS@ +#define AP_MAX_FQUEUES @AP_MAX_FQUEUES@ + +#define DU_BUFF_HEADSPACE @DU_BUFF_HEADSPACE@ +#define DU_BUFF_TAILSPACE @DU_BUFF_TAILSPACE@ + +#define CDAP_REPLY_TIMEOUT @CDAP_REPLY_TIMEOUT@ diff --git a/src/lib/dev.c b/src/lib/dev.c index 9354855b..b6c6087f 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -20,7 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + #include <ouroboros/errno.h> #include <ouroboros/dev.h> #include <ouroboros/ipcp-dev.h> @@ -34,6 +37,8 @@ #include <ouroboros/utils.h> #include <ouroboros/fqueue.h> #include <ouroboros/qoscube.h> +#include <ouroboros/timerwheel.h> +#include <ouroboros/frct_pci.h> #include <stdlib.h> #include <string.h> @@ -41,8 +46,14 @@ #define BUF_SIZE 1500 +#define TW_ELEMENTS 6000 +#define TW_RESOLUTION 1 /* ms */ + +#define MPL 2000 /* ms */ + struct flow_set { size_t idx; + bool np1_set; }; struct fqueue { @@ -59,6 +70,22 @@ enum port_state { PORT_DESTROY }; +struct frcti { + bool used; + + struct tw_f * snd_inact; + bool snd_drf; + uint64_t snd_lwe; + uint64_t snd_rwe; + + struct tw_f * rcv_inact; + bool rcv_drf; + uint64_t rcv_lwe; + uint64_t rcv_rwe; + + uint8_t conf_flags; +}; + struct port { int fd; @@ -89,10 +116,13 @@ 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 frcti * frcti; pthread_rwlock_t lock; } ai; @@ -203,6 +233,268 @@ static int api_announce(char * ap_name) return ret; } +/* Call under flows lock */ +static int finalize_write(int fd, + size_t idx) +{ + if (shm_rbuff_write(ai.flows[fd].tx_rb, idx) < 0) + return -ENOTALLOC; + + shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id); + + return 0; +} + +static int frcti_init(int fd) +{ + struct frcti * frcti; + + frcti = &(ai.frcti[fd]); + + frcti->used = true; + + frcti->snd_drf = true; + frcti->snd_lwe = 0; + frcti->snd_rwe = 0; + + frcti->rcv_drf = true; + frcti->rcv_lwe = 0; + frcti->rcv_rwe = 0; + + frcti->conf_flags = CONF_ERROR_CHECK; + + return 0; +} + +static void frcti_clear(int fd) +{ + struct frcti * frcti; + + frcti = &(ai.frcti[fd]); + + frcti->used = false; + frcti->snd_inact = NULL; + frcti->rcv_inact = NULL; +} + +static void frcti_fini(int fd) +{ + struct frcti * frcti; + + frcti = &(ai.frcti[fd]); + + /* FIXME: We actually need to wait until these timers become NULL. */ + if (frcti->snd_inact != NULL) + timerwheel_stop(ai.tw, frcti->snd_inact); + + if (frcti->rcv_inact != NULL) + timerwheel_stop(ai.tw, frcti->rcv_inact); + + frcti_clear(fd); +} + +static int frcti_configure(int fd, + qosspec_t * qos) +{ + /* FIXME: Send configuration message here to other side. */ + + (void) fd; + (void) qos; + + return 0; +} + +static void frcti_snd_inactivity(void * arg) +{ + struct frcti * frcti; + + pthread_rwlock_wrlock(&ai.lock); + + frcti = (struct frcti * ) arg; + + frcti->snd_drf = true; + frcti->snd_inact = NULL; + + pthread_rwlock_unlock(&ai.lock); +} + +/* Called under flows lock */ +static int frcti_write(int fd, + struct shm_du_buff * sdb) +{ + struct frcti * frcti; + struct frct_pci pci; + + memset(&pci, 0, sizeof(pci)); + + frcti = &(ai.frcti[fd]); + + pthread_rwlock_unlock(&ai.lock); + + timerwheel_move(ai.tw); + + pthread_rwlock_rdlock(&ai.lock); + + /* + * Set the DRF in the first packet of a new run of SDUs, + * otherwise simply recharge the timer. + */ + if (frcti->snd_drf) { + frcti->snd_inact = timerwheel_start(ai.tw, frcti_snd_inactivity, + frcti, 2 * MPL); + if (frcti->snd_inact == NULL) + return -1; + + pci.flags |= FLAG_DATA_RUN; + frcti->snd_drf = false; + } else { + if (timerwheel_restart(ai.tw, frcti->snd_inact, 2 * MPL)) + return -1; + } + + pci.seqno = frcti->snd_lwe++; + pci.type |= PDU_TYPE_DATA; + + if (frct_pci_ser(sdb, &pci, frcti->conf_flags & CONF_ERROR_CHECK)) + return -1; + + if (finalize_write(fd, shm_du_buff_get_idx(sdb))) + return -ENOTALLOC; + + return 0; +} + +static void frcti_rcv_inactivity(void * arg) +{ + struct frcti * frcti; + + pthread_rwlock_wrlock(&ai.lock); + + frcti = (struct frcti * ) arg; + + frcti->rcv_drf = true; + frcti->rcv_inact = NULL; + + pthread_rwlock_unlock(&ai.lock); +} + +static ssize_t frcti_read(int fd) +{ + ssize_t idx = -1; + struct timespec abstime; + struct frcti * frcti; + struct frct_pci pci; + struct shm_du_buff * sdb; + + timerwheel_move(ai.tw); + + pthread_rwlock_rdlock(&ai.lock); + + if (ai.flows[fd].oflags & FLOW_O_NONBLOCK) { + idx = shm_rbuff_read(ai.flows[fd].rx_rb); + pthread_rwlock_unlock(&ai.lock); + } else { + struct shm_rbuff * rb = ai.flows[fd].rx_rb; + bool timeo = ai.flows[fd].timesout; + struct timespec timeout = ai.flows[fd].rcv_timeo; + + pthread_rwlock_unlock(&ai.lock); + + if (timeo) { + clock_gettime(PTHREAD_COND_CLOCK, &abstime); + ts_add(&abstime, &timeout, &abstime); + idx = shm_rbuff_read_b(rb, &abstime); + } else { + idx = shm_rbuff_read_b(rb, NULL); + } + } + + if (idx < 0) + return idx; + + pthread_rwlock_rdlock(&ai.lock); + + frcti = &(ai.frcti[fd]); + + sdb = shm_rdrbuff_get(ai.rdrb, idx); + + /* SDU may be corrupted. */ + if (frct_pci_des(sdb, &pci, frcti->conf_flags & CONF_ERROR_CHECK)) { + pthread_rwlock_unlock(&ai.lock); + shm_rdrbuff_remove(ai.rdrb, idx); + return -EAGAIN; + } + + /* We don't accept packets when there is no inactivity timer. */ + if (frcti->rcv_drf && !(pci.flags & FLAG_DATA_RUN)) { + pthread_rwlock_unlock(&ai.lock); + shm_rdrbuff_remove(ai.rdrb, idx); + return -EAGAIN; + } + + /* + * If there is an inactivity timer and the DRF is set, + * reset the state of the connection. + */ + if (pci.flags & FLAG_DATA_RUN) { + frcti->rcv_drf = true; + if (frcti->rcv_inact != NULL) + timerwheel_stop(ai.tw, frcti->rcv_inact); + frcti->rcv_lwe = pci.seqno; + } + + /* + * Start receiver inactivity if this packet has the DRF, + * otherwise simply restart it. + */ + if (frcti->rcv_drf) { + frcti->rcv_inact = timerwheel_start(ai.tw, frcti_rcv_inactivity, + frcti, 3 * MPL); + if (frcti->rcv_inact == NULL) { + pthread_rwlock_unlock(&ai.lock); + shm_rdrbuff_remove(ai.rdrb, idx); + return -EAGAIN; + } + + frcti->rcv_drf = false; + } else { + if (timerwheel_restart(ai.tw, frcti->rcv_inact, 3 * MPL)) { + pthread_rwlock_unlock(&ai.lock); + shm_rdrbuff_remove(ai.rdrb, idx); + return -EAGAIN; + } + } + + pthread_rwlock_unlock(&ai.lock); + + return idx; +} + +static int frcti_event_wait(struct flow_set * set, + struct fqueue * fq, + const struct timespec * timeout) +{ + int ret; + + assert(set); + assert(fq); + + timerwheel_move(ai.tw); + + /* + * FIXME: Return the fq only if a data SDU + * for the application is available. + */ + + ret = shm_flow_set_wait(ai.fqset, set->idx, fq->fqueue, timeout); + if (ret == -ETIMEDOUT) { + fq->fqsize = 0; + return -ETIMEDOUT; + } + + return ret; +} + static void flow_clear(int fd) { assert(!(fd < 0)); @@ -230,6 +522,9 @@ static void flow_fini(int fd) if (ai.flows[fd].set != NULL) shm_flow_set_close(ai.flows[fd].set); + if (ai.frcti[fd].used) + frcti_fini(fd); + flow_clear(fd); } @@ -316,10 +611,16 @@ int ouroboros_init(const char * ap_name) if (ai.flows == NULL) goto fail_flows; - for (i = 0; i < AP_MAX_FLOWS; ++i) + ai.frcti = malloc(sizeof(*ai.frcti) * AP_MAX_FLOWS); + if (ai.frcti == NULL) + goto fail_frcti; + + for (i = 0; i < AP_MAX_FLOWS; ++i) { flow_clear(i); + frcti_clear(i); + } - ai.ports = malloc(sizeof(*ai.ports) * IRMD_MAX_FLOWS); + ai.ports = malloc(sizeof(*ai.ports) * SYS_MAX_FLOWS); if (ai.ports == NULL) goto fail_ports; @@ -334,7 +635,7 @@ int ouroboros_init(const char * ap_name) } } - for (i = 0; i < IRMD_MAX_FLOWS; ++i) { + 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; @@ -353,24 +654,33 @@ int ouroboros_init(const char * ap_name) if (pthread_rwlock_init(&ai.lock, NULL)) goto fail_lock; + ai.tw = timerwheel_create(TW_RESOLUTION, + TW_RESOLUTION * TW_ELEMENTS); + if (ai.tw == NULL) + goto fail_timerwheel; + return 0; + fail_timerwheel: + pthread_rwlock_destroy(&ai.lock); fail_lock: - for (i = 0; i < IRMD_MAX_FLOWS; ++i) + for (i = 0; i < SYS_MAX_FLOWS; ++i) pthread_cond_destroy(&ai.ports[i].state_cond); fail_state_cond: - for (i = 0; i < IRMD_MAX_FLOWS; ++i) + for (i = 0; i < SYS_MAX_FLOWS; ++i) pthread_mutex_destroy(&ai.ports[i].state_lock); fail_announce: free(ai.ap_name); fail_ap_name: free(ai.ports); fail_ports: + free(ai.frcti); + fail_frcti: free(ai.flows); fail_flows: shm_rdrbuff_close(ai.rdrb); fail_rdrb: - shm_flow_set_destroy(ai.fqset); + shm_flow_set_destroy(ai.fqset); fail_fqset: bmp_destroy(ai.fqueues); fail_fqueues: @@ -402,13 +712,16 @@ void ouroboros_fini() } } - for (i = 0; i < IRMD_MAX_FLOWS; ++i) { + for (i = 0; i < SYS_MAX_FLOWS; ++i) { pthread_mutex_destroy(&ai.ports[i].state_lock); pthread_cond_destroy(&ai.ports[i].state_cond); } shm_rdrbuff_close(ai.rdrb); + if (ai.tw != NULL) + timerwheel_destroy(ai.tw); + free(ai.flows); free(ai.ports); @@ -463,9 +776,15 @@ int flow_accept(qosspec_t * qs, if (fd < 0) return fd; + pthread_rwlock_wrlock(&ai.lock); + + frcti_init(fd); + if (qs != NULL) *qs = ai.flows[fd].spec; + pthread_rwlock_unlock(&ai.lock); + return fd; } @@ -505,7 +824,7 @@ int flow_alloc(const char * dst_name, return -EIRMD; } - if (recv_msg->result != 0) { + if (recv_msg->result != 0) { int res = recv_msg->result; irm_msg__free_unpacked(recv_msg, NULL); return res; @@ -520,6 +839,22 @@ int flow_alloc(const char * dst_name, irm_msg__free_unpacked(recv_msg, NULL); + if (fd < 0) + return fd; + + pthread_rwlock_wrlock(&ai.lock); + + frcti_init(fd); + + if (frcti_configure(fd, qs)) { + flow_fini(fd); + bmp_release(ai.fds, fd); + pthread_rwlock_unlock(&ai.lock); + return -1; + } + + pthread_rwlock_unlock(&ai.lock); + return fd; } @@ -720,34 +1055,31 @@ ssize_t flow_write(int fd, return idx; } - if (shm_rbuff_write(ai.flows[fd].tx_rb, idx) < 0) { - shm_rdrbuff_remove(ai.rdrb, idx); - pthread_rwlock_unlock(&ai.lock); - return -ENOTALLOC; - } } else { /* blocking */ - struct shm_rdrbuff * rdrb = ai.rdrb; - struct shm_rbuff * tx_rb = ai.flows[fd].tx_rb; - pthread_rwlock_unlock(&ai.lock); - assert(tx_rb); - - idx = shm_rdrbuff_write_b(rdrb, + idx = shm_rdrbuff_write_b(ai.rdrb, DU_BUFF_HEADSPACE, DU_BUFF_TAILSPACE, buf, count); - if (shm_rbuff_write(tx_rb, idx) < 0) { - shm_rdrbuff_remove(rdrb, idx); - return -ENOTALLOC; - } - pthread_rwlock_rdlock(&ai.lock); } - shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id); + if (!ai.frcti[fd].used) { + if (finalize_write(fd, idx)) { + pthread_rwlock_unlock(&ai.lock); + shm_rdrbuff_remove(ai.rdrb, idx); + return -ENOTALLOC; + } + } else { + if (frcti_write(fd, shm_rdrbuff_get(ai.rdrb, idx))) { + pthread_rwlock_unlock(&ai.lock); + shm_rdrbuff_remove(ai.rdrb, idx); + return -1; + } + } pthread_rwlock_unlock(&ai.lock); @@ -772,21 +1104,12 @@ ssize_t flow_read(int fd, return -ENOTALLOC; } - if (ai.flows[fd].oflags & FLOW_O_NONBLOCK) { - idx = shm_rbuff_read(ai.flows[fd].rx_rb); - pthread_rwlock_unlock(&ai.lock); - } else { - struct shm_rbuff * rb = ai.flows[fd].rx_rb; - bool timeo = ai.flows[fd].timesout; - struct timespec timeout = ai.flows[fd].rcv_timeo; - - pthread_rwlock_unlock(&ai.lock); + pthread_rwlock_unlock(&ai.lock); - if (timeo) - idx = shm_rbuff_read_b(rb, &timeout); - else - idx = shm_rbuff_read_b(rb, NULL); - } + if (!ai.frcti[fd].used) + idx = shm_rbuff_read(ai.flows[fd].rx_rb); + else + idx = frcti_read(fd); if (idx < 0) { assert(idx == -EAGAIN || idx == -ETIMEDOUT); @@ -823,6 +1146,8 @@ struct flow_set * flow_set_create() return NULL; } + set->np1_set = false; + pthread_rwlock_unlock(&ai.lock); return set; @@ -891,6 +1216,9 @@ int flow_set_add(struct flow_set * set, for (i = 0; i < sdus; i++) shm_flow_set_notify(ai.fqset, ai.flows[fd].port_id); + if (ai.frcti[fd].used) + set->np1_set = true; + pthread_rwlock_unlock(&ai.lock); return ret; @@ -960,7 +1288,9 @@ int flow_event_wait(struct flow_set * set, struct fqueue * fq, const struct timespec * timeout) { - ssize_t ret; + ssize_t ret; + struct timespec abstime; + struct timespec * t = NULL; if (set == NULL || fq == NULL) return -EINVAL; @@ -970,7 +1300,18 @@ int flow_event_wait(struct flow_set * set, assert(!fq->next); - ret = shm_flow_set_wait(ai.fqset, set->idx, fq->fqueue, timeout); + if (timeout != NULL) { + clock_gettime(PTHREAD_COND_CLOCK, &abstime); + ts_add(&abstime, timeout, &abstime); + t = &abstime; + } + + if (set->np1_set) + ret = frcti_event_wait(set, fq, t); + else + ret = shm_flow_set_wait(ai.fqset, set->idx, + fq->fqueue, t); + if (ret == -ETIMEDOUT) { fq->fqsize = 0; return -ETIMEDOUT; @@ -1132,9 +1473,8 @@ int ipcp_flow_read(int fd, { ssize_t idx = -1; int port_id = -1; - struct shm_rbuff * rb; - assert(fd >=0); + assert(fd >= 0); assert(sdb); pthread_rwlock_rdlock(&ai.lock); @@ -1144,11 +1484,13 @@ int ipcp_flow_read(int fd, return -ENOTALLOC; } - rb = ai.flows[fd].rx_rb; - pthread_rwlock_unlock(&ai.lock); - idx = shm_rbuff_read(rb); + if (!ai.frcti[fd].used) + idx = shm_rbuff_read(ai.flows[fd].rx_rb); + else + idx = frcti_read(fd); + if (idx < 0) return idx; @@ -1160,8 +1502,6 @@ int ipcp_flow_read(int fd, int ipcp_flow_write(int fd, struct shm_du_buff * sdb) { - size_t idx; - if (sdb == NULL) return -EINVAL; @@ -1179,10 +1519,17 @@ int ipcp_flow_write(int fd, assert(ai.flows[fd].tx_rb); - idx = shm_du_buff_get_idx(sdb); - - shm_rbuff_write(ai.flows[fd].tx_rb, idx); - shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id); + if (!ai.frcti[fd].used) { + if (finalize_write(fd, shm_du_buff_get_idx(sdb))) { + pthread_rwlock_unlock(&ai.lock); + return -ENOTALLOC; + } + } else { + if (frcti_write(fd, sdb)) { + pthread_rwlock_unlock(&ai.lock); + return -1; + } + } pthread_rwlock_unlock(&ai.lock); @@ -1274,32 +1621,11 @@ int local_flow_write(int fd, return -ENOTALLOC; } - shm_rbuff_write(ai.flows[fd].tx_rb, idx); - - shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id); - - pthread_rwlock_unlock(&ai.lock); - - return 0; -} - -int ipcp_read_shim(int fd, - struct shm_du_buff ** sdb) -{ - ssize_t idx; - - pthread_rwlock_rdlock(&ai.lock); - - assert(ai.flows[fd].rx_rb); - - idx = shm_rbuff_read(ai.flows[fd].rx_rb); - if (idx < 0) { + if (finalize_write(fd, idx)) { pthread_rwlock_unlock(&ai.lock); - return -EAGAIN; + return -ENOTALLOC; } - *sdb = shm_rdrbuff_get(ai.rdrb, idx); - pthread_rwlock_unlock(&ai.lock); return 0; diff --git a/src/lib/frct_pci.c b/src/lib/frct_pci.c new file mode 100644 index 00000000..5ee14829 --- /dev/null +++ b/src/lib/frct_pci.c @@ -0,0 +1,112 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Protocol Control Information of FRCT + * + * Dimitri Staessens <[email protected]> + * Sander Vrijders <[email protected]> + * + * 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/frct_pci.h> +#include <ouroboros/hash.h> +#include <ouroboros/errno.h> + +#define OUROBOROS_PREFIX "frct-pci" +#include <ouroboros/logs.h> + +#include <assert.h> +#include <string.h> + +#define TYPE_SIZE 1 +#define SEQNO_SIZE 8 +#define FLAGS_SIZE 1 + +/* FIXME: Head size will differ on type */ +#define HEAD_SIZE TYPE_SIZE + FLAGS_SIZE + SEQNO_SIZE + +int frct_pci_ser(struct shm_du_buff * sdb, + struct frct_pci * pci, + bool error_check) +{ + uint8_t * head; + uint8_t * tail; + + assert(sdb); + assert(pci); + + head = shm_du_buff_head_alloc(sdb, HEAD_SIZE); + if (head == NULL) + return -EPERM; + + memcpy(head, &pci->type, TYPE_SIZE); + memcpy(head + TYPE_SIZE, &pci->flags, FLAGS_SIZE); + memcpy(head + TYPE_SIZE + FLAGS_SIZE, &pci->seqno, SEQNO_SIZE); + + if (error_check) { + tail = shm_du_buff_tail_alloc(sdb, hash_len(HASH_CRC32)); + if (tail == NULL) { + shm_du_buff_head_release(sdb, HEAD_SIZE); + return -EPERM; + } + + *((uint32_t *) tail) = 0; + mem_hash(HASH_CRC32, (uint32_t *) tail, head, tail - head); + } + + return 0; +} + +int frct_pci_des(struct shm_du_buff * sdb, + struct frct_pci * pci, + bool error_check) +{ + uint8_t * head; + uint8_t * tail; + uint32_t crc; + uint32_t crc2; + + assert(sdb); + assert(pci); + + head = shm_du_buff_head(sdb); + + /* FIXME: Depending on the type a different deserialization */ + memcpy(&pci->type, head, TYPE_SIZE); + memcpy(&pci->flags, head + TYPE_SIZE, FLAGS_SIZE); + memcpy(&pci->seqno, head + TYPE_SIZE + FLAGS_SIZE, SEQNO_SIZE); + + if (error_check) { + tail = shm_du_buff_tail(sdb); + if (tail == NULL) + return -EPERM; + + mem_hash(HASH_CRC32, &crc, head, + tail - head - hash_len(HASH_CRC32)); + + memcpy(&crc2, tail - hash_len(HASH_CRC32), + hash_len(HASH_CRC32)); + + /* Corrupted SDU */ + if (crc != crc2) + return -1; + + shm_du_buff_tail_release(sdb, hash_len(HASH_CRC32)); + } + + shm_du_buff_head_release(sdb, HEAD_SIZE); + + return 0; +} diff --git a/src/lib/hash.c b/src/lib/hash.c index d8cabfd3..09e5be8c 100644 --- a/src/lib/hash.c +++ b/src/lib/hash.c @@ -23,7 +23,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#include "config.h" + #include <ouroboros/hash.h> #ifndef HAVE_LIBGCRYPT @@ -64,45 +65,46 @@ uint16_t hash_len(enum hash_algo algo) #endif } -void str_hash(enum hash_algo algo, - void * buf, - const char * str) +void mem_hash(enum hash_algo algo, + void * dst, + const uint8_t * buf, + size_t len) { #ifdef HAVE_LIBGCRYPT - gcry_md_hash_buffer(algo, buf, str, strlen(str)); + gcry_md_hash_buffer(algo, dst, buf, len); #else struct sha3_ctx sha3_ctx; struct md5_ctx md5_ctx; switch (algo) { case HASH_CRC32: - memset(buf, 0, CRC32_HASH_LEN); - crc32((uint32_t *) buf, str, strlen(str)); + memset(dst, 0, CRC32_HASH_LEN); + crc32((uint32_t *) dst, buf, len); break; case HASH_MD5: rhash_md5_init(&md5_ctx); - rhash_md5_update(&md5_ctx, str, strlen(str)); - rhash_md5_final(&md5_ctx, (uint8_t *) buf); + rhash_md5_update(&md5_ctx, buf, len); + rhash_md5_final(&md5_ctx, (uint8_t *) dst); break; case HASH_SHA3_224: rhash_sha3_224_init(&sha3_ctx); - rhash_sha3_update(&sha3_ctx, str, strlen(str)); - rhash_sha3_final(&sha3_ctx, (uint8_t *) buf); + rhash_sha3_update(&sha3_ctx, buf, len); + rhash_sha3_final(&sha3_ctx, (uint8_t *) dst); break; case HASH_SHA3_256: rhash_sha3_256_init(&sha3_ctx); - rhash_sha3_update(&sha3_ctx, str, strlen(str)); - rhash_sha3_final(&sha3_ctx, (uint8_t *) buf); + rhash_sha3_update(&sha3_ctx, buf, len); + rhash_sha3_final(&sha3_ctx, (uint8_t *) dst); break; case HASH_SHA3_384: rhash_sha3_384_init(&sha3_ctx); - rhash_sha3_update(&sha3_ctx, str, strlen(str)); - rhash_sha3_final(&sha3_ctx, (uint8_t *) buf); + rhash_sha3_update(&sha3_ctx, buf, len); + rhash_sha3_final(&sha3_ctx, (uint8_t *) dst); break; case HASH_SHA3_512: rhash_sha3_512_init(&sha3_ctx); - rhash_sha3_update(&sha3_ctx, str, strlen(str)); - rhash_sha3_final(&sha3_ctx, (uint8_t *) buf); + rhash_sha3_update(&sha3_ctx, buf, len); + rhash_sha3_final(&sha3_ctx, (uint8_t *) dst); break; default: assert(false); @@ -110,3 +112,10 @@ void str_hash(enum hash_algo algo, } #endif } + +void str_hash(enum hash_algo algo, + void * dst, + const char * str) +{ + return mem_hash(algo, dst, (const uint8_t *) str, strlen(str)); +} diff --git a/src/lib/irm.c b/src/lib/irm.c index a6075d33..4232cec1 100644 --- a/src/lib/irm.c +++ b/src/lib/irm.c @@ -20,7 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + #include <ouroboros/errno.h> #include <ouroboros/hash.h> #include <ouroboros/irm.h> diff --git a/src/lib/lockfile.c b/src/lib/lockfile.c index e2e4d289..4a3dcb91 100644 --- a/src/lib/lockfile.c +++ b/src/lib/lockfile.c @@ -20,7 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200112L + +#include "config.h" + #include <ouroboros/lockfile.h> #include <stdlib.h> @@ -47,7 +50,7 @@ struct lockfile * lockfile_create() { mask = umask(0); - fd = shm_open(LOCKFILE_NAME, O_CREAT | O_EXCL | O_RDWR, 0666); + fd = shm_open(SHM_LOCKFILE_NAME, O_CREAT | O_EXCL | O_RDWR, 0666); if (fd == -1) { free(lf); return NULL; @@ -69,7 +72,7 @@ struct lockfile * lockfile_create() { close (fd); if (lf->api == MAP_FAILED) { - shm_unlink(LOCKFILE_NAME); + shm_unlink(SHM_LOCKFILE_NAME); free(lf); return NULL; } @@ -85,7 +88,7 @@ struct lockfile * lockfile_open() { if (lf == NULL) return NULL; - fd = shm_open(LOCKFILE_NAME, O_RDWR, 0666); + fd = shm_open(SHM_LOCKFILE_NAME, O_RDWR, 0666); if (fd < 0) { free(lf); return NULL; @@ -100,7 +103,7 @@ struct lockfile * lockfile_open() { close(fd); if (lf->api == MAP_FAILED) { - shm_unlink(LOCKFILE_NAME); + shm_unlink(SHM_LOCKFILE_NAME); free(lf); return NULL; } @@ -126,7 +129,7 @@ void lockfile_destroy(struct lockfile * lf) munmap(lf->api, LF_SIZE); - shm_unlink(LOCKFILE_NAME); + shm_unlink(SHM_LOCKFILE_NAME); free(lf); } diff --git a/src/lib/md5.c b/src/lib/md5.c index a4d92de3..3394f406 100644 --- a/src/lib/md5.c +++ b/src/lib/md5.c @@ -1,7 +1,7 @@ /* * Ouroboros - Copyright (C) 2016 - 2017 * - * SHA3 algorithm + * MD5 algorithm * * Dimitri Staessens <[email protected]> * Sander Vrijders <[email protected]> diff --git a/src/lib/nsm.c b/src/lib/nsm.c deleted file mode 100644 index 2dd5729b..00000000 --- a/src/lib/nsm.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2017 - * - * The API to instruct the global Namespace Manager - * - * Dimitri Staessens <[email protected]> - * Sander Vrijders <[email protected]> - * - * 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/nsm.h> - -int nsm_reg(char * name, - char ** dafs, - size_t dafs_size) -{ - (void) name; - (void) dafs; - (void) dafs_size; - - return -1; -} - -int nsm_unreg(char * name, - char ** dafs, - size_t dafs_size) -{ - (void) name; - (void) dafs; - (void) dafs_size; - - - return -1; -} - -ssize_t nsm_resolve(char * name, - char ** dafs) -{ - (void) name; - (void) dafs; - - return -1; -} diff --git a/src/lib/random.c b/src/lib/random.c index 66aefaa3..27719b26 100644 --- a/src/lib/random.c +++ b/src/lib/random.c @@ -20,7 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#include "config.h" + #include <ouroboros/random.h> #if defined(__APPLE__) /* Barf */ diff --git a/src/lib/rib.c b/src/lib/rib.c index e8cf97d4..104dc0cc 100644 --- a/src/lib/rib.c +++ b/src/lib/rib.c @@ -20,7 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + #include <ouroboros/errno.h> #include <ouroboros/list.h> #include <ouroboros/rib.h> diff --git a/src/lib/shm_flow_set.c b/src/lib/shm_flow_set.c index cd6946d4..78fdce36 100644 --- a/src/lib/shm_flow_set.c +++ b/src/lib/shm_flow_set.c @@ -20,7 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + #include <ouroboros/lockfile.h> #include <ouroboros/time_utils.h> #include <ouroboros/shm_flow_set.h> @@ -38,11 +41,22 @@ #include <string.h> #include <assert.h> +/* + * pthread_cond_timedwait has a WONTFIX bug as of glibc 2.25 where it + * doesn't test pthread cancellation when passed an expired timeout + * with the clock set to CLOCK_MONOTONIC. + */ +#if ((defined(__linux__) || (defined(__MACH__) && !defined(__APPLE__))) \ + && (defined(__GLIBC__) && ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2025)) \ + && (PTHREAD_COND_CLOCK == CLOCK_MONOTONIC)) +#define HAVE_CANCEL_BUG +#endif + #define FN_MAX_CHARS 255 #define FQUEUESIZE ((SHM_BUFFER_SIZE) * sizeof(int)) -#define SHM_FLOW_SET_FILE_SIZE (IRMD_MAX_FLOWS * sizeof(ssize_t) \ +#define SHM_FLOW_SET_FILE_SIZE (SYS_MAX_FLOWS * sizeof(ssize_t) \ + AP_MAX_FQUEUES * sizeof(size_t) \ + AP_MAX_FQUEUES * sizeof(pthread_cond_t) \ + AP_MAX_FQUEUES * FQUEUESIZE \ @@ -109,7 +123,7 @@ struct shm_flow_set * shm_flow_set_create() } set->mtable = shm_base; - set->heads = (size_t *) (set->mtable + IRMD_MAX_FLOWS); + set->heads = (size_t *) (set->mtable + SYS_MAX_FLOWS); set->conds = (pthread_cond_t *)(set->heads + AP_MAX_FQUEUES); set->fqueues = (int *) (set->conds + AP_MAX_FQUEUES); set->lock = (pthread_mutex_t *) @@ -132,7 +146,7 @@ struct shm_flow_set * shm_flow_set_create() pthread_cond_init(&set->conds[i], &cattr); } - for (i = 0; i < IRMD_MAX_FLOWS; ++i) + for (i = 0; i < SYS_MAX_FLOWS; ++i) set->mtable[i] = -1; set->api = getpid(); @@ -175,7 +189,7 @@ struct shm_flow_set * shm_flow_set_open(pid_t api) } set->mtable = shm_base; - set->heads = (size_t *) (set->mtable + IRMD_MAX_FLOWS); + set->heads = (size_t *) (set->mtable + SYS_MAX_FLOWS); set->conds = (pthread_cond_t *)(set->heads + AP_MAX_FQUEUES); set->fqueues = (int *) (set->conds + AP_MAX_FQUEUES); set->lock = (pthread_mutex_t *) @@ -233,7 +247,7 @@ void shm_flow_set_zero(struct shm_flow_set * set, pthread_mutex_lock(set->lock); - for (i = 0; i < IRMD_MAX_FLOWS; ++i) + for (i = 0; i < SYS_MAX_FLOWS; ++i) if (set->mtable[i] == (ssize_t) idx) set->mtable[i] = -1; @@ -248,7 +262,7 @@ int shm_flow_set_add(struct shm_flow_set * set, int port_id) { assert(set); - assert(!(port_id < 0) && port_id < IRMD_MAX_FLOWS); + assert(!(port_id < 0) && port_id < SYS_MAX_FLOWS); assert(idx < AP_MAX_FQUEUES); pthread_mutex_lock(set->lock); @@ -270,7 +284,7 @@ void shm_flow_set_del(struct shm_flow_set * set, int port_id) { assert(set); - assert(!(port_id < 0) && port_id < IRMD_MAX_FLOWS); + assert(!(port_id < 0) && port_id < SYS_MAX_FLOWS); assert(idx < AP_MAX_FQUEUES); pthread_mutex_lock(set->lock); @@ -288,7 +302,7 @@ int shm_flow_set_has(struct shm_flow_set * set, int ret = 0; assert(set); - assert(!(port_id < 0) && port_id < IRMD_MAX_FLOWS); + assert(!(port_id < 0) && port_id < SYS_MAX_FLOWS); assert(idx < AP_MAX_FQUEUES); pthread_mutex_lock(set->lock); @@ -305,7 +319,7 @@ void shm_flow_set_notify(struct shm_flow_set * set, int port_id) { assert(set); - assert(!(port_id < 0) && port_id < IRMD_MAX_FLOWS); + assert(!(port_id < 0) && port_id < SYS_MAX_FLOWS); pthread_mutex_lock(set->lock); @@ -326,10 +340,9 @@ 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, - const struct timespec * timeout) + const struct timespec * abstime) { ssize_t ret = 0; - struct timespec abstime; assert(set); assert(idx < AP_MAX_FQUEUES); @@ -341,22 +354,23 @@ ssize_t shm_flow_set_wait(const struct shm_flow_set * set, if (pthread_mutex_lock(set->lock) == EOWNERDEAD) pthread_mutex_consistent(set->lock); #endif - if (timeout != NULL) { - clock_gettime(PTHREAD_COND_CLOCK, &abstime); - ts_add(&abstime, timeout, &abstime); - } pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock, (void *) set->lock); while (set->heads[idx] == 0 && ret != -ETIMEDOUT) { - if (timeout != NULL) + if (abstime != NULL) { ret = -pthread_cond_timedwait(set->conds + idx, set->lock, - &abstime); - else + abstime); +#ifdef HAVE_CANCEL_BUG + 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); diff --git a/src/lib/shm_rbuff.c b/src/lib/shm_rbuff.c index 7f8af9f5..93108332 100644 --- a/src/lib/shm_rbuff.c +++ b/src/lib/shm_rbuff.c @@ -19,9 +19,12 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> -#if ((SHM_RBUFF_LOCKLESS > 0) && \ +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + +#if (defined(SHM_RBUFF_LOCKLESS) && \ (defined(__GNUC__) || defined (__clang__))) #include "shm_rbuff_ll.c" #else diff --git a/src/lib/shm_rbuff_ll.c b/src/lib/shm_rbuff_ll.c index 33e236b0..ec0199c0 100644 --- a/src/lib/shm_rbuff_ll.c +++ b/src/lib/shm_rbuff_ll.c @@ -20,7 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#include "config.h" + #include <ouroboros/shm_rbuff.h> #include <ouroboros/lockfile.h> #include <ouroboros/time_utils.h> @@ -281,9 +282,8 @@ ssize_t shm_rbuff_read(struct shm_rbuff * rb) } ssize_t shm_rbuff_read_b(struct shm_rbuff * rb, - const struct timespec * timeout) + const struct timespec * abstime) { - struct timespec abstime; ssize_t idx = -1; assert(rb); @@ -293,11 +293,6 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff * rb, if (idx != -EAGAIN) return idx; - if (timeout != NULL) { - clock_gettime(PTHREAD_COND_CLOCK, &abstime); - ts_add(&abstime, timeout, &abstime); - } - #ifndef HAVE_ROBUST_MUTEX pthread_mutex_lock(rb->lock); #else @@ -308,10 +303,10 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff * rb, (void *) rb->lock); while (shm_rbuff_empty(rb) && (idx != -ETIMEDOUT)) { - if (timeout != NULL) + if (abstime != NULL) idx = -pthread_cond_timedwait(rb->add, rb->lock, - &abstime); + abstime); else idx = -pthread_cond_wait(rb->add, rb->lock); #ifdef HAVE_ROBUST_MUTEX diff --git a/src/lib/shm_rbuff_pthr.c b/src/lib/shm_rbuff_pthr.c index 44001458..9567762f 100644 --- a/src/lib/shm_rbuff_pthr.c +++ b/src/lib/shm_rbuff_pthr.c @@ -20,7 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + #include <ouroboros/shm_rbuff.h> #include <ouroboros/lockfile.h> #include <ouroboros/time_utils.h> @@ -284,18 +285,12 @@ ssize_t shm_rbuff_read(struct shm_rbuff * rb) } ssize_t shm_rbuff_read_b(struct shm_rbuff * rb, - const struct timespec * timeout) + const struct timespec * abstime) { - struct timespec abstime; ssize_t idx = -1; assert(rb); - if (timeout != NULL) { - clock_gettime(PTHREAD_COND_CLOCK, &abstime); - ts_add(&abstime, timeout, &abstime); - } - #ifndef HAVE_ROBUST_MUTEX pthread_mutex_lock(rb->lock); #else @@ -306,10 +301,10 @@ ssize_t shm_rbuff_read_b(struct shm_rbuff * rb, (void *) rb->lock); while (shm_rbuff_empty(rb) && (idx != -ETIMEDOUT)) { - if (timeout != NULL) + if (abstime != NULL) idx = -pthread_cond_timedwait(rb->add, rb->lock, - &abstime); + abstime); else idx = -pthread_cond_wait(rb->add, rb->lock); #ifdef HAVE_ROBUST_MUTEX diff --git a/src/lib/shm_rdrbuff.c b/src/lib/shm_rdrbuff.c index 0919b1e0..447f8b35 100644 --- a/src/lib/shm_rdrbuff.c +++ b/src/lib/shm_rdrbuff.c @@ -20,7 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200809L + +#include "config.h" + #include <ouroboros/errno.h> #include <ouroboros/shm_rdrbuff.h> #include <ouroboros/shm_du_buff.h> diff --git a/src/lib/sockets.c b/src/lib/sockets.c index 7f0c4dd4..9f1b326e 100644 --- a/src/lib/sockets.c +++ b/src/lib/sockets.c @@ -20,7 +20,6 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> #include <ouroboros/errno.h> #include <ouroboros/sockets.h> #include <ouroboros/utils.h> @@ -96,40 +95,32 @@ static void close_ptr(void * o) irm_msg_t * send_recv_irm_msg(irm_msg_t * msg) { - int sockfd; - buffer_t buf; - ssize_t count = 0; - irm_msg_t * recv_msg = NULL; + int sockfd; + uint8_t buf[IRM_MSG_BUF_SIZE]; + ssize_t len; + irm_msg_t * recv_msg; sockfd = client_socket_open(IRM_SOCK_PATH); if (sockfd < 0) return NULL; - buf.len = irm_msg__get_packed_size(msg); - if (buf.len == 0) { - close(sockfd); - return NULL; - } - - buf.data = malloc(IRM_MSG_BUF_SIZE); - if (buf.data == NULL) { + len = irm_msg__get_packed_size(msg); + if (len == 0) { close(sockfd); return NULL; } pthread_cleanup_push(close_ptr, &sockfd); - pthread_cleanup_push((void (*)(void *)) free, (void *) buf.data); - irm_msg__pack(msg, buf.data); + irm_msg__pack(msg, buf); - if (write(sockfd, buf.data, buf.len) != -1) - count = read(sockfd, buf.data, IRM_MSG_BUF_SIZE); + if (write(sockfd, buf, len) != -1) + len = read(sockfd, buf, IRM_MSG_BUF_SIZE); - if (count > 0) - recv_msg = irm_msg__unpack(NULL, count, buf.data); + if (len > 0) + recv_msg = irm_msg__unpack(NULL, len, buf); pthread_cleanup_pop(true); - pthread_cleanup_pop(true); return recv_msg; } diff --git a/src/lib/tests/CMakeLists.txt b/src/lib/tests/CMakeLists.txt index 41c2074a..0223262a 100644 --- a/src/lib/tests/CMakeLists.txt +++ b/src/lib/tests/CMakeLists.txt @@ -1,6 +1,12 @@ get_filename_component(PARENT_PATH ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) get_filename_component(PARENT_DIR ${PARENT_PATH} NAME) +if (NOT (APPLE OR GNU)) + set(TIMERWHEEL_TEST "timerwheel_test.c") +else () + set(TIMERWHEEL_TEST "") +endif () + create_test_sourcelist(${PARENT_DIR}_tests test_suite.c # Add new tests here bitmap_test.c @@ -11,6 +17,7 @@ create_test_sourcelist(${PARENT_DIR}_tests test_suite.c rib_test.c sha3_test.c time_utils_test.c + ${TIMERWHEEL_TEST} ) add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}) diff --git a/src/lib/tests/rib_test.c b/src/lib/tests/rib_test.c index e1fa427d..6a2446b9 100644 --- a/src/lib/tests/rib_test.c +++ b/src/lib/tests/rib_test.c @@ -20,7 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 199309L + #include <ouroboros/time_utils.h> #include <ouroboros/rib.h> #include <ouroboros/rqueue.h> diff --git a/src/lib/tests/timerwheel_test.c b/src/lib/tests/timerwheel_test.c new file mode 100644 index 00000000..d7478487 --- /dev/null +++ b/src/lib/tests/timerwheel_test.c @@ -0,0 +1,104 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Test of the timer wheel + * + * Dimitri Staessens <[email protected]> + * Sander Vrijders <[email protected]> + * + * 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 "timerwheel.c" + +#include <pthread.h> +#include <time.h> +#include <stdlib.h> +#include <stdio.h> + +#define MAX_ELEMENTS 100 +#define MAX_RESOLUTION 10 /* ms */ +#define MAX_ADDITIONS 1000 + +int total; + +int add(void * o) +{ + total += *((int *) o); + return 0; +} + +int timerwheel_test(int argc, char ** argv) +{ + struct timerwheel * tw; + long resolution; + long elements; + struct timespec wait; + + int additions; + + int check_total = 0; + + int i; + int var = 5; + + struct tw_f * f; + + (void) argc; + (void) argv; + + total = 0; + + srand(time(NULL)); + + resolution = rand() % (MAX_RESOLUTION - 1) + 1; + elements = rand() % (MAX_ELEMENTS - 10) + 10; + + tw = timerwheel_create(resolution, resolution * elements); + if (tw == NULL) { + printf("Failed to create timerwheel.\n"); + return -1; + } + + wait.tv_sec = (resolution * elements) / 1000; + wait.tv_nsec = ((resolution * elements) % 1000) * MILLION; + + additions = rand() % MAX_ADDITIONS + 1000; + + for (i = 0; i < additions; ++i) { + int delay = rand() % (resolution * elements); + check_total += var; + f = timerwheel_start(tw, + (void (*)(void *)) add, + (void *) &var, + delay); + if (f == NULL) { + printf("Failed to add function."); + return -1; + } + } + + nanosleep(&wait, NULL); + + timerwheel_move(tw); + + timerwheel_destroy(tw); + + if (total != check_total) { + printf("Totals do not match: %d and %d.\n", total, check_total); + return -1; + } + + return 0; +} diff --git a/src/lib/time_utils.c b/src/lib/time_utils.c index 2dec4524..22937d4b 100644 --- a/src/lib/time_utils.c +++ b/src/lib/time_utils.c @@ -20,7 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 199309L + #include <ouroboros/time_utils.h> #include <stddef.h> diff --git a/src/lib/timerwheel.c b/src/lib/timerwheel.c new file mode 100644 index 00000000..2952c5d3 --- /dev/null +++ b/src/lib/timerwheel.c @@ -0,0 +1,232 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Timerwheel + * + * Dimitri Staessens <[email protected]> + * Sander Vrijders <[email protected]> + * + * 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 _POSIX_C_SOURCE 200112L + +#include "config.h" + +#include <ouroboros/time_utils.h> +#include <ouroboros/errno.h> +#include <ouroboros/list.h> + +#include <pthread.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#define FRAC 10 /* accuracy of the timer */ + +#define tw_used(tw) ((tw->head + tw->elements - tw->tail) & (tw->elements - 1)); +#define tw_free(tw) (tw_used(tw) + 1 < tw->elements) +#define tw_empty(tw) (tw->head == tw->tail) + +struct tw_f { + struct list_head next; + void (* func)(void *); + void * arg; +}; + +struct tw_el { + struct list_head funcs; + struct timespec expiry; +}; + +struct timerwheel { + struct tw_el * wheel; + + struct timespec intv; + + size_t pos; + + pthread_mutex_t lock; + + time_t resolution; + unsigned int elements; +}; + +static void tw_el_fini(struct tw_el * e) +{ + struct list_head * p; + struct list_head * h; + + list_for_each_safe(p, h, &e->funcs) { + struct tw_f * f = list_entry(p, struct tw_f, next); + list_del(&f->next); + } +} + +void timerwheel_move(struct timerwheel * tw) +{ + struct timespec now = {0, 0}; + long ms = tw->resolution * tw->elements; + struct timespec total = {ms / 1000, + (ms % 1000) * MILLION}; + struct list_head * p; + struct list_head * h; + + clock_gettime(CLOCK_MONOTONIC, &now); + + pthread_mutex_lock(&tw->lock); + + while (ts_diff_us(&tw->wheel[tw->pos].expiry, &now) > 0) { + list_for_each_safe(p, h, &tw->wheel[tw->pos].funcs) { + struct tw_f * f = list_entry(p, struct tw_f, next); + list_del(&f->next); + f->func(f->arg); + free(f); + } + + ts_add(&tw->wheel[tw->pos].expiry, + &total, + &tw->wheel[tw->pos].expiry); + + tw->pos = (tw->pos + 1) & (tw->elements - 1); + } + + pthread_mutex_unlock(&tw->lock); +} + +struct timerwheel * timerwheel_create(time_t resolution, + time_t max_delay) +{ + struct timespec now = {0, 0}; + struct timespec res_ts = {resolution / 1000, + (resolution % 1000) * MILLION}; + unsigned long i; + + struct timerwheel * tw; + + assert(resolution != 0); + + tw = malloc(sizeof(*tw)); + if (tw == NULL) + return NULL; + + if (pthread_mutex_init(&tw->lock, NULL)) + return NULL; + + tw->elements = 1; + + while (tw->elements < max_delay / resolution) + tw->elements <<= 1; + + tw->wheel = malloc(sizeof(*tw->wheel) * tw->elements); + if (tw->wheel == NULL) + goto fail_wheel_malloc; + + tw->resolution = resolution; + + tw->intv.tv_sec = (tw->resolution / FRAC) / 1000; + tw->intv.tv_nsec = ((tw->resolution / FRAC) % 1000) * MILLION; + + if (pthread_mutex_init(&tw->lock, NULL)) + goto fail_lock_init; + + tw->pos = 0; + + clock_gettime(CLOCK_MONOTONIC, &now); + now.tv_nsec -= (now.tv_nsec % MILLION); + + for (i = 0; i < tw->elements; ++i) { + list_head_init(&tw->wheel[i].funcs); + tw->wheel[i].expiry = now; + ts_add(&now, &res_ts, &now); + } + + return tw; + + fail_lock_init: + free(tw->wheel); + fail_wheel_malloc: + free(tw); + return NULL; +} + +void timerwheel_destroy(struct timerwheel * tw) +{ + unsigned long i; + + for (i = 0; i < tw->elements; ++i) + tw_el_fini(&tw->wheel[i]); + + pthread_mutex_destroy(&tw->lock); + free(tw->wheel); + free(tw); +} + +struct tw_f * timerwheel_start(struct timerwheel * tw, + void (* func)(void *), + void * arg, + time_t delay) +{ + int pos; + struct tw_f * f = malloc(sizeof(*f)); + if (f == NULL) + return NULL; + + f->func = func; + f->arg = arg; + + assert(delay < tw->elements * tw->resolution); + + pthread_mutex_lock(&tw->lock); + + pos = (tw->pos + delay / tw->resolution) & (tw->elements - 1); + list_add(&f->next, &tw->wheel[pos].funcs); + + pthread_mutex_unlock(&tw->lock); + + return f; +} + +int timerwheel_restart(struct timerwheel * tw, + struct tw_f * f, + time_t delay) +{ + int pos; + + assert(tw); + assert(delay < tw->elements * tw->resolution); + + pthread_mutex_lock(&tw->lock); + + list_del(&f->next); + pos = (tw->pos + delay / tw->resolution) & (tw->elements - 1); + list_add(&f->next, &tw->wheel[pos].funcs); + + pthread_mutex_unlock(&tw->lock); + + return 0; +} + +void timerwheel_stop(struct timerwheel * tw, + struct tw_f * f) +{ + assert(tw); + + pthread_mutex_lock(&tw->lock); + + list_del(&f->next); + free(f); + + pthread_mutex_unlock(&tw->lock); +} diff --git a/src/lib/tpm.c b/src/lib/tpm.c index 739996c4..dd71d276 100644 --- a/src/lib/tpm.c +++ b/src/lib/tpm.c @@ -20,7 +20,10 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#include <ouroboros/config.h> +#define _POSIX_C_SOURCE 200112L + +#include "config.h" + #include <ouroboros/errno.h> #include <ouroboros/list.h> #include <ouroboros/time_utils.h> |