From 45c6615484ffe347654c34decb72ff1ef9bde0f3 Mon Sep 17 00:00:00 2001
From: dimitri staessens <dimitri.staessens@ugent.be>
Date: Sat, 9 Sep 2017 13:50:47 +0200
Subject: ipcpd: Revise internals of normal IPCP

This removes the RIB as a datastructure and CDAP as the protocol
between IPCPs. CDAP, the rib and related sources are deprecated. The
link-state protocol policy is udpated to use its own protocol based on
a simple broadcast strategy along a tree. The neighbors struct is
deprecated and moved to the library as a generic notifier component.
---
 src/lib/CMakeLists.txt       |   11 +-
 src/lib/cdap.c               |  868 -------------------------
 src/lib/cdap.proto           |   32 -
 src/lib/cdap_req.c           |  208 ------
 src/lib/cdap_req.h           |   74 ---
 src/lib/hashtable.c          |    3 +-
 src/lib/notifier.c           |  128 ++++
 src/lib/rib.c                | 1431 ------------------------------------------
 src/lib/ro.proto             |   31 -
 src/lib/tests/CMakeLists.txt |    1 -
 src/lib/tests/rib_test.c     |  289 ---------
 11 files changed, 132 insertions(+), 2944 deletions(-)
 delete mode 100644 src/lib/cdap.c
 delete mode 100644 src/lib/cdap.proto
 delete mode 100644 src/lib/cdap_req.c
 delete mode 100644 src/lib/cdap_req.h
 create mode 100644 src/lib/notifier.c
 delete mode 100644 src/lib/rib.c
 delete mode 100644 src/lib/ro.proto
 delete mode 100644 src/lib/tests/rib_test.c

(limited to 'src/lib')

diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index eeb7966b..f126a52a 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -8,8 +8,6 @@ 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(DIF_CONFIG_PROTO_SRCS DIF_CONFIG_PROTO_HDRS
   ipcp_config.proto)
-protobuf_generate_c(CDAP_PROTO_SRCS CDAP_PROTO_HDRS cdap.proto)
-protobuf_generate_c(RO_PROTO_SRCS RO_PROTO_HDRS ro.proto)
 protobuf_generate_c(CACEP_PROTO_SRCS CACEP_PROTO_HDRS cacep.proto)
 
 if (NOT APPLE)
@@ -134,8 +132,6 @@ else ()
 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
@@ -154,8 +150,6 @@ set(SOURCE_FILES
   bitmap.c
   btree.c
   cacep.c
-  cdap.c
-  cdap_req.c
   crc32.c
   dev.c
   frct_pci.c
@@ -166,10 +160,10 @@ set(SOURCE_FILES
   lockfile.c
   logs.c
   md5.c
+  notifier.c
   qos.c
   qoscube.c
   random.c
-  rib.c
   sha3.c
   shm_flow_set.c
   shm_rbuff.c
@@ -185,8 +179,7 @@ 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})
+  ${IPCP_PROTO_SRCS} ${DIF_CONFIG_PROTO_SRCS} ${CACEP_PROTO_SRCS})
 
 include(AddCompileFlags)
 if (CMAKE_BUILD_TYPE MATCHES Debug)
