Support non-default TRP and TID ports
[trust_router.git] / trp / trp_upd.c
1 /*
2  * Copyright (c) 2016, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34
35 #include <strings.h>
36 #include <jansson.h>
37 #include <talloc.h>
38
39 #include <tr_name_internal.h>
40 #include <trp_internal.h>
41 #include <tr_comm.h>
42 #include <tr_apc.h>
43 #include <tr_debug.h>
44
45
46 /* static prototypes */
47 static TRP_INFOREC_DATA *trp_inforec_route_new(TALLOC_CTX *mem_ctx);
48 static void trp_inforec_route_print(TRP_INFOREC_DATA *);
49 static TRP_INFOREC_DATA *trp_inforec_comm_new(TALLOC_CTX *mem_ctx);
50 static void trp_inforec_comm_print(TRP_INFOREC_DATA *);
51
52
53 struct trp_inforec_type_entry {
54   const char *name;
55   TRP_INFOREC_TYPE type;
56   TRP_INFOREC_DATA *(*allocate)(TALLOC_CTX *);
57   void (*print)(TRP_INFOREC_DATA *);
58 };
59 static struct trp_inforec_type_entry trp_inforec_type_table[] = {
60   { "route", TRP_INFOREC_TYPE_ROUTE, trp_inforec_route_new, trp_inforec_route_print },
61   { "comm", TRP_INFOREC_TYPE_COMMUNITY, trp_inforec_comm_new, trp_inforec_comm_print },
62   { NULL, TRP_INFOREC_TYPE_UNKNOWN, NULL, NULL } /* must be the last entry */
63 };
64
65
66 /* look up an entry in the trp_inforec_type_table */
67 static struct trp_inforec_type_entry *get_trp_inforec_type_entry(TRP_INFOREC_TYPE msgtype)
68 {
69   struct trp_inforec_type_entry *entry=trp_inforec_type_table;
70
71   while ((entry->type != TRP_INFOREC_TYPE_UNKNOWN)
72         && (entry->type != msgtype)) {
73     entry ++;
74   }
75   return entry;
76 }
77
78 /* translate strings to codes */
79 TRP_INFOREC_TYPE trp_inforec_type_from_string(const char *s)
80 {
81   struct trp_inforec_type_entry *entry=trp_inforec_type_table;
82
83   while ((entry->type != TRP_INFOREC_TYPE_UNKNOWN)
84         && (strcasecmp(s, entry->name)!=0)) {
85     entry++;
86   }
87   return entry->type;
88 }
89 /* translate codes to strings (do not need to be freed) 
90  * Returns NULL on an unknown code */
91 const char *trp_inforec_type_to_string(TRP_INFOREC_TYPE msgtype)
92 {
93   struct trp_inforec_type_entry *entry=get_trp_inforec_type_entry(msgtype);
94   return entry->name;
95 }
96
97 /* called by talloc when destroying an update message body */
98 static int trp_inforec_route_destructor(void *object)
99 {
100   TRP_INFOREC_ROUTE *body=talloc_get_type_abort(object, TRP_INFOREC_ROUTE);
101   
102   /* clean up TR_NAME data, which are not managed by talloc */
103   if (body->trust_router != NULL)
104     tr_free_name(body->trust_router);
105   if (body->next_hop != NULL)
106     tr_free_name(body->next_hop);
107   return 0;
108 }
109
110 static TRP_INFOREC_DATA *trp_inforec_route_new(TALLOC_CTX *mem_ctx)
111 {
112   TRP_INFOREC_DATA *new_data=talloc(mem_ctx, TRP_INFOREC_DATA);
113   TRP_INFOREC_ROUTE *new_rec=NULL;
114
115   if (new_data==NULL)
116     return NULL;
117
118   new_rec=talloc(new_data, TRP_INFOREC_ROUTE);
119   if (new_rec == NULL) {
120     talloc_free(new_data);
121     new_data=NULL;
122   } else {
123     new_rec->trust_router=NULL;
124     new_rec->next_hop=NULL;
125     new_rec->next_hop_port=0;
126     new_rec->metric=TRP_METRIC_INFINITY;
127     new_rec->interval=0;
128     talloc_set_destructor((void *)new_rec, trp_inforec_route_destructor);
129     new_data->route=new_rec;
130   }
131     
132   return new_data;
133 }
134
135
136 static int trp_inforec_comm_destructor(void *obj)
137 {
138   TRP_INFOREC_COMM *rec=talloc_get_type_abort(obj, TRP_INFOREC_COMM);
139   if (rec->owner_realm!=NULL)
140     tr_free_name(rec->owner_realm);
141   if (rec->owner_contact!=NULL)
142     tr_free_name(rec->owner_contact);
143   if (rec->provenance!=NULL)
144     json_decref(rec->provenance);
145   return 0;
146 }
147
148 static TRP_INFOREC_DATA *trp_inforec_comm_new(TALLOC_CTX *mem_ctx)
149 {
150   TRP_INFOREC_DATA *new_data=talloc(mem_ctx, TRP_INFOREC_DATA);
151   TRP_INFOREC_COMM *new_rec=NULL;
152
153   if (new_data==NULL)
154     return NULL;
155
156   new_rec=talloc(new_data, TRP_INFOREC_COMM);
157   if (new_rec==NULL) {
158     talloc_free(new_data);
159     new_data=NULL;
160   } else {
161     new_rec->comm_type=TR_COMM_UNKNOWN;
162     new_rec->role=TR_ROLE_UNKNOWN;
163     new_rec->apcs=NULL;
164     new_rec->owner_realm=NULL;
165     new_rec->owner_contact=NULL;
166     new_rec->expiration_interval=0;
167     new_rec->provenance=NULL;
168     new_rec->interval=0;
169     talloc_set_destructor((void *)new_rec, trp_inforec_comm_destructor);
170     new_data->comm=new_rec;
171   }
172
173   return new_data;
174 }
175
176 TRP_INFOREC *trp_inforec_get_next(TRP_INFOREC *rec)
177 {
178   if (rec!=NULL)
179     return rec->next;
180   else
181     return NULL;
182 }
183
184 static TRP_INFOREC *trp_inforec_get_tail(TRP_INFOREC *rec)
185 {
186   while ((rec->next)!=NULL)
187     rec=trp_inforec_get_next(rec);
188   return rec;
189 }
190
191 void trp_inforec_set_next(TRP_INFOREC *rec, TRP_INFOREC *next_rec)
192 {
193   if (rec !=NULL)
194     rec->next=next_rec;
195 }
196
197 TRP_INFOREC_TYPE trp_inforec_get_type(TRP_INFOREC *rec)
198 {
199   if (rec!=NULL)
200     return rec->type;
201   else
202     return TRP_INFOREC_TYPE_UNKNOWN;
203 }
204
205 void trp_inforec_set_type(TRP_INFOREC *rec, TRP_INFOREC_TYPE type)
206 {
207   if (rec!=NULL)
208     rec->type=type;
209 }
210
211 TR_NAME *trp_inforec_get_trust_router(TRP_INFOREC *rec)
212 {
213   switch (rec->type) {
214     case TRP_INFOREC_TYPE_ROUTE:
215       if (rec->data->route!=NULL)
216         return rec->data->route->trust_router;
217       break;
218     default:
219       break;
220   }
221   return NULL;
222 }
223
224 int trp_inforec_get_trust_router_port(TRP_INFOREC *rec)
225 {
226   switch (rec->type) {
227     case TRP_INFOREC_TYPE_ROUTE:
228       if (rec->data->route!=NULL)
229         return rec->data->route->trust_router_port;
230       /* fall through */
231     default:
232       return -1;
233   }
234 }
235
236 TR_NAME *trp_inforec_dup_trust_router(TRP_INFOREC *rec)
237 {
238   return tr_dup_name(trp_inforec_get_trust_router(rec));
239 }
240
241 TRP_RC trp_inforec_set_trust_router(TRP_INFOREC *rec, TR_NAME *trust_router, int port)
242 {
243   switch (rec->type) {
244   case TRP_INFOREC_TYPE_ROUTE:
245     if (rec->data->route!=NULL) {
246       rec->data->route->trust_router=trust_router;
247       return TRP_SUCCESS;
248     }
249     break;
250   default:
251     break;
252   }
253   return TRP_ERROR;
254 }
255
256 TR_NAME *trp_inforec_get_next_hop(TRP_INFOREC *rec)
257 {
258   switch (rec->type) {
259     case TRP_INFOREC_TYPE_ROUTE:
260       if (rec->data->route!=NULL)
261         return rec->data->route->next_hop;
262       break;
263     default:
264       break;
265   }
266   return NULL;
267 }
268
269 TR_NAME *trp_inforec_dup_next_hop(TRP_INFOREC *rec)
270 {
271   return tr_dup_name(trp_inforec_get_next_hop(rec));
272 }
273
274 /**
275  * Set the next hop for the inforec
276  *
277  * Returns TRP_SUCCESS if it set the next hop value for the inforec.
278  * Returns TRP_UNSUPPORTED if the inforec does not have a next hop record but
279  * otherwise nothing went wrong.
280  * Returns TRP_ERROR or another error if there was a failure.
281  *
282  * @param rec
283  * @param next_hop
284  * @return TRP_SUCCESS if the value was set, TRP_UNSUPPORTED if the inforec does not support next hop, or an error code on failure
285  */
286 TRP_RC trp_inforec_set_next_hop(TRP_INFOREC *rec, TR_NAME *next_hop, int port)
287 {
288   /* Any inforec types that support next_hop should set it here. */
289   switch (rec->type) {
290   case TRP_INFOREC_TYPE_ROUTE:
291     if (rec->data->route==NULL)
292       return TRP_ERROR;
293     rec->data->route->next_hop = next_hop;
294     rec->data->route->next_hop_port = port;
295     break;
296
297   default:
298     /* next hop not used for other records */
299     return TRP_UNSUPPORTED;
300   }
301   return TRP_SUCCESS;
302 }
303
304 int trp_inforec_get_next_hop_port(TRP_INFOREC *rec)
305 {
306   switch (rec->type) {
307     case TRP_INFOREC_TYPE_ROUTE:
308       if (rec->data->route!=NULL)
309         return rec->data->route->next_hop_port;
310       /* fall through */
311     default:
312       return -1;
313   }
314 }
315
316 unsigned int trp_inforec_get_metric(TRP_INFOREC *rec)
317 {
318   switch (rec->type) {
319   case TRP_INFOREC_TYPE_ROUTE:
320     if (rec->data->route!=NULL)
321       return rec->data->route->metric;
322     break;
323   default:
324     break;
325   }
326   return TRP_METRIC_INVALID;
327 }
328
329 TRP_RC trp_inforec_set_metric(TRP_INFOREC *rec, unsigned int metric)
330 {
331   switch (rec->type) {
332   case TRP_INFOREC_TYPE_ROUTE:
333     if (rec->data->route!=NULL) {
334       rec->data->route->metric=metric;
335       return TRP_SUCCESS;
336     }
337     break;
338   default:
339     break;
340   }
341   return TRP_ERROR;
342 }
343
344 unsigned int trp_inforec_get_interval(TRP_INFOREC *rec)
345 {
346   switch (rec->type) {
347   case TRP_INFOREC_TYPE_ROUTE:
348     if (rec->data->route!=NULL)
349       return rec->data->route->interval;
350     break;
351   case TRP_INFOREC_TYPE_COMMUNITY:
352     if (rec->data->comm!=NULL)
353       return rec->data->comm->interval;
354     break;
355   default:
356     break;
357   }
358   return TRP_INTERVAL_INVALID;
359 }
360
361 TRP_RC trp_inforec_set_interval(TRP_INFOREC *rec, unsigned int interval)
362 {
363   switch (rec->type) {
364   case TRP_INFOREC_TYPE_ROUTE:
365     if (rec->data->route!=NULL) {
366       rec->data->route->interval=interval;
367       return TRP_SUCCESS;
368     }
369     break;
370   case TRP_INFOREC_TYPE_COMMUNITY:
371     if (rec->data->comm!=NULL) {
372       rec->data->comm->interval=interval;
373       return TRP_SUCCESS;
374     }
375   default:
376     break;
377   }
378   return TRP_ERROR;
379 }
380
381 time_t trp_inforec_get_exp_interval(TRP_INFOREC *rec)
382 {
383   switch (rec->type) {
384   case TRP_INFOREC_TYPE_COMMUNITY:
385     if (rec->data->comm!=NULL)
386       return rec->data->comm->expiration_interval;
387     break;
388   default:
389     break;
390   }
391   return 0;
392 }
393
394 TRP_RC trp_inforec_set_exp_interval(TRP_INFOREC *rec, time_t expint)
395 {
396   switch (rec->type) {
397   case TRP_INFOREC_TYPE_COMMUNITY:
398     if (rec->data->comm!=NULL) {
399       rec->data->comm->expiration_interval=expint;
400       return TRP_SUCCESS;
401     }
402     break;
403   default:
404     break;
405   }
406   return TRP_ERROR;
407 }
408
409 TR_COMM_TYPE trp_inforec_get_comm_type(TRP_INFOREC *rec)
410 {
411   switch (rec->type) {
412   case TRP_INFOREC_TYPE_COMMUNITY:
413     if (rec->data->comm!=NULL)
414       return rec->data->comm->comm_type;
415     break;
416   default:
417     break;
418   }
419   return TR_COMM_UNKNOWN;
420 }
421
422 TRP_RC trp_inforec_set_comm_type(TRP_INFOREC *rec, TR_COMM_TYPE type)
423 {
424   switch (rec->type) {
425   case TRP_INFOREC_TYPE_COMMUNITY:
426     if (rec->data->comm!=NULL) {
427       rec->data->comm->comm_type=type;
428       return TRP_SUCCESS;
429     }
430     break;
431   default:
432     break;
433   }
434   return TRP_ERROR;
435 }
436
437 TR_REALM_ROLE trp_inforec_get_role(TRP_INFOREC *rec)
438 {
439   switch (rec->type) {
440   case TRP_INFOREC_TYPE_COMMUNITY:
441     if (rec->data->comm!=NULL)
442       return rec->data->comm->role;
443     break;
444   default:
445     break;
446   }
447   return TR_ROLE_UNKNOWN;
448 }
449
450 TRP_RC trp_inforec_set_role(TRP_INFOREC *rec, TR_REALM_ROLE role)
451 {
452   switch (rec->type) {
453   case TRP_INFOREC_TYPE_COMMUNITY:
454     if (rec->data->comm!=NULL) {
455       rec->data->comm->role=role;
456       return TRP_SUCCESS;
457       break;
458     }
459   default:
460     break;
461   }
462   return TRP_ERROR;
463 }
464
465 TR_APC *trp_inforec_get_apcs(TRP_INFOREC *rec)
466 {
467   switch (rec->type) {
468   case TRP_INFOREC_TYPE_COMMUNITY:
469     if (rec->data->comm!=NULL)
470       return rec->data->comm->apcs;
471     break;
472   default:
473     break;
474   }
475   return NULL;
476 }
477
478 TRP_RC trp_inforec_set_apcs(TRP_INFOREC *rec, TR_APC *apcs)
479 {
480   switch (rec->type) {
481   case TRP_INFOREC_TYPE_COMMUNITY:
482     if (rec->data->comm!=NULL) {
483       rec->data->comm->apcs=apcs;
484       talloc_steal(rec, apcs);
485       return TRP_SUCCESS;
486     }
487     break;
488
489   default:
490     break;
491   }
492   return TRP_ERROR;
493 }
494
495 TR_NAME *trp_inforec_get_owner_realm(TRP_INFOREC *rec)
496 {
497   switch (rec->type) {
498   case TRP_INFOREC_TYPE_COMMUNITY:
499     if (rec->data->comm!=NULL)
500       return rec->data->comm->owner_realm;
501     break;
502   default:
503     break;
504   }
505   return NULL;
506 }
507
508 TRP_RC trp_inforec_set_owner_realm(TRP_INFOREC *rec, TR_NAME *name)
509 {
510   switch (rec->type) {
511   case TRP_INFOREC_TYPE_COMMUNITY:
512     if (rec->data->comm!=NULL) {
513       rec->data->comm->owner_realm=name;
514       return TRP_SUCCESS;
515   default:
516     break;
517     }
518     break;
519   }
520   return TRP_ERROR;
521 }
522
523 TR_NAME *trp_inforec_get_owner_contact(TRP_INFOREC *rec)
524 {
525   switch (rec->type) {
526   case TRP_INFOREC_TYPE_COMMUNITY:
527     if (rec->data->comm!=NULL)
528       return rec->data->comm->owner_contact;
529     break;
530   default:
531     break;
532   }
533   return NULL;
534 }
535
536 TRP_RC trp_inforec_set_owner_contact(TRP_INFOREC *rec, TR_NAME *name)
537 {
538   switch (rec->type) {
539   case TRP_INFOREC_TYPE_COMMUNITY:
540     if (rec->data->comm!=NULL) {
541       rec->data->comm->owner_contact=name;
542       return TRP_SUCCESS;
543     }
544     break;
545   default:
546     break;
547   }
548   return TRP_ERROR;
549 }
550
551 /* caller needs to incref the output if they're going to hang on to it */
552 json_t *trp_inforec_get_provenance(TRP_INFOREC *rec)
553 {
554   switch (rec->type) {
555   case TRP_INFOREC_TYPE_COMMUNITY:
556     if (rec->data->comm!=NULL)
557       return rec->data->comm->provenance;
558     break;
559   default:
560     break;
561   }
562   return NULL;
563 }
564
565 /* increments the reference count */
566 TRP_RC trp_inforec_set_provenance(TRP_INFOREC *rec, json_t *prov)
567 {
568   switch (rec->type) {
569   case TRP_INFOREC_TYPE_COMMUNITY:
570     if (rec->data->comm!=NULL) {
571       if (rec->data->comm->provenance!=NULL)
572         json_decref(rec->data->comm->provenance);
573       rec->data->comm->provenance=prov;
574       json_incref(prov);
575       return TRP_SUCCESS;
576     }
577     break;
578   default:
579     break;
580   }
581   return TRP_ERROR;
582 }
583
584 static TRP_RC trp_inforec_add_to_provenance(TRP_INFOREC *rec, TR_NAME *name)
585 {
586   json_t *jname=NULL;
587
588   switch (rec->type) {
589   case TRP_INFOREC_TYPE_ROUTE:
590     /* no provenance list */
591     break;
592   case TRP_INFOREC_TYPE_COMMUNITY:
593     jname=tr_name_to_json_string(name);
594     if (jname==NULL)
595       return TRP_ERROR;
596     if (rec->data->comm->provenance==NULL) {
597       rec->data->comm->provenance=json_array();
598       if (rec->data->comm->provenance==NULL) {
599         json_decref(jname);
600         return TRP_ERROR;
601       }
602     }
603     if (0!=json_array_append_new(rec->data->comm->provenance, jname)) {
604       json_decref(jname);
605       return TRP_ERROR;
606     }
607     break;
608   default:
609     break;
610   }
611   return TRP_SUCCESS;
612 }
613
614 TR_NAME *trp_inforec_dup_origin(TRP_INFOREC *rec)
615 {
616   TR_NAME *origin=NULL;
617   json_t *prov=trp_inforec_get_provenance(rec);
618   const char *s=NULL;
619
620   if (prov==NULL)
621     return NULL;
622
623   s=json_string_value(json_array_get(prov, 0));
624   if (s==NULL) {
625     tr_debug("trp_inforec_dup_origin: empty origin in provenance list.");
626     return NULL;
627   }
628   origin=tr_new_name(s);
629   return origin;
630 }
631
632 /* generic record type */
633 TRP_INFOREC *trp_inforec_new(TALLOC_CTX *mem_ctx, TRP_INFOREC_TYPE type)
634 {
635   TRP_INFOREC *new_rec=talloc(mem_ctx, TRP_INFOREC);
636   TRP_INFOREC_DATA *data=NULL;
637   struct trp_inforec_type_entry *dtype=get_trp_inforec_type_entry(type);
638
639   if ((new_rec != NULL) && (dtype->type != TRP_INFOREC_TYPE_UNKNOWN)) {
640     trp_inforec_set_type(new_rec, type);
641     trp_inforec_set_next(new_rec, NULL);
642     if (dtype->allocate!=NULL) {
643       data=dtype->allocate(new_rec);
644       if (data!=NULL)
645         new_rec->data=data;
646       else {
647         talloc_free(new_rec);
648         return NULL;
649       }
650     }
651   }
652   return new_rec;
653 }
654
655 void trp_inforec_free(TRP_INFOREC *rec)
656 {
657   if (rec!=NULL)
658     talloc_free(rec);
659 }
660
661 static int trp_upd_destructor(void *object)
662 {
663   TRP_UPD *upd=talloc_get_type_abort(object, TRP_UPD);
664   if (upd->realm!=NULL)
665     tr_free_name(upd->realm);
666   if (upd->comm!=NULL)
667     tr_free_name(upd->comm);
668   if (upd->peer!=NULL)
669     tr_free_name(upd->peer);
670   return 0;
671 }
672
673 TRP_UPD *trp_upd_new(TALLOC_CTX *mem_ctx)
674 {
675   TRP_UPD *new_body=talloc(mem_ctx, TRP_UPD);
676
677   if (new_body!=NULL) {
678     new_body->realm=NULL;
679     new_body->comm=NULL;
680     new_body->records=NULL;
681     new_body->peer=NULL;
682     talloc_set_destructor((void *)new_body, trp_upd_destructor);
683   }
684   return new_body;
685 }
686
687 void trp_upd_free(TRP_UPD *update)
688 {
689   if (update!=NULL)
690     talloc_free(update);
691 }
692
693 TRP_INFOREC *trp_upd_get_inforec(TRP_UPD *upd)
694 {
695   if (upd!=NULL)
696     return upd->records;
697   else
698     return NULL;
699 }
700
701 void trp_upd_set_inforec(TRP_UPD *upd, TRP_INFOREC *rec)
702 {
703   if (upd!=NULL)
704     upd->records=rec;
705 }
706
707 void trp_upd_add_inforec(TRP_UPD *upd, TRP_INFOREC *rec)
708 {
709   tr_debug("trp_upd_add_inforec: adding record.");
710   if (upd->records==NULL)
711     upd->records=rec;
712   else
713     trp_inforec_set_next(trp_inforec_get_tail(upd->records), rec);
714   talloc_steal(upd, rec);
715 }
716
717 /**
718  * Removes and frees the selected inforec.
719  *
720  * @param upd Update to remove from
721  * @param rec Inforec to remove
722  */
723 void trp_upd_remove_inforec(TRP_UPD *upd, TRP_INFOREC *rec)
724 {
725   TRP_INFOREC *this=upd->records;
726
727   /* special case for the first element */
728   if (this==rec) {
729     upd->records=upd->records->next;
730     trp_inforec_free(this);
731     return;
732   }
733
734   while (this->next!=NULL) {
735     if (this->next==rec) {
736       this->next=this->next->next; /* this->next is not null */
737       trp_inforec_free(rec);
738     }
739     this=this->next;
740   }
741 }
742
743 size_t trp_upd_num_inforecs(TRP_UPD *upd)
744 {
745   size_t count=0;
746   TRP_INFOREC *this=upd->records;
747
748   while (this != NULL) {
749     count++;
750     this=this->next;
751   }
752   return count;
753 }
754
755
756 TR_NAME *trp_upd_get_realm(TRP_UPD *upd)
757 {
758   return upd->realm;
759 }
760
761 TR_NAME *trp_upd_dup_realm(TRP_UPD *upd)
762 {
763   return tr_dup_name(upd->realm);
764 }
765
766 void trp_upd_set_realm(TRP_UPD *upd, TR_NAME *realm)
767 {
768   if (upd->realm!=NULL)
769     tr_free_name(upd->realm);
770   upd->realm=realm;
771 }
772
773 TR_NAME *trp_upd_get_comm(TRP_UPD *upd)
774 {
775   return upd->comm;
776 }
777
778 TR_NAME *trp_upd_dup_comm(TRP_UPD *upd)
779 {
780   return tr_dup_name(upd->comm);
781 }
782
783 void trp_upd_set_comm(TRP_UPD *upd, TR_NAME *comm)
784 {
785   if (upd->comm!=NULL)
786     tr_free_name(upd->comm);
787   upd->comm=comm;
788 }
789
790 TR_NAME *trp_upd_get_peer(TRP_UPD *upd)
791 {
792   return upd->peer;
793 }
794
795 TR_NAME *trp_upd_dup_peer(TRP_UPD *upd)
796 {
797   return tr_dup_name(upd->peer);
798 }
799
800 void trp_upd_set_peer(TRP_UPD *upd, TR_NAME *peer)
801 {
802   upd->peer=peer;
803 }
804
805 void trp_upd_set_next_hop(TRP_UPD *upd, const char *hostname, unsigned int port)
806 {
807   TRP_INFOREC *rec=NULL;
808   TR_NAME *cpy=NULL;
809
810   for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
811     switch (trp_inforec_set_next_hop(rec, cpy=tr_new_name(hostname), port)) {
812       case TRP_SUCCESS:
813         /* Success, the TR_NAME in cpy is now stored with the inforec */
814         break;
815
816       case TRP_UNSUPPORTED:
817         /* No error, but the inforec does not accept a next_hop. Free our copy. */
818         tr_free_name(cpy);
819         break;
820
821       default:
822         tr_err("trp_upd_set_next_hop: error setting next hop.");
823         tr_free_name(cpy);
824         break;
825     }
826   }
827 }
828
829 void trp_upd_add_to_provenance(TRP_UPD *upd, TR_NAME *name)
830 {
831   TRP_INFOREC *rec=NULL;
832
833   /* add it to all inforecs */
834   for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
835     if (TRP_SUCCESS!=trp_inforec_add_to_provenance(rec, name))
836       tr_err("trp_upd_set_peer: error adding peer to provenance list.");
837   }
838 }
839
840 /* pretty print */
841 static void trp_inforec_route_print(TRP_INFOREC_DATA *data)
842 {
843   if (data->route!=NULL) {
844     tr_info("     trust_router=%.*s\n     metric=%d\n     interval=%d]\n",
845            data->route->trust_router->len, data->route->trust_router->buf,
846            data->route->metric, data->route->interval);
847   }
848 }
849
850 static void trp_inforec_comm_print(TRP_INFOREC_DATA *data)
851 {
852   if (data->comm!=NULL) {
853     tr_info("     type=%s\n     role=%s\n     owner=%.*s\n     contact=%.*s]\n",
854            tr_comm_type_to_str(data->comm->comm_type),
855            tr_realm_role_to_str(data->comm->role),
856            data->comm->owner_realm->len, data->comm->owner_realm->buf,
857            data->comm->owner_contact->len, data->comm->owner_contact->buf);
858     /* TODO: print apcs */
859   }
860 }