#include <stdbool.h>
#include <string.h>
#include "array_list.h"
+#include "common.h"
/*
* Storage of VRPs (term taken from RFC 6811 "Validated ROA Payload") and
time_t last_modified_date;
} state;
+/* Read and Write locks */
+sem_t rlock, wlock;
+
+/* Readers counter */
+unsigned int rcounter;
+
static int
delta_init(struct delta *delta)
{
/* Minus 1 to prevent same ID */
state.v1_session_id = state.v0_session_id - 1;
+ sem_init(&rlock, 0, 1);
+ sem_init(&wlock, 0, 1);
+ rcounter = 0;
+
return 0;
}
return error;
result->serial = base_delta->serial;
+ read_lock(&rlock, &wlock, &rcounter);
/* First check for announcements */
base = &base_delta->vrps;
search_list = &state.base_db.vrps;
error = delta_add_vrp(result, cursor);
if (error) {
warnx("Couldn't add announcement to summary");
+ read_unlock(&rlock, &wlock, &rcounter);
return error;
}
}
error = delta_add_vrp(result, cursor);
if (error) {
warnx("Couldn't add withdrawal to summary");
+ read_unlock(&rlock, &wlock, &rcounter);
return error;
}
}
+ read_unlock(&rlock, &wlock, &rcounter);
return 0;
}
int result;
result = 0;
+ read_lock(&rlock, &wlock, &rcounter);
delta.serial = state.current_serial;
+ read_unlock(&rlock, &wlock, &rcounter);
/* Store only updates */
if (delta.serial != START_SERIAL) {
result = delta_summary(&delta, &summary);
warnx("Error summarizing new delta");
return result;
}
+ sem_wait(&wlock);
result = deltasdb_add(&state.deltas_db, &summary);
+ sem_post(&wlock);
}
/* Don't set the base in case of error */
if (result != 0) {
return result;
}
+ sem_wait(&wlock);
free(state.base_db.vrps.array);
state.base_db = delta;
state.current_serial++;
+ sem_post(&wlock);
return result;
}
void
deltas_db_destroy(void)
{
-
+ sem_wait(&wlock);
delta_destroy(&state.base_db);
deltasdb_cleanup(&state.deltas_db, delta_destroy);
+ sem_post(&wlock);
+
+ sem_destroy(&wlock);
+ sem_destroy(&rlock);
}
/*
deltas_db_status(u_int32_t *serial)
{
struct delta *delta;
+ int result;
- if (state.base_db.vrps.len == 0)
- return NO_DATA_AVAILABLE;
+ read_lock(&rlock, &wlock, &rcounter);
+ if (state.base_db.vrps.len == 0) {
+ result = NO_DATA_AVAILABLE;
+ goto end;
+ }
/* No serial to match, and there's data at DB */
- if (serial == NULL)
- return DIFF_AVAILABLE;
+ if (serial == NULL) {
+ result = DIFF_AVAILABLE;
+ goto end;
+ }
/* Is the last version? */
- if (*serial == state.base_db.serial)
- return NO_DIFF;
+ if (*serial == state.base_db.serial) {
+ result = NO_DIFF;
+ goto end;
+ }
/* Get the delta corresponding to the serial */
- ARRAYLIST_FOREACH(&state.deltas_db, delta) {
- if (delta->serial == *serial)
- return DIFF_AVAILABLE;
- }
+ ARRAYLIST_FOREACH(&state.deltas_db, delta)
+ if (delta->serial == *serial) {
+ result = DIFF_AVAILABLE;
+ goto end;
+ }
+
+ /* No match yet, release lock */
+ read_unlock(&rlock, &wlock, &rcounter);
/* The first serial isn't at deltas */
if (*serial == START_SERIAL)
/* Reached end, diff can't be determined */
return DIFF_UNDETERMINED;
+end:
+ read_unlock(&rlock, &wlock, &rcounter);
+ return result;
}
static void
{
struct delta *delta1;
struct vrps summary;
+ unsigned int vrps_len;
+ read_lock(&rlock, &wlock, &rcounter);
/* No data */
- if (state.base_db.vrps.len == 0)
+ if (state.base_db.vrps.len == 0) {
+ read_unlock(&rlock, &wlock, &rcounter);
return 0;
+ }
/* NULL start? Send the last version, there's no need to iterate DB */
if (start_serial == NULL) {
copy_vrps(result, state.base_db.vrps.array,
state.base_db.vrps.len);
- return state.base_db.vrps.len;
+ vrps_len = state.base_db.vrps.len;
+ read_unlock(&rlock, &wlock, &rcounter);
+ return vrps_len;
}
/* Apparently nothing to return */
- if (*start_serial >= *end_serial)
+ if (*start_serial >= *end_serial) {
+ read_unlock(&rlock, &wlock, &rcounter);
return 0;
+ }
/* Get the delta corresponding to the serials */
vrps_init(&summary);
if (delta1->serial == *end_serial)
break;
}
+ read_unlock(&rlock, &wlock, &rcounter);
copy_vrps(result, summary.array, summary.len);
vrps_cleanup(&summary, vrp_destroy);
void
set_vrps_last_modified_date(time_t new_date)
{
+ sem_wait(&wlock);
state.last_modified_date = new_date;
+ sem_post(&wlock);
}
u_int32_t
get_last_serial_number(void)
{
- return state.current_serial - 1;
+ u_int32_t serial;
+
+ read_lock(&rlock, &wlock, &rcounter);
+ serial = state.current_serial - 1;
+ read_unlock(&rlock, &wlock, &rcounter);
+
+ return serial;
}
u_int16_t
get_current_session_id(u_int8_t rtr_version)
{
+ /* Semaphore isn't needed since this value is set at initialization */
if (rtr_version == 1)
return state.v1_session_id;
return state.v0_session_id;
time_t
get_vrps_last_modified_date(void)
{
- return state.last_modified_date;
+ time_t date;
+
+ read_lock(&rlock, &wlock, &rcounter);
+ date = state.last_modified_date;
+ read_unlock(&rlock, &wlock, &rcounter);
+
+ return date;
}