DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
-bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/dh_test/tr_dh_test common/mq_test/mq_test common/mq_test/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/cfg_test/cfg_test
+bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/tests/tr_dh_test common/tests/mq_test common/tests/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/tests/cfg_test common/tests/commtest
AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS)
AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS)
SUBDIRS = gsscon
tid_example_tids_SOURCES = tid/example/tids_main.c
tid_example_tids_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
-common_dh_test_tr_dh_test_SOURCES = common/tr_dh.c \
+common_tests_tr_dh_test_SOURCES = common/tr_dh.c \
common/tr_debug.c \
-common/dh_test/dh_test.c
+common/tests/dh_test.c
-common_mq_test_mq_test_SOURCES = common/tr_mq.c \
-common/mq_test/mq_test.c
+common_tests_mq_test_SOURCES = common/tr_mq.c \
+common/tests/mq_test.c
-common_mq_test_mq_test_CFLAGS = -pthread
-common_mq_test_mq_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
+common_tests_mq_test_CFLAGS = -pthread
+common_tests_mq_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
-common_cfg_test_cfg_test_SOURCES = common/cfg_test/cfg_test.c \
+common_tests_cfg_test_SOURCES = common/tests/cfg_test.c \
$(trp_srcs)
-common_cfg_test_cfg_test_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
-common_cfg_test_cfg_test_CFLAGS = -pthread
-common_cfg_test_cfg_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
+common_tests_cfg_test_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
+common_tests_cfg_test_CFLAGS = -pthread
+common_tests_cfg_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
-common_mq_test_thread_test_SOURCES = common/tr_mq.c \
+common_tests_thread_test_SOURCES = common/tr_mq.c \
common/tr_debug.c \
-common/mq_test/thread_test.c
+common/tests/thread_test.c
-common_mq_test_thread_test_CFLAGS = -pthread
-common_mq_test_thread_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
+common_tests_thread_test_CFLAGS = -pthread
+common_tests_thread_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
+
+common_tests_commtest_SOURCES = common/tests/commtest.c \
+$(trp_srcs)
+common_tests_commtest_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
+common_tests_commtest_CFLAGS = -pthread
+common_test_commtest_LDFLAGS = $(AM_LDFLAGS) -ltalloc
pkginclude_HEADERS = include/trust_router/tid.h include/trust_router/tr_name.h \
include/tr_debug.h \
--- /dev/null
+#include <talloc.h>
+#include <assert.h>
+#include <jansson.h>
+
+#include <tr_apc.h>
+#include <tr_comm.h>
+#include <tr_rp.h>
+#include <trust_router/tr_name.h>
+
+/**********************************************************************/
+/* APC test stuff */
+struct apc_entry {
+ const char *id; /* only allows a single entry for now */
+};
+
+static TR_APC *apc_entry_to_apc(TALLOC_CTX *mem_ctx, struct apc_entry *ae)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *apcs=NULL;
+
+ apcs=tr_apc_new(tmp_ctx);
+ if (apcs!=NULL) {
+ tr_apc_set_id(apcs, tr_new_name(ae->id));
+ talloc_steal(mem_ctx, apcs);
+ }
+
+ talloc_free(tmp_ctx);
+ return apcs;
+}
+
+/**********************************************************************/
+/* TR_COMM test stuff */
+
+struct comm_entry {
+ const char *id;
+ TR_COMM_TYPE type;
+ struct apc_entry *apcs;
+};
+
+static TR_COMM *comm_entry_to_comm(TALLOC_CTX *mem_ctx, struct comm_entry *ce)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM *comm=tr_comm_new(tmp_ctx);
+
+ if (comm!=NULL) {
+ tr_comm_set_id(comm, tr_new_name(ce->id));
+ tr_comm_set_type(comm, ce->type);
+ if (ce->apcs!=NULL)
+ tr_comm_set_apcs(comm, apc_entry_to_apc(tmp_ctx, ce->apcs));
+
+ if ((tr_comm_get_id(comm)==NULL) ||
+ ((ce->apcs!=NULL)&&(tr_comm_get_apcs(comm)==NULL)))
+ comm=NULL; /* it's in tmp_ctx, so will be freed */
+ else
+ talloc_steal(mem_ctx, comm);
+ }
+
+ talloc_free(tmp_ctx);
+ return comm;
+}
+
+static int add_comm_set(TR_COMM_TABLE *ctab, struct comm_entry *entries)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct comm_entry *this=NULL;
+ size_t ii=0;
+ TR_COMM *new=NULL;
+ int rc=-1;
+
+ for (this=entries,ii=0; this->id!=NULL; this++, ii++) {
+ new=comm_entry_to_comm(tmp_ctx, this);
+ if (new==NULL) {
+ printf("Error creating community %d.\n", ii+1);
+ rc=1;
+ goto cleanup;
+ }
+ tr_comm_table_add_comm(ctab, new);
+ }
+ /* success */
+ rc=0;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int verify_comm_set(TR_COMM_TABLE *ctab, struct comm_entry *entries)
+{
+ struct comm_entry *this=NULL;
+ TR_COMM *comm=NULL;
+ TR_NAME *this_id=NULL;
+
+ for (this=entries; this->id!=NULL; this++) {
+ this_id=tr_new_name(this->id);
+ comm=tr_comm_table_find_comm(ctab, this_id);
+ tr_free_name(this_id); this_id=NULL;
+
+ if (comm==NULL) {
+ printf("Error, community %s missing from community table.\n", this->id);
+ return -1;
+ }
+ if (tr_comm_get_type(comm)!=this->type) {
+ printf("Error, community %s has wrong type (was %s, expected %s).\n",
+ this->id,
+ tr_comm_type_to_str(tr_comm_get_type(comm)),
+ tr_comm_type_to_str(this->type));
+ return -1;
+ }
+ /* TODO: verify apcs */
+ }
+ return 0;
+}
+
+/* removes entry n from ctab */
+static int remove_comm_set_member(TR_COMM_TABLE *ctab, struct comm_entry *entries, size_t n)
+{
+ TR_NAME *comm_name=tr_new_name(entries[n].id);
+ TR_COMM *comm=tr_comm_table_find_comm(ctab, comm_name);
+ TR_COMM *comm2=NULL;
+
+ if (comm==NULL) {
+ printf("Can't remove community %s, not in table.\n", entries[n].id);
+ tr_free_name(comm_name);
+ return 1;
+ }
+
+ tr_comm_table_remove_comm(ctab, comm);
+ comm2=tr_comm_table_find_comm(ctab, comm_name);
+ if (comm2!=NULL) {
+ printf("Community %s still in table after removal.\n", entries[n].id);
+ tr_comm_free(comm);
+ tr_free_name(comm_name);
+ return 2;
+ }
+
+ tr_comm_free(comm);
+ tr_free_name(comm_name);
+ return 0;
+}
+
+/**********************************************************************/
+/* TR_RP_REALM test stuff */
+
+struct rp_realm_entry {
+ const char *id;
+};
+
+static TR_RP_REALM *rp_realm_entry_to_rp_realm(TALLOC_CTX *mem_ctx, struct rp_realm_entry *re)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_REALM *realm=NULL;
+
+ realm=tr_rp_realm_new(tmp_ctx);
+ if (realm!=NULL) {
+ tr_rp_realm_set_id(realm, tr_new_name(re->id));
+ talloc_steal(mem_ctx, realm);
+ }
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
+
+static int add_rp_realm_set(TR_COMM_TABLE *ctab, struct rp_realm_entry *entries)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct rp_realm_entry *this=NULL;
+ TR_RP_REALM *realm=NULL;
+ int rc=-1;
+
+ for (this=entries; this->id!=NULL; this++) {
+ realm=rp_realm_entry_to_rp_realm(tmp_ctx, this);
+ if (realm==NULL) {
+ printf("Error creating RP realm %s.\n", this->id);
+ rc=1;
+ goto cleanup;
+ }
+ tr_comm_table_add_rp_realm(ctab, realm);
+ }
+ rc=0;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int verify_rp_realm_set(TR_COMM_TABLE *ctab, struct rp_realm_entry *entries)
+{
+ struct rp_realm_entry *this=NULL;
+ TR_RP_REALM *rp_realm=NULL;
+ TR_NAME *this_id=NULL;
+
+ for (this=entries; this->id!=NULL; this++) {
+ this_id=tr_new_name(this->id);
+ rp_realm=tr_comm_table_find_rp_realm(ctab, this_id);
+ tr_free_name(this_id); this_id=NULL;
+
+ if (rp_realm==NULL) {
+ printf("Error, RP realm %s missing from community table.\n", this->id);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* removes entry n from ctab */
+static int remove_rp_realm_set_member(TR_COMM_TABLE *ctab, struct rp_realm_entry *entries, size_t n)
+{
+ TR_NAME *rp_realm_name=tr_new_name(entries[n].id);
+ TR_RP_REALM *rp_realm=tr_comm_table_find_rp_realm(ctab, rp_realm_name);
+ TR_RP_REALM *rp_realm2=NULL;
+
+ if (rp_realm==NULL) {
+ printf("Can't remove RP realm %s, not in table.\n", entries[n].id);
+ tr_free_name(rp_realm_name);
+ return 1;
+ }
+
+ tr_comm_table_remove_rp_realm(ctab, rp_realm);
+ rp_realm2=tr_comm_table_find_rp_realm(ctab, rp_realm_name);
+ if (rp_realm2!=NULL) {
+ printf("RP realm %s still in table after removal.\n", entries[n].id);
+ tr_rp_realm_free(rp_realm);
+ tr_free_name(rp_realm_name);
+ return 2;
+ }
+
+ tr_rp_realm_free(rp_realm);
+ tr_free_name(rp_realm_name);
+ return 0;
+}
+
+/**********************************************************************/
+/* TR_AAA_SERVER test stuff */
+
+struct aaa_entry {
+ const char *hostname; /* only supports one for testing right now */
+};
+
+static TR_AAA_SERVER *aaa_entry_to_aaa_server(TALLOC_CTX *mem_ctx, struct aaa_entry *ae)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_AAA_SERVER *aaa=tr_aaa_server_new(tmp_ctx, tr_new_name(ae->hostname));
+
+ if ((aaa==NULL) || (aaa->hostname==NULL))
+ aaa=NULL;
+ else
+ talloc_steal(mem_ctx, aaa);
+
+ talloc_free(tmp_ctx);
+ return aaa;
+}
+
+
+/**********************************************************************/
+/* TR_IDP_REALM test stuff */
+
+struct idp_realm_entry {
+ const char *id;
+ struct aaa_entry *aaa_servers;
+ struct apc_entry *apcs;
+};
+
+static TR_IDP_REALM *idp_realm_entry_to_idp_realm(TALLOC_CTX *mem_ctx, struct idp_realm_entry *re)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realm=NULL;
+
+ realm=tr_idp_realm_new(tmp_ctx);
+ if (realm!=NULL) {
+ tr_idp_realm_set_id(realm, tr_new_name(re->id));
+ realm->aaa_servers=aaa_entry_to_aaa_server(realm, re->aaa_servers);
+ if (realm->aaa_servers==NULL)
+ realm=NULL; /* still in tmp_ctx so will be freed */
+ else {
+ tr_idp_realm_set_apcs(realm, apc_entry_to_apc(tmp_ctx, re->apcs));
+ if (tr_idp_realm_get_apcs==NULL)
+ realm=NULL;
+ }
+ }
+
+ if (realm!=NULL)
+ talloc_steal(mem_ctx, realm);
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
+
+static int add_idp_realm_set(TR_COMM_TABLE *ctab, struct idp_realm_entry *entries)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct idp_realm_entry *this=NULL;
+ TR_IDP_REALM *realm=NULL;
+ int rc=-1;
+
+ for (this=entries; this->id!=NULL; this++) {
+ realm=idp_realm_entry_to_idp_realm(tmp_ctx, this);
+ if (realm==NULL) {
+ printf("Error creating IDP realm %s.\n", this->id);
+ rc=1;
+ goto cleanup;
+ }
+ tr_comm_table_add_idp_realm(ctab, realm);
+ }
+ rc=0;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int verify_idp_realm_set(TR_COMM_TABLE *ctab, struct idp_realm_entry *entries)
+{
+ struct idp_realm_entry *this=NULL;
+ TR_IDP_REALM *idp_realm=NULL;
+ TR_NAME *this_id=NULL;
+
+ for (this=entries; this->id!=NULL; this++) {
+ this_id=tr_new_name(this->id);
+ idp_realm=tr_comm_table_find_idp_realm(ctab, this_id);
+ tr_free_name(this_id); this_id=NULL;
+
+ if (idp_realm==NULL) {
+ printf("Error, IDP realm %s missing from community table.\n", this->id);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* removes entry n from ctab */
+static int remove_idp_realm_set_member(TR_COMM_TABLE *ctab, struct idp_realm_entry *entries, size_t n)
+{
+ TR_NAME *idp_realm_name=tr_new_name(entries[n].id);
+ TR_IDP_REALM *idp_realm=tr_comm_table_find_idp_realm(ctab, idp_realm_name);
+ TR_IDP_REALM *idp_realm2=NULL;
+
+ if (idp_realm==NULL) {
+ printf("Can't remove IDP realm %s, not in table.\n", entries[n].id);
+ tr_free_name(idp_realm_name);
+ return 1;
+ }
+
+ tr_comm_table_remove_idp_realm(ctab, idp_realm);
+ idp_realm2=tr_comm_table_find_idp_realm(ctab, idp_realm_name);
+ if (idp_realm2!=NULL) {
+ printf("IDP realm %s still in table after removal.\n", entries[n].id);
+ tr_idp_realm_free(idp_realm);
+ tr_free_name(idp_realm_name);
+ return 2;
+ }
+
+ tr_idp_realm_free(idp_realm);
+ tr_free_name(idp_realm_name);
+ return 0;
+}
+
+/**********************************************************************/
+/* Community Membership test stuff */
+
+struct comm_memb_entry {
+ TR_REALM_ROLE role;
+ const char *realm_name;
+ const char *comm_name;
+ const char *origin;
+ /* TODO: test provenance */
+};
+
+/* add an existing realm to an existing community (these must
+ * exist in the community table lists) */
+static int add_comm_membership(TR_COMM_TABLE *ctab, struct comm_memb_entry *entry)
+{
+ TR_NAME *comm_name=tr_new_name(entry->comm_name);
+ TR_NAME *realm_name=tr_new_name(entry->realm_name);
+ TR_COMM *comm=tr_comm_table_find_comm(ctab, comm_name);
+ TR_RP_REALM *rp_realm=(entry->role==TR_ROLE_RP)?(tr_comm_table_find_rp_realm(ctab, realm_name)):(NULL);
+ TR_IDP_REALM *idp_realm=(entry->role==TR_ROLE_IDP)?(tr_comm_table_find_idp_realm(ctab, realm_name)):(NULL);
+ json_t *prov=NULL;
+
+ if ((comm==NULL) || ((rp_realm==NULL)&&(idp_realm==NULL)))
+ return 1;
+
+ prov=json_array();
+ if (entry->origin!=NULL)
+ json_array_append(prov, json_string(entry->origin));
+
+ switch (entry->role) {
+ case TR_ROLE_IDP:
+ tr_comm_add_idp_realm(ctab, comm, idp_realm, 0, prov, NULL); /* Expiry!? */
+ break;
+ case TR_ROLE_RP:
+ tr_comm_add_rp_realm(ctab, comm, rp_realm, 0, prov, NULL); /* Expiry!? */
+ break;
+ default:
+ return 2;
+ }
+
+ return 0;
+}
+
+static int add_member_set(TR_COMM_TABLE *ctab, struct comm_memb_entry *entries)
+{
+ struct comm_memb_entry *this=NULL;
+
+ for (this=entries; this->role!=TR_ROLE_UNKNOWN; this++) {
+ if (0!=add_comm_membership(ctab, this)) {
+ printf("Error adding %s realm %s to community %s (origin %s).\n",
+ (this->role==TR_ROLE_RP)?"RP":"IDP",
+ this->realm_name,
+ this->comm_name,
+ (this->origin!=NULL)?(this->origin):"null");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int remove_membership(TR_COMM_TABLE *ctab, struct comm_memb_entry *entries, size_t n)
+{
+ TR_NAME *realm_name=tr_new_name(entries[n].realm_name);
+ TR_NAME *comm_name=tr_new_name(entries[n].comm_name);
+ TR_NAME *origin=(entries[n].origin!=NULL)?(tr_new_name(entries[n].origin)):NULL;
+ TR_COMM_MEMB *memb=NULL;
+ int rc=-1;
+
+ switch (entries[n].role) {
+ case TR_ROLE_IDP:
+ memb=tr_comm_table_find_idp_memb_origin(ctab, realm_name, comm_name, origin);
+ break;
+ case TR_ROLE_RP:
+ memb=tr_comm_table_find_rp_memb_origin(ctab, realm_name, comm_name, origin);
+ break;
+ default:
+ rc=1;
+ goto cleanup;
+ }
+
+ if (memb==NULL) {
+ printf("%s realm %s not in comm %s from origin %s, can't remove membership.\n",
+ (entries[n].role==TR_ROLE_RP)?"RP":"IDP",
+ entries[n].realm_name,
+ entries[n].comm_name,
+ (entries[n].origin!=NULL)?(entries[n].origin):"null");
+ rc=2;
+ goto cleanup;
+ }
+ tr_comm_table_remove_memb(ctab, memb);
+ tr_comm_memb_free(memb);
+ rc=0;
+
+cleanup:
+ tr_free_name(realm_name);
+ tr_free_name(comm_name);
+ if (origin!=NULL)
+ tr_free_name(origin);
+ return rc;
+}
+
+/**********************************************************************/
+/* Test data */
+
+struct apc_entry apc_1={ "apc" };
+
+struct comm_entry comm_set_1[]={
+ { "apc", TR_COMM_APC, NULL },
+ { "comm 1", TR_COMM_COI, &apc_1 },
+ { "comm 2", TR_COMM_COI, &apc_1 },
+ { NULL }
+};
+
+struct rp_realm_entry rp_realm_set_1[]={
+ { "rp 1" },
+ { "rp 2" },
+ { "rp 3" },
+ { NULL }
+};
+
+struct aaa_entry aaa_1= { "aaa 1" };
+struct aaa_entry aaa_2= { "aaa 2" };
+struct aaa_entry aaa_3= { "aaa 3" };
+
+struct idp_realm_entry idp_realm_set_1[]={
+ { "idp 1", &aaa_1, &apc_1 },
+ { "idp 2", &aaa_2, &apc_1 },
+ { "idp 3", &aaa_3, &apc_1 },
+ { NULL }
+};
+
+struct comm_memb_entry member_set_1[]={
+ { TR_ROLE_RP, "rp 1", "apc", NULL },
+ { TR_ROLE_RP, "rp 2", "apc", NULL },
+ { TR_ROLE_RP, "rp 3", "apc", NULL },
+ { TR_ROLE_IDP, "idp 1", "apc", NULL },
+ { TR_ROLE_IDP, "idp 2", "apc", NULL },
+ { TR_ROLE_IDP, "idp 3", "apc", NULL },
+ { TR_ROLE_RP, "rp 1", "comm 1", NULL },
+ { TR_ROLE_RP, "rp 2", "comm 1", NULL },
+ { TR_ROLE_RP, "rp 2", "comm 1", "peer 1" },
+ { TR_ROLE_RP, "rp 2", "comm 1", "peer 2" },
+ { TR_ROLE_IDP, "idp 1", "comm 1", NULL },
+ { TR_ROLE_IDP, "idp 1", "comm 1", "peer 1" },
+ { TR_ROLE_IDP, "idp 1", "comm 1", "peer 2" },
+ { TR_ROLE_IDP, "idp 2", "comm 1", NULL },
+ { TR_ROLE_RP, "rp 1", "comm 2", NULL },
+ { TR_ROLE_RP, "rp 2", "comm 2", NULL },
+ { TR_ROLE_RP, "rp 2", "comm 2", "peer 1" },
+ { TR_ROLE_RP, "rp 2", "comm 2", "peer 2" },
+ { TR_ROLE_IDP, "idp 1", "comm 2", NULL },
+ { TR_ROLE_IDP, "idp 1", "comm 2", "peer 1" },
+ { TR_ROLE_IDP, "idp 1", "comm 2", "peer 2" },
+ { TR_ROLE_IDP, "idp 2", "comm 2", NULL },
+ { TR_ROLE_UNKNOWN }
+};
+
+
+/**********************************************************************/
+/* Test routines */
+
+/* the first few tests here insert a few things into the community table (comms,
+ * rp_realms, or idp_realms), then verify that they're all there. They
+ * then remove them in various orders, put them back, try removing
+ * things that are not present, etc. */
+
+static int community_test(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_COMM_TABLE *ctab=tr_comm_table_new(mem_ctx);
+
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(0==tr_comm_table_size(ctab));
+
+ assert(1==remove_comm_set_member(ctab, comm_set_1, 1)); /* should not be in the table */
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(2==tr_comm_table_size(ctab));
+ assert(1==remove_comm_set_member(ctab, comm_set_1, 1)); /* should not be in the table */
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(0==tr_comm_table_size(ctab));
+ assert(1==remove_comm_set_member(ctab, comm_set_1, 1)); /* should not be in the table */
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(1==tr_comm_table_size(ctab));
+ assert(1==remove_comm_set_member(ctab, comm_set_1, 1)); /* should not be in the table */
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(0==tr_comm_table_size(ctab));
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+static int rp_realm_test(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_COMM_TABLE *ctab=tr_comm_table_new(mem_ctx);
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+
+ assert(1==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1)); /* should not be in the table */
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(1==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1)); /* should not be in the table */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(1==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1)); /* should not be in the table */
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(1==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1)); /* should not be in the table */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+static int idp_realm_test(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_COMM_TABLE *ctab=tr_comm_table_new(mem_ctx);
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+
+ assert(1==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1)); /* should not be in the table */
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(1==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1)); /* should not be in the table */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(1==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1)); /* should not be in the table */
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(1==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1)); /* should not be in the table */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+static int membership_test(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_COMM_TABLE *ctab=tr_comm_table_new(mem_ctx);
+ size_t ii=0;
+ size_t size=0;
+
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==add_member_set(ctab, member_set_1));
+
+ size=tr_comm_table_size(ctab);
+ tr_comm_table_sweep(ctab);
+ assert(size==tr_comm_table_size(ctab));
+
+ /* now remove memberships */
+ for (ii=0; member_set_1[ii].role!=TR_ROLE_UNKNOWN; ii++) {
+ assert(0==remove_membership(ctab, member_set_1, ii));
+ assert(2==remove_membership(ctab, member_set_1, ii)); /* should not be in the table */
+ }
+
+ assert(NULL==ctab->memberships);
+
+ /* put them back */
+ assert(0==add_member_set(ctab, member_set_1));
+ /* tr_comm_table_print(stdout, ctab); */
+
+ tr_comm_table_sweep(ctab);
+ assert(size==tr_comm_table_size(ctab));
+
+ /* remove in the reverse order */
+ for(; ii>0; ii--) {
+ assert(0==remove_membership(ctab, member_set_1, ii-1));
+ assert(2==remove_membership(ctab, member_set_1, ii-1)); /* should not be in the table */
+ /* tr_comm_table_print(stdout, ctab); */
+ }
+
+ assert(NULL==ctab->memberships);
+
+ assert(size==tr_comm_table_size(ctab));
+ tr_comm_table_sweep(ctab);
+ assert(0==tr_comm_table_size(ctab));
+
+ talloc_free(mem_ctx);
+}
+
+
+/**********************************************************************/
+/* main */
+int main(void)
+{
+ assert(0==community_test());
+ printf("Community tests passed.\n");
+ assert(0==rp_realm_test());
+ printf("RP realm tests passed.\n");
+ assert(0==idp_realm_test());
+ printf("IDP realm tests passed.\n");
+ assert(0==membership_test());
+ printf("Membership tests passed.\n");
+ return 0;
+}
*
*/
+#include <stdio.h>
#include <jansson.h>
#include <talloc.h>
#include <sys/time.h>
#include <tr_debug.h>
-/* static prototypes */
-static TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb);
-
-
static int tr_comm_destructor(void *obj)
{
TR_COMM *comm=talloc_get_type_abort(obj, TR_COMM);
return comm->refcount;
}
-/* add to the table if it's a new membership or has a shorter
- * provenance list than our existing membership */
+/* 0 if equivalent, nonzero if different, only considers
+ * nhops last hops (nhops==0 means consider all, nhops==1
+ * only considers last hop) */
+static int tr_comm_memb_provenance_cmp(TR_COMM_MEMB *m1, TR_COMM_MEMB *m2, int nhops)
+{
+ size_t ii;
+
+ if ((m1->provenance==NULL) || (m2->provenance==NULL))
+ return m1->provenance!=m2->provenance; /* return 0 if both null, 1 if only one null */
+
+ if (json_array_size(m1->provenance)!=json_array_size(m2->provenance))
+ return 1;
+
+ if (nhops==0)
+ nhops=json_array_size(m1->provenance); /* same as size(m2->provenance) */
+
+ for (ii=0; ii<json_array_size(m1->provenance); ii++) {
+ if (0==strcmp(json_string_value(json_array_get(m1->provenance, ii)),
+ json_string_value(json_array_get(m2->provenance, ii)))) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Accepts an update that either came from the same peer as the previous
+ * origin, has a shorter provenance list, or can replace an expired
+ * membership. Otherwise keeps the existing one.
+ * On replacement, frees the old member and moves new member to ctab's
+ * context. Caller should not free newmemb except by freeing its original
+ * context. */
static void tr_comm_add_if_shorter(TR_COMM_TABLE *ctab, TR_COMM_MEMB *existing, TR_COMM_MEMB *newmemb)
{
+ int accept=0;
+
if (existing==NULL) {
/* not in the table */
tr_comm_table_add_memb(ctab, newmemb);
} else {
- /* Had an entry. Replace if we have shorter provenance. */
- if (tr_comm_memb_provenance_len(newmemb) < tr_comm_memb_provenance_len(existing)) {
+ if (0==tr_comm_memb_provenance_cmp(existing, newmemb, 1))
+ accept=1; /* always accept a replacement from the same peer */
+ else if (tr_comm_memb_provenance_len(newmemb) < tr_comm_memb_provenance_len(existing))
+ accept=1; /* accept a shorter provenance */
+ else if (existing->times_expired>0)
+ accept=1;
+ else
+ accept=0;
+
+ if (accept) {
tr_comm_table_remove_memb(ctab, existing);
tr_comm_memb_free(existing);
tr_comm_table_add_memb(ctab, newmemb);
- }
+ }
}
}
void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab,
TR_COMM *comm,
TR_IDP_REALM *realm,
+ unsigned int interval,
json_t *provenance,
struct timespec *expiry)
{
tr_comm_memb_set_idp_realm(newmemb, 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_idp_memb_origin(ctab,
tr_idp_realm_get_id(realm),
tr_comm_get_id(comm),
tr_comm_memb_get_origin(newmemb));
tr_comm_add_if_shorter(ctab, existing, newmemb); /* takes newmemb out of tmp_ctx if needed */
+
talloc_free(tmp_ctx);
}
void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab,
TR_COMM *comm,
TR_RP_REALM *realm,
+ unsigned int interval,
json_t *provenance,
struct timespec *expiry)
{
tr_comm_memb_set_rp_realm(newmemb, 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),
* the list head was in. */
comms=comms->next;
if (comms!=NULL) {
- talloc_steal(list_ctx, comms->next);
+ talloc_steal(list_ctx, comms);
/* now put all the other elements in the context of the list head */
for (this=comms->next; this!=NULL; this=this->next)
talloc_steal(comms, this);
} else {
/* not removing the head; no need to play with contexts */
for (this=comms; this->next!=NULL; this=this->next) {
- if (this->next==remove)
+ if (this->next==remove) {
this->next=remove->next;
+ break;
+ }
}
}
return comms;
}
+/* remove any with zero refcount
+ * Call via macro. */
+#define tr_comm_sweep(head) ((head)=tr_comm_sweep_func((head)))
+static TR_COMM *tr_comm_sweep_func(TR_COMM *head)
+{
+ TR_COMM *comm=NULL;
+ TR_COMM *old_next=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ while ((head!=NULL) && (head->refcount==0)) {
+ comm=head; /* keep a pointer so we can remove it */
+ tr_comm_remove(head, comm); /* use this to get talloc contexts right */
+ tr_comm_free(comm);
+ }
+
+ if (head==NULL)
+ return NULL;
+
+ /* will not remove the head here, that has already been done */
+ for (comm=head; 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_free(old_next);
+ }
+ }
+
+ return head;
+}
+
TR_IDP_REALM *tr_comm_find_idp(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *idp_realm)
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
if (iter!=NULL) {
iter->cur_comm=NULL;
iter->cur_memb=NULL;
+ iter->cur_orig_head=NULL;
iter->match=NULL;
iter->realm=NULL;
}
return s;
}
+/* iterate along the origin list for this member */
TR_COMM_MEMB *tr_comm_memb_iter_first(TR_COMM_ITER *iter, TR_COMM_MEMB *memb)
{
iter->cur_memb=memb;
return iter->cur_memb;
}
+
+/* iterate over all memberships in the table */
+TR_COMM_MEMB *tr_comm_memb_iter_all_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab)
+{
+ 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;
+ }
+ } else {
+ iter->cur_memb=iter->cur_memb->origin_next;
+ }
+ return iter->cur_memb;
+}
+
+
TR_COMM_TYPE tr_comm_type_from_str(const char *s)
{
if (strcmp(s, "apc")==0)
memb->provenance=NULL;
memb->interval=0;
memb->triggered=0;
+ memb->times_expired=0;
memb->expiry=talloc(memb, struct timespec);
if (memb->expiry==NULL) {
talloc_free(memb);
talloc_free(memb);
}
+/* Returns 0 if they are the same, nonzero if they differ.
+ * Ignores expiry, triggered, and times_expired, next pointers */
+int tr_comm_memb_cmp(TR_COMM_MEMB *m1, TR_COMM_MEMB *m2)
+{
+ if ((m1->idp==m2->idp) &&
+ (m1->rp==m2->rp) &&
+ (m1->comm==m2->comm) &&
+ (tr_comm_memb_provenance_cmp(m1, m2, 0)==0) &&
+ (m1->interval==m2->interval))
+ return 0;
+ return 1;
+}
+
TR_REALM_ROLE tr_comm_memb_get_role(TR_COMM_MEMB *memb)
{
if (memb->rp!=NULL)
void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov)
{
+ const char *s=NULL;
+
if (memb->provenance)
json_decref(memb->provenance);
/* next line sets origin to NULL if provenance is empty because jansson
* routines return NULL on error */
- memb->origin=tr_new_name(json_string_value(json_array_get(prov, 0)));
+ s=json_string_value(json_array_get(prov, 0));
+ if (s==NULL)
+ tr_comm_memb_set_origin(memb, NULL);
+ else
+ memb->origin=tr_new_name(s);
} else {
tr_comm_memb_set_origin(memb, NULL);
}
&&(curtime->tv_nsec >= memb->expiry->tv_nsec)));
}
-void tr_comm_set_triggered(TR_COMM_MEMB *memb, int trig)
+void tr_comm_memb_set_triggered(TR_COMM_MEMB *memb, int trig)
{
memb->triggered=trig;
}
-int tr_comm_is_triggered(TR_COMM_MEMB *memb)
+int tr_comm_memb_is_triggered(TR_COMM_MEMB *memb)
{
return memb->triggered;
}
+void tr_comm_memb_reset_times_expired(TR_COMM_MEMB *memb)
+{
+ memb->times_expired=0;
+}
+
+/* bumps the expiration count */
+void tr_comm_memb_expire(TR_COMM_MEMB *memb)
+{
+ /* avoid overflow */
+ if (memb->times_expired+1>memb->times_expired)
+ memb->times_expired++;
+}
+
+unsigned int tr_comm_memb_get_times_expired(TR_COMM_MEMB *memb)
+{
+ return memb->times_expired;
+}
TR_COMM_TABLE *tr_comm_table_new(TALLOC_CTX *mem_ctx)
{
{
TR_COMM_MEMB *cur=NULL;
- /* TODO: validate the member (must have valid comm and realm) */
+ /* TODO: further validate the member (must have valid comm and realm) */
+ if ((new->next!=NULL) || (new->origin_next!=NULL)) {
+ tr_debug("tr_comm_table_add_memb: attempting to add member already in a list.");
+ }
/* handle the empty list case */
if (ctab->memberships==NULL) {
/* see if it's the first member */
if (ctab->memberships==memb) {
if (memb->origin_next!=NULL) {
- memb->origin_next->next=ctab->memberships->next;
+ memb->origin_next->next=memb->next;
ctab->memberships=memb->origin_next;
} else
ctab->memberships=memb->next;
}
/* see if it's in first member's origin list */
- for (orig_cur=ctab->memberships->origin_next;
- orig_cur!=NULL;
- orig_cur=ctab->memberships->origin_next) {
- if (orig_cur==memb) {
+ for (orig_cur=ctab->memberships;
+ orig_cur->origin_next!=NULL;
+ orig_cur=orig_cur->origin_next) {
+ if (orig_cur->origin_next==memb) {
orig_cur->origin_next=memb->origin_next;
return;
}
for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) {
if (cur->next==memb) {
/* it matched an entry on the main list */
- if (memb->origin_next!=NULL) {
+ if (memb->origin_next==NULL)
+ cur->next=memb->next; /* no origin list, just drop memb */
+ else {
/* replace the entry in the main list with the next element on the origin list */
memb->origin_next->next=memb->next;
cur->next=memb->origin_next;
- } else
- cur->next=memb->next; /* no origin list, just drop memb */
+ }
return;
} else {
/* it was not on the main list, walk the origin list */
- for (orig_cur=cur; orig_cur->next!=NULL; orig_cur=orig_cur->next) {
- if (orig_cur->next==memb) {
- orig_cur->next=memb->next;
+ for (orig_cur=cur; orig_cur->origin_next!=NULL; orig_cur=orig_cur->origin_next) {
+ if (orig_cur->origin_next==memb) {
+ orig_cur->origin_next=memb->origin_next;
return; /* just drop the element from the origin list */
}
}
}
}
+ /* if we got here, cur->next was null. Still have to check the origin_next list */
+ for (orig_cur=cur; orig_cur->origin_next!=NULL; orig_cur=orig_cur->origin_next) {
+ if (orig_cur->origin_next==memb) {
+ orig_cur->origin_next=memb->origin_next;
+ return; /* just drop the element from the origin list */
+ }
+ }
}
-static TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb)
+TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb)
{
if (memb->rp!=NULL)
return tr_rp_realm_get_id(memb->rp);
void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new)
{
tr_comm_add(ctab->comms, new);
+ if (ctab->comms!=NULL)
+ talloc_steal(ctab, ctab->comms); /* make sure it's in the right context */
}
void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm)
tr_comm_remove(ctab->comms, comm);
}
+TR_RP_REALM *tr_comm_table_find_rp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id)
+{
+ return tr_rp_realm_lookup(ctab->rp_realms, realm_id);
+}
+
+void tr_comm_table_add_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *new)
+{
+ tr_rp_realm_add(ctab->rp_realms, new);
+ if (ctab->rp_realms!=NULL)
+ talloc_steal(ctab, ctab->rp_realms); /* make sure it's in the right context */
+}
+
+void tr_comm_table_remove_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *realm)
+{
+ tr_rp_realm_remove(ctab->rp_realms, realm);
+}
+
+TR_IDP_REALM *tr_comm_table_find_idp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id)
+{
+ return tr_idp_realm_lookup(ctab->idp_realms, realm_id);
+}
+
+void tr_comm_table_add_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *new)
+{
+ tr_idp_realm_add(ctab->idp_realms, new);
+ if (ctab->idp_realms!=NULL)
+ talloc_steal(ctab, ctab->idp_realms); /* make sure it's in the right context */
+}
+
+void tr_comm_table_remove_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *realm)
+{
+ tr_idp_realm_remove(ctab->idp_realms, realm);
+}
+
+
/* how many communities in the table? */
size_t tr_comm_table_size(TR_COMM_TABLE *ctab)
{
return count;
}
+/* clean up unreferenced realms, etc */
+void tr_comm_table_sweep(TR_COMM_TABLE *ctab)
+{
+ tr_rp_realm_sweep(ctab->rp_realms);
+ tr_idp_realm_sweep(ctab->idp_realms);
+ tr_comm_sweep(ctab->comms);
+}
+
const char *tr_realm_role_to_str(TR_REALM_ROLE role)
{
return TR_ROLE_UNKNOWN;
}
+void tr_comm_table_print(FILE *f, TR_COMM_TABLE *ctab)
+{
+ 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");
+ 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);
+ 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);
+ }
+ fprintf(f, "\n");
+ }
+}
*rc=TR_CFG_ERROR;
return;
}
- tr_comm_add_idp_realm(trc->ctable, comm, found_idp, NULL, NULL); /* no provenance, never expires */
+ tr_comm_add_idp_realm(trc->ctable, comm, found_idp, 0, NULL, NULL); /* no provenance, never expires */
}
*rc=TR_CFG_SUCCESS;
tr_rp_realm_set_id(new_rp, rp_name);
rp_name=NULL; /* rp_name no longer belongs to us */
tr_rp_realm_add(trc->ctable->rp_realms, new_rp);
+ talloc_steal(trc->ctable, trc->ctable->rp_realms); /* make sure head is in the right context */
}
- tr_comm_add_rp_realm(trc->ctable, comm, new_rp, NULL, NULL);
+ tr_comm_add_rp_realm(trc->ctable, comm, new_rp, 0, NULL, NULL);
}
}
return head;
}
+/* use the macro */
+TR_IDP_REALM *tr_idp_realm_remove_func(TR_IDP_REALM *head, TR_IDP_REALM *remove)
+{
+ TALLOC_CTX *list_ctx=talloc_parent(head);
+ TR_IDP_REALM *this=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ if (head==remove) {
+ /* if we're removing the head, put the next element (if present) into the context
+ * the list head was in. */
+ head=head->next;
+ if (head!=NULL) {
+ talloc_steal(list_ctx, head);
+ /* now put all the other elements in the context of the list head */
+ for (this=head->next; this!=NULL; this=this->next)
+ talloc_steal(head, this);
+ }
+ } else {
+ /* not removing the head; no need to play with contexts */
+ for (this=head; this->next!=NULL; this=this->next) {
+ if (this->next==remove) {
+ this->next=remove->next;
+ break;
+ }
+ }
+ }
+ return head;
+}
+
static int tr_idp_realm_apc_count(TR_IDP_REALM *idp)
{
int ii=0;
if (realm->refcount>0)
realm->refcount--;
}
+
+/* remove any with zero refcount
+ * Call via macro. */
+TR_IDP_REALM *tr_idp_realm_sweep_func(TR_IDP_REALM *head)
+{
+ TR_IDP_REALM *idp=NULL;
+ TR_IDP_REALM *old_next=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ while ((head!=NULL) && (head->refcount==0)) {
+ idp=head; /* keep a pointer so we can remove it */
+ tr_idp_realm_remove(head, idp); /* use this to get talloc contexts right */
+ tr_idp_realm_free(idp);
+ }
+
+ if (head==NULL)
+ return NULL;
+
+ /* will not remove the head here, that has already been done */
+ for (idp=head; idp->next!=NULL; idp=idp->next) {
+ if (idp->next->refcount==0) {
+ old_next=idp->next;
+ tr_idp_realm_remove(head, idp->next); /* changes idp->next */
+ tr_idp_realm_free(old_next);
+ }
+ }
+
+ return head;
+}
+
}
trp_inforec_set_apcs(rec, apcs);
- rc=tr_msg_get_json_string(jrecord, "owner_realm", &s, tmp_ctx);
- if (rc != TRP_SUCCESS)
- goto cleanup;
- if (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_new_name(s))) {
- rc=TRP_ERROR;
+ rc=tr_msg_get_json_integer(jrecord, "interval", &num);
+ tr_debug("tr_msg_decode_trp_inforec_comm: interval=%u", num);
+ if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
goto cleanup;
+
+ trp_inforec_set_provenance(rec, json_object_get(jrecord, "provenance"));
+
+ /* optional */
+ rc=tr_msg_get_json_string(jrecord, "owner_realm", &s, tmp_ctx);
+ if (rc == TRP_SUCCESS) {
+ if (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_new_name(s))) {
+ rc=TRP_ERROR;
+ goto cleanup;
+ }
+ if (s!=NULL) {
+ talloc_free(s);
+ s=NULL;
+ }
}
- talloc_free(s); s=NULL;
rc=tr_msg_get_json_string(jrecord, "owner_contact", &s, tmp_ctx);
- if (rc != TRP_SUCCESS)
- goto cleanup;
- if (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_new_name(s))) {
- rc=TRP_ERROR;
- goto cleanup;
+ if (rc == TRP_SUCCESS) {
+ if (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_new_name(s))) {
+ rc=TRP_ERROR;
+ goto cleanup;
+ }
+ if (s!=NULL) {
+ talloc_free(s);
+ s=NULL;
+ }
}
- talloc_free(s); s=NULL;
-
- trp_inforec_set_provenance(rec, json_object_get(jrecord, "provenance"));
-
- rc=tr_msg_get_json_integer(jrecord, "interval", &num);
- if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
- goto cleanup;
cleanup:
talloc_free(tmp_ctx);
return head;
}
+/* use the macro */
+TR_RP_REALM *tr_rp_realm_remove_func(TR_RP_REALM *head, TR_RP_REALM *remove)
+{
+ TALLOC_CTX *list_ctx=talloc_parent(head);
+ TR_RP_REALM *this=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ if (head==remove) {
+ /* if we're removing the head, put the next element (if present) into the context
+ * the list head was in. */
+ head=head->next;
+ if (head!=NULL) {
+ talloc_steal(list_ctx, head);
+ /* now put all the other elements in the context of the list head */
+ for (this=head->next; this!=NULL; this=this->next)
+ talloc_steal(head, this);
+ }
+ } else {
+ /* not removing the head; no need to play with contexts */
+ for (this=head; this->next!=NULL; this=this->next) {
+ if (this->next==remove) {
+ this->next=remove->next;
+ break;
+ }
+ }
+ }
+ return head;
+}
+
void tr_rp_realm_incref(TR_RP_REALM *realm)
{
realm->refcount++;
realm->refcount--;
}
+/* remove any with zero refcount
+ * Call via macro. */
+TR_RP_REALM *tr_rp_realm_sweep_func(TR_RP_REALM *head)
+{
+ TR_RP_REALM *rp=NULL;
+ TR_RP_REALM *old_next=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ while ((head!=NULL) && (head->refcount==0)) {
+ rp=head; /* keep a pointer so we can remove it */
+ tr_rp_realm_remove(head, rp); /* use this to get talloc contexts right */
+ tr_rp_realm_free(rp);
+ }
+
+ if (head==NULL)
+ return NULL;
+
+ /* will not remove the head here, that has already been done */
+ for (rp=head; rp->next!=NULL; rp=rp->next) {
+ if (rp->next->refcount==0) {
+ old_next=rp->next;
+ tr_rp_realm_remove(head, rp->next); /* changes rp->next */
+ tr_rp_realm_free(old_next);
+ }
+ }
+
+ return head;
+}
+
TR_NAME *tr_rp_realm_get_id(TR_RP_REALM *rp)
{
if (rp==NULL)
#ifndef TR_COMM_H
#define TR_COMM_H
+#include <stdio.h>
#include <talloc.h>
#include <time.h>
json_t *provenance; /* array of names of systems traversed */
unsigned int interval;
struct timespec *expiry;
+ unsigned int times_expired; /* how many times has this expired? */
int triggered; /* do we need to send this with triggered updates? */
} TR_COMM_MEMB;
typedef struct tr_comm_iter {
TR_COMM *cur_comm;
TR_COMM_MEMB *cur_memb;
+ TR_COMM_MEMB *cur_orig_head; /* for iterating along orig_next list */
TR_NAME *match; /* realm or comm to match */
TR_REALM *realm; /* handle so caller does not have to manage memory, private */
} TR_COMM_ITER;
TR_COMM_TABLE *tr_comm_table_new(TALLOC_CTX *mem_ctx);
void tr_comm_table_free(TR_COMM_TABLE *ctab);
+void tr_comm_table_sweep(TR_COMM_TABLE *ctab);
void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new);
void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm);
+TR_RP_REALM *tr_comm_table_find_rp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id);
+void tr_comm_table_add_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *new);
+void tr_comm_table_remove_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *realm);
+TR_IDP_REALM *tr_comm_table_find_idp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id);
+void tr_comm_table_add_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *new);
+void tr_comm_table_remove_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *realm);
void tr_comm_table_add_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *new);
void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb);
TR_COMM_MEMB *tr_comm_table_find_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin);
TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *idp_realm, TR_NAME *comm);
TR_COMM *tr_comm_table_find_comm(TR_COMM_TABLE *ctab, TR_NAME *comm_id);
size_t tr_comm_table_size(TR_COMM_TABLE *ctab);
+void tr_comm_table_print(FILE *f, TR_COMM_TABLE *ctab);
TR_COMM_MEMB *tr_comm_memb_new(TALLOC_CTX *mem_ctx);
void tr_comm_memb_free(TR_COMM_MEMB *memb);
+int tr_comm_memb_cmp(TR_COMM_MEMB *m1, TR_COMM_MEMB *m2);
TR_REALM_ROLE tr_comm_memb_get_role(TR_COMM_MEMB *memb);
void tr_comm_memb_set_rp_realm(TR_COMM_MEMB *memb, TR_RP_REALM *realm);
TR_RP_REALM *tr_comm_memb_get_rp_realm(TR_COMM_MEMB *memb);
void tr_comm_memb_set_idp_realm(TR_COMM_MEMB *memb, TR_IDP_REALM *realm);
TR_IDP_REALM *tr_comm_memb_get_idp_realm(TR_COMM_MEMB *memb);
+TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb);
void tr_comm_memb_set_comm(TR_COMM_MEMB *memb, TR_COMM *comm);
TR_COMM *tr_comm_memb_get_comm(TR_COMM_MEMB *memb);
TR_NAME *tr_comm_memb_get_origin(TR_COMM_MEMB *memb);
void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time);
struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb);
int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime);
-void tr_comm_set_triggered(TR_COMM_MEMB *memb, int trig);
-int tr_comm_is_triggered(TR_COMM_MEMB *memb);
+void tr_comm_memb_set_triggered(TR_COMM_MEMB *memb, int trig);
+int tr_comm_memb_is_triggered(TR_COMM_MEMB *memb);
+void tr_comm_memb_reset_times_expired(TR_COMM_MEMB *memb);
+void tr_comm_memb_expire(TR_COMM_MEMB *memb);
+unsigned int tr_comm_memb_get_times_expired(TR_COMM_MEMB *memb);
TR_COMM *tr_comm_new(TALLOC_CTX *mem_ctx);
void tr_comm_free(TR_COMM *comm);
void tr_comm_set_owner_contact(TR_COMM *comm, TR_NAME *contact);
TR_NAME *tr_comm_get_owner_contact(TR_COMM *comm);
TR_NAME *tr_comm_dup_owner_contact(TR_COMM *comm);
-void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_IDP_REALM *realm, json_t *provenance, struct timespec *expiry);
-void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_RP_REALM *realm, json_t *provenance, struct timespec *expiry);
+void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_IDP_REALM *realm, unsigned int interval, json_t *provenance, struct timespec *expiry);
+void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_RP_REALM *realm, unsigned int interval, json_t *provenance, struct timespec *expiry);
TR_RP_REALM *tr_comm_find_rp(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *rp_realm);
TR_IDP_REALM *tr_comm_find_idp(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *idp_realm);
const char *tr_comm_type_to_str(TR_COMM_TYPE type);
TR_COMM_MEMB *tr_comm_memb_iter_first(TR_COMM_ITER *iter, TR_COMM_MEMB *memb);
TR_COMM_MEMB *tr_comm_memb_iter_next(TR_COMM_ITER *iter);
+/* iterate over all members */
+TR_COMM_MEMB *tr_comm_memb_iter_all_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab);
+TR_COMM_MEMB *tr_comm_memb_iter_all_next(TR_COMM_ITER *iter);
+
/* general realm stuff, should probably move */
TR_NAME *tr_realm_get_id(TR_REALM *realm);
TR_NAME *tr_realm_dup_id(TR_REALM *realm);
TR_IDP_REALM *tr_idp_realm_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_name);
TR_IDP_REALM *tr_idp_realm_add_func(TR_IDP_REALM *head, TR_IDP_REALM *new);
#define tr_idp_realm_add(head,new) ((head)=tr_idp_realm_add_func((head),(new)))
+TR_IDP_REALM *tr_idp_realm_remove_func(TR_IDP_REALM *head, TR_IDP_REALM *remove);
+#define tr_idp_realm_remove(head,remove) ((head)=tr_idp_realm_remove_func((head),(remove)))
+TR_IDP_REALM *tr_idp_realm_sweep_func(TR_IDP_REALM *head);
+#define tr_idp_realm_sweep(head) ((head)=tr_idp_realm_sweep_func((head)))
char *tr_idp_realm_to_str(TALLOC_CTX *mem_ctx, TR_IDP_REALM *idp);
void tr_idp_realm_incref(TR_IDP_REALM *realm);
void tr_idp_realm_decref(TR_IDP_REALM *realm);
TR_RP_REALM *tr_rp_realm_lookup(TR_RP_REALM *rp_realms, TR_NAME *rp_name);
TR_RP_REALM *tr_rp_realm_add_func(TR_RP_REALM *head, TR_RP_REALM *new);
#define tr_rp_realm_add(head,new) ((head)=tr_rp_realm_add_func((head),(new)))
+TR_RP_REALM *tr_rp_realm_remove_func(TR_RP_REALM *head, TR_RP_REALM *remove);
+#define tr_rp_realm_remove(head,remove) ((head)=tr_rp_realm_remove_func((head),(remove)))
+TR_RP_REALM *tr_rp_realm_sweep_func(TR_RP_REALM *head);
+#define tr_rp_realm_sweep(head) ((head)=tr_rp_realm_sweep_func((head)))
void tr_rp_realm_incref(TR_RP_REALM *realm);
void tr_rp_realm_decref(TR_RP_REALM *realm);
TRP_ROUTE *trps_get_selected_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm);
TR_NAME *trps_get_next_hop(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm);
TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps);
+TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps);
TRP_RC trps_add_route(TRPS_INSTANCE *trps, TRP_ROUTE *route);
TRP_RC trps_add_peer(TRPS_INSTANCE *trps, TRP_PEER *peer);
TRP_PEER *trps_get_peer_by_gssname(TRPS_INSTANCE *trps, TR_NAME *gssname);
tr_debug("tr_trps_sweep: sweeping routes.");
trps_sweep_routes(trps);
+ tr_debug("tr_trps_sweep: sweeping communities.");
+ trps_sweep_ctable(trps);
tr_trps_print_route_table(trps, stderr);
/* schedule the event to run again */
event_add(ev, &(trps->sweep_interval));
#include <glib.h>
#include <gsscon.h>
+#include <tr_comm.h>
#include <tr_apc.h>
#include <tr_rp.h>
#include <trust_router/tr_name.h>
* the next table sweep if it does not get any realms before that happens */
goto cleanup;
}
- tr_rp_realm_add(trps->ctable->rp_realms, rp_realm);
+ tr_comm_table_add_rp_realm(trps->ctable, rp_realm);
}
/* TODO: if realm existed, see if data match the new inforec and update or complain */
- tr_comm_add_rp_realm(trps->ctable, comm, rp_realm, trp_inforec_get_provenance(rec), &expiry);
+ tr_comm_add_rp_realm(trps->ctable, comm, rp_realm, trp_inforec_get_interval(rec), trp_inforec_get_provenance(rec), &expiry);
tr_debug("trps_handle_inforec_comm: added RP realm %.*s to comm %.*s (origin %.*s).",
realm_id->len, realm_id->buf,
comm_id->len, comm_id->buf,
* the next table sweep if it does not get any realms before that happens */
goto cleanup;
}
- tr_idp_realm_add(trps->ctable->idp_realms, idp_realm);
+ tr_comm_table_add_idp_realm(trps->ctable, idp_realm);
}
/* TODO: if realm existed, see if data match the new inforec and update or complain */
- tr_comm_add_idp_realm(trps->ctable, comm, idp_realm, trp_inforec_get_provenance(rec), &expiry);
+ tr_comm_add_idp_realm(trps->ctable, comm, idp_realm, trp_inforec_get_interval(rec), trp_inforec_get_provenance(rec), &expiry);
tr_debug("trps_handle_inforec_comm: added IDP realm %.*s to comm %.*s (origin %.*s).",
realm_id->len, realm_id->buf,
comm_id->len, comm_id->buf,
return TRP_SUCCESS;
}
+
+static char *timespec_to_str(struct timespec *ts)
+{
+ struct tm tm;
+ char *s=NULL;
+
+ if (localtime_r(&(ts->tv_sec), &tm)==NULL)
+ return NULL;
+
+ s=malloc(40); /* long enough to contain strftime result */
+ if (s==NULL)
+ return NULL;
+
+ if (strftime(s, 40, "%F %T", &tm)==0) {
+ free(s);
+ return NULL;
+ }
+ return s;
+}
+
+
+/* Sweep for expired communities/realms/memberships. */
+TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct timespec sweep_time={0,0};
+ TR_COMM_MEMB *memb=NULL;
+ TR_COMM_ITER *iter=NULL;
+ TRP_RC rc=TRP_ERROR;
+
+ /* use a single time for the entire sweep */
+ if (0!=clock_gettime(CLOCK_REALTIME, &sweep_time)) {
+ tr_err("trps_sweep_ctable: could not read realtime clock.");
+ sweep_time.tv_sec=0;
+ sweep_time.tv_nsec=0;
+ goto cleanup;
+ }
+
+ /* iterate all memberships */
+ iter=tr_comm_iter_new(tmp_ctx);
+ if (iter==NULL) {
+ tr_err("trps_sweep_ctable: unable to allocate iterator.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+ for (memb=tr_comm_memb_iter_all_first(iter, trps->ctable);
+ memb!=NULL;
+ memb=tr_comm_memb_iter_all_next(iter)) {
+ if (tr_comm_memb_get_origin(memb)==NULL)
+ continue; /* do not expire local entries */
+
+ if (tr_comm_memb_is_expired(memb, &sweep_time)) {
+ if (tr_comm_memb_get_times_expired(memb)>0) {
+ /* Already expired once; flush. */
+ tr_debug("trps_sweep_ctable: flushing expired community membership (%.*s in %.*s, origin %.*s, expired %s).",
+ tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf,
+ tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf,
+ tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf,
+ timespec_to_str(tr_comm_memb_get_expiry(memb)));
+ tr_comm_table_remove_memb(trps->ctable, memb);
+ tr_comm_memb_free(memb);
+ } else {
+ /* This is the first expiration. Note this and reset the expiry time. */
+ tr_comm_memb_expire(memb);
+ trps_compute_expiry(trps, tr_comm_memb_get_interval(memb), tr_comm_memb_get_expiry(memb));
+ tr_debug("trps_sweep_ctable: community membership expired, resetting expiry to %s (%.*s in %.*s, origin %.*s).",
+ timespec_to_str(tr_comm_memb_get_expiry(memb)),
+ tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf,
+ tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf,
+ tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf);
+ }
+ }
+ }
+
+ /* get rid of any unreferenced realms, etc */
+ tr_comm_table_sweep(trps->ctable);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
/* add metrics */
static unsigned int trps_metric_add(unsigned int m1, unsigned int m2)
{
goto cleanup;
}
- if (TRP_SUCCESS!=trp_inforec_set_interval(rec, tr_comm_memb_get_interval(memb))) {
+ if (TRP_SUCCESS!=trp_inforec_set_interval(rec, trps_get_update_interval(trps))) {
rec=NULL;
goto cleanup;
}