diff --git a/src/lib/cdap.c b/src/lib/cdap.c
deleted file mode 100644
index d9cb2036..00000000
--- a/src/lib/cdap.c
+++ /dev/null
@@ -1,868 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2017
- *
- * The Common Distributed Application Protocol
- *
- *    Dimitri Staessens <dimitri.staessens@ugent.be>
- *    Sander Vrijders   <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define _POSIX_C_SOURCE 200809L
-
-#include <ouroboros/cdap.h>
-#include <ouroboros/bitmap.h>
-#include <ouroboros/dev.h>
-#include <ouroboros/fqueue.h>
-#include <ouroboros/errno.h>
-
-#include "cdap_req.h"
-
-#include <stdlib.h>
-#include <pthread.h>
-#include <string.h>
-#include <assert.h>
-
-#include "cdap.pb-c.h"
-typedef Cdap cdap_t;
-
-#define CDAP_REPLY (CDAP_DELETE + 1)
-
-#define INVALID_ID -1
-#define IDS_SIZE 2048
-#define BUF_SIZE 2048
-
-struct fd_el {
-        struct list_head next;
-
-        int              fd;
-};
-
-struct cdap {
-        fset_t *         set;
-        fqueue_t *       fq;
-
-        bool             proc;
-        pthread_mutex_t  mtx;
-        pthread_cond_t   cond;
-
-        size_t           n_flows;
-        struct list_head flows;
-        pthread_rwlock_t flows_lock;
-
-        struct bmp *     ids;
-        pthread_mutex_t  ids_lock;
-
-        struct list_head sent;
-        pthread_rwlock_t sent_lock;
-
-        struct list_head rcvd;
-        pthread_cond_t   rcvd_cond;
-        pthread_mutex_t  rcvd_lock;
-
-        pthread_t        reader;
-};
-
-struct cdap_rcvd {
-        struct list_head next;
-
-        int              fd;
-        bool             proc;
-
-        invoke_id_t      iid;
-        cdap_key_t       key;
-
-        enum cdap_opcode opcode;
-        char *           name;
-        void *           data;
-        size_t           len;
-        uint32_t         flags;
-};
-
-static int next_id(struct cdap * instance)
-{
-        int ret;
-
-        assert(instance);
-
-        pthread_mutex_lock(&instance->ids_lock);
-
-        ret = bmp_allocate(instance->ids);
-        if (!bmp_is_id_valid(instance->ids, ret))
-                ret = INVALID_ID;
-
-        pthread_mutex_unlock(&instance->ids_lock);
-
-        return ret;
-}
-
-static int release_id(struct cdap * instance,
-                      int32_t       id)
-{
-        int ret;
-
-        assert(instance);
-
-        pthread_mutex_lock(&instance->ids_lock);
-
-        ret = bmp_release(instance->ids, id);
-
-        pthread_mutex_unlock(&instance->ids_lock);
-
-        return ret;
-}
-
-#define cdap_sent_has_key(i, key) (cdap_sent_get_by_key(i, key) != NULL)
-
-static struct cdap_req * cdap_sent_get_by_key(struct cdap * instance,
-                                              cdap_key_t    key)
-{
-        struct list_head * p = NULL;
-        struct cdap_req *  req = NULL;
-
-        assert(instance);
-
-        pthread_rwlock_rdlock(&instance->sent_lock);
-
-        list_for_each(p, &instance->sent) {
-                req = list_entry(p, struct cdap_req, next);
-                if (req->key == key) {
-                        pthread_rwlock_unlock(&instance->sent_lock);
-                        return req;
-                }
-        }
-
-        pthread_rwlock_unlock(&instance->sent_lock);
-
-        return NULL;
-}
-
-static struct cdap_req * cdap_sent_get_by_iid(struct cdap * instance,
-                                              invoke_id_t   iid)
-{
-        struct list_head * p = NULL;
-        struct cdap_req *  req = NULL;
-
-        assert(instance);
-
-        pthread_rwlock_rdlock(&instance->sent_lock);
-
-        list_for_each(p, &instance->sent) {
-                req = list_entry(p, struct cdap_req, next);
-                if (req->iid == iid) {
-                        pthread_rwlock_unlock(&instance->sent_lock);
-                        return req;
-                }
-        }
-
-        pthread_rwlock_unlock(&instance->sent_lock);
-
-        return NULL;
-}
-
-static struct cdap_rcvd * cdap_rcvd_get_by_key(struct cdap * instance,
-                                               cdap_key_t    key)
-{
-        struct list_head * p = NULL;
-        struct list_head * h = NULL;
-        struct cdap_rcvd * rcvd = NULL;
-
-        assert(instance);
-
-        pthread_mutex_lock(&instance->rcvd_lock);
-
-        list_for_each_safe(p, h, &instance->rcvd) {
-                rcvd = list_entry(p, struct cdap_rcvd, next);
-                if (rcvd->key == key) {
-                        list_del(&rcvd->next);
-                        pthread_mutex_unlock(&instance->rcvd_lock);
-                        return rcvd;
-                }
-        }
-
-        pthread_mutex_unlock(&instance->rcvd_lock);
-
-        assert(false);
-
-        return NULL;
-}
-
-static struct cdap_req * cdap_sent_add(struct cdap * instance,
-                                       int           fd,
-                                       invoke_id_t   iid,
-                                       cdap_key_t    key)
-{
-        struct cdap_req * req;
-
-        assert(instance);
-        assert(!cdap_sent_has_key(instance, key));
-
-        req = cdap_req_create(fd, iid, key);
-        if (req == NULL)
-                return NULL;
-
-        pthread_rwlock_wrlock(&instance->sent_lock);
-
-        list_add(&req->next, &instance->sent);
-
-        pthread_rwlock_unlock(&instance->sent_lock);
-
-        return req;
-}
-
-static void cdap_sent_del(struct cdap *     instance,
-                          struct cdap_req * req)
-{
-        assert(instance);
-        assert(req);
-
-        assert(cdap_sent_has_key(instance, req->key));
-
-        pthread_rwlock_wrlock(&instance->sent_lock);
-
-        list_del(&req->next);
-
-        pthread_rwlock_unlock(&instance->sent_lock);
-
-        cdap_req_destroy(req);
-}
-
-static void cdap_sent_destroy(struct cdap * instance)
-{
-        struct list_head * p = NULL;
-        struct list_head * h = NULL;
-
-        assert(instance);
-
-        pthread_rwlock_wrlock(&instance->sent_lock);
-
-        list_for_each_safe(p, h, &instance->sent) {
-                struct cdap_req * req = list_entry(p, struct cdap_req, next);
-                list_del(&req->next);
-                cdap_req_cancel(req);
-                cdap_req_destroy(req);
-        }
-
-        pthread_rwlock_unlock(&instance->sent_lock);
-}
-
-static void cdap_rcvd_destroy(struct cdap * instance)
-{
-        struct list_head * p = NULL;
-        struct list_head * h = NULL;
-
-        assert(instance);
-
-        pthread_mutex_lock(&instance->rcvd_lock);
-
-        list_for_each_safe(p, h, &instance->rcvd) {
-                struct cdap_rcvd * r = list_entry(p, struct cdap_rcvd, next);
-                list_del(&r->next);
-                if (r->data != NULL)
-                        free(r->data);
-                if (r->name != NULL)
-                        free(r->name);
-                free(r);
-        }
-
-        pthread_cond_broadcast(&instance->rcvd_cond);
-
-        pthread_mutex_unlock(&instance->rcvd_lock);
-}
-
-static void set_proc(struct cdap * instance,
-                     bool          status)
-{
-        pthread_mutex_lock(&instance->mtx);
-
-        instance->proc = status;
-        pthread_cond_signal(&instance->cond);
-
-        pthread_mutex_unlock(&instance->mtx);
-}
-
-static void * sdu_reader(void * o)
-{
-        struct cdap * instance = (struct cdap *) o;
-        struct cdap_req * req;
-        struct cdap_rcvd * rcvd;
-        cdap_t * msg;
-        uint8_t buf[BUF_SIZE];
-        ssize_t len;
-        buffer_t data;
-
-        while (fevent(instance->set, instance->fq, NULL)) {
-                int fd;
-                set_proc(instance, true);
-                fd = fqueue_next(instance->fq);
-                len = flow_read(fd, buf, BUF_SIZE);
-                if (len < 0) {
-                        set_proc(instance, false);
-                        continue;
-                }
-
-                msg = cdap__unpack(NULL, len, buf);
-                if (msg == NULL) {
-                        set_proc(instance, false);
-                        continue;
-                }
-
-                if (msg->opcode != CDAP_REPLY) {
-                        rcvd = malloc(sizeof(*rcvd));
-                        if (rcvd == NULL) {
-                                cdap__free_unpacked(msg, NULL);
-                                set_proc(instance, false);
-                                continue;
-                        }
-
-                        assert(msg->name);
-
-                        rcvd->opcode = msg->opcode;
-                        rcvd->fd     = fd;
-                        rcvd->iid    = msg->invoke_id;
-                        rcvd->key    = next_id(instance);
-                        if (rcvd->key == INVALID_ID) {
-                                cdap__free_unpacked(msg, NULL);
-                                set_proc(instance, false);
-                                free(rcvd);
-                                continue;
-                        }
-
-                        rcvd->flags  = msg->flags;
-                        rcvd->proc   = false;
-                        rcvd->name   = strdup(msg->name);
-                        if (rcvd->name == NULL) {
-                                release_id(instance, rcvd->key);
-                                cdap__free_unpacked(msg, NULL);
-                                set_proc(instance, false);
-                                free(rcvd);
-                                continue;
-                        }
-
-                        if (msg->has_value) {
-                                rcvd->len = msg->value.len;
-                                rcvd->data = malloc(rcvd->len);
-                                if (rcvd->data == NULL) {
-                                        release_id(instance, rcvd->key);
-                                        cdap__free_unpacked(msg, NULL);
-                                        set_proc(instance, false);
-                                        free(rcvd->name);
-                                        free(rcvd);
-                                        continue;
-                                }
-                                memcpy(rcvd->data, msg->value.data, rcvd->len);
-                        } else {
-                                rcvd->len = 0;
-                                rcvd->data = NULL;
-                        }
-
-                        pthread_mutex_lock(&instance->rcvd_lock);
-
-                        list_add(&rcvd->next, &instance->rcvd);
-
-                        pthread_cond_signal(&instance->rcvd_cond);
-                        pthread_mutex_unlock(&instance->rcvd_lock);
-                } else  {
-                        req = cdap_sent_get_by_iid(instance, msg->invoke_id);
-                        if (req == NULL) {
-                                cdap__free_unpacked(msg, NULL);
-                                set_proc(instance, false);
-                                continue;
-                        }
-
-                        if (msg->has_value) {
-                                data.len = msg->value.len;
-                                data.data = malloc(data.len);
-                                if (data.data == NULL) {
-                                        cdap__free_unpacked(msg, NULL);
-                                        set_proc(instance, false);
-                                        continue;
-                                }
-                                memcpy(data.data, msg->value.data, data.len);
-                        } else {
-                                data.len = 0;
-                                data.data = NULL;
-                        }
-
-                        cdap_req_respond(req, msg->result, data);
-                }
-
-                cdap__free_unpacked(msg, NULL);
-                set_proc(instance, false);
-        }
-
-        return (void *) 0;
-}
-
-struct cdap * cdap_create()
-{
-        struct cdap * instance = NULL;
-
-        instance = malloc(sizeof(*instance));
-        if (instance == NULL)
-                goto fail_malloc;
-
-        if (pthread_rwlock_init(&instance->flows_lock, NULL))
-                goto fail_flows_lock;
-
-        if (pthread_mutex_init(&instance->ids_lock, NULL))
-                goto fail_ids_lock;
-
-        if (pthread_mutex_init(&instance->rcvd_lock, NULL))
-                goto fail_rcvd_lock;
-
-        if (pthread_rwlock_init(&instance->sent_lock, NULL))
-                goto fail_sent_lock;
-
-        if (pthread_cond_init(&instance->rcvd_cond, NULL))
-                goto fail_rcvd_cond;
-
-        if (pthread_mutex_init(&instance->mtx, NULL))
-                goto fail_mtx;
-
-        if (pthread_cond_init(&instance->cond, NULL))
-                goto fail_cond;
-
-        instance->ids = bmp_create(IDS_SIZE, 0);
-        if (instance->ids == NULL)
-                goto fail_bmp_create;
-
-        instance->set = fset_create();
-        if (instance->set == NULL)
-                goto fail_set_create;
-
-        instance->fq = fqueue_create();
-        if (instance->fq == NULL)
-                goto fail_fqueue_create;
-
-        instance->n_flows = 0;
-        instance->proc = false;
-
-        list_head_init(&instance->flows);
-        list_head_init(&instance->sent);
-        list_head_init(&instance->rcvd);
-
-        if (pthread_create(&instance->reader, NULL, sdu_reader, instance))
-                goto fail_pthread_create;
-
-        return instance;
-
- fail_pthread_create:
-        fqueue_destroy(instance->fq);
- fail_fqueue_create:
-        fset_destroy(instance->set);
- fail_set_create:
-        bmp_destroy(instance->ids);
- fail_bmp_create:
-        pthread_cond_destroy(&instance->cond);
- fail_cond:
-        pthread_mutex_destroy(&instance->mtx);
- fail_mtx:
-        pthread_cond_destroy(&instance->rcvd_cond);
- fail_rcvd_cond:
-        pthread_rwlock_destroy(&instance->sent_lock);
- fail_sent_lock:
-        pthread_mutex_destroy(&instance->rcvd_lock);
- fail_rcvd_lock:
-        pthread_mutex_destroy(&instance->ids_lock);
- fail_ids_lock:
-        pthread_rwlock_destroy(&instance->flows_lock);
- fail_flows_lock:
-        free(instance);
- fail_malloc:
-        return NULL;
-}
-
-int cdap_destroy(struct cdap * instance)
-{
-        struct list_head * p;
-        struct list_head * h;
-
-        if (instance == NULL)
-                return 0;
-
-        pthread_cancel(instance->reader);
-        pthread_join(instance->reader, NULL);
-
-        fqueue_destroy(instance->fq);
-
-        fset_destroy(instance->set);
-
-        pthread_cond_destroy(&instance->cond);
-        pthread_mutex_destroy(&instance->mtx);
-
-        pthread_rwlock_wrlock(&instance->flows_lock);
-
-        list_for_each_safe(p,h, &instance->flows) {
-                struct fd_el * e = list_entry(p, struct fd_el, next);
-                list_del(&e->next);
-                free(e);
-        }
-
-        pthread_rwlock_unlock(&instance->flows_lock);
-
-        pthread_rwlock_destroy(&instance->flows_lock);
-
-        pthread_mutex_lock(&instance->ids_lock);
-
-        bmp_destroy(instance->ids);
-
-        pthread_mutex_unlock(&instance->ids_lock);
-
-        pthread_mutex_destroy(&instance->ids_lock);
-
-        cdap_sent_destroy(instance);
-
-        pthread_rwlock_destroy(&instance->sent_lock);
-
-        cdap_rcvd_destroy(instance);
-
-        pthread_mutex_destroy(&instance->rcvd_lock);
-
-        free(instance);
-
-        return 0;
-}
-
-int cdap_add_flow(struct cdap * instance,
-                  int           fd)
-{
-        struct fd_el * e;
-
-        if (fd < 0)
-                return -EINVAL;
-
-        e = malloc(sizeof(*e));
-        if (e == NULL)
-                return -ENOMEM;
-
-        e->fd = fd;
-
-        pthread_rwlock_wrlock(&instance->flows_lock);
-
-        if (fset_add(instance->set, fd)) {
-                pthread_rwlock_unlock(&instance->flows_lock);
-                free(e);
-                return -1;
-        }
-
-        list_add(&e->next, &instance->flows);
-
-        ++instance->n_flows;
-
-        pthread_rwlock_unlock(&instance->flows_lock);
-
-        return 0;
-}
-
-int cdap_del_flow(struct cdap * instance,
-                  int           fd)
-{
-        struct list_head * p;
-        struct list_head * h;
-
-        if (fd < 0)
-                return -EINVAL;
-
-        pthread_rwlock_wrlock(&instance->flows_lock);
-
-        fset_del(instance->set, fd);
-
-        list_for_each_safe(p, h, &instance->flows) {
-                struct fd_el * e = list_entry(p, struct fd_el, next);
-                if (e->fd == fd) {
-                        list_del(&e->next);
-                        free(e);
-                        break;
-                }
-        }
-
-        --instance->n_flows;
-
-        pthread_rwlock_unlock(&instance->flows_lock);
-
-        pthread_mutex_lock(&instance->mtx);
-
-        pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
-                             (void *) &instance->mtx);
-
-        while (instance->proc)
-                pthread_cond_wait(&instance->cond, &instance->mtx);
-
-        pthread_cleanup_pop(true);
-
-        return 0;
-}
-
-static int write_msg(int           fd,
-                     cdap_t *      msg)
-{
-        uint8_t * data;
-        size_t len;
-
-        assert(msg);
-
-        len = cdap__get_packed_size(msg);
-        if (len == 0)
-                return -1;
-
-        data = malloc(len);
-        if (data == NULL)
-                return -ENOMEM;
-
-        cdap__pack(msg, data);
-
-        if (flow_write(fd, data, len)) {
-                free(data);
-                return -1;
-        }
-
-        free(data);
-
-        return 0;
-}
-
-cdap_key_t * cdap_request_send(struct cdap *    instance,
-                               enum cdap_opcode code,
-                               const char *     name,
-                               const void *     data,
-                               size_t           len,
-                               uint32_t         flags)
-{
-        cdap_key_t *       keys;
-        cdap_key_t *       key;
-        cdap_t             msg = CDAP__INIT;
-        struct list_head * p;
-        int                ret;
-
-        if (instance == NULL || name == NULL || code > CDAP_DELETE)
-                return NULL;
-
-        pthread_rwlock_rdlock(&instance->flows_lock);
-
-        keys = malloc(sizeof(*keys) * (instance->n_flows + 1));
-        if (keys == NULL) {
-                pthread_rwlock_unlock(&instance->flows_lock);
-                return NULL;
-        }
-
-        memset(keys, INVALID_CDAP_KEY, sizeof(*keys) * (instance->n_flows + 1));
-
-        key = keys;
-
-        cdap__init(&msg);
-
-        msg.opcode = code;
-        msg.name = (char *) name;
-        msg.has_flags = true;
-        msg.flags = flags;
-
-        if (data != NULL) {
-                msg.has_value = true;
-                msg.value.data = (uint8_t *) data;
-                msg.value.len = len;
-        }
-
-        list_for_each(p, &instance->flows) {
-                struct cdap_req * req;
-                invoke_id_t iid;
-                struct fd_el * e;
-
-                iid = next_id(instance);
-                if (iid == INVALID_ID) {
-                        pthread_rwlock_unlock(&instance->flows_lock);
-                        return keys;
-                }
-
-                msg.invoke_id = iid;
-
-                e = list_entry(p, struct fd_el, next);
-
-                *key = next_id(instance);
-                if (*key == INVALID_ID) {
-                        release_id(instance, iid);
-                        pthread_rwlock_unlock(&instance->flows_lock);
-                        return keys;
-                }
-
-                req = cdap_sent_add(instance, e->fd, iid, *key);
-                if (req == NULL) {
-                        release_id(instance, *key);
-                        release_id(instance, iid);
-                        pthread_rwlock_unlock(&instance->flows_lock);
-                        *key = INVALID_CDAP_KEY;
-                        return keys;
-                }
-
-                ret = write_msg(e->fd, &msg);
-                if (ret == -ENOMEM) {
-                        cdap_sent_del(instance, req);
-                        release_id(instance, *key);
-                        release_id(instance, iid);
-                        pthread_rwlock_unlock(&instance->flows_lock);
-                        *key = INVALID_CDAP_KEY;
-                        return keys;
-                }
-
-                if (ret < 0) {
-                        cdap_sent_del(instance, req);
-                        release_id(instance, *key);
-                        release_id(instance, iid);
-                        pthread_rwlock_unlock(&instance->flows_lock);
-                        *key = INVALID_CDAP_KEY;
-                        return keys;
-                }
-
-                ++key;
-        }
-
-        pthread_rwlock_unlock(&instance->flows_lock);
-
-        return keys;
-}
-
-int cdap_reply_wait(struct cdap * instance,
-                    cdap_key_t    key,
-                    uint8_t **    data,
-                    size_t *      len)
-{
-        int ret;
-        struct cdap_req * r;
-        invoke_id_t iid;
-
-        if (instance == NULL || (data != NULL && len == NULL))
-                return -EINVAL;
-
-        r = cdap_sent_get_by_key(instance, key);
-        if (r == NULL)
-                return -EINVAL;
-
-        iid = r->iid;
-
-        ret = cdap_req_wait(r);
-        if (ret < 0) {
-                cdap_sent_del(instance, r);
-                release_id(instance, iid);
-                release_id(instance, key);
-                return ret;
-        }
-
-        assert(ret == 0);
-
-        if (data != NULL) {
-                *data = r->data.data;
-                *len  = r->data.len;
-        }
-
-        ret = r->response;
-
-        cdap_sent_del(instance, r);
-        release_id(instance, iid);
-        release_id(instance, key);
-
-        return ret;
-}
-
-cdap_key_t cdap_request_wait(struct cdap *      instance,
-                             enum cdap_opcode * opcode,
-                             char **            name,
-                             uint8_t **         data,
-                             size_t *           len,
-                             uint32_t *         flags)
-{
-        struct cdap_rcvd * rcv = NULL;
-
-        if (instance == NULL || opcode == NULL || name == NULL || data == NULL
-            || len == NULL || flags == NULL)
-                return -EINVAL;
-
-        pthread_mutex_lock(&instance->rcvd_lock);
-
-        pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
-                             (void *) &instance->rcvd_lock);
-
-        while (rcv == NULL) {
-                while (list_is_empty(&instance->rcvd))
-                        pthread_cond_wait(&instance->rcvd_cond,
-                                          &instance->rcvd_lock);
-
-                rcv = list_first_entry(&instance->rcvd, struct cdap_rcvd, next);
-                if (rcv->proc) {
-                        rcv = NULL;
-                        pthread_cond_wait(&instance->rcvd_cond,
-                                          &instance->rcvd_lock);
-                }
-        }
-
-        assert(rcv->proc == false);
-
-        rcv->proc = true;
-        list_del(&rcv->next);
-        list_add_tail(&rcv->next, &instance->rcvd);
-
-        pthread_cleanup_pop(true);
-
-        *opcode = rcv->opcode;
-        *name   = rcv->name;
-        *data   = rcv->data;
-        *len    = rcv->len;
-        *flags  = rcv->flags;
-
-        rcv->name = NULL;
-        rcv->data = NULL;
-
-        return rcv->key;
-}
-
-int cdap_reply_send(struct cdap * instance,
-                    cdap_key_t    key,
-                    int           result,
-                    const void *  data,
-                    size_t        len)
-{
-        int                fd;
-        cdap_t             msg  = CDAP__INIT;
-        struct cdap_rcvd * rcvd;
-
-        if (instance == NULL)
-                return -EINVAL;
-
-        rcvd = cdap_rcvd_get_by_key(instance, key);
-        if (rcvd == NULL)
-                return -1;
-
-        msg.opcode = CDAP_REPLY;
-        msg.invoke_id = rcvd->iid;
-        msg.has_result = true;
-        msg.result = result;
-
-        if (data != NULL) {
-                msg.has_value = true;
-                msg.value.data = (uint8_t *) data;
-                msg.value.len = len;
-        }
-
-        fd = rcvd->fd;
-
-        release_id(instance, rcvd->key);
-
-        assert(rcvd->data == NULL);
-        assert(rcvd->name == NULL);
-        assert(rcvd->proc);
-
-        free(rcvd);
-
-        return write_msg(fd, &msg);
-}
diff --git a/src/lib/cdap.proto b/src/lib/cdap.proto
deleted file mode 100644
index 29effc9a..00000000
--- a/src/lib/cdap.proto
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016- 2017
- *
- * CDAP message
- *
- *    Dimitri Staessens <dimitri.staessens@ugent.be>
- *    Sander Vrijders   <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-syntax = "proto2";
-
-message cdap {
-        required uint32 opcode    = 1;
-        required uint32 invoke_id = 2;
-        optional uint32 flags     = 3;
-        optional string name      = 4;
-        optional bytes value      = 5;
-        optional int32 result     = 6;
-}
diff --git a/src/lib/cdap_req.c b/src/lib/cdap_req.c
deleted file mode 100644
index a9b85525..00000000
--- a/src/lib/cdap_req.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2017
- *
- * CDAP - CDAP request management
- *
- *    Dimitri Staessens <dimitri.staessens@ugent.be>
- *    Sander Vrijders   <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define _POSIX_C_SOURCE 200809L
-
-#include "config.h"
-
-#include <ouroboros/time_utils.h>
-#include <ouroboros/errno.h>
-
-#include "cdap_req.h"
-
-#include <stdlib.h>
-#include <assert.h>
-
-struct cdap_req * cdap_req_create(int         fd,
-                                  invoke_id_t iid,
-                                  cdap_key_t  key)
-{
-        struct cdap_req * creq = malloc(sizeof(*creq));
-        pthread_condattr_t cattr;
-
-        if (creq == NULL)
-                return NULL;
-
-        creq->fd        = fd;
-        creq->iid       = iid;
-        creq->key       = key;
-        creq->state     = REQ_INIT;
-        creq->response  = -1;
-        creq->data.data = NULL;
-        creq->data.len  = 0;
-
-        if (pthread_mutex_init(&creq->lock, NULL)) {
-                free(creq);
-                return NULL;
-        }
-
-        pthread_condattr_init(&cattr);
-#ifndef __APPLE__
-        pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
-        if (pthread_cond_init(&creq->cond, &cattr)) {
-                pthread_condattr_destroy(&cattr);
-                pthread_mutex_destroy(&creq->lock);
-                free(creq);
-                return NULL;
-        }
-
-        pthread_condattr_destroy(&cattr);
-
-        list_head_init(&creq->next);
-
-        clock_gettime(PTHREAD_COND_CLOCK, &creq->birth);
-
-        return creq;
-}
-
-void cdap_req_destroy(struct cdap_req * creq)
-{
-        assert(creq);
-
-        pthread_mutex_lock(&creq->lock);
-
-        switch(creq->state) {
-        case REQ_DESTROY:
-                pthread_mutex_unlock(&creq->lock);
-                return;
-        case REQ_INIT:
-                creq->state = REQ_NULL;
-                pthread_cond_broadcast(&creq->cond);
-                break;
-        case REQ_INIT_PENDING:
-        case REQ_PENDING:
-        case REQ_RESPONSE:
-                creq->state = REQ_DESTROY;
-                pthread_cond_broadcast(&creq->cond);
-                break;
-        default:
-                break;
-        }
-
-        while (creq->state != REQ_NULL)
-                pthread_cond_wait(&creq->cond, &creq->lock);
-
-        pthread_mutex_unlock(&creq->lock);
-
-        pthread_cond_destroy(&creq->cond);
-        pthread_mutex_destroy(&creq->lock);
-
-        free(creq);
-}
-
-int cdap_req_wait(struct cdap_req * creq)
-{
-        struct timespec timeout = {(CDAP_REPLY_TIMEOUT / 1000),
-                                   (CDAP_REPLY_TIMEOUT % 1000) * MILLION};
-        struct timespec abstime;
-        int ret = -1;
-
-        assert(creq);
-
-        ts_add(&creq->birth, &timeout, &abstime);
-
-        pthread_mutex_lock(&creq->lock);
-
-        if (creq->state != REQ_INIT) {
-                pthread_mutex_unlock(&creq->lock);
-                return -EINVAL;
-        }
-
-        creq->state = REQ_PENDING;
-        pthread_cond_broadcast(&creq->cond);
-
-        while (creq->state == REQ_PENDING && ret != -ETIMEDOUT)
-                ret = -pthread_cond_timedwait(&creq->cond,
-                                              &creq->lock,
-                                              &abstime);
-
-        switch(creq->state) {
-        case REQ_DESTROY:
-                ret = -1;
-                /* FALLTHRU */
-        case REQ_PENDING:
-                creq->state = REQ_NULL;
-                pthread_cond_broadcast(&creq->cond);
-                break;
-        case REQ_RESPONSE:
-                creq->state = REQ_DONE;
-                pthread_cond_broadcast(&creq->cond);
-                break;
-        default:
-                assert(false);
-                break;
-        }
-
-        pthread_mutex_unlock(&creq->lock);
-
-        return ret;
-}
-
-void cdap_req_respond(struct cdap_req * creq,
-                      int               response,
-                      buffer_t          data)
-{
-        assert(creq);
-
-        pthread_mutex_lock(&creq->lock);
-
-        if (creq->state == REQ_INIT)
-                creq->state = REQ_INIT_PENDING;
-
-        while (creq->state == REQ_INIT_PENDING)
-                pthread_cond_wait(&creq->cond, &creq->lock);
-
-        if (creq->state != REQ_PENDING) {
-                creq->state = REQ_NULL;
-                pthread_cond_broadcast(&creq->cond);
-                pthread_mutex_unlock(&creq->lock);
-                return;
-        }
-
-        creq->state    = REQ_RESPONSE;
-        creq->response = response;
-        creq->data     = data;
-
-        pthread_cond_broadcast(&creq->cond);
-
-        while (creq->state == REQ_RESPONSE)
-                pthread_cond_wait(&creq->cond, &creq->lock);
-
-        creq->state = REQ_NULL;
-        pthread_cond_broadcast(&creq->cond);
-
-        pthread_mutex_unlock(&creq->lock);
-}
-
-
-void cdap_req_cancel(struct cdap_req * creq)
-{
-        assert(creq);
-
-        pthread_mutex_lock(&creq->lock);
-
-        creq->state = REQ_NULL;
-        pthread_cond_broadcast(&creq->cond);
-
-        pthread_mutex_unlock(&creq->lock);
-}
diff --git a/src/lib/cdap_req.h b/src/lib/cdap_req.h
deleted file mode 100644
index 4c9cd15b..00000000
--- a/src/lib/cdap_req.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2017
- *
- * CDAP - CDAP request management
- *
- *    Dimitri Staessens <dimitri.staessens@ugent.be>
- *    Sander Vrijders   <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#ifndef OUROBOROS_CDAP_REQ_H
-#define OUROBOROS_CDAP_REQ_H
-
-#include <ouroboros/cdap.h>
-#include <ouroboros/list.h>
-#include <ouroboros/utils.h>
-
-#include <pthread.h>
-
-typedef cdap_key_t invoke_id_t;
-
-enum creq_state {
-        REQ_NULL = 0,
-        REQ_INIT,
-        REQ_INIT_PENDING,
-        REQ_PENDING,
-        REQ_RESPONSE,
-        REQ_DONE,
-        REQ_DESTROY
-};
-
-struct cdap_req {
-        struct list_head next;
-
-        int              fd;
-        struct timespec  birth;
-        cdap_key_t       key;
-        invoke_id_t      iid;
-
-        int              response;
-        buffer_t         data;
-
-        enum creq_state  state;
-        pthread_cond_t   cond;
-        pthread_mutex_t  lock;
-};
-
-struct cdap_req * cdap_req_create(int         fd,
-                                  cdap_key_t  key,
-                                  invoke_id_t iid);
-
-void              cdap_req_destroy(struct cdap_req * creq);
-
-int               cdap_req_wait(struct cdap_req * creq);
-
-void              cdap_req_respond(struct cdap_req * creq,
-                                   int               response,
-                                   buffer_t          data);
-
-void              cdap_req_cancel(struct cdap_req * creq);
-
-#endif /* OUROBOROS_CDAP_REQ_H */
diff --git a/src/lib/hashtable.c b/src/lib/hashtable.c
index 75cdee84..2aa248ba 100644
--- a/src/lib/hashtable.c
+++ b/src/lib/hashtable.c
@@ -38,7 +38,8 @@ struct htable {
         uint64_t           buckets_size;
 };
 
