]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Merge remote-tracking branch 'origin/slurm-use' into cleanup
authorpcarana <pc.moreno2099@gmail.com>
Tue, 14 May 2019 20:27:13 +0000 (15:27 -0500)
committerpcarana <pc.moreno2099@gmail.com>
Tue, 14 May 2019 20:27:13 +0000 (15:27 -0500)
19 files changed:
1  2 
src/Makefile.am
src/address.c
src/clients.c
src/rtr/db/roa_table.c
src/rtr/db/roa_table.h
src/rtr/db/vrps.c
src/rtr/err_pdu.c
src/rtr/err_pdu.h
src/rtr/pdu.c
src/rtr/pdu_sender.c
src/rtr/pdu_serializer.c
src/rtr/rtr.c
src/slurm/slurm_db.c
src/slurm/slurm_db.h
src/slurm/slurm_loader.c
test/Makefile.am
test/impersonator.c
test/rtr/db/impersonator.c
test/rtr/db/roa_table_test.c

diff --cc src/Makefile.am
Simple merge
diff --cc src/address.c
Simple merge
diff --cc src/clients.c
index df5e6e1cd049605a616b2aace28a098c4ae8c468,b107f4ba893d2395201d5d50cb825dc52ccb2009..d3d4288c28cec136de84e3607665752e0a03b337
@@@ -3,13 -3,8 +3,9 @@@
  #include <pthread.h>
  #include "common.h"
  #include "log.h"
- #include "data_structure/uthash.h"
+ #include "data_structure/uthash_nonfatal.h"
 +#include "rtr/pdu.h"
  
- /*
-  * TODO uthash panics on memory allocations...
-  * http://troydhanson.github.io/uthash/userguide.html#_out_of_memory
-  */
  
  #define SADDR_IN(addr) ((struct sockaddr_in *) addr)
  #define SADDR_IN6(addr) ((struct sockaddr_in6 *) addr)
