304d7fee382491eb18ac8ff2e525b3e62780a016
[trust_router.git] / trp / trp_msg.c
1 #include <jansson.h>
2 #include <talloc.h>
3
4 #include <tr_name.h>
5 #include <trp_internal.h>
6 #include <tr_debug.h>
7
8
9 /* static prototypes */
10 static void *trp_route_update_new(TALLOC_CTX *mem_ctx);
11 static json_t *trp_encode_route_update(void *req_in);
12 static TRP_RC trp_parse_route_update(TRP_MSG *msg, json_t *jmsg);
13 static void trp_route_update_print(void *);
14
15 static void *trp_route_req_new(TALLOC_CTX *mem_ctx);
16 static json_t *trp_encode_route_req(void *req_in);
17 static TRP_RC trp_parse_route_req(TRP_MSG *msg, json_t *jmsg);
18 static void trp_route_req_print(void *);
19
20 static void *trp_msg_info_route_new(TALLOC_CTX *mem_ctx);
21 static TRP_RC trp_encode_info_route(json_t *jrec, void *route_in);
22 static TRP_RC trp_parse_info_route(TRP_MSG *msg, json_t *jmsg);
23 static void trp_msg_info_route_print(void *);
24
25 /* table of string names for TMT_MSG_TYPE codes */
26 struct trp_msg_type_entry {
27   const char *name;
28   TRP_MSG_TYPE type;
29   void *(*allocate)(TALLOC_CTX *);
30   json_t *(*encode)(void *);
31   TRP_RC (*parse)(TRP_MSG *, json_t *);
32   void (*print)(void *);
33 };
34 static struct trp_msg_type_entry trp_msg_type_table[] = {
35   { "update", TRP_MSG_TYPE_UPDATE, trp_route_update_new, trp_encode_route_update, trp_parse_route_update, trp_route_update_print },
36   { "route_req", TRP_MSG_TYPE_ROUTE_REQ, trp_route_req_new, trp_encode_route_req, trp_parse_route_req, trp_route_req_print },
37   { NULL, TRP_MSG_TYPE_UNKNOWN, NULL, NULL, NULL, NULL } /* must be the last entry */
38 };
39
40 struct trp_msg_info_type_entry {
41   const char *name;
42   TRP_MSG_INFO_TYPE type;
43   void *(*allocate)(TALLOC_CTX *);
44   TRP_RC (*encode)(json_t *, void *);
45   void (*print)(void *);
46 };
47 static struct trp_msg_info_type_entry trp_msg_info_type_table[] = {
48   { "route_info", TRP_MSG_INFO_TYPE_ROUTE, trp_msg_info_route_new, trp_encode_info_route, trp_msg_info_route_print },
49   { "comm_info", TRP_MSG_INFO_TYPE_COMMUNITY, NULL, NULL, NULL },
50   { NULL, TRP_MSG_INFO_TYPE_UNKNOWN, NULL, NULL, NULL } /* must be the last entry */
51 };
52
53 /* Use talloc's dynamic type checking to verify type.
54  * By default, this will cause program abort, but can be overridden
55  * via talloc_set_abort_fn() if more graceful handling is needed. */
56 static void msg_body_type_check(TRP_MSG_TYPE msgtype, void *p)
57 {
58   switch (msgtype) {
59   case TRP_MSG_TYPE_UPDATE:
60     talloc_get_type_abort(p, TRP_ROUTE_UPDATE);
61     break;
62
63   case TRP_MSG_TYPE_ROUTE_REQ:
64     talloc_get_type_abort(p, TRP_ROUTE_REQ);
65     break;
66
67   default:
68     break;
69   }
70 }
71
72 /* look up an entry in the trp_msg_type_table */
73 static struct trp_msg_type_entry *get_trp_msg_type_entry(TRP_MSG_TYPE msgtype)
74 {
75   struct trp_msg_type_entry *entry=trp_msg_type_table;
76
77   while ((entry->type != TRP_MSG_TYPE_UNKNOWN)
78         && (entry->type != msgtype)) {
79     entry ++;
80   }
81   return entry;
82 }
83
84 /* look up an entry in the trp_msg_info_type_table */
85 static struct trp_msg_info_type_entry *get_trp_msg_info_type_entry(TRP_MSG_INFO_TYPE msgtype)
86 {
87   struct trp_msg_info_type_entry *entry=trp_msg_info_type_table;
88
89   while ((entry->type != TRP_MSG_INFO_TYPE_UNKNOWN)
90         && (entry->type != msgtype)) {
91     entry ++;
92   }
93   return entry;
94 }
95
96 /* translate strings to codes */
97 TRP_MSG_TYPE trp_msg_type_from_string(const char *s)
98 {
99   struct trp_msg_type_entry *entry=trp_msg_type_table;
100
101   while ((entry->type != TRP_MSG_TYPE_UNKNOWN)
102         && (strcmp(s, entry->name)!=0)) {
103     entry++;
104   }
105   return entry->type;
106 }
107 /* translate codes to strings (do not need to be freed) 
108  * Returns NULL on an unknown code */
109 const char *trp_msg_type_to_string(TRP_MSG_TYPE msgtype)
110 {
111   struct trp_msg_type_entry *entry=get_trp_msg_type_entry(msgtype);
112   return entry->name;
113 }
114
115 /* translate strings to codes */
116 TRP_MSG_INFO_TYPE trp_msg_info_type_from_string(const char *s)
117 {
118   struct trp_msg_info_type_entry *entry=trp_msg_info_type_table;
119
120   while ((entry->type != TRP_MSG_INFO_TYPE_UNKNOWN)
121         && (strcmp(s, entry->name)!=0)) {
122     entry++;
123   }
124   return entry->type;
125 }
126 /* translate codes to strings (do not need to be freed) 
127  * Returns NULL on an unknown code */
128 const char *trp_msg_info_type_to_string(TRP_MSG_INFO_TYPE msgtype)
129 {
130   struct trp_msg_info_type_entry *entry=get_trp_msg_info_type_entry(msgtype);
131   return entry->name;
132 }
133
134
135 TRP_MSG *trp_msg_new(TALLOC_CTX *mem_ctx)
136 {
137   TRP_MSG *new_msg=talloc(mem_ctx, TRP_MSG);
138
139   if (new_msg != NULL) {
140     new_msg->type=TRP_MSG_INFO_TYPE_UNKNOWN;
141     new_msg->body=NULL;
142   }
143   return new_msg;
144 }
145
146 void trp_msg_destroy(TRP_MSG *msg)
147 {
148   if (msg)
149     talloc_free(msg);
150 }
151
152
153 /* JSON helpers */
154 /* Read attribute attr from msg as an integer */
155 static TRP_RC trp_get_json_integer(json_t *jmsg, const char *attr, int *dest)
156 {
157   json_error_t err;
158   json_t *obj;
159
160   obj=json_object_get(jmsg, attr);
161   if (obj == NULL) {
162     return TRP_NOPARSE;
163   }
164   /* check type */
165   if (!json_is_integer(obj)) {
166     return TRP_BADTYPE;
167   }
168
169   (*dest)=json_integer_value(obj);
170   return TRP_SUCCESS;
171 }
172
173 /* Read attribute attr from msg as a string. Copies string into mem_ctx context so jmsg can
174  * be destroyed safely. */
175 static TRP_RC trp_get_json_string(json_t *jmsg, const char *attr, char **dest, TALLOC_CTX *mem_ctx)
176 {
177   json_error_t err;
178   json_t *obj;
179
180   obj=json_object_get(jmsg, attr);
181   if (obj == NULL)
182     return TRP_NOPARSE;
183
184   /* check type */
185   if (!json_is_string(obj))
186     return TRP_BADTYPE;
187
188   *dest=talloc_strdup(mem_ctx, json_string_value(obj));
189   if (*dest==NULL)
190     return TRP_NOMEM;
191
192   return TRP_SUCCESS;
193 }
194
195
196 /* called by talloc when destroying an update message body */
197 static int trp_msg_info_route_destructor(void *object)
198 {
199   TRP_MSG_INFO_ROUTE *body=talloc_get_type_abort(object, TRP_MSG_INFO_ROUTE);
200   
201   /* clean up TR_NAME data, which are not managed by talloc */
202   if (body->comm != NULL) {
203     tr_free_name(body->comm);
204     body->comm=NULL;
205     tr_debug("trp_msg_info_route_destructor: freed community");
206   }
207   if (body->realm != NULL) {
208     tr_free_name(body->realm);
209     body->realm=NULL;
210     tr_debug("trp_msg_info_route_destructor: freed realm");
211   }
212   if (body->trust_router != NULL) {
213     tr_free_name(body->trust_router);
214     body->trust_router=NULL;
215     tr_debug("trp_msg_info_route_destructor: freed trust_router");
216   }
217
218   return 0;
219 }
220
221 static void *trp_msg_info_route_new(TALLOC_CTX *mem_ctx)
222 {
223   TRP_MSG_INFO_ROUTE *new_rec=talloc(mem_ctx, TRP_MSG_INFO_ROUTE);
224
225   if (new_rec != NULL) {
226     new_rec->comm=NULL;
227     new_rec->realm=NULL;
228     new_rec->trust_router=NULL;
229     new_rec->metric=TRP_METRIC_INFINITY;
230     new_rec->interval=0;
231     talloc_set_destructor((void *)new_rec, trp_msg_info_route_destructor);
232   }
233   return new_rec;
234 }
235
236 TR_NAME *trp_msg_info_route_get_comm(TRP_MSG_INFO_REC *rec)
237 {
238   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
239   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL))
240     return route->comm;
241   else
242     return NULL;
243 }
244
245 TRP_RC trp_msg_info_route_set_comm(TRP_MSG_INFO_REC *rec, TR_NAME *comm)
246 {
247   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
248   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL)) {
249     route->comm=comm;
250     return TRP_SUCCESS;
251   } else
252     return TRP_BADTYPE;
253 }
254
255 TR_NAME *trp_msg_info_route_get_realm(TRP_MSG_INFO_REC *rec)
256 {
257   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
258   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL))
259     return route->realm;
260   else
261     return NULL;
262 }
263
264 TRP_RC trp_msg_info_route_set_realm(TRP_MSG_INFO_REC *rec, TR_NAME *realm)
265 {
266   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
267   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL)) {
268     route->realm=realm;
269     return TRP_SUCCESS;
270   } else
271     return TRP_BADTYPE;
272 }
273
274 TR_NAME *trp_msg_info_route_get_trust_router(TRP_MSG_INFO_REC *rec)
275 {
276   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
277   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL))
278     return route->trust_router;
279   else
280     return NULL;
281 }
282
283 TRP_RC trp_msg_info_route_set_trust_router(TRP_MSG_INFO_REC *rec, TR_NAME *trust_router)
284 {
285   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
286   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL)) {
287     route->trust_router=trust_router;
288     return TRP_SUCCESS;
289   } else
290     return TRP_BADTYPE;
291 }
292
293 unsigned int trp_msg_info_route_get_metric(TRP_MSG_INFO_REC *rec)
294 {
295   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
296   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL))
297     return route->metric;
298   else
299     return TRP_METRIC_INVALID;
300 }
301
302 TRP_RC trp_msg_info_route_set_metric(TRP_MSG_INFO_REC *rec, unsigned int metric)
303 {
304   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
305   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL)) {
306     route->metric=metric;
307     return TRP_SUCCESS;
308   } else
309     return TRP_BADTYPE;
310 }
311
312 unsigned int trp_msg_info_route_get_interval(TRP_MSG_INFO_REC *rec)
313 {
314   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
315   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL))
316     return route->interval;
317   else
318     return TRP_INTERVAL_INVALID;
319 }
320
321 TRP_RC trp_msg_info_route_set_interval(TRP_MSG_INFO_REC *rec, unsigned int interval)
322 {
323   TRP_MSG_INFO_ROUTE *route=talloc_get_type(rec->data, TRP_MSG_INFO_ROUTE);
324   if ((rec->type==TRP_MSG_INFO_TYPE_ROUTE) && (route!=NULL)) {
325     route->interval=interval;
326     return TRP_SUCCESS;
327   } else
328     return TRP_BADTYPE;
329 }
330
331 /* generic record type */
332 static void *trp_msg_info_rec_new(TALLOC_CTX *mem_ctx, TRP_MSG_INFO_TYPE type)
333 {
334   TRP_MSG_INFO_REC *new_rec=talloc(mem_ctx, TRP_MSG_INFO_REC);
335   struct trp_msg_info_type_entry *dtype=get_trp_msg_info_type_entry(type);
336
337   if ((new_rec != NULL) && (dtype->type != TRP_MSG_INFO_TYPE_UNKNOWN)) {
338     new_rec->next=NULL;
339     new_rec->type=type;
340     if (dtype->allocate!=NULL)
341       new_rec->data=dtype->allocate(new_rec);
342     if (new_rec->data==NULL) {
343       /* dtype->allocate() failed or did not exist */
344       talloc_free(new_rec); new_rec=NULL;
345     }
346   }
347   return new_rec;
348 }
349
350 /* parse a single record */
351 static TRP_RC trp_parse_update_record(TALLOC_CTX *mem_ctx, TRP_MSG_INFO_REC **rec, json_t *jrecord)
352 {
353   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
354   TRP_MSG_INFO_TYPE rectype;
355   TRP_RC rc=TRP_ERROR;
356   char *s=NULL;
357   int num=0;
358   
359   rc=trp_get_json_string(jrecord, "record_type", &s, tmp_ctx);
360   if (rc != TRP_SUCCESS)
361     goto cleanup;
362   rectype=trp_msg_info_type_from_string(s);
363   talloc_free(s); s=NULL;
364
365   (*rec)=trp_msg_info_rec_new(tmp_ctx, rectype);
366   if ((*rec)==NULL) {
367     rc=TRP_NOMEM;
368     goto cleanup;
369   }
370
371   /* We only support route_info records for now*/
372   if ((*rec)->type!=TRP_MSG_INFO_TYPE_ROUTE) {
373     rc=TRP_UNSUPPORTED;
374     goto cleanup;
375   }
376
377   tr_debug("trp_parse_update_record: '%s' record found.", trp_msg_info_type_to_string((*rec)->type));
378
379   rc=trp_get_json_string(jrecord, "community", &s, tmp_ctx);
380   if (rc != TRP_SUCCESS)
381     goto cleanup;
382   if (TRP_SUCCESS!=trp_msg_info_route_set_comm(*rec, tr_new_name(s))) /* assumes route_info */
383     goto cleanup;
384   talloc_free(s); s=NULL;
385
386   rc=trp_get_json_string(jrecord, "realm", &s, tmp_ctx);
387   if (rc != TRP_SUCCESS)
388     goto cleanup;
389   if (TRP_SUCCESS!=trp_msg_info_route_set_realm(*rec, tr_new_name(s))) /* assumes route_info */
390     goto cleanup;
391   talloc_free(s); s=NULL;
392
393   rc=trp_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
394   if (rc != TRP_SUCCESS)
395     goto cleanup;
396   if (TRP_SUCCESS!=trp_msg_info_route_set_trust_router(*rec, tr_new_name(s))) /* assumes route_info */
397     goto cleanup;
398   talloc_free(s); s=NULL;
399
400   rc=trp_get_json_integer(jrecord, "metric", &num);
401   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_msg_info_route_set_metric(*rec,num)))
402     goto cleanup;
403
404   rc=trp_get_json_integer(jrecord, "interval", &num);
405   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_msg_info_route_set_interval(*rec,num)))
406     goto cleanup;
407
408   talloc_steal(mem_ctx, *rec);
409   rc=TRP_SUCCESS;
410
411 cleanup:
412   if (rc != TRP_SUCCESS) {
413     /* kind of a hack, assumes we only have route_info records */
414     trp_msg_info_route_destructor((*rec)->data);
415     (*rec)=NULL;
416   }
417   talloc_free(tmp_ctx);
418   return rc;
419 }
420
421 static void *trp_route_update_new(TALLOC_CTX *mem_ctx)
422 {
423   TRP_ROUTE_UPDATE *new_body=talloc(mem_ctx, TRP_ROUTE_UPDATE);
424
425   if (new_body!=NULL) {
426     new_body->records=NULL;
427   }
428 }
429
430 /* Parse an update body. Creates a linked list of records in the msg->body talloc context.
431  *
432  * An error will be returned if any unparseable records are encountered. 
433  *
434  * TODO: clean up return codes. 
435  * TODO: should take a body, not a msg */
436 static TRP_RC trp_parse_route_update(TRP_MSG *msg, json_t *jbody)
437 {
438   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
439   json_t *jrecords=NULL;
440   size_t ii=0;
441   size_t nrec=0;
442   TRP_ROUTE_UPDATE *msg_body=NULL;
443   TRP_MSG_INFO_REC *new_rec=NULL;
444   TRP_MSG_INFO_REC *list_tail=NULL;
445   TRP_RC rc=TRP_ERROR;
446
447   if (msg->type != TRP_MSG_TYPE_UPDATE) {
448     rc=TRP_BADTYPE;
449     goto cleanup;
450   }
451   msg_body=talloc_get_type(msg->body, TRP_ROUTE_UPDATE);
452   if (msg_body==NULL) {
453     rc=TRP_BADTYPE;
454     goto cleanup;
455   }
456
457   jrecords=json_object_get(jbody, "records");
458   if ((jrecords==NULL) || (!json_is_array(jrecords))) {
459     rc=TRP_NOPARSE;
460     goto cleanup;
461   }
462
463   tr_debug("trp_parse_route_update: found %d records", json_array_size(jrecords));
464   /* process the array */
465   for (ii=0; ii<json_array_size(jrecords); ii++) {
466     if (TRP_SUCCESS != trp_parse_update_record(tmp_ctx, &new_rec, json_array_get(jrecords, ii))) {
467       rc=TRP_NOPARSE;
468       goto cleanup;
469     }
470
471     if (list_tail==NULL)
472       msg_body->records=new_rec; /* first is a special case */
473     else
474       list_tail->next=new_rec;
475
476     list_tail=new_rec;
477   }
478
479   /* Succeeded. Move all of our new allocations into the correct talloc context */
480   for (list_tail=msg_body->records; list_tail != NULL; list_tail=list_tail->next)
481     talloc_steal(msg->body, list_tail); /* all successfully parsed bodies belong to msg context */
482
483   rc=TRP_SUCCESS;
484
485 cleanup:
486   talloc_free(tmp_ctx);
487   if ((rc != TRP_SUCCESS) && (msg_body != NULL))
488     msg_body->records=NULL; /* don't leave this hanging */
489
490   return rc;
491 }
492
493 /* pretty print */
494 static void trp_msg_info_route_print(void *rec_in)
495 {
496   TRP_MSG_INFO_ROUTE *rec=talloc_get_type(rec_in, TRP_MSG_INFO_ROUTE); /* null if wrong type */
497
498   if (rec!=NULL) {
499     printf("     community=%.*s\n     realm=%.*s\n     trust_router=%.*s\n     metric=%d\n     interval=%d]\n",
500            rec->comm->len, rec->comm->buf,
501            rec->realm->len, rec->realm->buf,
502            rec->trust_router->len, rec->trust_router->buf,
503            rec->metric, rec->interval);
504   }
505 }
506
507
508 static int trp_route_req_destructor(void *object)
509 {
510   TRP_ROUTE_REQ *body=talloc_get_type_abort(object, TRP_ROUTE_REQ);
511   
512   /* clean up TR_NAME data, which are not managed by talloc */
513   if (body->comm != NULL) {
514     tr_free_name(body->comm);
515     body->comm=NULL;
516     tr_debug("trp_route_req_destructor: freed community");
517   }
518   if (body->realm != NULL) {
519     tr_free_name(body->realm);
520     body->realm=NULL;
521     tr_debug("trp_route_req_destructor: freed realm");
522   }
523   return 0;
524 }
525
526 void *trp_route_req_new(TALLOC_CTX *mem_ctx)
527 {
528   TRP_ROUTE_REQ *new_body=talloc(mem_ctx, TRP_ROUTE_REQ);
529
530   if (new_body != NULL) {
531     new_body->comm=NULL;
532     new_body->realm=NULL;
533   }
534
535   talloc_set_destructor((void *)new_body, trp_route_req_destructor);
536   return new_body;
537 }
538
539 void trp_route_req_set_comm(TRP_ROUTE_REQ *req, TR_NAME *comm)
540 {
541   req->comm=comm;
542 }
543
544 void trp_route_req_set_realm(TRP_ROUTE_REQ *req, TR_NAME *realm)
545 {
546   req->realm=realm;
547 }
548
549 /* TODO: clean up return codes. 
550  * TODO: should take a body, not a msg */
551 static TRP_RC trp_parse_route_req(TRP_MSG *msg, json_t *jbody)
552 {
553   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
554   TRP_ROUTE_REQ *msg_body=NULL;
555   char *s=NULL;
556   TRP_RC rc=TRP_ERROR;
557
558   /* check message type and body type for agreement */
559   if (msg->type != TRP_MSG_TYPE_ROUTE_REQ) {
560     rc=TRP_BADTYPE;
561     goto cleanup;
562   }
563   msg_body=talloc_get_type(msg->body, TRP_ROUTE_REQ);
564   if (msg_body==NULL) {
565     rc=TRP_BADTYPE;
566     goto cleanup;
567   }
568
569   rc=trp_get_json_string(jbody, "community", &s, tmp_ctx);
570   if (rc!=TRP_SUCCESS)
571     goto cleanup;
572   msg_body->comm=tr_new_name(s);
573   talloc_free(s); s=NULL;
574
575   rc=trp_get_json_string(jbody, "realm", &s, tmp_ctx);
576   if (rc!=TRP_SUCCESS)
577     goto cleanup;
578   msg_body->realm=tr_new_name(s);
579   talloc_free(s); s=NULL;
580
581   rc=TRP_SUCCESS;
582 cleanup:
583   talloc_free(tmp_ctx);
584   return rc;
585 }
586
587 static json_t *trp_encode_body(TRP_MSG_TYPE type, void *body)
588 {
589   struct trp_msg_type_entry *msgtype=get_trp_msg_type_entry(type);
590
591   if ((msgtype->type==TRP_MSG_TYPE_UNKNOWN) || (msgtype->encode==NULL))
592     return NULL;
593
594   return msgtype->encode(body);
595 }
596
597 char *trp_encode_msg(TRP_MSG *msg)
598 {
599   json_t *jmsg=NULL;
600   json_t *jtype=NULL;
601   json_t *jbody=NULL;
602   char *encoded=NULL;
603
604   jbody=trp_encode_body(msg->type, msg->body);
605   if (jbody!=NULL) {
606     jmsg=json_object();
607     if (jmsg==NULL) {
608       /* failed */
609       json_decref(jbody);
610     } else {
611       jtype=json_string(trp_msg_type_to_string(msg->type));
612       if (jtype==NULL) {
613         json_decref(jbody);
614       } else {
615         json_object_set_new(jmsg, "message_type", jtype);
616         json_object_set_new(jmsg, "body", jbody);
617         encoded=json_dumps(jmsg, 0);
618       }
619       json_decref(jmsg);
620     }
621   }
622   return encoded;
623 }
624
625 /* add record data to jrec */
626 static TRP_RC trp_encode_info_route(json_t *jrec, void *route_in)
627 {
628   TRP_MSG_INFO_ROUTE *route=talloc_get_type(route_in, TRP_MSG_INFO_ROUTE);
629   json_t *jstr=NULL;
630   json_t *jint=NULL;
631   char *s=NULL;
632
633   if (route==NULL)
634     return TRP_BADTYPE;
635
636   s=tr_name_strdup(route->comm);
637   if (s==NULL)
638     return TRP_NOMEM;
639   jstr=json_string(s);
640   free(s);s=NULL;
641   if(jstr==NULL)
642     return TRP_ERROR;
643   json_object_set_new(jrec, "community", jstr);
644
645   s=tr_name_strdup(route->realm);
646   if (s==NULL)
647     return TRP_NOMEM;
648   jstr=json_string(s);
649   free(s);s=NULL;
650   if(jstr==NULL)
651     return TRP_ERROR;
652   json_object_set_new(jrec, "realm", jstr);
653
654   s=tr_name_strdup(route->trust_router);
655   if (s==NULL)
656     return TRP_NOMEM;
657   jstr=json_string(s);
658   free(s);s=NULL;
659   if(jstr==NULL)
660     return TRP_ERROR;
661   json_object_set_new(jrec, "trust_router", jstr);
662
663   jint=json_integer(route->metric);
664   if(jint==NULL)
665     return TRP_ERROR;
666   json_object_set_new(jrec, "metric", jint);
667
668   jint=json_integer(route->interval);
669   if(jint==NULL)
670     return TRP_ERROR;
671   json_object_set_new(jrec, "interval", jint);
672
673   return TRP_SUCCESS;
674 }
675
676 static json_t *trp_encode_info_rec(TRP_MSG_INFO_REC *rec)
677 {
678   struct trp_msg_info_type_entry *rectype=get_trp_msg_info_type_entry(rec->type);
679   json_t *jrec=NULL;
680   json_t *jstr=NULL;
681
682   if (rectype->type==TRP_MSG_INFO_TYPE_UNKNOWN)
683     return NULL;
684
685   jrec=json_object();
686   if (jrec==NULL)
687     return NULL;
688
689   jstr=json_string(trp_msg_info_type_to_string(rec->type));
690   if (jstr==NULL) {
691     json_decref(jrec);
692     return NULL;
693   }
694   json_object_set_new(jrec, "record_type", jstr);
695
696   if ((rectype->encode==NULL) || (TRP_SUCCESS!=rectype->encode(jrec, rec->data))) {
697     json_decref(jrec);
698     return NULL;
699   }
700
701   return jrec;
702 }
703
704 static json_t *trp_encode_route_update(void *update_in)
705 {
706   TRP_ROUTE_UPDATE *update=talloc_get_type(update_in, TRP_ROUTE_UPDATE); /* null if wrong type */
707   json_t *jbody=NULL;
708   json_t *jrecords=NULL;
709   json_t *jrec=NULL;
710   TRP_MSG_INFO_REC *rec;
711
712   if (update==NULL)
713     return NULL;
714
715   jbody=json_object();
716   if (jbody==NULL)
717     return NULL;
718
719   jrecords=json_array();
720   if (jrecords==NULL) {
721     json_decref(jbody);
722     return NULL;
723   }
724   json_object_set_new(jbody, "records", jrecords); /* jrecords now a "borrowed" reference */
725   for (rec=update->records; rec!=NULL; rec=rec->next) {
726     jrec=trp_encode_info_rec(rec);
727     if (jrec==NULL) {
728       json_decref(jbody); /* also decs jrecords and any elements */
729       return NULL;
730     }
731     if (0!=json_array_append_new(jrecords, jrec)) {
732       json_decref(jbody); /* also decs jrecords and any elements */
733       json_decref(jrec); /* this one did not get added so dec explicitly */
734       return NULL;
735     }
736   }
737
738   return jbody;
739 }
740
741 static json_t *trp_encode_route_req(void *req_in)
742 {
743   TRP_ROUTE_REQ *req=talloc_get_type(req_in, TRP_ROUTE_REQ); /* null if wrong type */
744   json_t *jbody=NULL;
745   json_t *jstr=NULL;
746   char *s=NULL;
747
748   if (req==NULL)
749     return NULL;
750
751   jbody=json_object();
752   if (jbody==NULL)
753     return NULL;
754
755   s=tr_name_strdup(req->comm); /* ensures null termination */
756   if (s==NULL) {
757     json_decref(jbody);
758     return NULL;
759   }
760   jstr=json_string(s);
761   free(s); s=NULL;
762   if (jstr==NULL) {
763     json_decref(jbody);
764     return NULL;
765   }
766   json_object_set_new(jbody, "community", jstr);
767     
768   s=tr_name_strdup(req->realm); /* ensures null termination */
769   if (s==NULL) {
770     json_decref(jbody);
771     return NULL;
772   }
773   jstr=json_string(s);
774   free(s); s=NULL;
775   if (jstr==NULL) {
776     json_decref(jbody);
777     return NULL;
778   }
779   json_object_set_new(jbody, "realm", jstr);
780
781   return jbody;
782 }
783
784 static void trp_msg_info_rec_print(TRP_MSG_INFO_REC *rec)
785 {
786   struct trp_msg_info_type_entry *rectype=get_trp_msg_info_type_entry(rec->type);
787
788   if (rectype->print != NULL) {
789     printf("    [record_type=%s\n", trp_msg_info_type_to_string(rec->type));
790     rectype->print(rec->data);
791   }
792   else
793     printf("    [record_type=%s, (no print method)]\n");
794 }
795
796 static void trp_route_update_print(void *body_in)
797 {
798   TRP_ROUTE_UPDATE *body=talloc_get_type(body_in, TRP_ROUTE_UPDATE); /* null if wrong type */
799   TRP_MSG_INFO_REC *rec=NULL;
800
801   if (body!=NULL) {
802     printf("  {records=\n");
803     for (rec=body->records; rec!=NULL; rec=rec->next) 
804       trp_msg_info_rec_print(rec);
805     printf("  }\n");
806   }
807 }
808
809 static void trp_route_req_print(void *body_in)
810 {
811   TRP_ROUTE_REQ *body=talloc_get_type(body_in, TRP_ROUTE_REQ); /* null if wrong type */
812
813   if (body!=NULL) {
814     printf("  {community=%.*s\n   realm=%.*s}\n",
815            body->comm->len, body->comm->buf,
816            body->realm->len, body->realm->buf);
817   }
818 }
819
820 static void trp_msg_body_print(void *body, TRP_MSG_TYPE msgtype)
821 {
822   struct trp_msg_type_entry *info=get_trp_msg_type_entry(msgtype);
823   info->print(body);
824 }
825
826 void trp_msg_print(TRP_MSG *msg)
827 {
828   /* right now just assumes update */
829   printf("{message_type=%s\n", trp_msg_type_to_string(msg->type));
830   trp_msg_body_print(msg->body, msg->type);
831   printf("}\n");
832 }
833
834 /* returns a pointer to one of the message body types, or NULL on error/unknown type */
835 static void *trp_msg_body_new(TALLOC_CTX *mem_ctx, TRP_MSG_TYPE msgtype)
836 {
837   void *new_body=NULL;
838   struct trp_msg_type_entry *info=get_trp_msg_type_entry(msgtype);
839
840   if (info->type==TRP_MSG_TYPE_UNKNOWN) {
841     tr_debug("trp_msg_body_new: Unknown type %d.", info->type);
842     return NULL;
843   }
844
845   new_body=info->allocate(mem_ctx);
846   msg_body_type_check(msgtype, new_body); /* aborts program on type violation */
847   return new_body;
848 }
849
850 /* call the correct parser */
851 static TRP_RC trp_parse_msg_body(TRP_MSG *msg, json_t *jbody)
852 {
853   struct trp_msg_type_entry *info=get_trp_msg_type_entry(msg->type);
854
855   if (info->type==TRP_MSG_TYPE_UNKNOWN) {
856     tr_debug("trp_msg_body_parse: Unknown type %d.", info->type);
857     return TRP_ERROR;
858   }
859
860   return info->parse(msg, jbody);
861 }
862
863
864 TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MSG **msg) 
865 {
866   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
867   TRP_MSG *new_msg=NULL;
868   TRP_RC msg_rc=TRP_ERROR;
869   json_error_t json_err;
870   json_t *jmsg=NULL; /* handle for the whole msg */
871   json_t *jbody=NULL;
872   char *s;
873
874   tr_debug("trp_parse_msg: parsing %d bytes", buflen);
875
876   jmsg=json_loadb(buf, buflen, 0, &json_err);
877   if (jmsg == NULL) {
878     tr_debug("trp_parse_msg: Error parsing message.");
879     msg_rc=TRP_NOPARSE;
880     goto cleanup;
881   }
882
883   /* parse the common part of the message */
884   new_msg=trp_msg_new(tmp_ctx);
885   if (new_msg == NULL) {
886     tr_debug("trp_parse_msg: Error allocating message.");
887     msg_rc=TRP_NOMEM;
888     goto cleanup;
889   }
890
891   switch (trp_get_json_string(jmsg, "message_type", &s, new_msg)) {
892   case TRP_SUCCESS:
893     break;
894   case TRP_NOPARSE:
895     tr_debug("trp_parse_msg: required attribute 'message_type' not present.");
896     msg_rc=TRP_NOPARSE;
897     goto cleanup;
898   case TRP_BADTYPE:
899     tr_debug("trp_parse_msg: required attribute 'message_type' is not a string.");
900     msg_rc=TRP_NOPARSE;
901     goto cleanup;
902   default:
903     tr_debug("trp_parse_msg: error parsing 'message_type'.");
904     msg_rc=TRP_NOPARSE;
905     goto cleanup;
906   }
907   
908   tr_debug("trp_parse_msg: 'message_type' is '%s'", s);
909   new_msg->type = trp_msg_type_from_string(s);
910   if (new_msg->type==TRP_MSG_TYPE_UNKNOWN) {
911     tr_debug("trp_parse_msg: Parsing error, unknown message_type (%s).", s);
912     msg_rc=TRP_NOPARSE;
913     goto cleanup;
914   }  
915
916   new_msg->body=trp_msg_body_new(new_msg, new_msg->type);
917   if (new_msg->body==NULL) {
918     tr_debug("trp_parse_msg: Error allocating message body for message_type %d.", new_msg->type);
919     msg_rc=TRP_NOMEM;
920     goto cleanup;
921   }
922   jbody=json_object_get(jmsg, "body");
923   if (jbody==NULL) {
924     tr_debug("trp_parse_msg: Message body not found.");
925     msg_rc=TRP_NOPARSE;
926     goto cleanup;
927   }
928
929   switch (trp_parse_msg_body(new_msg, jbody)) {
930   case TRP_SUCCESS:
931     break;
932   default:
933     tr_debug("trp_parse_msg: Error parsing message body.");
934     goto cleanup;
935   }
936
937   /* success! */
938   (*msg)=new_msg;
939   new_msg=NULL;
940   talloc_steal(mem_ctx, *msg);
941   msg_rc=TRP_SUCCESS;
942
943 cleanup:
944   talloc_free(tmp_ctx);
945   json_decref(jmsg);
946   return msg_rc;
947 }