-struct htable * htable_create(uint64_t buckets, bool hash_key)
+struct htable * htable_create(uint64_t buckets,
+                              bool     hash_key)
 {
         struct htable * tmp;
         unsigned int i;
diff --git a/src/lib/notifier.c b/src/lib/notifier.c
new file mode 100644
index 00000000..cfd383d4
--- /dev/null
+++ b/src/lib/notifier.c
@@ -0,0 +1,128 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2017
+ *
+ * Notifier event system using callbacks
+ *
+ *    Dimitri Staessens <dimitri.staessens@ugent.be>
+ *    Sander Vrijders   <sander.vrijders@ugent.be>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include <ouroboros/errno.h>
+#include <ouroboros/notifier.h>
+#include <ouroboros/list.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+
+struct listener {
+        struct list_head next;
+        notifier_fn_t    callback;
+};
+
+struct {
+        struct list_head listeners;
+        pthread_mutex_t  lock;
+} notifier;
+
+int notifier_init(void)
+{
+        if (pthread_mutex_init(&notifier.lock, NULL))
+                return -1;
+
+        list_head_init(&notifier.listeners);
+
+        return 0;
+}
+
+void notifier_fini(void)
+{
+        struct list_head * p;
+        struct list_head * h;
+
+        pthread_mutex_lock(&notifier.lock);
+
+        list_for_each_safe(p, h, &notifier.listeners) {
+                struct listener * l = list_entry(p, struct listener, next);
+                list_del(&l->next);
+                free(l);
+        }
+
+        pthread_mutex_unlock(&notifier.lock);
+
+        pthread_mutex_destroy(&notifier.lock);
+}
+
+void notifier_event(int          event,
+                    const void * o)
+{
+        struct list_head * p;
+
+        pthread_mutex_lock(&notifier.lock);
+
+        list_for_each(p, &notifier.listeners)
+                list_entry(p, struct listener, next)->callback(event, o);
+
+        pthread_mutex_unlock(&notifier.lock);
+}
+
+int notifier_reg(notifier_fn_t callback)
+{
+        struct listener *  l;
+        struct list_head * p;
+
+        pthread_mutex_lock(&notifier.lock);
+
+        list_for_each(p, &notifier.listeners) {
+                struct listener * l = list_entry(p, struct listener, next);
+                if (l->callback == callback) {
+                        pthread_mutex_unlock(&notifier.lock);
+                        return -EPERM;
+                }
+        }
+
+        l = malloc(sizeof(*l));
+        if (l == NULL) {
+                pthread_mutex_unlock(&notifier.lock);
+                return -ENOMEM;
+        }
+
+        l->callback = callback;
+
+        list_add(&l->next, &notifier.listeners);
+
+        pthread_mutex_unlock(&notifier.lock);
+
+        return 0;
+}
+
+void notifier_unreg(notifier_fn_t callback)
+{
+        struct list_head * p;
+        struct list_head * h;
+
+        pthread_mutex_lock(&notifier.lock);
+
+        list_for_each_safe(p, h, &notifier.listeners) {
+                struct listener * l = list_entry(p, struct listener, next);
+                if (l->callback == callback) {
+                        list_del(&l->next);
+                        free(l);
+                        break;
+                }
+        }
+
+        pthread_mutex_unlock(&notifier.lock);
+}
diff --git a/src/lib/rib.c b/src/lib/rib.c
deleted file mode 100644
index 9e45a302..00000000
--- a/src/lib/rib.c
+++ /dev/null
@@ -1,1431 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2017
- *
- * Resource Information Base
- *
- *    Dimitri Staessens <dimitri.staessens@ugent.be>
- *    Sander Vrijders   <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define _POSIX_C_SOURCE 200809L
-
-#include "config.h"
-
-#include <ouroboros/errno.h>
-#include <ouroboros/list.h>
-#include <ouroboros/rib.h>
-#include <ouroboros/rqueue.h>
-#include <ouroboros/bitmap.h>
-#include <ouroboros/crc32.h>
-#include <ouroboros/time_utils.h>
-#include <ouroboros/sha3.h>
-#include <ouroboros/btree.h>
-
-#include "ro.pb-c.h"
-typedef RoMsg ro_msg_t;
-
-#include <pthread.h>
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#define RIB_PATH_DLR     "/"
-#define RIB_BTREE_ORDER   64
-#define GEN_NAME_SIZE      8
-
-struct revent {
-        struct list_head next;
-
-        char *           path;
-        int32_t          flags;
-};
-
-struct rqueue {
-        struct list_head events;
-};
-
-struct ro_set {
-        uint32_t         sid;
-};
-
-struct rn_ptr {
-        struct list_head next;
-
-        struct rnode *   node;
-};
-
-struct rib_sub {
-        struct list_head next;
-
-        uint32_t         sid;
-
-        struct list_head rnodes;
-
-        struct list_head events;
-
-        pthread_cond_t   cond;
-        pthread_mutex_t  lock;
-};
-
-struct rn_sub {
-        struct list_head next;
-
-        struct rib_sub * sub;
-        int32_t          flags;
-};
-
-struct rnode {
-        char *           path;
-        char *           name;
-
-        uint8_t *        data;
-        size_t           len;
-
-        uint8_t          sha3[SHA3_256_HASH_LEN];
-
-        struct rnode *   parent;
-
-        size_t           chlen;
-        struct list_head children;
-
-        struct list_head subs;
-};
-
-struct child {
-        struct list_head next;
-
-        struct rnode * node;
-};
-
-struct rib {
-        struct rnode *   root;
-
-        struct btree *   idx;
-
-        pthread_rwlock_t lock;
-
-        struct bmp *     sids;
-
-        struct list_head subs;
-
-        pthread_rwlock_t s_lock;
-} rib;
-
-static void rnode_hash(struct rnode * node)
-{
-        struct sha3_ctx ctx;
-        struct list_head * p;
-
-        assert(node);
-        assert(node->path);
-        assert(node->name);
-
-        rhash_sha3_256_init(&ctx);
-
-        rhash_sha3_update(&ctx, (uint8_t *) node->path, strlen(node->path));
-
-        if (node->data != NULL)
-                rhash_sha3_update(&ctx, node->data, node->len);
-
-        list_for_each(p, &node->children) {
-                struct child * c = list_entry(p, struct child, next);
-                rhash_sha3_update(&ctx, c->node->sha3, SHA3_256_HASH_LEN);
-        }
-
-        rhash_sha3_final(&ctx, node->sha3);
-}
-
-static void branch_hash(struct rnode * node)
-{
-        assert(node);
-
-        do {
-                rnode_hash(node);
-                node = node->parent;
-        } while (node != NULL);
-}
-
-static struct revent * revent_dup(struct revent * ev)
-{
-        struct revent * re;
-
-        assert(ev);
-        assert(ev->path);
-
-        re = malloc(sizeof(*re));
-        if (re == NULL)
-                return NULL;
-
-        re->path = strdup(ev->path);
-        if (re->path == NULL) {
-                free(re);
-                return NULL;
-        }
-
-        re->flags = ev->flags;
-
-        list_head_init(&re->next);
-
-        return re;
-}
-
-/* defined below but needed here */
-static void rib_sub_del_rnode(struct rib_sub * sub,
-                              struct rnode *   node);
-
-static void rnode_notify_subs(struct rnode *  node,
-                              struct rnode *  ch,
-                              struct revent * ev)
-{
-        struct list_head * p;
-
-        assert(node);
-
-        list_for_each(p, &node->subs) {
-                struct rn_sub * s = list_entry(p, struct rn_sub, next);
-                if (s->flags & ev->flags) {
-                        struct revent * e = revent_dup(ev);
-                        if (e == NULL)
-                                continue;
-
-                        pthread_mutex_lock(&s->sub->lock);
-                        list_add_tail(&e->next, &s->sub->events);
-                        pthread_cond_signal(&s->sub->cond);
-                        pthread_mutex_unlock(&s->sub->lock);
-                }
-
-                if (ev->flags & RO_DELETE)
-                        rib_sub_del_rnode(s->sub, ch);
-        }
-}
-
-static int rnode_throw_event(struct rnode * node,
-                             int32_t        flags)
-{
-        struct revent * ev = malloc(sizeof(*ev));
-        struct rnode * rn = node;
-
-        assert(node);
-        assert(node->path);
-
-        if (ev == NULL)
-                return -ENOMEM;
-
-        list_head_init(&ev->next);
-
-        ev->path = strdup(node->path);
-        if (ev->path == NULL) {
-                free(ev);
-                return -ENOMEM;
-        }
-
-        ev->flags = flags;
-
-        do {
-                rnode_notify_subs(rn, node, ev);
-                rn = rn->parent;
-        } while (rn != NULL);
-
-        free(ev->path);
-        free(ev);
-
-        return 0;
-}
-
-static int rnode_add_child(struct rnode * node,
-                           struct rnode * child)
-{
-        struct child * c;
-        struct list_head * p;
-        struct child * n;
-
-        assert(node);
-        assert(child);
-
-        c = malloc(sizeof(*c));
-        if (c == NULL)
-                return -ENOMEM;
-
-        c->node = child;
-
-        list_for_each(p, &node->children) {
-                n = list_entry(p, struct child, next);
-                if (strcmp(n->node->name, child->name) > 0)
-                        break;
-        }
-
-        list_add_tail(&c->next, p);
-
-        ++node->chlen;
-
-        return 0;
-}
-
-static void rnode_remove_child(struct rnode * node,
-                               struct rnode * child)
-{
-        struct list_head * p;
-        struct list_head * h;
-
-        assert(node);
-        assert(child);
-
-        list_for_each_safe(p, h, &node->children) {
-                struct child * c = list_entry(p, struct child, next);
-                if (c->node == child) {
-                        list_del(&c->next);
-                        free(c);
-                        --node->chlen;
-                        return;
-                }
-        }
-}
-
-static struct rnode * rnode_create(struct rnode *  parent,
-                                   const char *    name)
-{
-        struct rnode * node;
-        char * parent_path;
-
-        uint32_t crc = 0;
-
-        assert(name);
-
-        node = malloc(sizeof(*node));
-        if (node == NULL)
-                return NULL;
-
-        list_head_init(&node->children);
-        list_head_init(&node->subs);
-
-        if (parent == NULL)
-                parent_path = "";
-        else
-                parent_path = parent->path;
-
-        node->path = malloc(strlen(parent_path)
-                            + strlen(RIB_PATH_DLR)
-                            + strlen(name)
-                            + 1);
-        if (node->path == NULL) {
-                free(node);
-                return NULL;
-        }
-
-        strcpy(node->path, parent_path);
-        node->name = node->path + strlen(parent_path);
-        if (parent != NULL) {
-                strcpy(node->name, RIB_PATH_DLR);
-                node->name += strlen(RIB_PATH_DLR);
-        }
-
-        strcpy(node->name, name);
-
-        if (parent != NULL) {
-                if (rnode_add_child(parent, node)) {
-                        free(node->path);
-                        free(node);
-                        return NULL;
-                }
-        }
-
-        node->data = NULL;
-        node->len = 0;
-
-        node->parent = parent;
-
-        node->chlen = 0;
-
-        crc32(&crc, node->path, strlen(node->path));
-        btree_insert(rib.idx, crc, node);
-
-        branch_hash(node);
-        rnode_throw_event(node, RO_CREATE);
-
-        return node;
-}
-
-static void destroy_rnode(struct rnode * node)
-{
-        struct list_head * p;
-        struct list_head * h;
-
-        uint32_t crc = 0;
-
-        assert(node);
-
-        if (node != rib.root) {
-                rnode_remove_child(node->parent, node);
-                branch_hash(node->parent);
-        }
-
-        if (node->parent != NULL)
-                rnode_throw_event(node->parent, RO_DELETE);
-
-        list_for_each_safe(p, h, &node->subs) {
-                struct rn_sub * s = list_entry(p, struct rn_sub, next);
-                list_del(&s->next);
-                free(s);
-        }
-
-        crc32(&crc, node->path, strlen(node->path));
-        btree_remove(rib.idx, crc);
-
-        free(node->path);
-        if (node->data != NULL)
-                free(node->data);
-
-        free(node);
-}
-
-static void destroy_rtree(struct rnode * node)
-{
-        struct list_head * p;
-        struct list_head * h;
-
-        assert(node);
-
-        list_for_each_safe(p, h, &node->children) {
-                struct child * c = list_entry(p, struct child, next);
-                destroy_rtree(c->node);
-        }
-
-        destroy_rnode(node);
-}
-
-static void rnode_update(struct rnode *  node,
-                         uint8_t *       data,
-                         size_t          len)
-{
-        assert(node);
-        assert(!(data == NULL && len != 0));
-        assert(!(data != NULL && len == 0));
-
-        if (node->data != NULL)
-                free(node->data);
-
-        node->data = data;
-        node->len = len;
-
-        rnode_throw_event(node, RO_MODIFY);
-
-        branch_hash(node);
-}
-
-static struct rn_sub * rnode_get_sub(struct rnode *   node,
-                                     struct rib_sub * sub)
-{
-        struct list_head * p;
-
-        list_for_each(p, &node->subs) {
-                struct rn_sub * r = list_entry(p, struct rn_sub, next);
-                if (r->sub == sub)
-                        return r;
-        }
-
-        return NULL;
-}
-
-static int rnode_add_sub(struct rnode *   node,
-                         struct rib_sub * sub,
-                         int32_t          flags)
-{
-        struct rn_sub * rs;
-
-        assert(node);
-        assert(sub);
-
-        rs = rnode_get_sub(node, sub);
-        if (rs != NULL)
-                return -EPERM;
-
-        rs = malloc(sizeof(*rs));
-        if (rs == NULL)
-                return -ENOMEM;
-
-        rs->sub = sub;
-        rs->flags = flags;
-
-        list_add(&rs->next, &node->subs);
-
-        return 0;
-}
-
-static int rnode_del_sub(struct rnode *   node,
-                         struct rib_sub * sub)
-{
-        struct rn_sub * rs;
-
-        assert(node);
-        assert(sub);
-
-        rs = rnode_get_sub(node, sub);
-        if (rs == NULL)
-                return 0;
-
-        list_del(&rs->next);
-        free(rs);
-
-        return 0;
-}
-
-static struct rnode * find_rnode_by_path(const char * path)
-{
-        uint32_t crc = 0;
-
-        if (strcmp(path, RIB_ROOT) == 0)
-                return rib.root;
-
-        crc32(&crc, path, strlen(path));
-
-        return (struct rnode *) btree_search(rib.idx, crc);
-}
-
-int rib_init(void)
-{
-        if (rib.root != NULL)
-                return -EPERM;
-
-        rib.idx = btree_create(RIB_BTREE_ORDER);
-        if (rib.idx == NULL) {
-                destroy_rtree(rib.root);
-                rib.root = NULL;
-                return -1;
-        }
-
-        rib.root = rnode_create(NULL, "");
-        if (rib.root == NULL)
-                return -ENOMEM;
-
-        rib.sids = bmp_create(32, 1);
-        if (rib.sids == NULL) {
-                btree_destroy(rib.idx);
-                destroy_rtree(rib.root);
-                rib.root = NULL;
-                return -1;
-        }
-
-        if (pthread_rwlock_init(&rib.lock, NULL)) {
-                bmp_destroy(rib.sids);
-                btree_destroy(rib.idx);
-                destroy_rtree(rib.root);
-                rib.root = NULL;
-                return -1;
-        }
-
-        if (pthread_rwlock_init(&rib.s_lock, NULL)) {
-                pthread_rwlock_destroy(&rib.lock);
-                bmp_destroy(rib.sids);
-                btree_destroy(rib.idx);
-                destroy_rtree(rib.root);
-                rib.root = NULL;
-                return -1;
-        }
-
-        list_head_init(&rib.subs);
-
-        assert(rib.root);
-
-        return 0;
-}
-
-void rib_fini(void)
-{
-        if (rib.root == NULL)
-                return;
-
-        bmp_destroy(rib.sids);
-
-        destroy_rtree(rib.root);
-        rib.root = NULL;
-
-        btree_destroy(rib.idx);
-
-        pthread_rwlock_destroy(&rib.lock);
-}
-
-int rib_add(const char * path,
-            const char * name)
-{
-        struct rnode * parent;
-        struct rnode * node;
-
-        if (name == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        parent = find_rnode_by_path(path);
-        if (parent == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -EPERM;
-        }
-
-        node = rnode_create(parent, name);
-        if (node == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -ENOMEM;
-        }
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return 0;
-}
-
-int rib_del(char * path)
-{
-        struct rnode * node;
-
-        if (path == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        node = find_rnode_by_path(path);
-        if (node == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -EINVAL;
-        }
-
-        destroy_rtree(node);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return 0;
-}
-
-ssize_t rib_read(const char * path,
-                 void *       data,
-                 size_t       len)
-{
-        struct rnode * node;
-        ssize_t        rlen;
-
-        if (path == NULL || data == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_rdlock(&rib.lock);
-
-        node = find_rnode_by_path(path);
-        if (node == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -EPERM;
-        }
-
-        if (len < node->len) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -EFBIG;
-        }
-
-        if (node->data == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return 0;
-        }
-
-        assert(node->len > 0);
-
-        memcpy(data, node->data, node->len);
-        rlen = node->len;
-
-        rnode_throw_event(node, RO_READ);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return rlen;
-}
-
-int rib_write(const char * path,
-              const void * data,
-              size_t       len)
-{
-        struct rnode * node;
-
-        uint8_t * cdata;
-
-        if (path == NULL || data == NULL || len == 0)
-                return -EINVAL;
-
-        cdata = malloc(len);
-        if (cdata == NULL)
-                return -ENOMEM;
-
-        memcpy(cdata, data, len);
-
-        pthread_rwlock_rdlock(&rib.lock);
-
-        node = find_rnode_by_path(path);
-        if (node == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                free(cdata);
-                return -1;
-        }
-
-        rnode_update(node, cdata, len);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return 0;
-}
-
-int rib_put(const char * path,
-            void *       data,
-            size_t       len)
-{
-        struct rnode * node;
-
-        if (path == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_rdlock(&rib.lock);
-
-        node = find_rnode_by_path(path);
-        if (node != NULL)
-                rnode_update(node, (uint8_t *) data, len);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return 0;
-}
-
-bool rib_has(const char * path)
-{
-        struct rnode * node;
-
-        if (path == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_rdlock(&rib.lock);
-
-        node = find_rnode_by_path(path);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return node != NULL;
-}
-
-ssize_t rib_children(const char * path,
-                     char ***     children)
-{
-        struct list_head * p;
-
-        struct rnode * node;
-
-        ssize_t i = 0;
-
-        if (path == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_rdlock(&rib.lock);
-
-        node = find_rnode_by_path(path);
-        if (node == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -EPERM;
-        }
-
-        if (children == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                assert((ssize_t) node->chlen >= 0);
-                return (ssize_t) node->chlen;
-        }
-
-        if (node->chlen == 0) {
-                pthread_rwlock_unlock(&rib.lock);
-                *children = NULL;
-                return 0;
-        }
-
-        *children = malloc(sizeof(**children) * node->chlen);
-        if (*children == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -ENOMEM;
-        }
-
-        list_for_each(p, &node->children) {
-                struct child * c = list_entry(p, struct child, next);
-                (*children)[i] = strdup(c->node->name);
-                if ((*children)[i] == NULL) {
-                        ssize_t j;
-                        pthread_rwlock_unlock(&rib.lock);
-                        for (j = 0; j < i; ++j)
-                                free((*children)[j]);
-                        free(*children);
-                        return -ENOMEM;
-                }
-                ++i;
-        }
-
-        assert(i > 0);
-        assert((size_t) i == node->chlen);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return i;
-}
-
-static struct rib_sub * rib_get_sub(uint32_t sid)
-{
-        struct list_head * p;
-        struct list_head * h;
-
-        list_for_each_safe(p, h, &rib.subs) {
-                struct rib_sub * r = list_entry(p, struct rib_sub, next);
-                if (r->sid == sid)
-                        return r;
-        }
-
-        return NULL;
-}
-
-static struct rib_sub * rib_sub_create(uint32_t sid)
-{
-        pthread_condattr_t cattr;
-        struct rib_sub * sub = malloc(sizeof(*sub));
-        if (sub == NULL)
-                return NULL;
-
-        if (pthread_condattr_init(&cattr)) {
-                free(sub);
-                return NULL;
-        }
-#ifndef __APPLE__
-        pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
-        if (pthread_cond_init(&sub->cond, &cattr)) {
-                free(sub);
-                return NULL;
-        }
-
-        if (pthread_mutex_init(&sub->lock, NULL)) {
-                pthread_cond_destroy(&sub->cond);
-                free(sub);
-                return NULL;
-        }
-
-        list_head_init(&sub->rnodes);
-        list_head_init(&sub->events);
-
-        sub->sid = sid;
-
-        return sub;
-}
-
-static void rib_sub_zero(struct rib_sub * sub)
-{
-        struct list_head * p;
-        struct list_head * h;
-
-        assert(sub);
-
-        list_for_each_safe(p, h, &sub->rnodes) {
-                struct rn_ptr * r = list_entry(p, struct rn_ptr, next);
-                assert(r->node);
-                rnode_del_sub(r->node, sub);
-                list_del(&r->next);
-                free(r);
-        }
-
-        list_for_each_safe(p, h, &sub->events) {
-                struct revent * r = list_entry(p, struct revent, next);
-                list_del(&r->next);
-                assert(r->path);
-                free(r->path);
-                free(r);
-        }
-}
-
-static struct rn_ptr * rib_sub_get_rn_ptr(struct rib_sub * sub,
-                                          struct rnode *   node)
-{
-        struct list_head * p;
-
-        list_for_each(p, &sub->rnodes) {
-                struct rn_ptr * r = list_entry(p, struct rn_ptr, next);
-                assert(r->node);
-                if (r->node == node)
-                        return r;
-        }
-
-        return NULL;
-}
-
-static int rib_sub_add_rnode(struct rib_sub * sub,
-                             struct rnode *   node)
-{
-        struct rn_ptr * rn;
-
-        assert(sub);
-        assert(node);
-
-        if (rib_sub_get_rn_ptr(sub, node) != NULL)
-                return 0;
-
-        rn = malloc(sizeof(*rn));
-        if (rn == NULL)
-                return -ENOMEM;
-
-        rn->node = node;
-
-        list_add(&rn->next, &sub->rnodes);
-
-        return 0;
-}
-
-static void rib_sub_del_rnode(struct rib_sub * sub,
-                              struct rnode *   node)
-{
-        struct rn_ptr * rn;
-
-        assert(sub);
-        assert(node);
-
-        rn = rib_sub_get_rn_ptr(sub, node);
-        if (rn == NULL)
-                return;
-
-        list_del(&rn->next);
-
-        free(rn);
-}
-
-static void rib_sub_destroy(struct rib_sub * sub)
-{
-        assert(sub);
-
-        rib_sub_zero(sub);
-
-        free(sub);
-}
-
-/* Event calls from rqueue.h. */
-ro_set_t * ro_set_create(void)
-{
-        ro_set_t * set;
-        struct rib_sub * sub;
-
-        set = malloc(sizeof(*set));
-        if (set == NULL)
-                return NULL;
-
-        pthread_rwlock_wrlock(&rib.s_lock);
-
-        set->sid = bmp_allocate(rib.sids);
-        if (!bmp_is_id_valid(rib.sids, set->sid)) {
-                pthread_rwlock_unlock(&rib.s_lock);
-                free(set);
-                return NULL;
-        }
-
-        pthread_rwlock_unlock(&rib.s_lock);
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        sub = rib_sub_create(set->sid);
-        if (sub == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                free(set);
-                return NULL;
-        }
-
-        list_add(&sub->next, &rib.subs);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return set;
-}
-
-void ro_set_destroy(ro_set_t * set)
-{
-        struct rib_sub * sub = NULL;
-
-        struct list_head * p;
-        struct list_head * h;
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        list_for_each_safe(p, h, &rib.subs) {
-                struct rib_sub * r = list_entry(p, struct rib_sub, next);
-                if (r->sid == set->sid) {
-                        sub = r;
-                        break;
-                }
-        }
-
-        if (sub != NULL)
-                rib_sub_destroy(sub);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        pthread_rwlock_wrlock(&rib.s_lock);
-
-        bmp_release(rib.sids, set->sid);
-
-        pthread_rwlock_unlock(&rib.s_lock);
-
-        free(set);
-}
-
-rqueue_t * rqueue_create(void)
-{
-        rqueue_t * rq = malloc(sizeof(*rq));
-        if (rq == NULL)
-                return NULL;
-
-        list_head_init(&rq->events);
-
-        return rq;
-}
-
-int rqueue_destroy(struct rqueue * rq)
-{
-        struct list_head * p;
-        struct list_head * h;
-
-        list_for_each_safe(p, h, &rq->events) {
-                struct revent * e = list_entry(p, struct revent, next);
-                list_del(&e->next);
-                free(e->path);
-                free(e);
-        }
-
-        free(rq);
-
-        return 0;
-}
-
-int ro_set_zero(ro_set_t * set)
-{
-        struct rib_sub * sub;
-
-        if (set == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        sub = rib_get_sub(set->sid);
-
-        assert(sub);
-
-        rib_sub_zero(sub);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return 0;
-}
-
-int ro_set_add(ro_set_t *   set,
-               const char * path,
-               int32_t      flags)
-{
-        struct rib_sub * sub;
-        struct rnode * node;
-
-        if (set == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        sub = rib_get_sub(set->sid);
-
-        assert(sub);
-
-        node = find_rnode_by_path(path);
-        if (node == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -1;
-        }
-
-        if (rnode_add_sub(node, sub, flags)) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -ENOMEM;
-        }
-
-        if (rib_sub_add_rnode(sub, node)) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -ENOMEM;
-        }
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return 0;
-}
-
-int ro_set_del(ro_set_t *   set,
-               const char * path)
-{
-        struct rib_sub * sub;
-        struct rnode * node;
-
-        if (set == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        sub = rib_get_sub(set->sid);
-
-        assert(sub);
-
-        node = find_rnode_by_path(path);
-        if (node == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -1;
-        }
-
-        rnode_del_sub(node, sub);
-
-        rib_sub_del_rnode(sub, node);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return 0;
-}
-
-int32_t rqueue_next(rqueue_t * rq,
-                    char *     path)
-{
-        struct revent * ev;
-        int32_t         ret;
-
-        if (list_is_empty(&rq->events))
-                return -1;
-
-        ev = list_first_entry(&rq->events, struct revent, next);
-        list_del(&ev->next);
-
-        strcpy(path, ev->path);
-        ret = ev->flags;
-
-        free(ev->path);
-        free(ev);
-
-        return ret;
-}
-
-int rib_event_wait(ro_set_t *              set,
-                   rqueue_t *              rq,
-                   const struct timespec * timeout)
-{
-        struct rib_sub * sub;
-        struct timespec abstime;
-        struct revent * ev;
-
-        ssize_t ret = 0;
-
-        if (set == NULL || rq == NULL)
-                return -EINVAL;
-
-        if (!list_is_empty(&rq->events))
-                return 0;
-
-        if (timeout != NULL) {
-                clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-                ts_add(&abstime, timeout, &abstime);
-        }
-
-        pthread_rwlock_rdlock(&rib.lock);
-
-        sub = rib_get_sub(set->sid);
-
-        assert(sub);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        pthread_mutex_lock(&sub->lock);
-
-        pthread_cleanup_push((void(*)(void *)) pthread_mutex_unlock,
-                             (void *) &sub->lock);
-
-        while (list_is_empty(&sub->events) && ret != -ETIMEDOUT) {
-                if (timeout != NULL)
-                        ret = -pthread_cond_timedwait(&sub->cond,
-                                                      &sub->lock,
-                                                      &abstime);
-                else
-                        ret = -pthread_cond_wait(&sub->cond, &sub->lock);
-        }
-
-        pthread_cleanup_pop(true);
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        if (ret != -ETIMEDOUT) {
-                ev = list_first_entry(&sub->events, struct revent, next);
-                list_move(&ev->next, &rq->events);
-        }
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        return ret;
-}
-
-/* Path name management. */
-char * rib_path_append(char *       path,
-                       const char * name)
-{
-        char * pos;
-
-        if (path == NULL || name == NULL || strstr(name, RIB_PATH_DLR))
-                return NULL;
-
-        pos = path + strlen(path);
-        memcpy(pos++, RIB_PATH_DLR, 1);
-        strcpy(pos, name);
-
-        return path;
-}
-
-char * rib_name_gen(void *       data,
-                    size_t       len)
-{
-        uint32_t crc = 0;
-        char * name;
-
-        if (data == NULL || len == 0)
-                return NULL;
-
-        name= malloc(GEN_NAME_SIZE + 1);
-        if (name == NULL)
-                return NULL;
-
-        crc32(&crc, data, len);
-
-        sprintf(name, "%08x", crc);
-
-        return name;
-}
-
-static ro_msg_t * rnode_pack(struct rnode * node,
-                             uint32_t       flags,
-                             bool           root)
-{
-        ro_msg_t * msg;
-
-        assert(node);
-
-        if (node->parent == NULL)
-                return NULL;
-
-        msg = malloc(sizeof(*msg));
-        if (msg == NULL)
-                return NULL;
-
-        ro_msg__init(msg);
-
-        msg->name = node->name;
-        if (root) {
-                assert(node->parent->path);
-                msg->parent = node->parent->path;
-        }
-
-        if ((root && (flags & PACK_HASH_ROOT)) ||
-            (flags & PACK_HASH_ALL)) {
-                msg->has_hash  = true;
-                msg->hash.data = node->sha3;
-                msg->hash.len  = SHA3_256_HASH_LEN;
-        }
-
-        if (node->data != NULL) {
-                msg->has_data  = true;
-                msg->data.data = node->data;
-                msg->data.len  = node->len;
-        }
-
-        if (node->chlen > 0) {
-                int n = 0;
-                struct list_head * p;
-                ro_msg_t ** msgs = malloc(sizeof(*msgs) * node->chlen);
-                if (msgs == NULL) {
-                        free(msg);
-                        return NULL;
-                }
-
-                msg->n_children = node->chlen;
-
-                list_for_each(p, &node->children) {
-                        struct child * c = list_entry(p, struct child, next);
-                        msgs[n] = rnode_pack(c->node, flags, false);
-                        if (msgs[n] == NULL) {
-                                int i;
-                                for (i = 0; i < n; ++i)
-                                        free(msgs[i]);
-                                free(msgs);
-                                free(msg);
-                                return NULL;
-                        }
-                        ++n;
-                }
-                msg->children = msgs;
-        }
-
-        return msg;
-}
-
-static void free_ro_msg(ro_msg_t * msg)
-{
-        size_t n = 0;
-        while (n < msg->n_children)
-                free_ro_msg(msg->children[n++]);
-
-        free(msg->children);
-        free(msg);
-}
-
-ssize_t rib_pack(const char *   path,
-                 uint8_t **     buf,
-                 uint32_t       flags)
-{
-        struct rnode * node;
-        ro_msg_t * msg;
-        ssize_t len;
-
-        if (path == NULL)
-                return -EINVAL;
-
-        pthread_rwlock_rdlock(&rib.lock);
-
-        node = find_rnode_by_path(path);
-        if (node == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -EPERM;
-        }
-
-        msg = rnode_pack(node, flags, true);
-        if (msg == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -EPERM;
-        }
-
-        len = ro_msg__get_packed_size(msg);
-        if (len == 0) {
-                pthread_rwlock_unlock(&rib.lock);
-                free_ro_msg(msg);
-                return 0;
-        }
-
-        *buf = malloc(len);
-        if (*buf == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                free_ro_msg(msg);
-                return -ENOMEM;
-        }
-
-        ro_msg__pack(msg, *buf);
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        free_ro_msg(msg);
-
-        return len;
-}
-
-static struct rnode * rnode_get_child(struct rnode * node,
-                                      const char *   name)
-{
-        struct list_head * p;
-
-        list_for_each(p, &node->children) {
-                struct child * c = list_entry(p, struct child, next);
-                if (strcmp(c->node->name, name) == 0)
-                        return c->node;
-        }
-
-        return NULL;
-}
-
-static int rnode_unpack(ro_msg_t *     msg,
-                        struct rnode * parent,
-                        uint32_t       flags)
-{
-        struct rnode * node;
-
-        size_t i;
-
-        assert(msg);
-        assert(parent);
-
-        node = rnode_get_child(parent, msg->name);
-        if (node == NULL) {
-                if (flags & UNPACK_CREATE)
-                        node = rnode_create(parent, msg->name);
-                else
-                        return -EPERM;
-        }
-
-        if (node == NULL)
-                return -ENOMEM;
-
-        /* Unpack in reverse order for faster insertion */
-        i = msg->n_children;
-        while (i > 0)
-                rnode_unpack(msg->children[--i], node, flags);
-
-        if (msg->has_data) {
-                uint8_t * data = malloc(msg->data.len);
-                if (data == NULL)
-                        return -ENOMEM;
-
-                memcpy(data, msg->data.data, msg->data.len);
-                rnode_update(node, data, msg->data.len);
-        }
-
-        return 0;
-}
-
-int rib_unpack(uint8_t * packed,
-               size_t    len,
-               uint32_t  flags)
-{
-        ro_msg_t * msg;
-        struct rnode * root;
-        int ret;
-
-        if (packed == NULL)
-                return -EINVAL;
-
-        msg = ro_msg__unpack(NULL, len, packed);
-        if (msg == NULL)
-                return -EPERM;
-
-        assert(msg->parent);
-
-        pthread_rwlock_wrlock(&rib.lock);
-
-        root = find_rnode_by_path(msg->parent);
-        if (root == NULL) {
-                pthread_rwlock_unlock(&rib.lock);
-                return -EPERM;
-        }
-
-        ret = rnode_unpack(msg, root, flags);
-
-        if (ret == 0 && msg->has_hash) {
-                root = rnode_get_child(root, msg->name);
-                if (memcmp(msg->hash.data, root->sha3, SHA3_256_HASH_LEN)) {
-                        ro_msg__free_unpacked(msg, NULL);
-                        pthread_rwlock_unlock(&rib.lock);
-                        return -EFAULT;
-                }
-        }
-
-        pthread_rwlock_unlock(&rib.lock);
-
-        ro_msg__free_unpacked(msg, NULL);
-
-        free(packed);
-
-        return ret;
-}
diff --git a/src/lib/ro.proto b/src/lib/ro.proto
deleted file mode 100644
index 8c547f14..00000000
--- a/src/lib/ro.proto
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2017
- *
- * RIB object message
- *
- *    Dimitri Staessens <dimitri.staessens@ugent.be>
- *    Sander Vrijders   <sander.vrijders@ugent.be>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-syntax = "proto2";
-
-message ro_msg {
-        required string name     = 1;
-        optional string parent   = 2;
-        optional bytes  data     = 3;
-        optional bytes  hash     = 4;
-        repeated ro_msg children = 5;
-}
\ No newline at end of file
diff --git a/src/lib/tests/CMakeLists.txt b/src/lib/tests/CMakeLists.txt
index 0223262a..a93bf321 100644
--- a/src/lib/tests/CMakeLists.txt
+++ b/src/lib/tests/CMakeLists.txt
@@ -14,7 +14,6 @@ create_test_sourcelist(${PARENT_DIR}_tests test_suite.c
   crc32_test.c
   hashtable_test.c
   md5_test.c
-  rib_test.c
   sha3_test.c
   time_utils_test.c
   ${TIMERWHEEL_TEST}
diff --git a/src/lib/tests/rib_test.c b/src/lib/tests/rib_test.c
deleted file mode 100644
index 6a2446b9..00000000
--- a/src/lib/tests/rib_test.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2017
- *
- * Test of the RIB
- *
- *    Dimitri Staessens <dimitri.staessens@ugent.be>
- *    Sander Vrijders   <sander.vrijders@ugent.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define _POSIX_C_SOURCE 199309L
-
-#include <ouroboros/time_utils.h>
-#include <ouroboros/rib.h>
-#include <ouroboros/rqueue.h>
-#include <ouroboros/errno.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define RIB_MAX_PATH_LEN 256
-
-int rib_test(int     argc,
-             char ** argv)
-{
-        uint64_t * address;
-
-        size_t addr_size = 8;
-        size_t addr_chk;
-
-        char * addr_name;
-
-        ro_set_t * set;
-        rqueue_t * rq;
-
-        int ret;
-
-        char tmp[RIB_MAX_PATH_LEN];
-
-        char ** kids;
-        ssize_t ch;
-
-        uint8_t * buf;
-        ssize_t   buf_len;
-
-        struct timespec t = {0, 100 * MILLION};
-
-        (void) argc;
-        (void) argv;
-
-        address = malloc(sizeof(*address));
-        if (address == NULL)
-                return -ENOMEM;
-
-        if (rib_init()) {
-                printf("Failed to initialize rib.\n");
-                return -1;
-        }
-
-        rib_fini();
-
-        if (rib_init()) {
-                printf("Failed to re-initialize rib.\n");
-                return -1;
-        }
-
-        if (rib_add(RIB_ROOT, "static_info")) {
-                printf("Failed to add element to rib.\n");
-                rib_fini();
-                return -1;
-        }
-
-        ch = rib_children("/static_info", &kids);
-        if (ch != 0) {
-                printf("Wrong number of children returned.\n");
-                rib_fini();
-                while (ch > 0)
-                        free(kids[--ch]);
-                free(kids);
-                return -1;
-        }
-
-        if (!rib_has("/static_info")) {
-                printf("Failed to find added element.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_add(RIB_ROOT, "dynamic_info")) {
-                printf("Failed to add element to rib.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_add("/static_info", "addr_size")) {
-                printf("Failed to add sub-element to rib.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_write("/static_info/addr_size",
-                    &addr_size, sizeof(addr_size))) {
-                printf("Failed to add sub-element to rib.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_add("/static_info", "addresses")) {
-                printf("Failed to add sub-element to rib.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (!rib_has("/static_info/addr_size")) {
-                printf("Failed to find added subelement.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_read("/static_info/addr_size",
-                     &addr_chk, sizeof(addr_chk))
-            != sizeof(addr_chk)) {
-                printf("Failed to read added element.\n");
-                rib_fini();
-                return -1;
-        }
-
-        ch = rib_children("/static_info", &kids);
-        if (ch != 2) {
-                printf("Wrong number of children returned.\n");
-                rib_fini();
-                return -1;
-        }
-
-        while (ch > 0)
-                free(kids[--ch]);
-        free(kids);
-
-        if (addr_chk != addr_size) {
-                printf("Failed to verify added element contents.\n");
-                rib_fini();
-                return -1;
-        }
-
-        addr_size = 16;
-
-        if (rib_write("/static_info/addr_size",
-                      &addr_size, sizeof(addr_size))) {
-                printf("Failed to write into added element.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_read("/static_info/addr_size",
-                     &addr_chk, sizeof(addr_chk))
-            != sizeof(addr_chk)) {
-                printf("Failed to verify added element update size.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (addr_chk != addr_size) {
-                printf("Failed to verify added element update size.\n");
-                rib_fini();
-                return -1;
-        }
-
-        addr_name = rib_name_gen(address, sizeof(*address));
-        if (addr_name == NULL) {
-                printf("Failed to create a name.\n");
-                rib_fini();
-                return -1;
-        }
-
-        strcpy(tmp, "/dynamic_info");
-
-        if (rib_add(tmp, addr_name)) {
-                free(addr_name);
-                printf("Failed to add address.\n");
-                rib_fini();
-                return -1;
-        }
-
-        rib_path_append(tmp, addr_name);
-
-        if (rib_put(tmp, address, sizeof(*address))) {
-                free(addr_name);
-                printf("Failed to add address.\n");
-                rib_fini();
-                return -1;
-        }
-
-        free(addr_name);
-
-        buf_len = rib_pack("/static_info", &buf, PACK_HASH_ALL);
-        if (buf_len < 0) {
-                printf("Failed pack.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_del("/static_info")) {
-                printf("Failed to delete.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_unpack(buf, buf_len, UNPACK_CREATE)) {
-                printf("Failed to unpack.\n");
-                rib_fini();
-                return -1;
-        }
-
-        if (!rib_has("/static_info")) {
-                printf("Failed to find unpacked element.\n");
-                rib_fini();
-                return -1;
-        }
-
-        ch = rib_children("/static_info", &kids);
-        if (ch != 2) {
-                printf("Wrong number of children returned.\n");
-                rib_fini();
-                return -1;
-        }
-
-        while (ch > 0)
-                free(kids[--ch]);
-        free(kids);
-
-        set = ro_set_create();
-        if (set == NULL) {
-                printf("Failed to create ro_set.\n");
-                rib_fini();
-                return -1;
-        }
-
-        rq = rqueue_create();
-        if (rq == NULL) {
-                printf("Failed to create rqueue.\n");
-                ro_set_destroy(set);
-                rib_fini();
-                return -1;
-        }
-
-        if (ro_set_add(set, "/static_info", RO_ALL_OPS)) {
-                printf("Failed to add to rqueue.\n");
-                ro_set_destroy(set);
-                rqueue_destroy(rq);
-                rib_fini();
-                return -1;
-        }
-
-        ret = rib_event_wait(set, rq, &t);
-        if (ret != -ETIMEDOUT) {
-                printf("Wait failed to timeout: %d.\n", ret);
-                ro_set_destroy(set);
-                rqueue_destroy(rq);
-                rib_fini();
-                return -1;
-        }
-
-        if (rib_del("/static_info")) {
-                printf("Failed to delete rib subtree.\n");
-                rib_fini();
-                return -1;
-        }
-
-        ro_set_destroy(set);
-
-        rqueue_destroy(rq);
-
-        rib_fini();
-
-        return 0;
-}
-- 
cgit v1.2.3