From: Jennifer Richards Date: Wed, 19 Oct 2016 19:57:12 +0000 (-0400) Subject: Gather/send community updates. Refactoring. Builds, not tested. X-Git-Tag: v2.1.1~30 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=commitdiff_plain;h=f4fa9a7584189324cff981ccf965802b4c69ddda Gather/send community updates. Refactoring. Builds, not tested. --- diff --git a/common/tr_apc.c b/common/tr_apc.c index 06229e6..bb37a10 100644 --- a/common/tr_apc.c +++ b/common/tr_apc.c @@ -88,10 +88,36 @@ TR_APC *tr_apc_add_func(TR_APC *head, TR_APC *new) } /* does not copy next pointer */ -TR_APC *tr_apc_dup(TALLOC_CTX *mem_ctx, TR_APC *apc) +TR_APC *tr_apc_dup_one(TALLOC_CTX *mem_ctx, TR_APC *apc) { TR_APC *new=tr_apc_new(mem_ctx); - tr_apc_set_id(new, tr_apc_dup_id(apc)); + if (new!=NULL) + tr_apc_set_id(new, tr_apc_dup_id(apc)); + return new; +} + +/* copies next pointer */ +TR_APC *tr_apc_dup(TALLOC_CTX *mem_ctx, TR_APC *apc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_APC *cur=NULL; + TR_APC *new=tr_apc_dup(tmp_ctx, apc); + + if (new==NULL) + return NULL; + + for (cur=new,apc=apc->next; apc!=NULL; cur=cur->next,apc=apc->next) { + cur->next=tr_apc_dup_one(new, apc); + if (cur->next==NULL) { + new=NULL; + goto cleanup; + } + } + + talloc_steal(mem_ctx, new); + +cleanup: + talloc_free(tmp_ctx); return new; } diff --git a/common/tr_comm.c b/common/tr_comm.c index 1d97f2f..2dd637a 100644 --- a/common/tr_comm.c +++ b/common/tr_comm.c @@ -201,10 +201,10 @@ void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab, tr_comm_memb_set_provenance(newmemb, provenance); tr_comm_memb_set_expiry(newmemb, expiry); - existing=tr_comm_table_find_idp_memb(ctab, - tr_idp_realm_get_id(realm), - tr_comm_get_id(comm), - tr_comm_memb_get_origin(newmemb)); + 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); } @@ -231,10 +231,10 @@ void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab, tr_comm_memb_set_provenance(newmemb, provenance); tr_comm_memb_set_expiry(newmemb, expiry); - existing=tr_comm_table_find_rp_memb(ctab, - tr_rp_realm_get_id(realm), - tr_comm_get_id(comm), - tr_comm_memb_get_origin(newmemb)); + existing=tr_comm_table_find_rp_memb_origin(ctab, + tr_rp_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); } @@ -351,8 +351,10 @@ TR_COMM_ITER *tr_comm_iter_new(TALLOC_CTX *mem_ctx) { TR_COMM_ITER *iter=talloc(mem_ctx, TR_COMM_ITER); if (iter!=NULL) { + iter->cur_comm=NULL; iter->cur_memb=NULL; iter->match=NULL; + iter->realm=NULL; } return iter; } @@ -444,6 +446,129 @@ TR_COMM *tr_comm_iter_next_idp(TR_COMM_ITER *iter) return NULL; } +static TR_REALM *tr_realm_new(TALLOC_CTX *mem_ctx) +{ + TR_REALM *realm=talloc(mem_ctx, TR_REALM); + if (realm!=NULL) { + realm->role=TR_ROLE_UNKNOWN; + realm->rp=NULL; + realm->idp=NULL; + } + return realm; +} + +static void tr_realm_free(TR_REALM *realm) +{ + talloc_free(realm); +} + +static void tr_realm_set_rp(TR_REALM *realm, TR_RP_REALM *rp) +{ + if (realm->rp!=NULL) + talloc_free(realm->rp); + if (realm->idp!=NULL) { + talloc_free(realm->idp); + realm->idp=NULL; + } + realm->role=TR_ROLE_RP; + realm->rp=rp; +} + +static void tr_realm_set_idp(TR_REALM *realm, TR_IDP_REALM *idp) +{ + if (realm->idp!=NULL) + talloc_free(realm->idp); + if (realm->rp!=NULL) { + talloc_free(realm->rp); + realm->rp=NULL; + } + realm->role=TR_ROLE_IDP; + realm->idp=idp; +} + +TR_NAME *tr_realm_get_id(TR_REALM *realm) +{ + switch (realm->role) { + case TR_ROLE_RP: + return tr_rp_realm_get_id(realm->rp); + case TR_ROLE_IDP: + return tr_idp_realm_get_id(realm->idp); + default: + break; + } + return NULL; +} + +TR_NAME *tr_realm_dup_id(TR_REALM *realm) +{ + return tr_dup_name(tr_realm_get_id(realm)); +} + +/* Iterate over either sort of realm. Do not free the TR_REALM returned. It becomes + * undefined/invalid after the next operation affecting the iterator. */ +TR_REALM *tr_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm) +{ + iter->match=comm; + if (iter->realm==NULL) + iter->realm=tr_realm_new(iter); + if (iter->realm==NULL) + return NULL; + + /* find memberships for this comm */ + for (iter->cur_memb=ctab->memberships; + iter->cur_memb!=NULL; + iter->cur_memb=iter->cur_memb->next) { + if (0==tr_name_cmp(iter->match, + tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))) { + /* found a match, determine whether it's an rp realm or an idp realm */ + if (tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) + tr_realm_set_rp(iter->realm, tr_comm_memb_get_rp_realm(iter->cur_memb)); + else if (tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) + tr_realm_set_idp(iter->realm, tr_comm_memb_get_idp_realm(iter->cur_memb)); + else { + if (iter->realm!=NULL) + tr_realm_free(iter->realm); + iter->realm=NULL; + } + return iter->realm; + } + } + if (iter->realm!=NULL) + tr_realm_free(iter->realm); + iter->realm=NULL; + return NULL; +} + +TR_REALM *tr_realm_iter_next(TR_COMM_ITER *iter) +{ + if (iter->realm==NULL) + return NULL; + + /* find memberships for this comm */ + for (iter->cur_memb=iter->cur_memb->next; + iter->cur_memb!=NULL; + iter->cur_memb=iter->cur_memb->next) { + if (0==tr_name_cmp(iter->match, + tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))) { + /* found a match, determine whether it's an rp realm or an idp realm */ + if (tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) + tr_realm_set_rp(iter->realm, tr_comm_memb_get_rp_realm(iter->cur_memb)); + else if (tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) + tr_realm_set_idp(iter->realm, tr_comm_memb_get_idp_realm(iter->cur_memb)); + else { + if (iter->realm!=NULL) + tr_realm_free(iter->realm); + iter->realm=NULL; + } + return iter->realm; + } + } + if (iter->realm!=NULL) + tr_realm_free(iter->realm); + iter->realm=NULL; + return NULL; +} + TR_RP_REALM *tr_rp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm) { iter->match=comm; @@ -498,6 +623,18 @@ TR_IDP_REALM *tr_idp_realm_iter_next(TR_COMM_ITER *iter) return NULL; } +/* iterators for all communities in a table */ +TR_COMM *tr_comm_table_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab) +{ + iter->cur_comm=ctab->comms; + return iter->cur_comm; +} + +TR_COMM *tr_comm_table_iter_next(TR_COMM_ITER *iter) +{ + return iter->cur_comm=iter->cur_comm->next; +} + const char *tr_comm_type_to_str(TR_COMM_TYPE type) { const char *s=NULL; @@ -517,6 +654,19 @@ const char *tr_comm_type_to_str(TR_COMM_TYPE type) return s; } +TR_COMM_MEMB *tr_comm_memb_iter_first(TR_COMM_ITER *iter, TR_COMM_MEMB *memb) +{ + iter->cur_memb=memb; + return iter->cur_memb; +} + +TR_COMM_MEMB *tr_comm_memb_iter_next(TR_COMM_ITER *iter) +{ + if (iter->cur_memb!=NULL) + 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) @@ -554,6 +704,7 @@ TR_COMM_MEMB *tr_comm_memb_new(TALLOC_CTX *mem_ctx) memb->comm=NULL; memb->origin=NULL; memb->provenance=NULL; + memb->interval=0; memb->expiry=NULL; talloc_set_destructor(memb, tr_comm_memb_destructor); } @@ -565,6 +716,15 @@ void tr_comm_memb_free(TR_COMM_MEMB *memb) talloc_free(memb); } +TR_REALM_ROLE tr_comm_memb_get_role(TR_COMM_MEMB *memb) +{ + if (memb->rp!=NULL) + return TR_ROLE_RP; + if (memb->idp!=NULL) + return TR_ROLE_IDP; + return TR_ROLE_UNKNOWN; +} + void tr_comm_memb_set_rp_realm(TR_COMM_MEMB *memb, TR_RP_REALM *realm) { if (memb->idp!=NULL) { @@ -634,6 +794,13 @@ TR_NAME *tr_comm_memb_dup_origin(TR_COMM_MEMB *memb) return NULL; } +json_t *tr_comm_memb_get_provenance(TR_COMM_MEMB *memb) +{ + if (memb!=NULL) + return memb->provenance; + return NULL; +} + void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov) { if (memb->provenance) @@ -679,6 +846,16 @@ size_t tr_comm_memb_provenance_len(TR_COMM_MEMB *memb) return json_array_size(memb->provenance); } +void tr_comm_memb_set_interval(TR_COMM_MEMB *memb, unsigned int interval) +{ + memb->interval=interval; +} + +unsigned int tr_comm_memb_get_interval(TR_COMM_MEMB *memb) +{ + return memb->interval; +} + void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time) { memb->expiry=time; @@ -711,35 +888,108 @@ void tr_comm_table_free(TR_COMM_TABLE *ctab) talloc_free(ctab); } +static TR_REALM_ROLE tr_comm_memb_role(TR_COMM_MEMB *memb) +{ + if (memb->rp!=NULL) + return TR_ROLE_RP; + if (memb->idp!=NULL) + return TR_ROLE_IDP; + + return TR_ROLE_UNKNOWN; +} + void tr_comm_table_add_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *new) { TR_COMM_MEMB *cur=NULL; + /* handle the empty list case */ if (ctab->memberships==NULL) { ctab->memberships=new; talloc_steal(ctab, new); - } else { + return; + } + + /* The list was not empty. See if we already have a membership for this realm/comm/role */ + switch (tr_comm_memb_role(new)) { + case TR_ROLE_RP: + cur=tr_comm_table_find_rp_memb(ctab, + tr_rp_realm_get_id(tr_comm_memb_get_rp_realm(new)), + tr_comm_get_id(tr_comm_memb_get_comm(new))); + break; + case TR_ROLE_IDP: + cur=tr_comm_table_find_idp_memb(ctab, + tr_idp_realm_get_id(tr_comm_memb_get_idp_realm(new)), + tr_comm_get_id(tr_comm_memb_get_comm(new))); + break; + case TR_ROLE_UNKNOWN: + default: + tr_err("tr_comm_table_add_memb: realm with unknown role added."); + cur=NULL; + } + + if (cur==NULL) { + /* no entry for this realm/comm/role, tack it on the end */ for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) { } cur->next=new; + } else { + /* Found an entry. Add to the end of its same-origin list. */ + while (cur->origin_next!=NULL) { + cur=cur->origin_next; + } + cur->origin_next=new; } + talloc_steal(ctab, new); } /* Remove memb from ctab. Do not free anything. Do nothing if memb not in ctab. */ void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb) { - TR_COMM_MEMB *cur=NULL; + TR_COMM_MEMB *cur=NULL; /* for walking the main list */ + TR_COMM_MEMB *orig_cur=NULL; /* for walking the origin list */ - if ((memb==NULL) || (ctab->memberships==NULL)) { + if ((memb==NULL) || (ctab->memberships==NULL)) return; - } else if (ctab->memberships==memb) { - ctab->memberships=memb->next; + + /* see if it's the first member */ + if (ctab->memberships==memb) { + if (memb->origin_next!=NULL) { + memb->origin_next->next=ctab->memberships->next; + ctab->memberships=memb->origin_next; + } else + ctab->memberships=memb->next; + return; - } else { - for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) { - if (cur->next==memb) { - cur->next=memb->next; - return; + } + + /* 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) { + orig_cur->origin_next=memb->origin_next; + return; + } + } + + /* now we have to walk the rest of the tree */ + 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) { + /* 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; + return; /* just drop the element from the origin list */ + } } } } @@ -753,7 +1003,8 @@ static TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb) return tr_idp_realm_get_id(memb->idp); } -TR_COMM_MEMB *tr_comm_table_find_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin) +/* find a membership from any origin */ +TR_COMM_MEMB *tr_comm_table_find_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm) { TR_COMM_MEMB *cur=NULL; TR_NAME *cur_realm_name=NULL; @@ -765,15 +1016,34 @@ TR_COMM_MEMB *tr_comm_table_find_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NA continue; } if ((0==tr_name_cmp(realm, cur_realm_name)) && - (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur)))) && - (0==tr_name_cmp(origin, tr_comm_memb_get_origin(cur)))) { + (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) { return cur; } } return NULL; } -TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin) +/* find a membership from a particular origin */ +TR_COMM_MEMB *tr_comm_table_find_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin) +{ + TR_NAME *cur_orig=NULL; + TR_COMM_MEMB *cur=tr_comm_table_find_memb(ctab, realm, comm); + if (cur==NULL) + return NULL; /* no match */ + + /* had a match for comm/realm; find origin match */ + while (cur!=NULL) { + if (((origin==NULL) && (cur_orig==NULL)) || + ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig)))) + return cur; /* found a match */ + cur=cur->origin_next; + } + return NULL; /* no match */ +} + + +/* find an idp membership regardless of its origin */ +TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm) { TR_COMM_MEMB *cur=NULL; TR_IDP_REALM *idp_realm=NULL; @@ -784,15 +1054,34 @@ TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, T continue; /* was not an idp */ if ((0==tr_name_cmp(realm, idp_realm->realm_id)) && - (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur)))) && - (0==tr_name_cmp(origin, tr_comm_memb_get_origin(cur)))) { + (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) { return cur; } } return NULL; } -TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin) +/* find an idp membership from a particular origin */ +TR_COMM_MEMB *tr_comm_table_find_idp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin) +{ + TR_NAME *cur_orig=NULL; + TR_COMM_MEMB *cur=tr_comm_table_find_idp_memb(ctab, realm, comm); + if (cur==NULL) + return NULL; /* no match */ + + /* had a match for comm/realm; find origin match */ + while (cur!=NULL) { + cur_orig=tr_comm_memb_get_origin(cur); + if (((origin==NULL) && (cur_orig==NULL)) || + ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig)))) + return cur; /* found a match */ + cur=cur->origin_next; + } + return NULL; /* no match */ +} + +/* find an rp membership from any origin */ +TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm) { TR_COMM_MEMB *cur=NULL; TR_RP_REALM *rp_realm=NULL; @@ -803,15 +1092,32 @@ TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR continue; /* was not an rp */ if ((0==tr_name_cmp(realm, tr_rp_realm_get_id(rp_realm))) && - (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur)))) && - (((NULL==origin)&&(NULL==tr_comm_memb_get_origin(cur))) || - (0==tr_name_cmp(origin, tr_comm_memb_get_origin(cur))))) { + (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) { return cur; } } return NULL; } +/* find an rp membership from a particular origin */ +TR_COMM_MEMB *tr_comm_table_find_rp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin) +{ + TR_NAME *cur_orig=NULL; + TR_COMM_MEMB *cur=tr_comm_table_find_rp_memb(ctab, realm, comm); + if (cur==NULL) + return NULL; /* no match */ + + /* had a match for comm/realm; find origin match */ + while (cur!=NULL) { + cur_orig=tr_comm_memb_get_origin(cur); + if (((origin==NULL) && (cur_orig==NULL)) || + ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig)))) + return cur; /* found a match */ + cur=cur->origin_next; + } + return NULL; /* no match */ +} + TR_COMM *tr_comm_table_find_comm(TR_COMM_TABLE *ctab, TR_NAME *comm_id) { return tr_comm_lookup(ctab->comms, comm_id); diff --git a/common/tr_idp.c b/common/tr_idp.c index 6579253..0c2a0c6 100644 --- a/common/tr_idp.c +++ b/common/tr_idp.c @@ -127,9 +127,20 @@ void tr_idp_realm_free(TR_IDP_REALM *idp) TR_NAME *tr_idp_realm_get_id(TR_IDP_REALM *idp) { + if (idp==NULL) + return NULL; + return idp->realm_id; } +TR_NAME *tr_idp_realm_dup_id(TR_IDP_REALM *idp) +{ + if (idp==NULL) + return NULL; + + return tr_dup_name(tr_idp_realm_get_id(idp)); +} + void tr_idp_realm_set_id(TR_IDP_REALM *idp, TR_NAME *id) { if (idp->realm_id!=NULL) diff --git a/common/tr_rp.c b/common/tr_rp.c index e6500c0..9a056c0 100644 --- a/common/tr_rp.c +++ b/common/tr_rp.c @@ -206,9 +206,20 @@ void tr_rp_realm_decref(TR_RP_REALM *realm) TR_NAME *tr_rp_realm_get_id(TR_RP_REALM *rp) { + if (rp==NULL) + return NULL; + return rp->realm_id; } +TR_NAME *tr_rp_realm_dup_id(TR_RP_REALM *rp) +{ + if (rp==NULL) + return NULL; + + return tr_dup_name(tr_rp_realm_get_id(rp)); +} + void tr_rp_realm_set_id(TR_RP_REALM *rp, TR_NAME *id) { if (rp->realm_id!=NULL) diff --git a/include/tr_apc.h b/include/tr_apc.h index 54ab7e1..2919f86 100644 --- a/include/tr_apc.h +++ b/include/tr_apc.h @@ -52,6 +52,7 @@ TR_APC *tr_apc_new(TALLOC_CTX *mem_ctx); void tr_apc_free(TR_APC *apc); TR_APC *tr_apc_add_func(TR_APC *apcs, TR_APC *new); #define tr_apc_add(apcs,new) ((apcs)=tr_apc_add_func((apcs),(new))) +TR_APC *tr_apc_dup_one(TALLOC_CTX *mem_ctx, TR_APC *apc); TR_APC *tr_apc_dup(TALLOC_CTX *mem_ctx, TR_APC *apc); void tr_apc_set_id(TR_APC *apc, TR_NAME *id); diff --git a/include/tr_comm.h b/include/tr_comm.h index a660435..fae2c82 100644 --- a/include/tr_comm.h +++ b/include/tr_comm.h @@ -64,11 +64,13 @@ typedef struct tr_comm { /* community membership - link realms to their communities */ typedef struct tr_comm_memb { struct tr_comm_memb *next; + struct tr_comm_memb *origin_next; /* for multiple copies from different origins */ TR_IDP_REALM *idp; /* only set one of idp and rp, other null */ TR_RP_REALM *rp; /* only set one of idp and rp, other null */ TR_COMM *comm; TR_NAME *origin; json_t *provenance; /* array of names of systems traversed */ + unsigned int interval; struct timespec *expiry; } TR_COMM_MEMB; @@ -78,17 +80,25 @@ struct tr_comm_table { TR_COMM_MEMB *memberships; /* head of the linked list of membership records */ }; -typedef struct tr_comm_iter { - TR_COMM_MEMB *cur_memb; - TR_NAME *match; /* realm or comm to match */ -} TR_COMM_ITER; - typedef enum tr_realm_role { TR_ROLE_UNKNOWN=0, TR_ROLE_IDP, TR_ROLE_RP } TR_REALM_ROLE; +typedef struct tr_realm { + TR_REALM_ROLE role; + TR_RP_REALM *rp; + TR_IDP_REALM *idp; +} TR_REALM; + +/* nb, not all iterator routines use all members */ +typedef struct tr_comm_iter { + TR_COMM *cur_comm; + TR_COMM_MEMB *cur_memb; + 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); @@ -100,14 +110,18 @@ 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); 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(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin); -TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *rp_realm, TR_NAME *comm, TR_NAME *origin); /* TODO ?? */ -TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *idp_realm, TR_NAME *comm, TR_NAME *origin); /* TODO ?? */ +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_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm); +TR_COMM_MEMB *tr_comm_table_find_rp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *rp_realm, TR_NAME *comm, TR_NAME *origin); +TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *rp_realm, TR_NAME *comm); +TR_COMM_MEMB *tr_comm_table_find_idp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *idp_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); TR_COMM_MEMB *tr_comm_memb_new(TALLOC_CTX *mem_ctx); void tr_comm_memb_free(TR_COMM_MEMB *memb); +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); @@ -116,9 +130,12 @@ 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); TR_NAME *tr_comm_memb_dup_origin(TR_COMM_MEMB *memb); +json_t *tr_comm_memb_get_provenance(TR_COMM_MEMB *memb); void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov); void tr_comm_memb_add_to_provenance(TR_COMM_MEMB *memb, TR_NAME *hop); size_t tr_comm_memb_provenance_len(TR_COMM_MEMB *memb); +void tr_comm_memb_set_interval(TR_COMM_MEMB *memb, unsigned int interval); +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); @@ -151,6 +168,10 @@ unsigned int tr_comm_get_refcount(TR_COMM *comm); TR_COMM_ITER *tr_comm_iter_new(TALLOC_CTX *mem_ctx); void tr_comm_iter_free(TR_COMM_ITER *iter); +/* iterate over all communities in a table */ +TR_COMM *tr_comm_table_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab); +TR_COMM *tr_comm_table_iter_next(TR_COMM_ITER *); + /* these iterate over communities for a realm */ TR_COMM *tr_comm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm); TR_COMM *tr_comm_iter_next(TR_COMM_ITER *iter); @@ -160,11 +181,21 @@ TR_COMM *tr_comm_iter_first_idp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME TR_COMM *tr_comm_iter_next_idp(TR_COMM_ITER *iter); /* iterate over realms for a community */ +TR_REALM *tr_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm); +TR_REALM *tr_realm_iter_next(TR_COMM_ITER *iter); TR_RP_REALM *tr_rp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm); TR_RP_REALM *tr_rp_realm_iter_next(TR_COMM_ITER *iter); TR_IDP_REALM *tr_idp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm); TR_IDP_REALM *tr_idp_realm_iter_next(TR_COMM_ITER *iter); +/* iterate over members with different origins */ +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); + +/* general realm stuff, should probably move */ +TR_NAME *tr_realm_get_id(TR_REALM *realm); +TR_NAME *tr_realm_dup_id(TR_REALM *realm); + const char *tr_realm_role_to_str(TR_REALM_ROLE role); TR_REALM_ROLE tr_realm_role_from_str(const char *s); diff --git a/include/tr_idp.h b/include/tr_idp.h index 5a6727e..1a5dfff 100644 --- a/include/tr_idp.h +++ b/include/tr_idp.h @@ -70,6 +70,7 @@ typedef struct tr_idp_realm { TR_IDP_REALM *tr_idp_realm_new(TALLOC_CTX *mem_ctx); void tr_idp_realm_free(TR_IDP_REALM *idp); TR_NAME *tr_idp_realm_get_id(TR_IDP_REALM *idp); +TR_NAME *tr_idp_realm_dup_id(TR_IDP_REALM *idp); void tr_idp_realm_set_id(TR_IDP_REALM *idp, TR_NAME *id); 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))) diff --git a/include/tr_rp.h b/include/tr_rp.h index 92e8a04..1fa48d7 100644 --- a/include/tr_rp.h +++ b/include/tr_rp.h @@ -66,6 +66,7 @@ TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name); TR_RP_REALM *tr_rp_realm_new(TALLOC_CTX *mem_ctx); void tr_rp_realm_free(TR_RP_REALM *rp); TR_NAME *tr_rp_realm_get_id(TR_RP_REALM *rp); +TR_NAME *tr_rp_realm_dup_id(TR_RP_REALM *rp); 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); diff --git a/trp/trps.c b/trp/trps.c index 04536bc..674af3d 100644 --- a/trp/trps.c +++ b/trp/trps.c @@ -853,6 +853,90 @@ TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps) return TRP_SUCCESS; } +/* add metrics */ +static unsigned int trps_metric_add(unsigned int m1, unsigned int m2) +{ + if (trp_metric_is_invalid(m1) || trp_metric_is_invalid(m2)) + return TRP_METRIC_INVALID; + + if (trp_metric_is_infinite(m1) || trp_metric_is_infinite(m2)) + return TRP_METRIC_INFINITY; + + if (trp_metric_is_finite(m1+m2)) + return m1+m2; + else + return TRP_METRIC_INFINITY; +} + +/* convert an rentry into a new trp update info record */ +static TRP_INFOREC *trps_route_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TRP_ROUTE *route) +{ + TRP_INFOREC *rec=trp_inforec_new(mem_ctx, TRP_INFOREC_TYPE_ROUTE); + unsigned int linkcost=0; + + if (rec!=NULL) { + if (trp_route_is_local(route)) + linkcost=0; + else { + linkcost=trp_peer_get_linkcost(trps_get_peer_by_gssname(trps, + trp_route_get_peer(route))); + } + + /* Note that we leave the next hop empty since the recipient fills that in. + * This is where we add the link cost (currently always 1) to the next peer. */ + if ((trp_inforec_set_trust_router(rec, trp_route_dup_trust_router(route)) != TRP_SUCCESS) + ||(trp_inforec_set_metric(rec, + trps_metric_add(trp_route_get_metric(route), + linkcost)) != TRP_SUCCESS) + ||(trp_inforec_set_interval(rec, trps_get_update_interval(trps)) != TRP_SUCCESS)) { + tr_err("trps_route_to_inforec: error creating route update."); + talloc_free(rec); + rec=NULL; + } + } + return rec; +} + +static TRP_UPD *trps_route_to_upd(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TRP_ROUTE *route) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TRP_UPD *upd=trp_upd_new(tmp_ctx); + TRP_INFOREC *rec=NULL; + + if (upd==NULL) { + tr_err("trps_route_to_upd: could not create update message."); + goto cleanup; + } + trp_upd_set_realm(upd, trp_route_dup_realm(route)); + if (trp_upd_get_realm(upd)==NULL) { + tr_err("trps_route_to_upd: could not copy realm."); + upd=NULL; /* it's still in tmp_ctx, so it will be freed */ + goto cleanup; + } + trp_upd_set_comm(upd, trp_route_dup_comm(route)); + if (trp_upd_get_comm(upd)==NULL) { + tr_err("trps_route_to_upd: could not copy comm."); + upd=NULL; /* it's still in tmp_ctx, so it will be freed */ + goto cleanup; + } + rec=trps_route_to_inforec(tmp_ctx, trps, route); + if (rec==NULL) { + tr_err("trps_route_to_upd: could not create route info record for realm %.*s in comm %.*s.", + trp_route_get_realm(route)->len, trp_route_get_realm(route)->buf, + trp_route_get_comm(route)->len, trp_route_get_comm(route)->buf); + upd=NULL; /* it's till in tmp_ctx, so it will be freed */ + goto cleanup; + } + trp_upd_add_inforec(upd, rec); + + /* sucess */ + talloc_steal(mem_ctx, upd); + +cleanup: + talloc_free(tmp_ctx); + return upd; +} + /* select the correct route to comm/realm to be announced to peer */ static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer_gssname) { @@ -878,10 +962,9 @@ static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, T return route; } -/* Adds inforecs for route updates to the updates Garray. If it fails, it may leave - * some inforecs in the list. Caller needs to arrange for these to be freed. */ +/* Add TRP_UPD msgs to the updates GPtrArray. Caller needs to arrange for these to be freed. */ static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx, - GArray *updates, + GPtrArray *updates, TRPS_INSTANCE *trps, TR_NAME *peer_gssname, int triggered) @@ -892,6 +975,7 @@ static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx, size_t n_realm=0; size_t ii=0, jj=0; TRP_ROUTE *best=NULL; + TRP_UPD *upd=NULL; if (updates==NULL) return TRP_BADARG; @@ -902,9 +986,16 @@ static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx, best=trps_select_realm_update(trps, comm[ii], realm[jj], peer_gssname); /* If we found a route, add it to the list. If triggered!=0, then only * add triggered routes. */ - if ((best!=NULL) && ((!triggered) || trp_route_is_triggered(best))) - g_array_append_val(updates, best); + if ((best!=NULL) && ((!triggered) || trp_route_is_triggered(best))) { + upd=trps_route_to_upd(mem_ctx, trps, best); + if (upd==NULL) { + tr_err("trps_select_route_updates_for_peer: unable to create update message."); + continue; + } + g_ptr_array_add(updates, upd); + } } + if (realm!=NULL) talloc_free(realm); realm=NULL; @@ -917,71 +1008,184 @@ static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx, return TRP_SUCCESS; } -/* add metrics */ -static unsigned int trps_metric_add(unsigned int m1, unsigned int m2) +static TRP_INFOREC *trps_memb_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TR_COMM_MEMB *memb) { - if (trp_metric_is_invalid(m1) || trp_metric_is_invalid(m2)) - return TRP_METRIC_INVALID; + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TRP_INFOREC *rec=NULL; + TR_COMM *comm=NULL; - if (trp_metric_is_infinite(m1) || trp_metric_is_infinite(m2)) - return TRP_METRIC_INFINITY; + if (memb==NULL) + goto cleanup; - if (trp_metric_is_finite(m1+m2)) - return m1+m2; - else - return TRP_METRIC_INFINITY; + comm=tr_comm_memb_get_comm(memb); + rec=trp_inforec_new(tmp_ctx, TRP_INFOREC_TYPE_COMMUNITY); + if (rec==NULL) + goto cleanup; + + if (TRP_SUCCESS!=trp_inforec_set_comm_type(rec, tr_comm_get_type(comm))) { + rec=NULL; + goto cleanup; + } + + if (TRP_SUCCESS!=trp_inforec_set_role(rec, tr_comm_memb_get_role(memb))) { + rec=NULL; + goto cleanup; + } + + if ((TRP_SUCCESS!=trp_inforec_set_apcs(rec, + tr_apc_dup(rec, tr_comm_get_apcs(comm)))) || + (NULL==trp_inforec_get_apcs(rec))) { + rec=NULL; + goto cleanup; + } + + if ((NULL!=tr_comm_get_owner_realm(comm)) && + ( (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_dup_name(tr_comm_get_owner_realm(comm)))) || + (NULL==trp_inforec_get_owner_realm(rec)))) { + rec=NULL; + goto cleanup; + } + + if ((NULL!=tr_comm_get_owner_contact(comm)) && + ( (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_dup_name(tr_comm_get_owner_contact(comm)))) || + (NULL==trp_inforec_get_owner_contact(rec)))) { + rec=NULL; + goto cleanup; + } + + if ((NULL!=tr_comm_memb_get_provenance(memb)) && + (TRP_SUCCESS!=trp_inforec_set_provenance(rec, tr_comm_memb_get_provenance(memb)))) { + rec=NULL; + goto cleanup; + } + + if (TRP_SUCCESS!=trp_inforec_set_interval(rec, tr_comm_memb_get_interval(memb))) { + rec=NULL; + goto cleanup; + } + + /* success! */ + talloc_steal(mem_ctx, rec); + +cleanup: + talloc_free(tmp_ctx); + return rec; } -/* Every realm has a community, so always returns at least one record except on error. */ -static TRP_INFOREC *trps_comm_inforecs_for_realm(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TR_NAME *comm_name, TR_NAME *realm) +/* construct an update with all the inforecs for comm/realm/role to be sent to peer */ +static TRP_UPD *trps_comm_update(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TR_NAME *peer_gssname, TR_COMM *comm, TR_REALM *realm) { TALLOC_CTX *tmp_ctx=talloc_new(NULL); -/* TRP_INFOREC *results=NULL;*/ -/* TRP_INFOREC *rec=NULL;*/ - TR_COMM *this_comm=NULL; - TR_COMM_ITER *comm_iter=NULL; + TRP_UPD *upd=trp_upd_new(tmp_ctx); + TRP_INFOREC *rec=NULL; + TR_COMM_ITER *iter=NULL; + TR_COMM_MEMB *memb=NULL; - comm_iter=tr_comm_iter_new(tmp_ctx); - for (this_comm=tr_comm_iter_first(comm_iter, trps->ctable, comm_name); - this_comm!=NULL; - this_comm=tr_comm_iter_next(comm_iter)) { - printf("dink"); + if (upd==NULL) + goto cleanup; + + trp_upd_set_comm(upd, tr_comm_dup_id(comm)); + trp_upd_set_realm(upd, tr_realm_dup_id(realm)); + /* leave peer empty */ + + iter=tr_comm_iter_new(tmp_ctx); + if (iter==NULL) { + tr_err("tr_comm_update: unable to allocate iterator."); + upd=NULL; + goto cleanup; } + + /* now add inforecs */ + switch (realm->role) { + case TR_ROLE_IDP: + memb=tr_comm_table_find_idp_memb(trps->ctable, + tr_realm_get_id(realm), + tr_comm_get_id(comm)); + break; + case TR_ROLE_RP: + memb=tr_comm_table_find_rp_memb(trps->ctable, + tr_realm_get_id(realm), + tr_comm_get_id(comm)); + break; + default: + break; + } + if (memb!=NULL) { + for (memb=tr_comm_memb_iter_first(iter, memb); + memb!=NULL; + memb=tr_comm_memb_iter_next(iter)) { + rec=trps_memb_to_inforec(tmp_ctx, trps, memb); + if (rec==NULL) { + tr_err("tr_comm_update: unable to allocate inforec."); + upd=NULL; + goto cleanup; + } + trp_upd_add_inforec(upd, rec); + } + } + + if (trp_upd_get_inforec(upd)==NULL) + upd=NULL; /* no inforecs, no reason to send the update */ + else + talloc_steal(mem_ctx, upd); /* success! */ +cleanup: talloc_free(tmp_ctx); - return NULL; + return upd; } -/* convert an rentry into a new trp update info record */ -static TRP_INFOREC *trps_route_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TRP_ROUTE *route) +/* Find all community updates to send to a peer and add these as TR_UPD records + * to the updates GPtrArray. */ +static TRP_RC trps_select_comm_updates_for_peer(TALLOC_CTX *mem_ctx, GPtrArray *updates, TRPS_INSTANCE *trps, TR_NAME *peer_gssname) { - TRP_INFOREC *rec=trp_inforec_new(mem_ctx, TRP_INFOREC_TYPE_ROUTE); - unsigned int linkcost=0; - - if (rec!=NULL) { - if (trp_route_is_local(route)) - linkcost=0; - else { - linkcost=trp_peer_get_linkcost(trps_get_peer_by_gssname(trps, - trp_route_get_peer(route))); - } + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_COMM_ITER *comm_iter=NULL; + TR_COMM *comm=NULL; + TR_COMM_ITER *realm_iter=NULL; + TR_REALM *realm=NULL; + TRP_UPD *upd=NULL; + TRP_RC rc=TRP_ERROR; + + comm_iter=tr_comm_iter_new(tmp_ctx); + realm_iter=tr_comm_iter_new(tmp_ctx); + if ((comm_iter==NULL) || (realm_iter==NULL)) { + tr_err("trps_select_comm_updates_for_peer: unable to allocate iterator."); + rc=TRP_NOMEM; + goto cleanup; + } - /* Note that we leave the next hop empty since the recipient fills that in. - * This is where we add the link cost (currently always 1) to the next peer. */ - if ((trp_inforec_set_trust_router(rec, trp_route_dup_trust_router(route)) != TRP_SUCCESS) - ||(trp_inforec_set_metric(rec, - trps_metric_add(trp_route_get_metric(route), - linkcost)) != TRP_SUCCESS) - ||(trp_inforec_set_interval(rec, trps_get_update_interval(trps)) != TRP_SUCCESS)) { - tr_err("trps_route_to_inforec: error creating route update."); - talloc_free(rec); - rec=NULL; + /* do every community */ + for (comm=tr_comm_table_iter_first(comm_iter, trps->ctable); + comm!=NULL; + comm=tr_comm_table_iter_next(comm_iter)) { + /* do every realm in this community */ + for (realm=tr_realm_iter_first(realm_iter, trps->ctable, tr_comm_get_id(comm)); + realm!=NULL; + realm=tr_realm_iter_next(realm_iter)) { + /* get the update for this comm/realm */ + upd=trps_comm_update(tmp_ctx, trps, peer_gssname, comm, realm); + if (upd!=NULL) { + g_ptr_array_add(updates, upd); + } } } - return rec; + + /* move anything needed into mem_ctx */ + + +cleanup: + talloc_free(tmp_ctx); + return rc; } -/* all routes to a single peer, unless comm/realm are specified (both or neither must be NULL) */ + +/* helper for trps_update_one_peer. Frees the TRP_UPD pointed to by a GPtrArray element */ +static void trps_trp_upd_destroy(gpointer data) +{ + trp_upd_free((TRP_UPD *)data); +} + +/* all routes/communities to a single peer, unless comm/realm are specified (both or neither must be NULL) */ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps, TRP_PEER *peer, TRP_UPDATE_TYPE update_type, @@ -991,13 +1195,18 @@ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps, TALLOC_CTX *tmp_ctx=talloc_new(NULL); TR_MSG msg; /* not a pointer! */ TRP_UPD *upd=NULL; - TRP_INFOREC *rec=NULL; TRP_ROUTE *route=NULL; size_t ii=0; char *encoded=NULL; TRP_RC rc=TRP_ERROR; TR_NAME *peer_label=trp_peer_get_label(peer); - GArray *updates=NULL; + GPtrArray *updates=g_ptr_array_new_with_free_func(trps_trp_upd_destroy); + + if (updates==NULL) { + tr_err("trps_update_one_peer: unable to allocate updates array."); + rc=TRP_NOMEM; + goto cleanup; + } switch (update_type) { case TRP_UPDATE_TRIGGERED: @@ -1011,14 +1220,14 @@ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps, case TRP_UPDATE_REQUESTED: tr_debug("trps_update_one_peer: preparing requested update for %.*s", peer_label->len, peer_label->buf); + break; + default: + tr_err("trps_update_one_peer: invalid update type requested."); + rc=TRP_BADARG; + goto cleanup; } - /* allocate updates array */ - updates=g_array_new(TRUE, FALSE, sizeof(TRP_ROUTE *)); - /* not setting the array to free entries when we free it, we will - * have to do that ourselves */ - - /* do not fill in peer, recipient does that */ + /* First, gather route updates. */ if ((comm==NULL) && (realm==NULL)) { /* do all realms */ rc=trps_select_route_updates_for_peer(tmp_ctx, @@ -1029,9 +1238,7 @@ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps, } else if ((comm!=NULL) && (realm!=NULL)) { /* a single community/realm was requested */ route=trps_select_realm_update(trps, comm, realm, peer_label); - if (route!=NULL) - g_array_append_val(updates, route); - else { + if (route==NULL) { /* we have no actual update to send back, MUST send a retraction */ tr_debug("trps_update_one_peer: community/realm without route requested, sending mandatory retraction."); route=trp_route_new(tmp_ctx); @@ -1041,60 +1248,29 @@ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps, trp_route_set_metric(route, TRP_METRIC_INFINITY); trp_route_set_trust_router(route, tr_new_name("")); trp_route_set_next_hop(route, tr_new_name("")); - g_array_append_val(updates, route); } + upd=trps_route_to_upd(tmp_ctx, trps, route); + if (upd==NULL) { + tr_err("trps_update_one_peer: unable to allocate route update."); + rc=TRP_NOMEM; + goto cleanup; + } + g_ptr_array_add(updates, upd); } else { tr_err("trps_update_one_peer: error: only comm or realm was specified. Need both or neither."); rc=TRP_ERROR; goto cleanup; } + /* Second, gather community updates */ + rc=trps_select_comm_updates_for_peer(tmp_ctx, updates, trps, peer_label); + /* see if we have anything to send */ if (updates->len<=0) tr_debug("trps_update_one_peer: no updates for %.*s", peer_label->len, peer_label->buf); else { tr_debug("trps_update_one_peer: sending %d update messages.", updates->len); - for (ii=0; NULL!=(route=g_array_index(updates, TRP_ROUTE *, ii)); ii++) { - upd=trp_upd_new(tmp_ctx); - if (upd==NULL) { - tr_err("trps_update_one_peer: could not create update message."); - rc=TRP_NOMEM; - goto cleanup; - } - trp_upd_set_realm(upd, trp_route_dup_realm(route)); - if (trp_upd_get_realm(upd)==NULL) { - tr_err("trps_update_one_peer: could not copy realm."); - rc=TRP_NOMEM; - goto cleanup; - } - trp_upd_set_comm(upd, trp_route_dup_comm(route)); - if (trp_upd_get_comm(upd)==NULL) { - tr_err("trps_update_one_peer: could not copy comm."); - rc=TRP_NOMEM; - goto cleanup; - } - rec=trps_route_to_inforec(tmp_ctx, trps, route); - if (rec==NULL) { - tr_err("trps_update_one_peer: could not create route info record for realm %.*s in comm %.*s.", - realm->len, realm->buf, - comm->len, comm->buf); - rc=TRP_NOMEM; - goto cleanup; - } - trp_upd_add_inforec(upd, rec); - - /* now add community info records */ - rec=trps_comm_inforecs_for_realm(tmp_ctx, - trps, - trp_route_get_comm(route), - trp_route_get_realm(route)); - if (rec==NULL) { - tr_err("trps_update_one_peer: could not create all update records."); - rc=TRP_NOMEM; - goto cleanup; - } - trp_upd_add_inforec(upd, rec); - + for (ii=0; NULL!=(upd=(TRP_UPD *)g_ptr_array_index(updates, ii)); ii++) { /* now encode the update message */ tr_msg_set_trp_upd(&msg, upd); encoded=tr_msg_encode(&msg); @@ -1112,15 +1288,14 @@ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps, tr_msg_free_encoded(encoded); encoded=NULL; - trp_upd_free(upd); - upd=NULL; } - g_array_free(updates, TRUE); } rc=TRP_SUCCESS; cleanup: + if (updates!=NULL) + g_ptr_array_free(updates, TRUE); /* frees any TRP_UPD records */ talloc_free(tmp_ctx); return rc; }