From: Jennifer Richards Date: Mon, 7 Nov 2016 17:22:21 +0000 (-0500) Subject: Fix community table sweep / removal. Trust router now stable. X-Git-Tag: v2.1.1~26 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=commitdiff_plain;h=44a04b1538480d17a3cfe168a7b92f74c0c3c4cf Fix community table sweep / removal. Trust router now stable. --- diff --git a/Makefile.am b/Makefile.am index 664a5d6..ebd0e8f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ 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 @@ -112,29 +112,35 @@ tid_example_tidc_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS) 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 \ diff --git a/common/cfg_test/cfg_test.c b/common/tests/cfg_test.c similarity index 100% rename from common/cfg_test/cfg_test.c rename to common/tests/cfg_test.c diff --git a/common/tests/commtest.c b/common/tests/commtest.c new file mode 100644 index 0000000..9c9c008 --- /dev/null +++ b/common/tests/commtest.c @@ -0,0 +1,837 @@ +#include +#include +#include + +#include +#include +#include +#include + +/**********************************************************************/ +/* 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; +} diff --git a/common/dh_test/dh_test.c b/common/tests/dh_test.c similarity index 100% rename from common/dh_test/dh_test.c rename to common/tests/dh_test.c diff --git a/common/cfg_test/idp.cfg b/common/tests/idp.cfg similarity index 100% rename from common/cfg_test/idp.cfg rename to common/tests/idp.cfg diff --git a/common/mq_test/mq_test.c b/common/tests/mq_test.c similarity index 100% rename from common/mq_test/mq_test.c rename to common/tests/mq_test.c diff --git a/common/mq_test/thread_test.c b/common/tests/thread_test.c similarity index 100% rename from common/mq_test/thread_test.c rename to common/tests/thread_test.c diff --git a/common/tr_comm.c b/common/tr_comm.c index 52d93f1..bd5c0bf 100644 --- a/common/tr_comm.c +++ b/common/tr_comm.c @@ -32,6 +32,7 @@ * */ +#include #include #include #include @@ -43,10 +44,6 @@ #include -/* 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); @@ -171,20 +168,59 @@ unsigned int tr_comm_get_refcount(TR_COMM *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; iiprovenance); 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); - } + } } } @@ -192,6 +228,7 @@ static void tr_comm_add_if_shorter(TR_COMM_TABLE *ctab, TR_COMM_MEMB *existing, 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) { @@ -207,14 +244,15 @@ void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab, 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); } @@ -222,6 +260,7 @@ void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab, 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) { @@ -237,8 +276,8 @@ void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab, 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), @@ -293,7 +332,7 @@ static TR_COMM *tr_comm_remove_func(TR_COMM *comms, TR_COMM *remove) * 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); @@ -301,13 +340,47 @@ static TR_COMM *tr_comm_remove_func(TR_COMM *comms, TR_COMM *remove) } 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); @@ -377,6 +450,7 @@ TR_COMM_ITER *tr_comm_iter_new(TALLOC_CTX *mem_ctx) if (iter!=NULL) { iter->cur_comm=NULL; iter->cur_memb=NULL; + iter->cur_orig_head=NULL; iter->match=NULL; iter->realm=NULL; } @@ -670,6 +744,7 @@ const char *tr_comm_type_to_str(TR_COMM_TYPE type) 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; @@ -683,6 +758,32 @@ TR_COMM_MEMB *tr_comm_memb_iter_next(TR_COMM_ITER *iter) 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) @@ -723,6 +824,7 @@ TR_COMM_MEMB *tr_comm_memb_new(TALLOC_CTX *mem_ctx) 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); @@ -739,6 +841,19 @@ void tr_comm_memb_free(TR_COMM_MEMB *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) @@ -826,6 +941,8 @@ json_t *tr_comm_memb_get_provenance(TR_COMM_MEMB *memb) void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov) { + const char *s=NULL; + if (memb->provenance) json_decref(memb->provenance); @@ -835,7 +952,11 @@ void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov) /* 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); } @@ -901,16 +1022,33 @@ int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime) &&(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) { @@ -943,7 +1081,10 @@ void tr_comm_table_add_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *new) { 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) { @@ -997,7 +1138,7 @@ void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb) /* 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; @@ -1006,10 +1147,10 @@ void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb) } /* 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; } @@ -1019,26 +1160,34 @@ void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb) 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); @@ -1169,6 +1318,8 @@ TR_COMM *tr_comm_table_find_comm(TR_COMM_TABLE *ctab, TR_NAME *comm_id) 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) @@ -1176,6 +1327,41 @@ 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) { @@ -1188,6 +1374,14 @@ 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) { @@ -1210,3 +1404,24 @@ TR_REALM_ROLE tr_realm_role_from_str(const char *s) 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"); + } +} diff --git a/common/tr_config.c b/common/tr_config.c index b07c8dd..bbbda1a 100644 --- a/common/tr_config.c +++ b/common/tr_config.c @@ -1635,7 +1635,7 @@ static void tr_cfg_parse_comm_idps(TR_CFG *trc, json_t *jidps, TR_COMM *comm, TR *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; @@ -1698,8 +1698,9 @@ static void tr_cfg_parse_comm_rps(TR_CFG *trc, json_t *jrps, TR_COMM *comm, TR_C 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); } } diff --git a/common/tr_idp.c b/common/tr_idp.c index 3019ef6..bcbbd8d 100644 --- a/common/tr_idp.c +++ b/common/tr_idp.c @@ -198,6 +198,37 @@ TR_IDP_REALM *tr_idp_realm_add_func(TR_IDP_REALM *head, TR_IDP_REALM *new) 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; @@ -308,3 +339,35 @@ void tr_idp_realm_decref(TR_IDP_REALM *realm) 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; +} + diff --git a/common/tr_msg.c b/common/tr_msg.c index 48965e5..ac57ebb 100644 --- a/common/tr_msg.c +++ b/common/tr_msg.c @@ -807,29 +807,37 @@ static TRP_RC tr_msg_decode_trp_inforec_comm(json_t *jrecord, TRP_INFOREC *rec) } 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); diff --git a/common/tr_rp.c b/common/tr_rp.c index 9a056c0..94a6360 100644 --- a/common/tr_rp.c +++ b/common/tr_rp.c @@ -193,6 +193,37 @@ TR_RP_REALM *tr_rp_realm_add_func(TR_RP_REALM *head, TR_RP_REALM *new) 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++; @@ -204,6 +235,37 @@ void tr_rp_realm_decref(TR_RP_REALM *realm) 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) diff --git a/include/tr_comm.h b/include/tr_comm.h index 4d47eaf..5f4b4ae 100644 --- a/include/tr_comm.h +++ b/include/tr_comm.h @@ -35,6 +35,7 @@ #ifndef TR_COMM_H #define TR_COMM_H +#include #include #include @@ -72,6 +73,7 @@ typedef struct tr_comm_memb { 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; @@ -99,6 +101,7 @@ typedef struct tr_realm { 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; @@ -109,8 +112,15 @@ void tr_comm_table_free(TR_COMM_TABLE *ctab); 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); @@ -121,14 +131,17 @@ TR_COMM_MEMB *tr_comm_table_find_idp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *i 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); @@ -142,8 +155,11 @@ unsigned int tr_comm_memb_get_interval(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); @@ -160,8 +176,8 @@ TR_NAME *tr_comm_dup_owner_realm(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); @@ -198,6 +214,10 @@ TR_IDP_REALM *tr_idp_realm_iter_next(TR_COMM_ITER *iter); 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); diff --git a/include/tr_idp.h b/include/tr_idp.h index aa407b8..361439c 100644 --- a/include/tr_idp.h +++ b/include/tr_idp.h @@ -75,6 +75,10 @@ TR_APC *tr_idp_realm_get_apcs(TR_IDP_REALM *idp); 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); diff --git a/include/tr_rp.h b/include/tr_rp.h index 1fa48d7..7e8f8f0 100644 --- a/include/tr_rp.h +++ b/include/tr_rp.h @@ -71,6 +71,10 @@ void tr_rp_realm_set_id(TR_RP_REALM *rp, TR_NAME *id); 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); diff --git a/include/trp_internal.h b/include/trp_internal.h index ac7e3ee..eb89692 100644 --- a/include/trp_internal.h +++ b/include/trp_internal.h @@ -245,6 +245,7 @@ TRP_ROUTE *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR 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); diff --git a/tr/tr_trp.c b/tr/tr_trp.c index b2b570f..a3b32b4 100644 --- a/tr/tr_trp.c +++ b/tr/tr_trp.c @@ -328,6 +328,8 @@ static void tr_trps_sweep(int listener, short event, void *arg) 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)); diff --git a/trp/trps.c b/trp/trps.c index e7703e3..9b1bfa4 100644 --- a/trp/trps.c +++ b/trp/trps.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -906,10 +907,10 @@ static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_IN * 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, @@ -927,10 +928,10 @@ static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_IN * 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, @@ -1140,6 +1141,88 @@ TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps) 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) { @@ -1347,7 +1430,7 @@ static TRP_INFOREC *trps_memb_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trp 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; }