Clean up TR_MSG, hopefully getting talloc context handling right
[trust_router.git] / common / tr_msg.c
1 /*
2  * Copyright (c) 2012-2014 , 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 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <string.h>
38 #include <openssl/dh.h>
39 #include <openssl/crypto.h>
40 #include <jansson.h>
41 #include <assert.h>
42 #include <talloc.h>
43
44
45 #include <tr_apc.h>
46 #include <tr_comm.h>
47 #include <mon_internal.h>
48 #include <trp_internal.h>
49 #include <tr_msg.h>
50 #include <tr_name_internal.h>
51 #include <trust_router/tr_constraint.h>
52 #include <trust_router/tr_dh.h>
53 #include <tr_debug.h>
54
55 /* JSON helpers */
56 /* Read attribute attr from msg as an integer. Returns nonzero on error. */
57 static int tr_msg_get_json_integer(json_t *jmsg, const char *attr, int *dest)
58 {
59   json_t *obj;
60
61   obj=json_object_get(jmsg, attr);
62   if (obj == NULL) {
63     return -1;
64   }
65   /* check type */
66   if (!json_is_integer(obj)) {
67     return -1;
68   }
69
70   (*dest)=json_integer_value(obj);
71   return 0;
72 }
73
74 /* Read attribute attr from msg as a string. Copies string into mem_ctx context so jmsg can
75  * be destroyed safely. Returns nonzero on error. */
76 static TRP_RC tr_msg_get_json_string(json_t *jmsg, const char *attr, char **dest, TALLOC_CTX *mem_ctx)
77 {
78   json_t *obj;
79
80   obj=json_object_get(jmsg, attr);
81   if (obj == NULL)
82     return TRP_ERROR;
83
84   /* check type */
85   if (!json_is_string(obj))
86     return TRP_ERROR;
87
88   *dest=talloc_strdup(mem_ctx, json_string_value(obj));
89   if (*dest==NULL)
90     return TRP_ERROR;
91
92   return TRP_SUCCESS;
93 }
94
95 enum msg_type tr_msg_get_msg_type(TR_MSG *msg) 
96 {
97   return msg->msg_type;
98 }
99
100 void tr_msg_set_msg_type(TR_MSG *msg, enum msg_type type)
101 {
102   msg->msg_type = type;
103 }
104
105 /* NOTE: If you are manipulating messages with these getters/setters, the msg_rep
106  * objects are *not* put in the talloc context of the msg. If you are allocating
107  * the message directly with talloc, then you can talloc_steal() the rep into the
108  * message's context, but this is not handled automatically. */
109
110 /**
111  * Get a TID_REQ message payload
112  *
113  * @param msg
114  * @return the message payload, or null if it is not a TID_REQUEST message
115  */
116 TID_REQ *tr_msg_get_req(TR_MSG *msg)
117 {
118   if (msg->msg_type == TID_REQUEST)
119     return (TID_REQ *)msg->msg_rep;
120   return NULL;
121 }
122
123 /**
124  * Set message's payload
125  *
126  * Does not manage talloc contexts, works with any means of allocating
127  * the objects.
128  */
129 void tr_msg_set_req(TR_MSG *msg, TID_REQ *req)
130 {
131   msg->msg_rep = req;
132   msg->msg_type = TID_REQUEST;
133 }
134
135 /**
136  * Get a TID_RESP message payload
137  *
138  * @param msg
139  * @return the message payload, or null if it is not a TID_RESPONSE message
140  */
141 TID_RESP *tr_msg_get_resp(TR_MSG *msg)
142 {
143   if (msg->msg_type == TID_RESPONSE)
144     return (TID_RESP *)msg->msg_rep;
145   return NULL;
146 }
147
148 /**
149  * Set message's payload
150  *
151  * Does not manage talloc contexts, works with any means of allocating
152  * the objects.
153  */
154 void tr_msg_set_resp(TR_MSG *msg, TID_RESP *resp)
155 {
156   msg->msg_rep = resp;
157   msg->msg_type = TID_RESPONSE;
158 }
159
160 /**
161  * Get a MON_REQ message payload
162  *
163  * @param msg
164  * @return the message payload, or null if it is not a MON_REQUEST message
165  */
166 MON_REQ *tr_msg_get_mon_req(TR_MSG *msg)
167 {
168   if (msg->msg_type == MON_REQUEST)
169     return (MON_REQ *)msg->msg_rep;
170   return NULL;
171 }
172
173 /**
174  * Set message's payload
175  *
176  * Does not manage talloc contexts, works with any means of allocating
177  * the objects.
178  */
179 void tr_msg_set_mon_req(TR_MSG *msg, MON_REQ *req)
180 {
181   msg->msg_rep = req;
182   msg->msg_type = MON_REQUEST;
183 }
184
185 /**
186  * Get a MON_RESP message payload
187  *
188  * @param msg
189  * @return the message payload, or null if it is not a MON_RESPONSE message
190  */
191 MON_RESP *tr_msg_get_mon_resp(TR_MSG *msg)
192 {
193   if (msg->msg_type == MON_RESPONSE)
194     return (MON_RESP *)msg->msg_rep;
195   return NULL;
196 }
197
198 /**
199  * Set message's payload
200  *
201  * Does not manage talloc contexts, works with any means of allocating
202  * the objects.
203  */
204 void tr_msg_set_mon_resp(TR_MSG *msg, MON_RESP *resp)
205 {
206   msg->msg_rep = resp;
207   msg->msg_type = MON_RESPONSE;
208 }
209
210 /**
211  * Get a TRP_UPD message payload
212  *
213  * @param msg
214  * @return the message payload, or null if it is not a TRP_UPDATE message
215  */
216 TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg)
217 {
218   if (msg->msg_type == TRP_UPDATE)
219     return (TRP_UPD *)msg->msg_rep;
220   return NULL;
221 }
222
223 /**
224  * Set message's payload
225  *
226  * Does not manage talloc contexts, works with any means of allocating
227  * the objects.
228  */
229 void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *update)
230 {
231   msg->msg_rep=update;
232   msg->msg_type=TRP_UPDATE;
233 }
234
235 /**
236  * Get a TRP_REQ message payload
237  *
238  * @param msg
239  * @return the message payload, or null if it is not a TRP_REQUEST message
240  */
241 TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg)
242 {
243   if (msg->msg_type == TRP_REQUEST)
244     return (TRP_REQ *)msg->msg_rep;
245   return NULL;
246 }
247
248 /**
249  * Set message's payload
250  *
251  * Does not manage talloc contexts, works with any means of allocating
252  * the objects.
253  */
254 void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req)
255 {
256   msg->msg_rep=req;
257   msg->msg_type=TRP_REQUEST;
258 }
259
260 static json_t *tr_msg_encode_dh(DH *dh)
261 {
262   json_t *jdh = NULL;
263   json_t *jbn = NULL;
264   char *s=NULL;
265
266   if ((!dh) || (!dh->p) || (!dh->g) || (!dh->pub_key))
267     return NULL;
268
269   jdh = json_object();
270
271   jbn = json_string(s=BN_bn2hex(dh->p));
272   OPENSSL_free(s);
273   json_object_set_new(jdh, "dh_p", jbn);
274
275   jbn = json_string(s=BN_bn2hex(dh->g));
276   OPENSSL_free(s);
277   json_object_set_new(jdh, "dh_g", jbn);
278
279   jbn = json_string(s=BN_bn2hex(dh->pub_key));
280   OPENSSL_free(s);
281   json_object_set_new(jdh, "dh_pub_key", jbn);
282
283   return jdh;
284 }
285
286 static DH *tr_msg_decode_dh(json_t *jdh)
287 {
288   DH *dh = NULL;
289   json_t *jp = NULL;
290   json_t *jg = NULL;
291   json_t *jpub_key = NULL;
292
293   if (!(dh=tr_dh_new())) {
294     tr_crit("tr_msg_decode_dh(): Error allocating DH structure.");
295     return NULL;
296   }
297  
298   /* store required fields from dh object */
299   if ((NULL == (jp = json_object_get(jdh, "dh_p"))) ||
300       (NULL == (jg = json_object_get(jdh, "dh_g"))) ||
301       (NULL == (jpub_key = json_object_get(jdh, "dh_pub_key")))) {
302     tr_debug("tr_msg_decode_dh(): Error parsing dh_info.");
303     tr_dh_destroy(dh);
304     return NULL;
305   }
306
307   BN_hex2bn(&(dh->p), json_string_value(jp));
308   BN_hex2bn(&(dh->g), json_string_value(jg));
309   BN_hex2bn(&(dh->pub_key), json_string_value(jpub_key));
310
311   return dh;
312 }
313
314 static json_t * tr_msg_encode_tidreq(TID_REQ *req)
315 {
316   json_t *jreq = NULL;
317   json_t *jstr = NULL;
318
319   if ((!req) || (!req->rp_realm) || (!req->realm) || !(req->comm))
320     return NULL;
321
322   jreq = json_object();
323   assert(jreq);
324
325   jstr = tr_name_to_json_string(req->rp_realm);
326   json_object_set_new(jreq, "rp_realm", jstr);
327
328   jstr = tr_name_to_json_string(req->realm);
329   json_object_set_new(jreq, "target_realm", jstr);
330
331   jstr = tr_name_to_json_string(req->comm);
332   json_object_set_new(jreq, "community", jstr);
333   
334   if (req->orig_coi) {
335     jstr = tr_name_to_json_string(req->orig_coi);
336     json_object_set_new(jreq, "orig_coi", jstr);
337   }
338
339   json_object_set_new(jreq, "dh_info", tr_msg_encode_dh(req->tidc_dh));
340
341   if (req->cons)
342     json_object_set(jreq, "constraints", (json_t *) req->cons);
343
344   if (req->path)
345     json_object_set(jreq, "path", req->path);
346   if (req->expiration_interval)
347     json_object_set_new(jreq, "expiration_interval",
348                         json_integer(req->expiration_interval));
349   
350   return jreq;
351 }
352
353 static TID_REQ *tr_msg_decode_tidreq(TALLOC_CTX *mem_ctx, json_t *jreq)
354 {
355   TID_REQ *treq = NULL;
356   json_t *jrp_realm = NULL;
357   json_t *jrealm = NULL;
358   json_t *jcomm = NULL;
359   json_t *jorig_coi = NULL;
360   json_t *jdh = NULL;
361   json_t *jpath = NULL;
362   json_t *jexpire_interval = NULL;
363
364   if (!(treq =tid_req_new())) {
365     tr_crit("tr_msg_decode_tidreq(): Error allocating TID_REQ structure.");
366     return NULL;
367   }
368   talloc_steal(mem_ctx, treq);
369
370   /* store required fields from request */
371   if ((NULL == (jrp_realm = json_object_get(jreq, "rp_realm"))) ||
372       (NULL == (jrealm = json_object_get(jreq, "target_realm"))) ||
373       (NULL == (jcomm = json_object_get(jreq, "community")))) {
374     tr_notice("tr_msg_decode(): Error parsing required fields.");
375     tid_req_free(treq);
376     return NULL;
377   }
378
379   jpath = json_object_get(jreq, "path");
380   jexpire_interval = json_object_get(jreq, "expiration_interval");
381
382   treq->rp_realm = tr_new_name((char *)json_string_value(jrp_realm));
383   treq->realm = tr_new_name((char *)json_string_value(jrealm));
384   treq->comm = tr_new_name((char *)json_string_value(jcomm));
385
386   /* Get DH Info from the request */
387   if (NULL == (jdh = json_object_get(jreq, "dh_info"))) {
388     tr_debug("tr_msg_decode(): Error parsing dh_info.");
389     tid_req_free(treq);
390     return NULL;
391   }
392   treq->tidc_dh = tr_msg_decode_dh(jdh);
393
394   /* store optional "orig_coi" field */
395   if (NULL != (jorig_coi = json_object_get(jreq, "orig_coi"))) {
396     treq->orig_coi = tr_new_name((char *)json_string_value(jorig_coi));
397   }
398
399   treq->cons = (TR_CONSTRAINT_SET *) json_object_get(jreq, "constraints");
400   if (treq->cons) {
401     if (!tr_constraint_set_validate(treq->cons)) {
402       tr_debug("Constraint set validation failed");
403     tid_req_free(treq);
404     return NULL;
405     }
406     json_incref((json_t *) treq->cons);
407     tid_req_cleanup_json(treq, (json_t *) treq->cons);
408   }
409   if (jpath) {
410     json_incref(jpath);
411     treq->path = jpath;
412     tid_req_cleanup_json(treq, jpath);
413   }
414   if (jexpire_interval)
415     treq->expiration_interval = json_integer_value(jexpire_interval);
416   
417   return treq;
418 }
419
420 static json_t *tr_msg_encode_one_server(TID_SRVR_BLK *srvr)
421 {
422   json_t *jsrvr = NULL;
423   json_t *jstr = NULL;
424   gchar *time_str = g_time_val_to_iso8601(&srvr->key_expiration);
425
426   tr_debug("Encoding one server.");
427
428   jsrvr = json_object();
429
430   jstr = json_string(srvr->aaa_server_addr);
431   json_object_set_new(jsrvr, "server_addr", jstr);
432
433   json_object_set_new(jsrvr,
434                       "key_expiration", json_string(time_str));
435   g_free(time_str);
436   /* Server DH Block */
437   jstr = tr_name_to_json_string(srvr->key_name);
438   json_object_set_new(jsrvr, "key_name", jstr);
439   json_object_set_new(jsrvr, "server_dh", tr_msg_encode_dh(srvr->aaa_server_dh));
440   if (srvr->path)
441     /* The path is owned by the srvr, so grab an extra ref*/
442     json_object_set(jsrvr, "path", (json_t *)(srvr->path));
443   return jsrvr;
444 }
445
446 static int tr_msg_decode_one_server(json_t *jsrvr, TID_SRVR_BLK *srvr) 
447 {
448   json_t *jsrvr_addr = NULL;
449   json_t *jsrvr_kn = NULL;
450   json_t *jsrvr_dh = NULL;
451   json_t *jsrvr_expire = NULL;
452
453   if (jsrvr == NULL)
454     return -1;
455
456
457   if ((NULL == (jsrvr_addr = json_object_get(jsrvr, "server_addr"))) ||
458       (NULL == (jsrvr_kn = json_object_get(jsrvr, "key_name"))) ||
459       (NULL == (jsrvr_dh = json_object_get(jsrvr, "server_dh")))) {
460     tr_notice("tr_msg_decode_one_server(): Error parsing required fields.");
461     return -1;
462   }
463
464   srvr->aaa_server_addr=talloc_strdup(srvr, json_string_value(jsrvr_addr));
465   srvr->key_name = tr_new_name((char *)json_string_value(jsrvr_kn));
466   srvr->aaa_server_dh = tr_msg_decode_dh(jsrvr_dh);
467   tid_srvr_blk_set_path(srvr, (TID_PATH *) json_object_get(jsrvr, "path"));
468   jsrvr_expire = json_object_get(jsrvr, "key_expiration");
469   if (jsrvr_expire && json_is_string(jsrvr_expire)) {
470     if (!g_time_val_from_iso8601(json_string_value(jsrvr_expire),
471                                  &srvr->key_expiration))
472       tr_notice("Key expiration %s cannot be parsed", json_string_value(jsrvr_expire));
473   }
474   
475   return 0;
476 }
477
478 static json_t *tr_msg_encode_servers(TID_RESP *resp)
479 {
480   json_t *jservers = NULL;
481   json_t *jsrvr = NULL;
482   TID_SRVR_BLK *srvr = NULL;
483   size_t index;
484
485   jservers = json_array();
486
487   tid_resp_servers_foreach(resp, srvr, index) {
488     if ((NULL == (jsrvr = tr_msg_encode_one_server(srvr))) ||
489         (-1 == json_array_append_new(jservers, jsrvr))) {
490       return NULL;
491     }
492   }
493
494   //  tr_debug("tr_msg_encode_servers(): servers contains:");
495   //  tr_debug("%s", json_dumps(jservers, 0));
496   return jservers;
497 }
498
499 static TID_SRVR_BLK *tr_msg_decode_servers(TALLOC_CTX *mem_ctx, json_t *jservers)
500 {
501   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
502   TID_SRVR_BLK *servers=NULL;
503   TID_SRVR_BLK *new_srvr=NULL;
504   json_t *jsrvr;
505   size_t i, num_servers;
506
507   num_servers = json_array_size(jservers);
508   tr_debug("tr_msg_decode_servers(): Number of servers = %u.", (unsigned) num_servers);
509   
510   if (0 == num_servers) {
511     tr_debug("tr_msg_decode_servers(): Server array is empty."); 
512     goto cleanup;
513   }
514
515   for (i = 0; i < num_servers; i++) {
516     jsrvr = json_array_get(jservers, i);
517
518     new_srvr=tid_srvr_blk_new(tmp_ctx);
519     if (new_srvr==NULL) {
520       servers=NULL; /* it's all in tmp_ctx, so we can just let go */
521       goto cleanup;
522     }
523     
524     if (0 != tr_msg_decode_one_server(jsrvr, new_srvr)) {
525       servers=NULL; /* it's all in tmp_ctx, so we can just let go */
526       goto cleanup;
527     }
528
529     tid_srvr_blk_add(servers, new_srvr);
530   }
531
532   talloc_steal(mem_ctx, servers);
533
534 cleanup:
535   talloc_free(tmp_ctx);
536   return servers;
537 }
538
539 static json_t * tr_msg_encode_tidresp(TID_RESP *resp)
540 {
541   json_t *jresp = NULL;
542   json_t *jstr = NULL;
543   json_t *jservers = NULL;
544
545   if ((!resp) || (!resp->rp_realm) || (!resp->realm) || !(resp->comm))
546     return NULL;
547
548   jresp = json_object();
549
550   if (TID_ERROR == resp->result) {
551     jstr = json_string("error");
552     json_object_set_new(jresp, "result", jstr);
553     if (resp->err_msg) {
554       jstr = tr_name_to_json_string(resp->err_msg);
555       json_object_set_new(jresp, "err_msg", jstr);
556     }
557   }
558   else {
559     jstr = json_string("success");
560     json_object_set_new(jresp, "result", jstr);
561   }
562
563   jstr = tr_name_to_json_string(resp->rp_realm);
564   json_object_set_new(jresp, "rp_realm", jstr);
565
566   jstr = tr_name_to_json_string(resp->realm);
567   json_object_set_new(jresp, "target_realm", jstr);
568
569   jstr = tr_name_to_json_string(resp->comm);
570   json_object_set_new(jresp, "comm", jstr);
571
572   if (resp->orig_coi) {
573     jstr = tr_name_to_json_string(resp->orig_coi);
574     json_object_set_new(jresp, "orig_coi", jstr);
575   }
576
577   if (NULL == resp->servers) {
578     tr_debug("tr_msg_encode_tidresp(): No servers to encode.");
579   }
580   else {
581     jservers = tr_msg_encode_servers(resp);
582     json_object_set_new(jresp, "servers", jservers);
583   }
584   if (resp->error_path)
585     json_object_set(jresp, "error_path", resp->error_path);
586   
587   
588   return jresp;
589 }
590
591 static TID_RESP *tr_msg_decode_tidresp(TALLOC_CTX *mem_ctx, json_t *jresp)
592 {
593   TID_RESP *tresp = NULL;
594   json_t *jresult = NULL;
595   json_t *jrp_realm = NULL;
596   json_t *jrealm = NULL;
597   json_t *jcomm = NULL;
598   json_t *jorig_coi = NULL;
599   json_t *jservers = NULL;
600   json_t *jerr_msg = NULL;
601
602   if (!(tresp=tid_resp_new(mem_ctx))) {
603     tr_crit("tr_msg_decode_tidresp(): Error allocating TID_RESP structure.");
604     return NULL;
605   }
606
607   /* store required fields from response */
608   if ((NULL == (jresult = json_object_get(jresp, "result"))) ||
609       (!json_is_string(jresult)) ||
610       (NULL == (jrp_realm = json_object_get(jresp, "rp_realm"))) ||
611       (!json_is_string(jrp_realm)) ||
612       (NULL == (jrealm = json_object_get(jresp, "target_realm"))) ||
613       (!json_is_string(jrealm)) ||
614       (NULL == (jcomm = json_object_get(jresp, "comm"))) ||
615       (!json_is_string(jcomm))) {
616     tr_debug("tr_msg_decode_tidresp(): Error parsing response.");
617     talloc_free(tresp);
618     return NULL;
619   }
620
621   if (0 == (strcmp(json_string_value(jresult), "success"))) {
622     tr_debug("tr_msg_decode_tidresp(): Success! result = %s.", json_string_value(jresult));
623     if ((NULL != (jservers = json_object_get(jresp, "servers"))) ||
624         (!json_is_array(jservers))) {
625       tresp->servers = tr_msg_decode_servers(tresp, jservers); 
626     } 
627     else {
628       talloc_free(tresp);
629       return NULL;
630     }
631     tresp->result = TID_SUCCESS;
632   }
633   else {
634     tresp->result = TID_ERROR;
635     tr_debug("tr_msg_decode_tidresp(): Error! result = %s.", json_string_value(jresult));
636     if ((NULL != (jerr_msg = json_object_get(jresp, "err_msg"))) ||
637         (!json_is_string(jerr_msg))) {
638       tresp->err_msg = tr_new_name(json_string_value(jerr_msg));
639     } else
640       tresp->err_msg = tr_new_name("No error message set.");
641
642     if (NULL !=(tresp->error_path = json_object_get(jresp, "error_path")))
643       json_incref(tresp->error_path);
644   }
645
646   tresp->rp_realm = tr_new_name(json_string_value(jrp_realm));
647   tresp->realm = tr_new_name(json_string_value(jrealm));
648   tresp->comm = tr_new_name(json_string_value(jcomm));
649
650   /* store optional "orig_coi" field */
651   if ((NULL != (jorig_coi = json_object_get(jresp, "orig_coi"))) &&
652       (!json_is_object(jorig_coi))) {
653     tresp->orig_coi = tr_new_name(json_string_value(jorig_coi));
654   }
655      
656   return tresp;
657 }
658
659
660 /* Information records for TRP update msg 
661  * requires that jrec already be allocated */
662 static TRP_RC tr_msg_encode_inforec_route(json_t *jrec, TRP_INFOREC *rec)
663 {
664   json_t *jstr=NULL;
665   json_t *jint=NULL;
666   char *s=NULL;
667
668   if (rec==NULL)
669     return TRP_BADTYPE;
670
671   if (trp_inforec_get_trust_router(rec)==NULL)
672     return TRP_ERROR;
673
674   s=tr_name_strdup(trp_inforec_get_trust_router(rec));
675   if (s==NULL)
676     return TRP_NOMEM;
677   jstr=json_string(s);
678   free(s);s=NULL;
679   if(jstr==NULL)
680     return TRP_ERROR;
681   json_object_set_new(jrec, "trust_router", jstr);
682
683   jint=json_integer(trp_inforec_get_metric(rec));
684   if(jint==NULL)
685     return TRP_ERROR;
686   json_object_set_new(jrec, "metric", jint);
687
688   jint=json_integer(trp_inforec_get_interval(rec));
689   if(jint==NULL)
690     return TRP_ERROR;
691   json_object_set_new(jrec, "interval", jint);
692
693   return TRP_SUCCESS;
694 }
695
696 /* returns a json array */
697 static json_t *tr_msg_encode_apcs(TR_APC *apcs)
698 {
699   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
700   TR_APC_ITER *iter=tr_apc_iter_new(tmp_ctx);
701   TR_APC *apc=NULL;
702   json_t *jarray=NULL;
703   json_t *jid=NULL;
704
705   if (iter==NULL)
706     goto cleanup;
707
708   jarray=json_array();
709   if (jarray==NULL)
710     goto cleanup;
711
712   for (apc=tr_apc_iter_first(iter, apcs); apc!=NULL; apc=tr_apc_iter_next(iter)) {
713     jid=tr_name_to_json_string(tr_apc_get_id(apc));
714     if ((jid==NULL) || (json_array_append_new(jarray, jid)!=0)) {
715       json_decref(jarray);
716       jarray=NULL;
717       goto cleanup;
718     }
719   }
720   
721 cleanup:
722   talloc_free(tmp_ctx);
723   return jarray;
724 }
725
726 static TR_APC *tr_msg_decode_apcs(TALLOC_CTX *mem_ctx, json_t *jarray, TRP_RC *rc)
727 {
728   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
729   size_t ii=0;
730   TR_APC *apc_list=NULL;
731   TR_APC *new=NULL;
732   json_t *jstr=NULL;
733
734   *rc=TRP_ERROR;
735
736   for (ii=0; ii<json_array_size(jarray); ii++) {
737     jstr=json_array_get(jarray, ii);
738     new=tr_apc_new(tmp_ctx);
739     if ((jstr==NULL) || (new==NULL) || (!json_is_string(jstr))) {
740       apc_list=NULL; /* these are all in tmp_ctx, so they'll still get cleaned up */
741       goto cleanup;
742     }
743
744     tr_apc_set_id(new, tr_new_name(json_string_value(jstr)));
745     if (tr_apc_get_id(new)==NULL) {
746       apc_list=NULL; /* these are all in tmp_ctx, so they'll still get cleaned up */
747       goto cleanup;
748     }
749
750     tr_apc_add(apc_list, new);
751   }
752
753   *rc=TRP_SUCCESS;
754
755   if (apc_list!=NULL)
756     talloc_steal(mem_ctx, apc_list);
757
758 cleanup:
759   talloc_free(tmp_ctx);
760   return apc_list;
761 }
762
763 static TRP_RC tr_msg_encode_inforec_comm(json_t *jrec, TRP_INFOREC *rec)
764 {
765   json_t *jstr=NULL;
766   json_t *jint=NULL;
767   json_t *japcs=NULL;
768   const char *sconst=NULL;
769   TR_COMM_TYPE commtype=TR_COMM_UNKNOWN;
770
771   if (rec==NULL)
772     return TRP_BADTYPE;
773
774   commtype=trp_inforec_get_comm_type(rec);
775   if (commtype==TR_COMM_UNKNOWN) {
776     tr_notice("tr_msg_encode_inforec_comm: unknown community type.");
777     return TRP_ERROR;
778   }
779   sconst=tr_comm_type_to_str(commtype);
780   if (sconst==NULL)
781     return TRP_ERROR;
782   jstr=json_string(sconst);
783   if(jstr==NULL)
784     return TRP_ERROR;
785   json_object_set_new(jrec, "type", jstr);
786
787   sconst=tr_realm_role_to_str(trp_inforec_get_role(rec));
788   if (sconst==NULL) {
789     tr_notice("tr_msg_encode_inforec_comm: unknown realm role.");
790     return TRP_ERROR;
791   }
792   jstr=json_string(sconst);
793   if(jstr==NULL)
794     return TRP_ERROR;
795   json_object_set_new(jrec, "role", jstr);
796
797   japcs=tr_msg_encode_apcs(trp_inforec_get_apcs(rec));
798   if (japcs==NULL) {
799     tr_notice("tr_msg_encode_inforec_comm: error encoding APCs.");
800     return TRP_ERROR;
801   }
802   json_object_set_new(jrec, "apcs", japcs);
803   
804
805   if (trp_inforec_get_owner_realm(rec)!=NULL) {
806     jstr=tr_name_to_json_string(trp_inforec_get_owner_realm(rec));
807     if(jstr==NULL)
808       return TRP_ERROR;
809     json_object_set_new(jrec, "owner_realm", jstr);
810   }  
811
812   if (trp_inforec_get_owner_contact(rec)!=NULL) {
813     jstr=tr_name_to_json_string(trp_inforec_get_owner_contact(rec));
814     if(jstr==NULL)
815       return TRP_ERROR;
816     json_object_set_new(jrec, "owner_contact", jstr);
817   }  
818
819   json_object_set(jrec, "provenance", trp_inforec_get_provenance(rec));
820
821   jint=json_integer(trp_inforec_get_interval(rec));
822   if(jint==NULL)
823     return TRP_ERROR;
824   json_object_set_new(jrec, "interval", jint);
825
826   return TRP_SUCCESS;
827 }
828
829 static json_t *tr_msg_encode_inforec(TRP_INFOREC *rec)
830 {
831   json_t *jrec=NULL;
832   json_t *jstr=NULL;
833
834   if ((rec==NULL) || (trp_inforec_get_type(rec)==TRP_INFOREC_TYPE_UNKNOWN))
835     return NULL;
836
837   jrec=json_object();
838   if (jrec==NULL)
839     return NULL;
840
841   jstr=json_string(trp_inforec_type_to_string(trp_inforec_get_type(rec)));
842   if (jstr==NULL) {
843     json_decref(jrec);
844     return NULL;
845   }
846   json_object_set_new(jrec, "record_type", jstr);
847
848   switch (rec->type) {
849   case TRP_INFOREC_TYPE_ROUTE:
850     if (TRP_SUCCESS!=tr_msg_encode_inforec_route(jrec, rec)) {
851       json_decref(jrec);
852       return NULL;
853     }
854     break;
855   case TRP_INFOREC_TYPE_COMMUNITY:
856     if (TRP_SUCCESS!=tr_msg_encode_inforec_comm(jrec, rec)) {
857       json_decref(jrec);
858       return NULL;
859     }
860     break;
861   default:
862     json_decref(jrec);
863     return NULL;
864   }
865   return jrec;
866 }
867
868 static TRP_RC tr_msg_decode_trp_inforec_route(json_t *jrecord, TRP_INFOREC *rec)
869 {
870   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
871   TRP_RC rc=TRP_ERROR;
872   char *s=NULL;
873   int num=0;
874
875   rc=tr_msg_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
876   if (rc != TRP_SUCCESS)
877     goto cleanup;
878   if (TRP_SUCCESS!=trp_inforec_set_trust_router(rec, tr_new_name(s))) {
879     rc=TRP_ERROR;
880     goto cleanup;
881   }
882   talloc_free(s); s=NULL;
883
884   trp_inforec_set_next_hop(rec, NULL); /* make sure this is null (filled in later) */
885
886   rc=tr_msg_get_json_integer(jrecord, "metric", &num);
887   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_metric(rec,num)))
888     goto cleanup;
889
890   rc=tr_msg_get_json_integer(jrecord, "interval", &num);
891   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
892     goto cleanup;
893
894 cleanup:
895   talloc_free(tmp_ctx);
896   return rc;
897 }
898
899 static TRP_RC tr_msg_decode_trp_inforec_comm(json_t *jrecord, TRP_INFOREC *rec)
900 {
901   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
902   TRP_RC rc=TRP_ERROR;
903   char *s=NULL;
904   int num=0;
905   TR_APC *apcs=NULL;
906
907   rc=tr_msg_get_json_string(jrecord, "type", &s, tmp_ctx);
908   if (rc != TRP_SUCCESS)
909     goto cleanup;
910   if (TRP_SUCCESS!=trp_inforec_set_comm_type(rec, tr_comm_type_from_str(s))) {
911     rc=TRP_ERROR;
912     goto cleanup;
913   }
914   talloc_free(s); s=NULL;
915
916   rc=tr_msg_get_json_string(jrecord, "role", &s, tmp_ctx);
917   if (rc != TRP_SUCCESS)
918     goto cleanup;
919   if (TRP_SUCCESS!=trp_inforec_set_role(rec, tr_realm_role_from_str(s))) {
920     rc=TRP_ERROR;
921     goto cleanup;
922   }
923   talloc_free(s); s=NULL;
924
925   apcs=tr_msg_decode_apcs(rec, json_object_get(jrecord, "apcs"), &rc);
926   if (rc!=TRP_SUCCESS) {
927     rc=TRP_ERROR;
928     goto cleanup;
929   }
930   trp_inforec_set_apcs(rec, apcs);
931
932   rc=tr_msg_get_json_integer(jrecord, "interval", &num);
933   tr_debug("tr_msg_decode_trp_inforec_comm: interval=%u", num);
934   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
935     goto cleanup;
936
937   trp_inforec_set_provenance(rec, json_object_get(jrecord, "provenance"));
938
939   /* optional */
940   rc=tr_msg_get_json_string(jrecord, "owner_realm", &s, tmp_ctx);
941   if (rc == TRP_SUCCESS) {
942     if (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_new_name(s))) {
943       rc=TRP_ERROR;
944       goto cleanup;
945     }
946     if (s!=NULL) {
947       talloc_free(s);
948       s=NULL;
949     }
950   }
951
952   rc=tr_msg_get_json_string(jrecord, "owner_contact", &s, tmp_ctx);
953   if (rc == TRP_SUCCESS) {
954     if (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_new_name(s))) {
955       rc=TRP_ERROR;
956       goto cleanup;
957     }
958     if (s!=NULL) {
959       talloc_free(s);
960       s=NULL;
961     }
962   }
963
964 cleanup:
965   talloc_free(tmp_ctx);
966   return rc;
967 }
968
969 /* decode a single record */
970 static TRP_INFOREC *tr_msg_decode_trp_inforec(TALLOC_CTX *mem_ctx, json_t *jrecord)
971 {
972   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
973   TRP_INFOREC_TYPE rectype;
974   TRP_INFOREC *rec=NULL;
975   TRP_RC rc=TRP_ERROR;
976   char *s=NULL;
977   
978   if (TRP_SUCCESS!=tr_msg_get_json_string(jrecord, "record_type", &s, tmp_ctx))
979     goto cleanup;
980
981   rectype=trp_inforec_type_from_string(s);
982   talloc_free(s); s=NULL;
983
984   rec=trp_inforec_new(tmp_ctx, rectype);
985   if (rec==NULL) {
986     rc=TRP_NOMEM;
987     goto cleanup;
988   }
989
990   tr_debug("tr_msg_decode_trp_inforec: '%s' record found.", trp_inforec_type_to_string(rec->type));
991
992   switch(trp_inforec_get_type(rec)) {
993   case TRP_INFOREC_TYPE_ROUTE:
994     rc=tr_msg_decode_trp_inforec_route(jrecord, rec);
995     break;
996   case TRP_INFOREC_TYPE_COMMUNITY:
997     rc=tr_msg_decode_trp_inforec_comm(jrecord, rec);
998     break;
999   default:
1000     rc=TRP_UNSUPPORTED;
1001     goto cleanup;
1002   }
1003
1004   talloc_steal(mem_ctx, rec);
1005   rc=TRP_SUCCESS;
1006
1007 cleanup:
1008   if (rc != TRP_SUCCESS) {
1009     trp_inforec_free(rec);
1010     rec=NULL;
1011   }
1012   talloc_free(tmp_ctx);
1013   return rec;
1014 }
1015
1016 /* TRP update msg */
1017 static json_t *tr_msg_encode_trp_upd(TRP_UPD *update)
1018 {
1019   json_t *jupdate=NULL;
1020   json_t *jrecords=NULL;
1021   json_t *jrec=NULL;
1022   json_t *jstr=NULL;
1023   TRP_INFOREC *rec;
1024   char *s=NULL;
1025
1026   if (update==NULL)
1027     return NULL;
1028
1029   jupdate=json_object();
1030   if (jupdate==NULL)
1031     return NULL;
1032
1033   s=tr_name_strdup(trp_upd_get_comm(update));
1034   if (s==NULL) {
1035     json_decref(jupdate);
1036     return NULL;
1037   }
1038   jstr=json_string(s);
1039   free(s);s=NULL;
1040   if(jstr==NULL) {
1041     json_decref(jupdate);
1042     return NULL;
1043   }
1044   json_object_set_new(jupdate, "community", jstr);
1045
1046   s=tr_name_strdup(trp_upd_get_realm(update));
1047   if (s==NULL) {
1048     json_decref(jupdate);
1049     return NULL;
1050   }
1051   jstr=json_string(s);
1052   free(s);s=NULL;
1053   if(jstr==NULL) {
1054     json_decref(jupdate);
1055     return NULL;
1056   }
1057   json_object_set_new(jupdate, "realm", jstr);
1058
1059   jrecords=json_array();
1060   if (jrecords==NULL) {
1061     json_decref(jupdate);
1062     return NULL;
1063   }
1064   json_object_set_new(jupdate, "records", jrecords); /* jrecords now a "borrowed" reference */
1065   for (rec=trp_upd_get_inforec(update); rec!=NULL; rec=trp_inforec_get_next(rec)) {
1066     tr_debug("tr_msg_encode_trp_upd: encoding inforec.");
1067     jrec=tr_msg_encode_inforec(rec);
1068     if (jrec==NULL) {
1069       json_decref(jupdate); /* also decs jrecords and any elements */
1070       return NULL;
1071     }
1072     if (0!=json_array_append_new(jrecords, jrec)) {
1073       json_decref(jupdate); /* also decs jrecords and any elements */
1074       json_decref(jrec); /* this one did not get added so dec explicitly */
1075       return NULL;
1076     }
1077   }
1078
1079   return jupdate;
1080 }
1081
1082 /* Creates a linked list of records in the msg->body talloc context.
1083  * An error will be returned if any unparseable records are encountered. 
1084  */
1085 static TRP_UPD *tr_msg_decode_trp_upd(TALLOC_CTX *mem_ctx, json_t *jupdate)
1086 {
1087   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1088   json_t *jrecords=NULL;
1089   size_t ii=0;
1090   TRP_UPD *update=NULL;
1091   TRP_INFOREC *new_rec=NULL;
1092   TRP_INFOREC *list_tail=NULL;
1093   char *s=NULL;
1094   TR_NAME *name;
1095   TRP_RC rc=TRP_ERROR;
1096
1097   update=trp_upd_new(tmp_ctx);
1098   if (update==NULL) {
1099     rc=TRP_NOMEM;
1100     goto cleanup;
1101   }
1102
1103   rc=tr_msg_get_json_string(jupdate, "community", &s, tmp_ctx);
1104   if (rc != TRP_SUCCESS) {
1105     tr_debug("tr_msg_decode_trp_upd: no community in TRP update message.");
1106     rc=TRP_NOPARSE;
1107     goto cleanup;
1108   }
1109   name=tr_new_name(s);
1110   if (name==NULL) {
1111     tr_debug("tr_msg_decode_trp_upd: could not allocate community name.");
1112     rc=TRP_NOMEM;
1113     goto cleanup;
1114   }
1115   talloc_free(s); s=NULL;
1116   trp_upd_set_comm(update, name);
1117
1118   rc=tr_msg_get_json_string(jupdate, "realm", &s, tmp_ctx);
1119   if (rc != TRP_SUCCESS) {
1120     tr_debug("tr_msg_decode_trp_upd: no realm in TRP update message.");
1121     rc=TRP_NOPARSE;
1122     goto cleanup;
1123   }
1124   name=tr_new_name(s);
1125   if (name==NULL) {
1126     tr_debug("tr_msg_decode_trp_upd: could not allocate realm name.");
1127     rc=TRP_NOMEM;
1128     goto cleanup;
1129   }
1130   talloc_free(s); s=NULL;
1131   trp_upd_set_realm(update, name);
1132
1133   jrecords=json_object_get(jupdate, "records");
1134   if ((jrecords==NULL) || (!json_is_array(jrecords))) {
1135     rc=TRP_NOPARSE;
1136     goto cleanup;
1137   }
1138
1139   tr_debug("tr_msg_decode_trp_upd: found %d records", json_array_size(jrecords));
1140   /* process the array */
1141   for (ii=0; ii<json_array_size(jrecords); ii++) {
1142     new_rec=tr_msg_decode_trp_inforec(update, json_array_get(jrecords, ii));
1143     if (new_rec==NULL) {
1144       rc=TRP_NOPARSE;
1145       goto cleanup;
1146     }
1147
1148     if (list_tail==NULL)
1149       trp_upd_set_inforec(update, new_rec); /* first is a special case */
1150     else
1151       trp_inforec_set_next(list_tail, new_rec);
1152
1153     list_tail=new_rec;
1154   }
1155
1156   /* Succeeded. Move new allocations into the correct talloc context */
1157   talloc_steal(mem_ctx, update);
1158   rc=TRP_SUCCESS;
1159
1160 cleanup:
1161   talloc_free(tmp_ctx);
1162   if (rc!=TRP_SUCCESS)
1163     return NULL;
1164   return update;
1165 }
1166
1167 static json_t *tr_msg_encode_trp_req(TRP_REQ *req)
1168 {
1169   json_t *jbody=NULL;
1170   json_t *jstr=NULL;
1171   char *s=NULL;
1172
1173   if (req==NULL)
1174     return NULL;
1175
1176   jbody=json_object();
1177   if (jbody==NULL)
1178     return NULL;
1179
1180   if ((NULL==trp_req_get_comm(req))
1181      || (NULL==trp_req_get_realm(req))) {
1182     json_decref(jbody);
1183     return NULL;
1184   }
1185
1186   s=tr_name_strdup(trp_req_get_comm(req)); /* ensures null termination */
1187   if (s==NULL) {
1188     json_decref(jbody);
1189     return NULL;
1190   }
1191   jstr=json_string(s);
1192   free(s); s=NULL;
1193   if (jstr==NULL) {
1194     json_decref(jbody);
1195     return NULL;
1196   }
1197   json_object_set_new(jbody, "community", jstr);
1198     
1199   s=tr_name_strdup(trp_req_get_realm(req)); /* ensures null termination */
1200   if (s==NULL) {
1201     json_decref(jbody);
1202     return NULL;
1203   }
1204   jstr=json_string(s);
1205   free(s); s=NULL;
1206   if (jstr==NULL) {
1207     json_decref(jbody);
1208     return NULL;
1209   }
1210   json_object_set_new(jbody, "realm", jstr);
1211
1212   return jbody;
1213 }
1214
1215 static TRP_REQ *tr_msg_decode_trp_req(TALLOC_CTX *mem_ctx, json_t *jreq)
1216 {
1217   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1218   TRP_REQ *req=NULL;
1219   char *s=NULL;
1220   TRP_RC rc=TRP_ERROR;
1221
1222   /* check message type and body type for agreement */
1223   req=trp_req_new(tmp_ctx);
1224   if (req==NULL) {
1225     rc=TRP_NOMEM;
1226     goto cleanup;
1227   }
1228
1229   rc=tr_msg_get_json_string(jreq, "community", &s, tmp_ctx);
1230   if (rc!=TRP_SUCCESS)
1231     goto cleanup;
1232   trp_req_set_comm(req, tr_new_name(s));
1233   talloc_free(s); s=NULL;
1234
1235   rc=tr_msg_get_json_string(jreq, "realm", &s, tmp_ctx);
1236   if (rc!=TRP_SUCCESS)
1237     goto cleanup;
1238   trp_req_set_realm(req, tr_new_name(s));
1239   talloc_free(s); s=NULL;
1240
1241   rc=TRP_SUCCESS;
1242   talloc_steal(mem_ctx, req);
1243
1244 cleanup:
1245   talloc_free(tmp_ctx);
1246   if (rc!=TRP_SUCCESS)
1247     return NULL;
1248   return req;
1249 }
1250
1251 char *tr_msg_encode(TALLOC_CTX *mem_ctx, TR_MSG *msg)
1252 {
1253   json_t *jmsg=NULL;
1254   json_t *jmsg_type=NULL;
1255   char *encoded_tmp=NULL;
1256   char *encoded=NULL;
1257   TID_RESP *tidresp=NULL;
1258   TID_REQ *tidreq=NULL;
1259   TRP_UPD *trpupd=NULL;
1260   TRP_REQ *trpreq=NULL;
1261   MON_REQ *monreq=NULL;
1262   MON_RESP *monresp=NULL;
1263
1264   /* TBD -- add error handling */
1265   jmsg = json_object();
1266
1267   switch (msg->msg_type) {
1268     case TID_REQUEST:
1269       jmsg_type = json_string("tid_request");
1270       json_object_set_new(jmsg, "msg_type", jmsg_type);
1271       tidreq=tr_msg_get_req(msg);
1272       json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidreq(tidreq));
1273       break;
1274
1275     case TID_RESPONSE:
1276       jmsg_type = json_string("tid_response");
1277       json_object_set_new(jmsg, "msg_type", jmsg_type);
1278       tidresp=tr_msg_get_resp(msg);
1279       json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidresp(tidresp));
1280       break;
1281
1282     case TRP_UPDATE:
1283       jmsg_type = json_string("trp_update");
1284       json_object_set_new(jmsg, "msg_type", jmsg_type);
1285       trpupd=tr_msg_get_trp_upd(msg);
1286       json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_upd(trpupd));
1287       break;
1288
1289     case TRP_REQUEST:
1290       jmsg_type = json_string("trp_request");
1291       json_object_set_new(jmsg, "msg_type", jmsg_type);
1292       trpreq=tr_msg_get_trp_req(msg);
1293       json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_req(trpreq));
1294       break;
1295
1296     case MON_REQUEST:
1297       jmsg_type = json_string("mon_request");
1298       json_object_set_new(jmsg, "msg_type", jmsg_type);
1299       monreq=tr_msg_get_mon_req(msg);
1300       json_object_set_new(jmsg, "msg_body", mon_req_encode(monreq));
1301       break;
1302
1303     case MON_RESPONSE:
1304       jmsg_type = json_string("mon_response");
1305       json_object_set_new(jmsg, "msg_type", jmsg_type);
1306       monresp=tr_msg_get_mon_resp(msg);
1307       json_object_set_new(jmsg, "msg_body", mon_resp_encode(monresp));
1308       break;
1309
1310     default:
1311       json_decref(jmsg);
1312       return NULL;
1313   }
1314
1315   /* We should perhaps use json_set_alloc_funcs to automatically use talloc, but for
1316    * now, we'll encode to a malloc'ed buffer, then copy that to a talloc'ed buffer. */
1317   encoded_tmp=json_dumps(jmsg, 0);                // malloc'ed version
1318   json_decref(jmsg);                              // free the JSON structure
1319   encoded = talloc_strdup(mem_ctx, encoded_tmp);  // get the talloc'ed version
1320   free(encoded_tmp);                              // free the malloc'ed version
1321
1322   tr_debug("tr_msg_encode: outgoing msg=%s", encoded);
1323   return encoded;
1324 }
1325
1326 TR_MSG *tr_msg_decode(TALLOC_CTX *mem_ctx, const char *jbuf, size_t buflen)
1327 {
1328   TR_MSG *msg=NULL;
1329   json_t *jmsg = NULL;
1330   json_error_t rc;
1331   json_t *jtype=NULL;
1332   json_t *jbody=NULL;
1333   const char *mtype = NULL;
1334
1335   if (NULL == (jmsg = json_loadb(jbuf, buflen, JSON_DISABLE_EOF_CHECK, &rc))) {
1336     tr_debug("tr_msg_decode(): error loading object");
1337     return NULL;
1338   }
1339
1340   if (!(msg = talloc_zero(mem_ctx, TR_MSG))) {
1341     tr_debug("tr_msg_decode(): Error allocating TR_MSG structure.");
1342     json_decref(jmsg);
1343     return NULL;
1344   }
1345  
1346   if ((NULL == (jtype = json_object_get(jmsg, "msg_type"))) ||
1347       (NULL == (jbody = json_object_get(jmsg, "msg_body")))) {
1348     tr_debug("tr_msg_decode(): Error parsing message header.");
1349     json_decref(jmsg);
1350     tr_msg_free_decoded(msg);
1351     return NULL;
1352   }
1353
1354   mtype = json_string_value(jtype);
1355
1356   if (0 == strcmp(mtype, "tid_request")) {
1357     msg->msg_type = TID_REQUEST;
1358     tr_msg_set_req(msg, tr_msg_decode_tidreq(msg, jbody));
1359   }
1360   else if (0 == strcmp(mtype, "tid_response")) {
1361     msg->msg_type = TID_RESPONSE;
1362     tr_msg_set_resp(msg, tr_msg_decode_tidresp(msg, jbody));
1363   }
1364   else if (0 == strcmp(mtype, "trp_update")) {
1365     msg->msg_type = TRP_UPDATE;
1366     tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(msg, jbody));
1367   }
1368   else if (0 == strcmp(mtype, "trp_request")) {
1369     msg->msg_type = TRP_UPDATE;
1370     tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(msg, jbody));
1371   }
1372   else if (0 == strcmp(mtype, "mon_request")) {
1373     msg->msg_type = MON_REQUEST;
1374     tr_msg_set_mon_req(msg, mon_req_decode(msg, jbody));
1375   }
1376   /* We do not currently handle monitoring responses */
1377   else if (0 == strcmp(mtype, "mon_response")) {
1378     msg->msg_type = MON_RESPONSE;
1379     tr_msg_set_mon_resp(msg, mon_resp_decode(msg, jbody));
1380   }
1381   else {
1382     msg->msg_type = TR_UNKNOWN;
1383     msg->msg_rep = NULL;
1384   }
1385
1386   json_decref(jmsg);
1387
1388   return msg;
1389 }
1390
1391 void tr_msg_free_encoded(char *jmsg)
1392 {
1393   if (jmsg)
1394     talloc_free(jmsg);
1395 }
1396
1397 void tr_msg_free_decoded(TR_MSG *msg)
1398 {
1399   if (msg)
1400     talloc_free(msg);
1401 }