@@@ -71,10 -84,24 +67,16 @@@ clients_add(struct rtr_client *client
  
        rwlock_write_lock(&lock);
  
 -      HASH_FIND_INT(table, &fd, old_client);
 +      HASH_FIND_INT(table, &client->fd, old_client);
        if (old_client == NULL) {
+               errno = 0;
                HASH_ADD_INT(table, meat.fd, new_client);
+               if (errno) {
+                       rwlock_unlock(&lock);
+                       free(new_client);
+                       return -pr_errno(errno, "Couldn't create client");
+               }
                new_client = NULL;
 -      } else {
 -              /*
 -               * Isn't ready to handle distinct version on clients
 -               * reconnection, but for now there's no problem since only
 -               * RTRv0 is supported.
 -               */
 -              if (old_client->meat.rtr_version != rtr_version)
 -                      error = -ERTR_VERSION_MISMATCH;
        }
  
        rwlock_unlock(&lock);
index ab528e1173968c4c79c309be475e47abb0079955,8f444783751cdb130c9887688bf7eb23d11b0e59..eba04e96093bb50764e67cf9e8e721407405b707
@@@ -99,6 -103,67 +102,67 @@@ add_roa(struct roa_table *table, struc
        return 0;
  }
  
 -roa_table_remove_roa(struct roa_table *table, struct vrp *del)
+ static int
+ duplicate_roa(struct roa_table *dst, struct hashable_roa *new)
+ {
+       struct vrp vrp;
+       struct ipv4_prefix prefix4;
+       struct ipv6_prefix prefix6;
+       vrp = new->data;
+       switch (vrp.addr_fam) {
+       case AF_INET:
+               prefix4.addr = vrp.prefix.v4;
+               prefix4.len = vrp.prefix_length;
+               return rtrhandler_handle_roa_v4(dst, vrp.asn, &prefix4,
+                   vrp.max_prefix_length);
+       case AF_INET6:
+               prefix6.addr = vrp.prefix.v6;
+               prefix6.len = vrp.prefix_length;
+               return rtrhandler_handle_roa_v6(dst, vrp.asn, &prefix6,
+                   vrp.max_prefix_length);
+       }
+       return pr_crit("Unknown address family: %d", vrp.addr_fam);
+ }
+ static int
+ roa_table_merge(struct roa_table *dst, struct roa_table *src)
+ {
+       struct hashable_roa *node, *tmp, *found;
+       int error;
+       /** Must look for it due to the new mem allocation */
+       HASH_ITER(hh, src->roas, node, tmp) {
+               HASH_FIND(hh, dst->roas, &node->data, sizeof(node->data),
+                   found);
+               if (found != NULL)
+                       continue;
+               error = duplicate_roa(dst, node);
+               if (error)
+                       return error;
+       }
+       return 0;
+ }
+ int
+ rtrhandler_merge(struct roa_table *dst, struct roa_table *src)
+ {
+       return roa_table_merge(dst, src);
+ }
+ void
++roa_table_remove_roa(struct roa_table *table, struct vrp const *del)
+ {
+       struct hashable_roa *ptr;
+       HASH_FIND(hh, table->roas, del, sizeof(*del), ptr);
+       if (ptr != NULL) {
+               HASH_DELETE(hh, table->roas, ptr);
+               free(ptr);
+       }
+ }
  int
  rtrhandler_handle_roa_v4(struct roa_table *table, uint32_t asn,
      struct ipv4_prefix const *prefix4, uint8_t max_length)
index 8bd0da2d9bb2422fbc2d0fbbff19075caca51ade,86541d1f9a7b1aa1b22ce1d8469153a2a58b9222..94aa7eb7d0ee6557683c3260f0efcacc488dba3c
@@@ -10,6 -10,7 +10,7 @@@ struct roa_table *roa_table_create(void
  void roa_table_destroy(struct roa_table *);
  
  int roa_table_foreach_roa(struct roa_table *, vrp_foreach_cb, void *);
 -void roa_table_remove_roa(struct roa_table *, struct vrp *);
++void roa_table_remove_roa(struct roa_table *, struct vrp const *);
  
  int rtrhandler_reset(struct roa_table *);
  int rtrhandler_handle_roa_v4(struct roa_table *, uint32_t,
index b8292b95d4224d15f97fa160de534a228d87e7d1,3a0971394d3d684ae67a178ede32e38daaa26929..f84fec9a6765ad4736968fce83a39042051cedd6
@@@ -1,11 -1,15 +1,15 @@@
  #include "vrps.h"
  
  #include <pthread.h>
 -#include <stdbool.h>
+ #include <string.h>
 +#include <time.h>
  #include "clients.h"
  #include "common.h"
+ #include "validation_handler.h"
+ #include "data_structure/array_list.h"
  #include "object/tal.h"
  #include "rtr/db/roa_table.h"
+ #include "slurm/slurm_loader.h"
  
  /*
   * Storage of VRPs (term taken from RFC 6811 "Validated ROA Payload") and
@@@ -139,9 -163,9 +160,9 @@@ __perform_standalone_validation(struct 
   * calculated according to the new start.
   */
  static void
 -resize_deltas_db(struct deltas_db *db, struct delta *start)
 +resize_deltas_db(struct deltas_db *db, struct delta_group *start)
  {
-       struct delta_group *tmp;
 -      struct delta *tmp, *ptr;
++      struct delta_group *tmp, *ptr;
  
        db->len -= (start - db->array);
        while (db->len < db->capacity / 2)
                pr_enomem();
                return;
        }
 -      memcpy(tmp, start, db->len * sizeof(struct delta));
 +      memcpy(tmp, start, db->len * sizeof(struct delta_group));
+       /* Release memory allocated */
+       for (ptr = db->array; ptr < start; ptr++)
 -              deltas_destroy(ptr->deltas);
++              deltas_put(ptr->deltas);
        free(db->array);
        db->array = tmp;
  }
index 3be96ef064261ec43f530fb674e252f6665bdba8,c18b23028744a9c765cd7d498c1a0099dbbe9ba5..f6172b6d7c88aa9110917314bda0035477ea72e1
@@@ -4,93 -4,21 +4,99 @@@
  #include "pdu_sender.h"
  #include "log.h"
  
 +typedef enum rtr_error_code {
 +      ERR_PDU_CORRUPT_DATA                    = 0,
 +      ERR_PDU_INTERNAL_ERROR                  = 1,
 +      ERR_PDU_NO_DATA_AVAILABLE               = 2,
 +      ERR_PDU_INVALID_REQUEST                 = 3,
 +      ERR_PDU_UNSUP_PROTO_VERSION             = 4,
 +      ERR_PDU_UNSUP_PDU_TYPE                  = 5,
 +      ERR_PDU_WITHDRAWAL_UNKNOWN              = 6,
 +      ERR_PDU_DUPLICATE_ANNOUNCE              = 7,
 +      /* RTRv1 only, so not used yet. */
 +      ERR_PDU_UNEXPECTED_PROTO_VERSION        = 8,
 +} rtr_error_code_t;
 +
 +/*
 + * TODO (urgent) According to the function below, NO_DATA_AVAILABLE is not
 + * fatal. However, some callers of this function are terminating the connection
 + * regardless of that.
 + */
 +static int
 +err_pdu_send(int fd, rtr_error_code_t code, struct rtr_request const *request,
 +    char const *message_const)
 +{
 +      char *message;
 +
 +      /*
 +       * This function must always return error so callers can interrupt
 +       * themselves easily.
 +       * But note that not all callers should use this.
 +       * TODO (now) Prevent errors to errors
 +       * (It's harder than it seems, because request->pdu is sometimes NULL.)
 +       */
 +
 +      message = (message_const != NULL) ? strdup(message_const) : NULL;
 +      send_error_report_pdu(fd, code, request, message);
 +      free(message);
 +
 +      return -EINVAL;
 +}
 +
  int
 -err_pdu_send(int fd, uint8_t version, uint16_t code, void *err_pdu_header,
 +err_pdu_send_corrupt_data(int fd, struct rtr_request const *request,
      char const *message)
  {
 -      int error;
 -
 -      error = send_error_report_pdu(fd, version, code, err_pdu_header,
 -          message);
 -      if (err_pdu_is_fatal(code)) {
 -              pr_warn("Fatal error report PDU sent [code %u], closing socket.",
 -                  code);
 -              close(fd);
 -      }
 +      return err_pdu_send(fd, ERR_PDU_CORRUPT_DATA, request, message);
 +}
 +
 +/*
 + * Please note: If you're planning to send this error due to a memory
 + * allocation failure, you probably shouldn't; you'd likely only aggravate the
 + * problem.
 + */
 +int
 +err_pdu_send_internal_error(int fd)
 +{
 +      return err_pdu_send(fd, ERR_PDU_INTERNAL_ERROR, NULL, NULL);
 +}
 +
 +int
 +err_pdu_send_no_data_available(int fd)
 +{
 +      return err_pdu_send(fd, ERR_PDU_NO_DATA_AVAILABLE, NULL, NULL);
 +}
  
 -      return error;
 +int
 +err_pdu_send_invalid_request(int fd, struct rtr_request const *request,
 +    char const *message)
 +{
 +      return err_pdu_send(fd, ERR_PDU_INVALID_REQUEST, request, message);
 +}
 +
 +/* Caution: @header is supposed to be in serialized form. */
 +int
 +err_pdu_send_invalid_request_truncated(int fd, unsigned char *header,
 +    char const *message)
 +{
 +      struct rtr_request request = {
 +              .bytes = header,
 +              .bytes_len = RTRPDU_HEADER_LEN,
 +              .pdu = NULL,
 +      };
 +      return err_pdu_send_invalid_request(fd, &request, message);
 +}
 +
++int
++err_pdu_send_unsupported_proto_version(int fd)
++{
++      return err_pdu_send(fd, ERR_PDU_UNSUP_PROTO_VERSION, NULL, NULL);
++}
++
 +int
 +err_pdu_send_unsupported_pdu_type(int fd, struct rtr_request const *request)
 +{
 +      return err_pdu_send(fd, ERR_PDU_UNSUP_PDU_TYPE, request, NULL);
  }
  
  bool
index 4082b6c6762d7eaa623ef147b85744395e072155,1d06c7a090289ec7fd5863498b6de19705a6a770..be6c00b63b160f263b3ffa32b2cc8dbab52ec889
@@@ -4,21 -4,19 +4,22 @@@
  #include <stdbool.h>
  #include <stdint.h>
  
 -#define ERR_PDU_CORRUPT_DATA                          0
 -#define ERR_PDU_INTERNAL_ERROR                                1
 -#define ERR_PDU_NO_DATA_AVAILABLE                     2
 -#define ERR_PDU_INVALID_REQUEST                               3
 -#define ERR_PDU_UNSUP_PROTO_VERSION                   4
 -#define ERR_PDU_UNSUP_PDU_TYPE                                5
 -#define ERR_PDU_WITHDRAWAL_UNKNOWN                    6
 -#define ERR_PDU_DUPLICATE_ANNOUNCE                    7
 -#define ERR_PDU_UNEXPECTED_PROTO_VERSION              8
 +#include "rtr/pdu.h"
  
 +/*
 + * Wrappers for err_pdu_send().
 + * Mainly, this is for the sake of making it easier to see whether the error is
 + * supposed to contain a message and/or the original PDU or not.
 + */
 +int err_pdu_send_corrupt_data(int, struct rtr_request const *, char const *);
 +int err_pdu_send_internal_error(int);
 +int err_pdu_send_no_data_available(int);
 +int err_pdu_send_invalid_request(int, struct rtr_request const *, char const *);
 +int err_pdu_send_invalid_request_truncated(int, unsigned char *, char const *);
++int err_pdu_send_unsupported_proto_version(int);
 +int err_pdu_send_unsupported_pdu_type(int, struct rtr_request const *);
  
 -int err_pdu_send(int, uint8_t, uint16_t, void *, char const *);
  bool err_pdu_is_fatal(uint16_t);
 -void err_pdu_log(uint16_t, char *);
 +char const *err_pdu_to_string(uint16_t);
  
  #endif /* SRC_RTR_ERR_PDU_H_ */
diff --cc src/rtr/pdu.c
index 67878018a705557132414b1be03fc7c7e5d1ace5,da216c3b02f6f35b32b8f04a7d87ba0057842def..1f52d8da8b8dc10decb55a75a3ed8ad4ca9cca3f
  
  #include "common.h"
  #include "log.h"
 +#include "rtr/err_pdu.h"
  #include "rtr/pdu_handler.h"
  
 -static int    pdu_header_from_stream(int, struct pdu_header *);
 -static int    serial_notify_from_stream(struct pdu_header *, int, void *);
 -static int    serial_query_from_stream(struct pdu_header *, int, void *);
 -static int    reset_query_from_stream(struct pdu_header *, int, void *);
 -static int    cache_response_from_stream(struct pdu_header *, int, void *);
 -static int    ipv4_prefix_from_stream(struct pdu_header *, int, void *);
 -static int    ipv6_prefix_from_stream(struct pdu_header *, int, void *);
 -static int    end_of_data_from_stream(struct pdu_header *, int, void *);
 -static int    cache_reset_from_stream(struct pdu_header *, int, void *);
 -static int    router_key_from_stream(struct pdu_header *, int, void *);
 -static int    error_report_from_stream(struct pdu_header *, int, void *);
 -static void   error_report_destroy(void *);
 +static int
 +pdu_header_from_reader(struct pdu_reader *reader, struct pdu_header *header)
 +{
 +      return read_int8(reader, &header->protocol_version)
 +          || read_int8(reader, &header->pdu_type)
 +          || read_int16(reader, &header->m.session_id)
 +          || read_int32(reader, &header->length);
 +}
  
  int
 -pdu_load(int fd, void **pdu, struct pdu_metadata const **metadata,
 -    uint8_t *rtr_version)
 +pdu_load(int fd, struct rtr_request *request,
 +    struct pdu_metadata const **metadata)
  {
 +      unsigned char hdr_bytes[RTRPDU_HEADER_LEN];
 +      struct pdu_reader reader;
        struct pdu_header header;
        struct pdu_metadata const *meta;
 -      int err;
 +      int error;
 +
 +      /* Read the header into its buffer. */
 +      /*
 +       * TODO (urgent) If the first read yields no bytes, the connection was
 +       * terminated. We're not ending gracefully in those cases.
 +       */
 +      error = pdu_reader_init(&reader, fd, hdr_bytes, RTRPDU_HEADER_LEN);
 +      if (error)
 +              /* Communication interrupted; omit error response */
 +              return error;
 +      error = pdu_header_from_reader(&reader, &header);
 +      if (error)
 +              /* No error response because the PDU might have been an error */
 +              return error;
  
 -      err = pdu_header_from_stream(fd, &header);
 -      if (err)
 -              return err;
 +      /*
-        * RTRv1 expects us to respond RTRv1 messages with RTRv0 messages,
-        * and future protocols will probably do the same.
-        * So don't validate the protocol version.
++       * For now, only RTRv0 is supported
 +       */
++      if (header.protocol_version != RTR_V0)
++              return err_pdu_send_unsupported_proto_version(fd);
 +
 +      if (header.length < RTRPDU_HEADER_LEN)
 +              return err_pdu_send_invalid_request_truncated(fd, hdr_bytes,
 +                  "PDU is too small. (< 8 bytes)");
 +
 +      /*
 +       * Error messages can be quite large.
 +       * But they're probably not legitimate, so drop 'em.
 +       * 512 is like a 5-paragraph error message, so it's probably enough.
 +       * (Warning: I'm assuming english tho.)
 +       */
 +      if (header.length > 512) {
 +              pr_warn("Got an extremely large PDU (%u bytes). WTF?",
 +                  header.length);
 +              return err_pdu_send_invalid_request_truncated(fd, hdr_bytes,
 +                  "PDU is too large. (> 512 bytes)");
 +      }
  
 +      /* Read the rest of the PDU into its buffer. */
 +      request->bytes_len = header.length;
 +      request->bytes = malloc(header.length);
 +      if (request->bytes == NULL)
 +              /* No error report PDU on allocation failures. */
 +              return pr_enomem();
 +
 +      memcpy(request->bytes, hdr_bytes, RTRPDU_HEADER_LEN);
 +      error = pdu_reader_init(&reader, fd,
 +          request->bytes + RTRPDU_HEADER_LEN,
 +          header.length - RTRPDU_HEADER_LEN);
 +      if (error)
 +              /* Communication interrupted; no error PDU. */
 +              goto revert_bytes;
 +
 +      /* Deserialize the PDU. */
        meta = pdu_get_metadata(header.pdu_type);
 -      if (!meta)
 -              return -ENOENT; /* TODO try to skip it anyway? */
 +      if (!meta) {
 +              error = err_pdu_send_unsupported_pdu_type(fd, request);
 +              goto revert_bytes;
 +      }
  
 -      *pdu = malloc(meta->length);
 -      if (*pdu == NULL)
 -              return -ENOMEM;
 +      request->pdu = malloc(meta->length);
 +      if (request->pdu == NULL) {
 +              error = pr_enomem();
 +              goto revert_bytes;
 +      }
  
 -      err = meta->from_stream(&header, fd, *pdu);
 -      if (err) {
 -              free(*pdu);
 -              return err;
 +      error = meta->from_stream(&header, &reader, request->pdu);
 +      if (error) {
 +              err_pdu_send_internal_error(fd);
 +              goto revert_pdu;
        }
 -      *rtr_version = header.protocol_version;
  
 -      if (metadata)
 -              *metadata = meta;
 +      /* Happy path. */
 +      *metadata = meta;
        return 0;
 -}
  
 -static int
 -pdu_header_from_stream(int fd, struct pdu_header *header)
 -{
 -      /* If the first read yields no bytes, the connection was terminated. */
 -      return read_int8(fd, &header->protocol_version)
 -          || read_int8(fd, &header->pdu_type)
 -          || read_int16(fd, &header->m.session_id)
 -          || read_int32(fd, &header->length);
 +revert_pdu:
 +      free(request->pdu);
 +revert_bytes:
 +      free(request->bytes);
 +      return error;
  }
  
  static int
index 98eedfffb44104ddf124d9b6c0079080b86a0e6c,9b1fb2cacbf55d1009cb512b8856a54675743f96..5a1d97ac08ca41c3d791fbb5c9d0dee8badaec31
@@@ -37,7 -52,36 +37,7 @@@ set_header_values(struct pdu_header *he
        header->m.reserved = reserved;
  }
  
- /* TODO Include Router Key PDU serials */
 -static uint32_t
 -length_serial_notify_pdu(struct serial_notify_pdu *pdu)
 -{
 -      return HEADER_LENGTH + sizeof(pdu->serial_number);
 -}
 -
 -static uint32_t
 -length_ipvx_prefix_pdu(bool isv4)
 -{
 -      return HEADER_LENGTH +
 -          (isv4 ? IPV4_PREFIX_LENGTH : IPV6_PREFIX_LENGTH);
 -}
 -
 -static uint32_t
 -length_end_of_data_pdu(struct end_of_data_pdu *pdu)
 -{
 -      uint32_t len;
 -
 -      len = HEADER_LENGTH;
 -      len += sizeof(pdu->serial_number);
 -      if (pdu->header.protocol_version == RTR_V1) {
 -              len += sizeof(pdu->refresh_interval);
 -              len += sizeof(pdu->retry_interval);
 -              len += sizeof(pdu->expire_interval);
 -      }
 -
 -      return len;
 -}
 -
+ /* TODO (next iteration) Include Router Key PDU serials */
  /**
   * static uint32_t
   * length_router_key_pdu(struct router_key_pdu *pdu)
   * }
   */
  
- /*
-  * TODO Needs some testing, this is just a beta version
-  */
- static int
- send_large_response(int fd, struct data_buffer *buffer)
 -static uint32_t
 -length_error_report_pdu(struct error_report_pdu *pdu)
--{
-       unsigned char *tmp_buffer, *ptr;
-       size_t buf_size, pending;
-       int written;
-       buf_size = buffer->capacity;
-       pending = buffer->len;
-       ptr = buffer->data;
-       while (pending > 0) {
-               tmp_buffer = calloc(pending, sizeof(unsigned char));
-               if (tmp_buffer == NULL)
-                       return pr_enomem();
-               memcpy(tmp_buffer, ptr, buf_size);
-               written = write(fd, tmp_buffer, buf_size);
-               free(tmp_buffer);
-               if (written < 0)
-                       return pr_err("Error sending response");
-               pending -= buf_size;
-               ptr += buf_size;
-               buf_size = pending > buffer->capacity ? buffer->capacity :
-                   pending;
-       }
-       return 0;
 -      return HEADER_LENGTH +
 -          pdu->error_pdu_length + sizeof(pdu->error_pdu_length) +
 -          pdu->error_message_length + sizeof(pdu->error_message_length);
--}
--
  static int
  send_response(int fd, unsigned char *data, size_t data_len)
  {
Simple merge
diff --cc src/rtr/rtr.c
index cadc2a0428f04b6dd9a6f6de0bd10ae2d7ff95c2,9ad8dbd8a98dc3b539682b35f1f597e4f4cfc66d..cf12812dfb0a794da29ab79d8048e87bc8dc4ac7
  #include "rtr/err_pdu.h"
  #include "rtr/pdu.h"
  
- /* TODO (urgent) this needs to be atomic */
- volatile bool loop;
 -/* TODO (next iteration) Support both RTR v0 and v1 */
 -#define RTR_VERSION_SUPPORTED RTR_V0
 -
+ struct sigaction act;
  
 -/*
 - * Arguments that the server socket thread will send to the client
 - * socket threads whenever it creates them.
 - */
 -struct thread_param {
 -      int client_fd;
 -      struct sockaddr_storage client_addr;
 -};
 -
  struct thread_node {
        pthread_t tid;
 -      struct thread_param params;
 +      struct rtr_client client;
        SLIST_ENTRY(thread_node) next;
  };
  
@@@ -173,25 -172,47 +172,25 @@@ end_client(struct rtr_client *client
   * The client socket threads' entry routine.
   */
  static void *
 -client_thread_cb(void *param_void)
 +client_thread_cb(void *arg)
  {
 -      struct thread_param *param = param_void;
 +      struct rtr_client *client = arg;
        struct pdu_metadata const *meta;
 -      void *pdu;
 -      int err;
 -      uint8_t rtr_version;
 +      struct rtr_request request;
 +      int error;
  
-       while (loop) { /* For each PDU... */
+       while (true) { /* For each PDU... */
 -              err = pdu_load(param->client_fd, &pdu, &meta, &rtr_version);
 -              if (err)
 -                      return end_client(param->client_fd, NULL, NULL);
 -
 -              /* Protocol Version Negotiation */
 -              if (rtr_version != RTR_VERSION_SUPPORTED) {
 -                      err_pdu_send(param->client_fd, RTR_VERSION_SUPPORTED,
 -                          ERR_PDU_UNSUP_PROTO_VERSION,
 -                          (struct pdu_header *) pdu, NULL);
 -                      return end_client(param->client_fd, meta, pdu);
 -              }
 -              /* RTR Version ready, now update client */
 -              err = clients_add(param->client_fd, &param->client_addr,
 -                  rtr_version);
 -              if (err) {
 -                      if (err == -ERTR_VERSION_MISMATCH) {
 -                              err_pdu_send(param->client_fd, rtr_version,
 -                                  (rtr_version == RTR_V0
 -                                  ? ERR_PDU_UNSUP_PROTO_VERSION
 -                                  : ERR_PDU_UNEXPECTED_PROTO_VERSION),
 -                                  (struct pdu_header *) pdu, NULL);
 -                      }
 -                      return end_client(param->client_fd, meta, pdu);
 -              }
 +              error = pdu_load(client->fd, &request, &meta);
 +              if (error)
 +                      break;
  
 -              err = meta->handle(param->client_fd, pdu);
 -              meta->destructor(pdu);
 -              if (err)
 -                      return end_client(param->client_fd, NULL, NULL);
 +              error = meta->handle(client->fd, &request);
 +              clean_request(&request, meta);
 +              if (error)
 +                      break;
        }
  
 -      return NULL; /* Unreachable. */
 +      return end_client(client);
  }
  
  /*
@@@ -244,27 -256,13 +243,27 @@@ handle_client_connections(int server_fd
                        continue;
                }
  
 -              new_thread->params.client_fd = client_fd;
 -              new_thread->params.client_addr = client_addr;
 +              new_thread->client.fd = client_fd;
 +              new_thread->client.addr = client_addr;
 +
 +              error = clients_add(&new_thread->client);
 +              if (error) {
 +                      /*
 +                       * Presently, clients_add() can only fail due to alloc
 +                       * failure. No error report PDU.
 +                       */
 +                      free(new_thread);
 +                      close(client_fd);
 +                      continue;
 +              }
  
 -              errno = pthread_create(&new_thread->tid, NULL,
 -                  client_thread_cb, &new_thread->params);
 -              if (errno) {
 -                      pr_errno(errno, "Could not spawn the client's thread");
 +              error = pthread_create(&new_thread->tid, NULL,
 +                  client_thread_cb, &new_thread->client);
-               if (error != EAGAIN)
++              if (error && error != EAGAIN)
 +                      err_pdu_send_internal_error(client_fd);
 +              if (error) {
 +                      pr_errno(error, "Could not spawn the client's thread");
 +                      clients_forget(client_fd);
                        free(new_thread);
                        close(client_fd);
                        continue;
index ea7749a2da8f1221778a85a198e1371c6d381205,827743b969e5e34f29556f928f45b32296b20dd9..837224effcd4b85336682bf7f29e8a188a5ec434
@@@ -149,71 -137,67 +137,67 @@@ bgpsec_equal(struct slurm_bgpsec *left
        return equal;
  }
  
- LOCATE_FUNCS(prefix_filter, struct slurm_prefix, struct al_filter_prefix,
-     prefix_equal, true)
- LOCATE_FUNCS(bgpsec_filter, struct slurm_bgpsec, struct al_filter_bgpsec,
-     bgpsec_equal, true)
- LOCATE_FUNCS(prefix_assertion, struct slurm_prefix, struct al_assertion_prefix,
-     prefix_equal, false)
- LOCATE_FUNCS(bgpsec_assertion, struct slurm_bgpsec, struct al_assertion_bgpsec,
-     bgpsec_equal, false)
- /*
-  * Try to persist the @prefix filter, if it already exists or is covered
-  * by another filter, then the error -EEXIST is returned; otherwise, returns
-  * the result of persisting the @prefix.
-  */
- int
- slurm_db_add_prefix_filter(struct slurm_prefix *prefix)
- {
-       if (prefix_filter_exists(&array_lists_db.filter_pfx_al, prefix))
-               return -EEXIST;
-       return al_filter_prefix_add(&array_lists_db.filter_pfx_al, prefix);
- }
+ #define ADD_FUNCS(name, type, list_name, db_list, equal_cb, filter)   \
+       static type *                                                   \
+       name##_locate(type *obj)                                        \
+       {                                                               \
+               type *cursor;                                           \
+                                                                       \
+               ARRAYLIST_FOREACH(db_list, cursor)                      \
+                       if (equal_cb(cursor, obj, filter))              \
+                               return cursor;                          \
+                                                                       \
+               return NULL;                                            \
+       }                                                               \
+                                                                       \
+       static bool                                                     \
+       name##_exists(type *obj)                                        \
+       {                                                               \
+               return name##_locate(obj) != NULL;                      \
+       }                                                               \
+                                                                       \
+       int                                                             \
+       slurm_db_add_##name(type *elem) {                               \
+               if (name##_exists(elem))                                \
+                       return -EEXIST;                                 \
+               return list_name##_add(db_list, elem);                  \
+       }
  
- /*
-  * Try to persist the @prefix assertion, if it already exists, then the error
-  * -EEXIST is returned; otherwise, returns the result of persisting the
-  * @prefix.
-  */
- int
- slurm_db_add_prefix_assertion(struct slurm_prefix *prefix)
+ ADD_FUNCS(prefix_filter, struct slurm_prefix, al_filter_prefix,
+     &array_lists_db.filter_pfx_al, prefix_equal, true)
+ ADD_FUNCS(bgpsec_filter, struct slurm_bgpsec, al_filter_bgpsec,
+     &array_lists_db.filter_bgps_al, bgpsec_equal, true)
+ ADD_FUNCS(prefix_assertion, struct slurm_prefix, al_assertion_prefix,
+     &array_lists_db.assertion_pfx_al, prefix_equal, false)
+ ADD_FUNCS(bgpsec_assertion, struct slurm_bgpsec, al_assertion_bgpsec,
+     &array_lists_db.assertion_bgps_al, bgpsec_equal, false)
+ bool
 -slurm_db_vrp_is_filtered(struct vrp *vrp)
++slurm_db_vrp_is_filtered(struct vrp const *vrp)
  {
-       if (prefix_assertion_exists(&array_lists_db.assertion_pfx_al, prefix))
-               return -EEXIST;
-       return al_assertion_prefix_add(&array_lists_db.assertion_pfx_al,
-           prefix);
- }
+       struct slurm_prefix slurm_prefix;
  
- /*
-  * Try to persist the @bgpsec filter, if it already exists or is covered
-  * by another filter, then the error -EEXIST is returned; otherwise, returns
-  * the result of persisting the @bgpsec.
-  */
- int
- slurm_db_add_bgpsec_filter(struct slurm_bgpsec *bgpsec)
- {
-       if (bgpsec_filter_exists(&array_lists_db.filter_bgps_al, bgpsec))
-               return -EEXIST;
+       slurm_prefix.data_flag = SLURM_COM_FLAG_ASN | SLURM_PFX_FLAG_PREFIX
+           | SLURM_PFX_FLAG_MAX_LENGTH;
+       slurm_prefix.vrp = *vrp;
+       slurm_prefix.comment = NULL;
  
-       return al_filter_bgpsec_add(&array_lists_db.filter_bgps_al, bgpsec);
+       return prefix_filter_exists(&slurm_prefix);
  }
  
- /*
-  * Try to persist the @bgpsec assertion, if it already exists, then the error
-  * -EEXIST is returned; otherwise, returns the result of persisting the
-  * @bgpsec.
-  */
  int
- slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *bgpsec)
+ slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb cb, void *arg)
  {
-       if (bgpsec_assertion_exists(&array_lists_db.assertion_bgps_al, bgpsec))
-               return -EEXIST;
+       struct slurm_prefix *cursor;
+       int error;
  
-       return al_assertion_bgpsec_add(&array_lists_db.assertion_bgps_al,
-           bgpsec);
+       ARRAYLIST_FOREACH(&array_lists_db.assertion_pfx_al, cursor) {
+               error = cb(cursor, arg);
+               if (error)
+                       return error;
+       }
+       return 0;
  }
  
  static void
index 2e090a56dd833bed9b4952e3521b5dd0f3b61d3c,b6f5139f5f8e4df3034fbb2ff4f7afb8850c4006..52d1974758a25dd32dc8436fcf1cf6c81e5790d0
@@@ -27,6 -30,9 +30,9 @@@ int slurm_db_add_prefix_assertion(struc
  int slurm_db_add_bgpsec_filter(struct slurm_bgpsec *);
  int slurm_db_add_bgpsec_assertion(struct slurm_bgpsec *);
  
 -bool slurm_db_vrp_is_filtered(struct vrp *vrp);
++bool slurm_db_vrp_is_filtered(struct vrp const *vrp);
+ int slurm_db_foreach_assertion_prefix(assertion_pfx_foreach_cb, void *);
  void slurm_db_cleanup(void);
  
- #endif /* SRC_SLURM_DB_H_ */
+ #endif /* SRC_SLURM_SLURM_DB_H_ */
index 0000000000000000000000000000000000000000,fe9dbe5a07d3797a3096c4bd9d1cb7ac538d3d15..69a70807a1714752e82f4a3b33239d2bfc5aa029
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,107 +1,107 @@@
 -slurm_pfx_filters_apply(struct vrp *vrp, void *arg)
+ #include "slurm_loader.h"
+ #include <stdlib.h>
+ #include <stdbool.h>
+ #include "log.h"
+ #include "config.h"
+ #include "common.h"
+ #include "slurm/slurm_db.h"
+ #include "slurm/slurm_parser.h"
+ #define SLURM_FILE_EXTENSION  ".slurm"
+ static int
+ slurm_load(bool *loaded)
+ {
+       /* Optional configuration */
+       *loaded = false;
+       if (config_get_slurm_location() == NULL)
+               return 0;
+       *loaded = true;
+       slurm_db_init();
+       return process_dir_files(config_get_slurm_location(),
+           SLURM_FILE_EXTENSION, slurm_parse, NULL);
+ }
+ static void
+ slurm_cleanup(void)
+ {
+       /* Only if the SLURM was configured */
+       if (config_get_slurm_location() != NULL)
+               slurm_db_cleanup();
+ }
+ static int
++slurm_pfx_filters_apply(struct vrp const *vrp, void *arg)
+ {
+       struct roa_table *table = arg;
+       if (slurm_db_vrp_is_filtered(vrp))
+               roa_table_remove_roa(table, vrp);
+       return 0;
+ }
+ static int
+ slurm_pfx_assertions_add(struct slurm_prefix *prefix, void *arg)
+ {
+       struct roa_table *table = arg;
+       struct ipv4_prefix prefix4;
+       struct ipv6_prefix prefix6;
+       struct vrp vrp;
+       vrp = prefix->vrp;
+       if ((prefix->data_flag & SLURM_PFX_FLAG_MAX_LENGTH) == 0)
+               vrp.max_prefix_length = vrp.prefix_length;
+       if (vrp.addr_fam == AF_INET) {
+               prefix4.addr = vrp.prefix.v4;
+               prefix4.len = vrp.prefix_length;
+               return rtrhandler_handle_roa_v4(table, vrp.asn, &prefix4,
+                   vrp.max_prefix_length);
+       }
+       if (vrp.addr_fam == AF_INET6) {
+               prefix6.addr = vrp.prefix.v6;
+               prefix6.len = vrp.prefix_length;
+               return rtrhandler_handle_roa_v6(table, vrp.asn, &prefix6,
+                   vrp.max_prefix_length);
+       }
+       return -pr_crit("Unkown addr family type");
+ }
+ static int
+ slurm_pfx_assertions_apply(struct roa_table *base)
+ {
+       return slurm_db_foreach_assertion_prefix(slurm_pfx_assertions_add,
+           base);
+ }
+ int
+ slurm_apply(struct roa_table *base)
+ {
+       bool loaded;
+       int error;
+       loaded = false;
+       error = slurm_load(&loaded);
+       if (error)
+               goto cleanup;
+       if (!loaded)
+               return 0;
+       error = roa_table_foreach_roa(base, slurm_pfx_filters_apply, base);
+       if (error)
+               goto cleanup;
+       error = slurm_pfx_assertions_apply(base);
+       /** TODO (next iteration) Apply BGPsec filters and assertions */
+ cleanup:
+       slurm_cleanup();
+       return error;
+ }
index 2873d3ee213d30e6fa07049195b2e3fb7d4b9720,6cb82fb6377739ab7e1117969a26b7d99a5785b1..29eb694cd53a434f902c5254056a3c410e15ec07
@@@ -20,6 -20,6 +20,15 @@@ MY_LDADD = ${CHECK_LIBS
  BASIC_MODULES  = ../src/log.c ../src/log.h
  BASIC_MODULES += impersonator.c
  
++SLURM_SOURCES  = ../src/address.c ../src/address.h
++SLURM_SOURCES += ../src/json_parser.c ../src/json_parser.h
++SLURM_SOURCES += ../src/crypto/base64.c ../src/crypto/base64.h
++SLURM_SOURCES += ../src/slurm/slurm_db.c ../src/slurm/slurm_db.h
++SLURM_SOURCES += ../src/slurm/slurm_loader.c
++SLURM_SOURCES += ../src/slurm/slurm_loader.h
++SLURM_SOURCES += ../src/slurm/slurm_parser.c
++SLURM_SOURCES += ../src/slurm/slurm_parser.h
++
  check_PROGRAMS  = address.test
  check_PROGRAMS += clients.test
  check_PROGRAMS += line_file.test
@@@ -50,17 -48,6 +59,18 @@@ line_file_test_SOURCES += ../src/line_f
  line_file_test_SOURCES += line_file_test.c
  line_file_test_LDADD = ${MY_LDADD}
  
- pdu_handler_test_LDADD = ${MY_LDADD}
 +pdu_handler_test_SOURCES  = ${BASIC_MODULES}
++pdu_handler_test_SOURCES += ${SLURM_SOURCES}
 +pdu_handler_test_SOURCES += ../src/common.c
 +pdu_handler_test_SOURCES += ../src/rtr/pdu_handler.c
 +pdu_handler_test_SOURCES += ../src/rtr/err_pdu.c
 +pdu_handler_test_SOURCES += ../src/rtr/db/delta.c
 +pdu_handler_test_SOURCES += ../src/rtr/db/roa_table.c
 +pdu_handler_test_SOURCES += ../src/rtr/db/vrps.c
 +pdu_handler_test_SOURCES += rtr/db/impersonator.c
 +pdu_handler_test_SOURCES += rtr/pdu_handler_test.c
++pdu_handler_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS}
 +
  roa_table_test_SOURCES  = ${BASIC_MODULES}
  roa_table_test_SOURCES += ../src/rtr/db/delta.c
  roa_table_test_SOURCES += ../src/rtr/db/roa_table.c
@@@ -87,15 -74,6 +97,16 @@@ vcard_test_SOURCES  = ${BASIC_MODULES
  vcard_test_SOURCES += vcard_test.c
  vcard_test_LDADD = ${MY_LDADD}
  
- vrps_test_LDADD = ${MY_LDADD}
 +vrps_test_SOURCES  = ${BASIC_MODULES}
++vrps_test_SOURCES += ${SLURM_SOURCES}
 +vrps_test_SOURCES += ../src/common.c
 +vrps_test_SOURCES += ../src/rtr/db/delta.c
 +vrps_test_SOURCES += ../src/rtr/db/roa_table.c
 +vrps_test_SOURCES += ../src/rtr/db/vrps.c
 +vrps_test_SOURCES += rtr/db/impersonator.c
 +vrps_test_SOURCES += rtr/db/vrps_test.c
++vrps_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS}
 +
  #rtr_pdu_test_SOURCES  = ${BASIC_MODULES}
  #rtr_pdu_test_SOURCES += rtr/pdu_test.c
  #rtr_pdu_test_SOURCES += rtr/stream.c
index 41cbbc2172b892c72d72832a92e21227d1b4b076,41cbbc2172b892c72d72832a92e21227d1b4b076..3d0f0ed4d8dde924d78b4b20983ea3a74ff90700
@@@ -69,3 -69,3 +69,9 @@@ config_get_rsync_args(bool is_ta
        static const struct string_array array = { 0 };
        return &array;
  }
++
++char const *
++config_get_slurm_location(void)
++{
++      return NULL;
++}
index 3e2f3a950ca246138576ad6d2de6ddaaf4078533,0000000000000000000000000000000000000000..fded5635119121bd067614671e98dc7aafaa9646
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,60 @@@
 +#include "object/tal.h"
 +
 +#include <check.h>
 +
 +static int iteration = 0;
 +
 +static void
 +add_v4(struct validation_handler *handler, uint32_t as)
 +{
 +      struct ipv4_prefix prefix;
 +      prefix.addr.s_addr = htonl(0xC0000200);
 +      prefix.len = 24;
 +      ck_assert_int_eq(0, handler->handle_roa_v4(as, &prefix, 32,
 +          handler->arg));
 +}
 +
 +static void
 +add_v6(struct validation_handler *handler, uint32_t as)
 +{
 +      struct ipv6_prefix prefix;
 +      prefix.addr.s6_addr32[0] = htonl(0x20010DB8);
 +      prefix.addr.s6_addr32[1] = 0;
 +      prefix.addr.s6_addr32[2] = 0;
 +      prefix.addr.s6_addr32[3] = 0;
 +      prefix.len = 96;
 +      ck_assert_int_eq(0, handler->handle_roa_v6(as, &prefix, 120,
 +          handler->arg));
 +}
 +
 +int
 +perform_standalone_validation(struct validation_handler *handler)
 +{
 +      ck_assert_int_eq(0, handler->reset(handler->arg));
 +
 +      switch (iteration) {
 +      case 0:
 +              add_v4(handler, 0);
 +              add_v6(handler, 0);
 +              break;
 +      case 1:
 +              add_v4(handler, 0);
 +              add_v6(handler, 0);
 +              add_v4(handler, 1);
 +              add_v6(handler, 1);
 +              break;
 +      case 2:
 +      case 3:
 +              add_v4(handler, 1);
 +              add_v6(handler, 1);
 +              break;
 +      default:
 +              ck_abort_msg("perform_standalone_validation() was called too many times (%d).",
 +                  iteration);
 +      }
++      if (handler->merge != NULL)
++              handler->merge(handler->merge_arg, handler->arg);
 +
 +      iteration++;
 +      return 0;
 +}
Simple merge