/*
- * Copyright (c) 2012, JANET(UK)
+ * Copyright (c) 2012-2018, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include <tr_rp.h>
#include <tr_idp.h>
-#include <trust_router/tr_name.h>
+#include <tr_name_internal.h>
+#include <trp_internal.h>
#include <tr_comm.h>
#include <tr_debug.h>
-
+#include <tr_util.h>
static int tr_comm_destructor(void *obj)
{
tr_comm_memb_set_comm(newmemb, comm);
tr_comm_memb_set_interval(newmemb, interval);
tr_comm_memb_set_provenance(newmemb, provenance);
+ tr_comm_memb_set_expiry(newmemb, expiry);
existing=tr_comm_table_find_idp_memb_origin(ctab,
tr_idp_realm_get_id(realm),
tr_comm_memb_set_comm(newmemb, comm);
tr_comm_memb_set_interval(newmemb, interval);
tr_comm_memb_set_provenance(newmemb, provenance);
+ tr_comm_memb_set_expiry(newmemb, expiry);
existing=tr_comm_table_find_rp_memb_origin(ctab,
tr_rp_realm_get_id(realm),
return NULL;
/* will not remove the head here, that has already been done */
- for (comm=head; comm->next!=NULL; comm=comm->next) {
+ for (comm=head; (comm!=NULL) && (comm->next!=NULL); comm=comm->next) {
if (comm->next->refcount==0) {
old_next=comm->next;
- tr_comm_remove(head, comm->next); /* changes comm->next */
+ tr_comm_remove(head, comm->next); /* changes comm->next, may make it null */
tr_comm_free(old_next);
}
}
}
-/* iterate over all memberships in the table */
+/* iterate over all memberships in the table
+ *
+ * The table is structured as a vertical list of memberships, each for a
+ * different community/realm. Each element in this list has a horizontal "origin list,"
+ * each for the same community/realm but with a different origin for the membership.
+ * Only the first element in the origin list has a vertical link ("next" pointer).
+ * Any element may have a horizontal link ("origin_next" pointer).
+ *
+ * (A) - (B) - (C) - X
+ * |
+ * (D) - (E) - X
+ * |
+ * (F) - X
+ * |
+ * (G) - (H) - X
+ * |
+ * X
+ *
+ * A, B, and C are all community/realm pair membership 1, with different origins
+ * D, E are a second community/realm pair, with different origins
+ * F is a third...
+ * G, H are a fourth pair, with different origins
+ *
+ * This iterator will return every element in the grid.
+ *
+ * Algorithm:
+ * The iterator struct stores the current member (cur_memb) and the origin head (cur_orig_head).
+ * The latter is a pointer to the head of the current origin list (i.e., first element in a row).
+ * The former can point to any element in the list. Both start at the root of the list (A in the
+ * diagram above).
+ *
+ * After each call to _first() or _next(), cur_memb points to the element just returned.
+ *
+ * 0. _first() just returns the first element. The rest of the steps are in _next()
+ *
+ * 1. If cur_memb has an origin_next element, walk the origin list. Move cur_memb to
+ * the origin_list element (next one in this row) and return it.
+ * 2. If cur_memb does not have an origin_next element, we've finished the current origin
+ * list. Move cur_memb to cur_orig_head's next element (the start of the next column),
+ * move cur_orig_head to that same place, and return it.
+ * 3. If neither cur_memb has an origin_next element nor cur_orig_head has a next element,
+ * then we have already reached the end of the list and there's nothing more to do.
+ * Return NULL.
+ */
TR_COMM_MEMB *tr_comm_memb_iter_all_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab)
{
+ /* step 0: return the root of the list */
iter->cur_memb=ctab->memberships;
iter->cur_orig_head=ctab->memberships;
return iter->cur_memb;
TR_COMM_MEMB *tr_comm_memb_iter_all_next(TR_COMM_ITER *iter)
{
- if (iter->cur_memb->next==NULL) {
- if (iter->cur_orig_head->next==NULL) {
- /* we're done */
- return NULL;
- } else {
- iter->cur_memb=iter->cur_orig_head->next;
- iter->cur_orig_head=iter->cur_orig_head->next;
- }
+ if (iter->cur_memb->origin_next) {
+ /* step 1: return the next element in the current origin list */
+ iter->cur_memb = iter->cur_memb->origin_next;
+ } else if (iter->cur_orig_head->next) {
+ /* step 2: move to the start of the next row and return the first element */
+ iter->cur_orig_head = iter->cur_memb = iter->cur_orig_head->next;
} else {
- iter->cur_memb=iter->cur_memb->origin_next;
+ /* step 3: both cur_memb->origin_next and cur_orig_head->next are null */
+ iter->cur_orig_head = iter->cur_memb = NULL;
}
return iter->cur_memb;
}
return NULL;
}
*(memb->expiry)=(struct timespec){0,0};
- talloc_set_destructor(memb, tr_comm_memb_destructor);
+ talloc_set_destructor((void *)memb, tr_comm_memb_destructor);
}
return memb;
}
return memb->expiry;
}
+/**
+ * Get the expiration according to the realtime clock
+ *
+ * @param memb
+ * @param result space to store the result
+ * @return pointer to the result, or null on error
+ */
+struct timespec *tr_comm_memb_get_expiry_realtime(TR_COMM_MEMB *memb, struct timespec *result)
+{
+ return tr_clock_convert(TRP_CLOCK, memb->expiry, CLOCK_REALTIME, result);
+}
+
int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime)
{
+ tr_debug("tr_comm_memb_is_expired: (cur->tv_sec>memb->expiry->tv_sec)=(%u > %u)=%s",
+ curtime->tv_sec,
+ memb->expiry->tv_sec,
+ (curtime->tv_sec > memb->expiry->tv_sec)?"true":"false");
+
return ((curtime->tv_sec > memb->expiry->tv_sec)
|| ((curtime->tv_sec == memb->expiry->tv_sec)
&&(curtime->tv_nsec >= memb->expiry->tv_nsec)));
return tr_comm_lookup(ctab->comms, comm_id);
}
-void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new)
+/**
+ * Add a community to the table.
+ *
+ * Does not allow duplicate community ids.
+ *
+ * @param ctab
+ * @param new
+ * @return 0 on success, -1 on failure
+ */
+int tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new)
{
+ if (tr_comm_table_find_comm(ctab, tr_comm_get_id(new)) != NULL)
+ return -1;
+
tr_comm_add(ctab->comms, new);
if (ctab->comms!=NULL)
talloc_steal(ctab, ctab->comms); /* make sure it's in the right context */
+ return 0;
}
void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm)
return TR_ROLE_UNKNOWN;
}
-void tr_comm_table_print(FILE *f, TR_COMM_TABLE *ctab)
+static char *tr_comm_table_append_provenance(char *ctable_s, json_t *prov)
{
+ const char *s=NULL;
+ char *tmp=NULL;
+ size_t ii=0;
+
+ for (ii=0; ii<json_array_size(prov); ii++) {
+ s=json_string_value(json_array_get(prov, ii));
+ if (s!=NULL) {
+ tmp=talloc_asprintf_append(ctable_s, "%s%s", s, ((ii + 1) == json_array_size(prov)) ? "" : ", ");
+ if (tmp==NULL)
+ return NULL;
+ ctable_s=tmp;
+ }
+ }
+ return ctable_s;
+}
+
+char *tr_comm_table_to_str(TALLOC_CTX *mem_ctx, TR_COMM_TABLE *ctab)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ char *ctable_s=NULL;
+ char *tmp=NULL;
+#define append_on_success_helper(tab,tmp,expr) if(NULL==((tmp)=(expr))){(tab)=NULL;goto cleanup;}(tab)=(tmp)
+
TR_COMM_MEMB *p1=NULL; /* for walking the main list */
TR_COMM_MEMB *p2=NULL; /* for walking the same-origin lists */
- fprintf(f, ">> Membership table start <<\n");
+ ctable_s=talloc_asprintf(tmp_ctx, ">> Membership table start <<\n");
+ if (ctable_s==NULL)
+ goto cleanup;
+
for (p1=ctab->memberships; p1!=NULL; p1=p1->next) {
- fprintf(f, "* %s %s/%s\n %s (%p)\n",
- tr_realm_role_to_str(tr_comm_memb_get_role(p1)),
- tr_comm_memb_get_realm_id(p1)->buf,
- tr_comm_get_id(tr_comm_memb_get_comm(p1))->buf,
- (tr_comm_memb_get_origin(p1)==NULL)?"null origin":(tr_comm_memb_get_origin(p1)->buf),
- p1);
+ append_on_success_helper(
+ ctable_s, tmp,
+ talloc_asprintf_append(ctable_s, "* %s %s/%s\n %s (%p) - prov: ",
+ tr_realm_role_to_str(tr_comm_memb_get_role(p1)),
+ tr_comm_memb_get_realm_id(p1)->buf,
+ tr_comm_get_id(tr_comm_memb_get_comm(p1))->buf,
+ (tr_comm_memb_get_origin(p1)==NULL)?"null origin":(tr_comm_memb_get_origin(p1)->buf),
+ p1));
+
+ append_on_success_helper(ctable_s, tmp, tr_comm_table_append_provenance(ctable_s, p1->provenance));
+
+ append_on_success_helper(ctable_s, tmp, talloc_strdup_append_buffer(ctable_s, "\n"));
+
for (p2=p1->origin_next; p2!=NULL; p2=p2->origin_next) {
- fprintf(f, " %s (%p)\n",
- (tr_comm_memb_get_origin(p2)==NULL)?"null origin":(tr_comm_memb_get_origin(p2)->buf),
- p2);
+ append_on_success_helper(
+ ctable_s, tmp,
+ talloc_asprintf_append(ctable_s, " %s (%p) - prov: ",
+ (tr_comm_memb_get_origin(p2)==NULL)?"null origin":(tr_comm_memb_get_origin(p2)->buf),
+ p2));
+ append_on_success_helper(ctable_s, tmp, tr_comm_table_append_provenance(ctable_s, p2->provenance));
+ append_on_success_helper(ctable_s, tmp, talloc_strdup_append_buffer(ctable_s, "\n"));
}
- fprintf(f, "\n");
+ append_on_success_helper(ctable_s, tmp, talloc_strdup_append_buffer(ctable_s, "\n"));
}
+
+cleanup:
+ if (ctable_s!=NULL)
+ talloc_steal(mem_ctx, ctable_s);
+
+ talloc_free(tmp_ctx);
+ return ctable_s;
}
+
+void tr_comm_table_print(FILE *f, TR_COMM_TABLE *ctab)
+{
+ char *s=tr_comm_table_to_str(NULL, ctab);
+ if (s!=NULL) {
+ tr_debug("%s", s);
+ talloc_free(s);
+ }
+}
\ No newline at end of file