Support non-default TRP and TID ports
[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 #include <tr_apc.h>
45 #include <tr_comm.h>
46 #include <trp_internal.h>
47 #include <mon_internal.h>
48 #include <tr_msg.h>
49 #include <tr_util.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. */
57 static TRP_RC 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 TRP_MISSING;
64   }
65   /* check type */
66   if (!json_is_integer(obj)) {
67     return TRP_BADTYPE;
68   }
69
70   (*dest)=json_integer_value(obj);
71   return TRP_SUCCESS;
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_MISSING;
83
84   /* check type */
85   if (!json_is_string(obj))
86     return TRP_BADTYPE;
87
88   *dest=talloc_strdup(mem_ctx, json_string_value(obj));
89   if (*dest==NULL)
90     return TRP_NOMEM;
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   if (tid_req_get_request_id(req)) {
340     jstr = tr_name_to_json_string(tid_req_get_request_id(req));
341     json_object_set_new(jreq, "request_id", jstr);
342   }
343
344   json_object_set_new(jreq, "dh_info", tr_msg_encode_dh(req->tidc_dh));
345
346   if (req->cons)
347     json_object_set(jreq, "constraints", (json_t *) req->cons);
348
349   if (req->path)
350     json_object_set(jreq, "path", req->path);
351   if (req->expiration_interval)
352     json_object_set_new(jreq, "expiration_interval",
353                         json_integer(req->expiration_interval));
354   
355   return jreq;
356 }
357
358 static TID_REQ *tr_msg_decode_tidreq(TALLOC_CTX *mem_ctx, json_t *jreq)
359 {
360   TID_REQ *treq = NULL;
361   json_t *jrp_realm = NULL;
362   json_t *jrealm = NULL;
363   json_t *jcomm = NULL;
364   json_t *jorig_coi = NULL;
365   json_t *jrequest_id = NULL;
366   json_t *jdh = NULL;
367   json_t *jpath = NULL;
368   json_t *jexpire_interval = NULL;
369
370   if (!(treq =tid_req_new())) {
371     tr_crit("tr_msg_decode_tidreq(): Error allocating TID_REQ structure.");
372     return NULL;
373   }
374   talloc_steal(mem_ctx, treq);
375
376   /* store required fields from request */
377   if ((NULL == (jrp_realm = json_object_get(jreq, "rp_realm"))) ||
378       (NULL == (jrealm = json_object_get(jreq, "target_realm"))) ||
379       (NULL == (jcomm = json_object_get(jreq, "community")))) {
380     tr_notice("tr_msg_decode(): Error parsing required fields.");
381     tid_req_free(treq);
382     return NULL;
383   }
384
385   jpath = json_object_get(jreq, "path");
386   jexpire_interval = json_object_get(jreq, "expiration_interval");
387
388   treq->rp_realm = tr_new_name(json_string_value(jrp_realm));
389   treq->realm = tr_new_name(json_string_value(jrealm));
390   treq->comm = tr_new_name(json_string_value(jcomm));
391
392   /* Get DH Info from the request */
393   if (NULL == (jdh = json_object_get(jreq, "dh_info"))) {
394     tr_debug("tr_msg_decode(): Error parsing dh_info.");
395     tid_req_free(treq);
396     return NULL;
397   }
398   treq->tidc_dh = tr_msg_decode_dh(jdh);
399
400   /* store optional "orig_coi" field */
401   if (NULL != (jorig_coi = json_object_get(jreq, "orig_coi"))) {
402     treq->orig_coi = tr_new_name(json_string_value(jorig_coi));
403   }
404
405   /* store optional "request_id" field */
406   if (NULL != (jrequest_id = json_object_get(jreq, "request_id"))) {
407     tid_req_set_request_id(treq, tr_new_name(json_string_value(jrequest_id)));
408   }
409
410   treq->cons = (TR_CONSTRAINT_SET *) json_object_get(jreq, "constraints");
411   if (treq->cons) {
412     if (!tr_constraint_set_validate(treq->cons)) {
413       tr_debug("Constraint set validation failed");
414     tid_req_free(treq);
415     return NULL;
416     }
417     json_incref((json_t *) treq->cons);
418     tid_req_cleanup_json(treq, (json_t *) treq->cons);
419   }
420   if (jpath) {
421     json_incref(jpath);
422     treq->path = jpath;
423     tid_req_cleanup_json(treq, jpath);
424   }
425   if (jexpire_interval)
426     treq->expiration_interval = json_integer_value(jexpire_interval);
427   
428   return treq;
429 }
430
431 static json_t *tr_msg_encode_one_server(TID_SRVR_BLK *srvr)
432 {
433   json_t *jsrvr = NULL;
434   json_t *jstr = NULL;
435   gchar *time_str = g_time_val_to_iso8601(&srvr->key_expiration);
436
437   tr_debug("Encoding one server.");
438
439   jsrvr = json_object();
440
441   jstr = json_string(srvr->aaa_server_addr);
442   json_object_set_new(jsrvr, "server_addr", jstr);
443
444   json_object_set_new(jsrvr,
445                       "key_expiration", json_string(time_str));
446   g_free(time_str);
447   /* Server DH Block */
448   jstr = tr_name_to_json_string(srvr->key_name);
449   json_object_set_new(jsrvr, "key_name", jstr);
450   json_object_set_new(jsrvr, "server_dh", tr_msg_encode_dh(srvr->aaa_server_dh));
451   if (srvr->path)
452     /* The path is owned by the srvr, so grab an extra ref*/
453     json_object_set(jsrvr, "path", (json_t *)(srvr->path));
454   return jsrvr;
455 }
456
457 static int tr_msg_decode_one_server(json_t *jsrvr, TID_SRVR_BLK *srvr) 
458 {
459   json_t *jsrvr_addr = NULL;
460   json_t *jsrvr_kn = NULL;
461   json_t *jsrvr_dh = NULL;
462   json_t *jsrvr_expire = NULL;
463
464   if (jsrvr == NULL)
465     return -1;
466
467
468   if ((NULL == (jsrvr_addr = json_object_get(jsrvr, "server_addr"))) ||
469       (NULL == (jsrvr_kn = json_object_get(jsrvr, "key_name"))) ||
470       (NULL == (jsrvr_dh = json_object_get(jsrvr, "server_dh")))) {
471     tr_notice("tr_msg_decode_one_server(): Error parsing required fields.");
472     return -1;
473   }
474
475   srvr->aaa_server_addr=talloc_strdup(srvr, json_string_value(jsrvr_addr));
476   srvr->key_name = tr_new_name((char *)json_string_value(jsrvr_kn));
477   srvr->aaa_server_dh = tr_msg_decode_dh(jsrvr_dh);
478   tid_srvr_blk_set_path(srvr, (TID_PATH *) json_object_get(jsrvr, "path"));
479   jsrvr_expire = json_object_get(jsrvr, "key_expiration");
480   if (jsrvr_expire && json_is_string(jsrvr_expire)) {
481     if (!g_time_val_from_iso8601(json_string_value(jsrvr_expire),
482                                  &srvr->key_expiration))
483       tr_notice("Key expiration %s cannot be parsed", json_string_value(jsrvr_expire));
484   }
485   
486   return 0;
487 }
488
489 static json_t *tr_msg_encode_servers(TID_RESP *resp)
490 {
491   json_t *jservers = NULL;
492   json_t *jsrvr = NULL;
493   TID_SRVR_BLK *srvr = NULL;
494   size_t index;
495
496   jservers = json_array();
497
498   tid_resp_servers_foreach(resp, srvr, index) {
499     if ((NULL == (jsrvr = tr_msg_encode_one_server(srvr))) ||
500         (-1 == json_array_append_new(jservers, jsrvr))) {
501       return NULL;
502     }
503   }
504
505   //  tr_debug("tr_msg_encode_servers(): servers contains:");
506   //  tr_debug("%s", json_dumps(jservers, 0));
507   return jservers;
508 }
509
510 static TID_SRVR_BLK *tr_msg_decode_servers(TALLOC_CTX *mem_ctx, json_t *jservers)
511 {
512   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
513   TID_SRVR_BLK *servers=NULL;
514   TID_SRVR_BLK *new_srvr=NULL;
515   json_t *jsrvr;
516   size_t i, num_servers;
517
518   num_servers = json_array_size(jservers);
519   tr_debug("tr_msg_decode_servers(): Number of servers = %u.", (unsigned) num_servers);
520   
521   if (0 == num_servers) {
522     tr_debug("tr_msg_decode_servers(): Server array is empty."); 
523     goto cleanup;
524   }
525
526   for (i = 0; i < num_servers; i++) {
527     jsrvr = json_array_get(jservers, i);
528
529     new_srvr=tid_srvr_blk_new(tmp_ctx);
530     if (new_srvr==NULL) {
531       servers=NULL; /* it's all in tmp_ctx, so we can just let go */
532       goto cleanup;
533     }
534     
535     if (0 != tr_msg_decode_one_server(jsrvr, new_srvr)) {
536       servers=NULL; /* it's all in tmp_ctx, so we can just let go */
537       goto cleanup;
538     }
539
540     tid_srvr_blk_add(servers, new_srvr);
541   }
542
543   talloc_steal(mem_ctx, servers);
544
545 cleanup:
546   talloc_free(tmp_ctx);
547   return servers;
548 }
549
550 static json_t * tr_msg_encode_tidresp(TID_RESP *resp)
551 {
552   json_t *jresp = NULL;
553   json_t *jstr = NULL;
554   json_t *jservers = NULL;
555
556   if ((!resp) || (!resp->rp_realm) || (!resp->realm) || !(resp->comm))
557     return NULL;
558
559   jresp = json_object();
560
561   if (TID_ERROR == resp->result) {
562     jstr = json_string("error");
563     json_object_set_new(jresp, "result", jstr);
564     if (resp->err_msg) {
565       jstr = tr_name_to_json_string(resp->err_msg);
566       json_object_set_new(jresp, "err_msg", jstr);
567     }
568   }
569   else {
570     jstr = json_string("success");
571     json_object_set_new(jresp, "result", jstr);
572   }
573
574   jstr = tr_name_to_json_string(resp->rp_realm);
575   json_object_set_new(jresp, "rp_realm", jstr);
576
577   jstr = tr_name_to_json_string(resp->realm);
578   json_object_set_new(jresp, "target_realm", jstr);
579
580   jstr = tr_name_to_json_string(resp->comm);
581   json_object_set_new(jresp, "comm", jstr);
582
583   if (resp->orig_coi) {
584     jstr = tr_name_to_json_string(resp->orig_coi);
585     json_object_set_new(jresp, "orig_coi", jstr);
586   }
587
588   if (tid_resp_get_request_id(resp)) {
589     jstr = tr_name_to_json_string(tid_resp_get_request_id(resp));
590     json_object_set_new(jresp, "request_id", jstr);
591   }
592
593   if (NULL == resp->servers) {
594     tr_debug("tr_msg_encode_tidresp(): No servers to encode.");
595   }
596   else {
597     jservers = tr_msg_encode_servers(resp);
598     json_object_set_new(jresp, "servers", jservers);
599   }
600   if (resp->error_path)
601     json_object_set(jresp, "error_path", resp->error_path);
602   
603   
604   return jresp;
605 }
606
607 static TID_RESP *tr_msg_decode_tidresp(TALLOC_CTX *mem_ctx, json_t *jresp)
608 {
609   TID_RESP *tresp = NULL;
610   json_t *jresult = NULL;
611   json_t *jrp_realm = NULL;
612   json_t *jrealm = NULL;
613   json_t *jcomm = NULL;
614   json_t *jorig_coi = NULL;
615   json_t *jrequest_id = NULL;
616   json_t *jservers = NULL;
617   json_t *jerr_msg = NULL;
618
619   if (!(tresp=tid_resp_new(mem_ctx))) {
620     tr_crit("tr_msg_decode_tidresp(): Error allocating TID_RESP structure.");
621     return NULL;
622   }
623
624   /* store required fields from response */
625   if ((NULL == (jresult = json_object_get(jresp, "result"))) ||
626       (!json_is_string(jresult)) ||
627       (NULL == (jrp_realm = json_object_get(jresp, "rp_realm"))) ||
628       (!json_is_string(jrp_realm)) ||
629       (NULL == (jrealm = json_object_get(jresp, "target_realm"))) ||
630       (!json_is_string(jrealm)) ||
631       (NULL == (jcomm = json_object_get(jresp, "comm"))) ||
632       (!json_is_string(jcomm))) {
633     tr_debug("tr_msg_decode_tidresp(): Error parsing response.");
634     talloc_free(tresp);
635     return NULL;
636   }
637
638   if (0 == (strcmp(json_string_value(jresult), "success"))) {
639     tr_debug("tr_msg_decode_tidresp(): Success! result = %s.", json_string_value(jresult));
640     if ((NULL != (jservers = json_object_get(jresp, "servers"))) ||
641         (!json_is_array(jservers))) {
642       tresp->servers = tr_msg_decode_servers(tresp, jservers); 
643     } 
644     else {
645       talloc_free(tresp);
646       return NULL;
647     }
648     tresp->result = TID_SUCCESS;
649   }
650   else {
651     tresp->result = TID_ERROR;
652     tr_debug("tr_msg_decode_tidresp(): Error! result = %s.", json_string_value(jresult));
653     if ((NULL != (jerr_msg = json_object_get(jresp, "err_msg"))) ||
654         (!json_is_string(jerr_msg))) {
655       tresp->err_msg = tr_new_name(json_string_value(jerr_msg));
656     } else
657       tresp->err_msg = tr_new_name("No error message set.");
658
659     if (NULL !=(tresp->error_path = json_object_get(jresp, "error_path")))
660       json_incref(tresp->error_path);
661   }
662
663   tresp->rp_realm = tr_new_name(json_string_value(jrp_realm));
664   tresp->realm = tr_new_name(json_string_value(jrealm));
665   tresp->comm = tr_new_name(json_string_value(jcomm));
666
667   /* store optional "orig_coi" field */
668   if ((NULL != (jorig_coi = json_object_get(jresp, "orig_coi"))) &&
669       json_is_string(jorig_coi)) {
670     tresp->orig_coi = tr_new_name(json_string_value(jorig_coi));
671   }
672
673   /* store optional "request_id" field */
674   if ((NULL != (jrequest_id = json_object_get(jresp, "request_id"))) &&
675       json_is_string(jrequest_id)) {
676     tid_resp_set_request_id(tresp, tr_new_name(json_string_value(jrequest_id)));
677   }
678
679   return tresp;
680 }
681
682 static json_t *hostname_and_port_to_json(TR_NAME *hostname, int port)
683 {
684   char *s_hostname = tr_name_strdup(hostname);
685   char *s;
686   json_t *j;
687
688   if (s_hostname == NULL)
689     return NULL;
690
691   s = talloc_asprintf(NULL, "%s:%d", s_hostname, port);
692   free(s_hostname);
693
694   if (s == NULL)
695     return NULL;
696
697   j = json_string(s);
698   talloc_free(s);
699
700   return j;
701 }
702
703 /* Information records for TRP update msg
704  * requires that jrec already be allocated */
705 static TRP_RC tr_msg_encode_inforec_route(json_t *jrec, TRP_INFOREC *rec)
706 {
707   json_t *jstr=NULL;
708   json_t *jint=NULL;
709
710   if (rec==NULL)
711     return TRP_BADTYPE;
712
713   if (trp_inforec_get_trust_router(rec)==NULL)
714     return TRP_ERROR;
715
716   jstr=hostname_and_port_to_json(trp_inforec_get_trust_router(rec),
717                                  trp_inforec_get_trust_router_port(rec));
718   if(jstr==NULL)
719     return TRP_NOMEM;
720   json_object_set_new(jrec, "trust_router", jstr);
721
722   jstr=hostname_and_port_to_json(trp_inforec_get_next_hop(rec),
723                                  trp_inforec_get_next_hop_port(rec));
724   if(jstr==NULL)
725     return TRP_NOMEM;
726   json_object_set_new(jrec, "next_hop", jstr);
727
728   jint=json_integer(trp_inforec_get_metric(rec));
729   if(jint==NULL)
730     return TRP_ERROR;
731   json_object_set_new(jrec, "metric", jint);
732
733   jint=json_integer(trp_inforec_get_interval(rec));
734   if(jint==NULL)
735     return TRP_ERROR;
736   json_object_set_new(jrec, "interval", jint);
737
738   return TRP_SUCCESS;
739 }
740
741 /* returns a json array */
742 static json_t *tr_msg_encode_apcs(TR_APC *apcs)
743 {
744   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
745   TR_APC_ITER *iter=tr_apc_iter_new(tmp_ctx);
746   TR_APC *apc=NULL;
747   json_t *jarray=NULL;
748   json_t *jid=NULL;
749
750   if (iter==NULL)
751     goto cleanup;
752
753   jarray=json_array();
754   if (jarray==NULL)
755     goto cleanup;
756
757   for (apc=tr_apc_iter_first(iter, apcs); apc!=NULL; apc=tr_apc_iter_next(iter)) {
758     jid=tr_name_to_json_string(tr_apc_get_id(apc));
759     if ((jid==NULL) || (json_array_append_new(jarray, jid)!=0)) {
760       json_decref(jarray);
761       jarray=NULL;
762       goto cleanup;
763     }
764   }
765   
766 cleanup:
767   talloc_free(tmp_ctx);
768   return jarray;
769 }
770
771 static TR_APC *tr_msg_decode_apcs(TALLOC_CTX *mem_ctx, json_t *jarray, TRP_RC *rc)
772 {
773   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
774   size_t ii=0;
775   TR_APC *apc_list=NULL;
776   TR_APC *new=NULL;
777   json_t *jstr=NULL;
778
779   *rc=TRP_ERROR;
780
781   for (ii=0; ii<json_array_size(jarray); ii++) {
782     jstr=json_array_get(jarray, ii);
783     new=tr_apc_new(tmp_ctx);
784     if ((jstr==NULL) || (new==NULL) || (!json_is_string(jstr))) {
785       apc_list=NULL; /* these are all in tmp_ctx, so they'll still get cleaned up */
786       goto cleanup;
787     }
788
789     tr_apc_set_id(new, tr_new_name(json_string_value(jstr)));
790     if (tr_apc_get_id(new)==NULL) {
791       apc_list=NULL; /* these are all in tmp_ctx, so they'll still get cleaned up */
792       goto cleanup;
793     }
794
795     tr_apc_add(apc_list, new);
796   }
797
798   *rc=TRP_SUCCESS;
799
800   if (apc_list!=NULL)
801     talloc_steal(mem_ctx, apc_list);
802
803 cleanup:
804   talloc_free(tmp_ctx);
805   return apc_list;
806 }
807
808 static TRP_RC tr_msg_encode_inforec_comm(json_t *jrec, TRP_INFOREC *rec)
809 {
810   json_t *jstr=NULL;
811   json_t *jint=NULL;
812   json_t *japcs=NULL;
813   const char *sconst=NULL;
814   TR_COMM_TYPE commtype=TR_COMM_UNKNOWN;
815
816   if (rec==NULL)
817     return TRP_BADTYPE;
818
819   commtype=trp_inforec_get_comm_type(rec);
820   if (commtype==TR_COMM_UNKNOWN) {
821     tr_notice("tr_msg_encode_inforec_comm: unknown community type.");
822     return TRP_ERROR;
823   }
824   sconst=tr_comm_type_to_str(commtype);
825   if (sconst==NULL)
826     return TRP_ERROR;
827   jstr=json_string(sconst);
828   if(jstr==NULL)
829     return TRP_ERROR;
830   json_object_set_new(jrec, "type", jstr);
831
832   sconst=tr_realm_role_to_str(trp_inforec_get_role(rec));
833   if (sconst==NULL) {
834     tr_notice("tr_msg_encode_inforec_comm: unknown realm role.");
835     return TRP_ERROR;
836   }
837   jstr=json_string(sconst);
838   if(jstr==NULL)
839     return TRP_ERROR;
840   json_object_set_new(jrec, "role", jstr);
841
842   japcs=tr_msg_encode_apcs(trp_inforec_get_apcs(rec));
843   if (japcs==NULL) {
844     tr_notice("tr_msg_encode_inforec_comm: error encoding APCs.");
845     return TRP_ERROR;
846   }
847   json_object_set_new(jrec, "apcs", japcs);
848   
849
850   if (trp_inforec_get_owner_realm(rec)!=NULL) {
851     jstr=tr_name_to_json_string(trp_inforec_get_owner_realm(rec));
852     if(jstr==NULL)
853       return TRP_ERROR;
854     json_object_set_new(jrec, "owner_realm", jstr);
855   }  
856
857   if (trp_inforec_get_owner_contact(rec)!=NULL) {
858     jstr=tr_name_to_json_string(trp_inforec_get_owner_contact(rec));
859     if(jstr==NULL)
860       return TRP_ERROR;
861     json_object_set_new(jrec, "owner_contact", jstr);
862   }  
863
864   json_object_set(jrec, "provenance", trp_inforec_get_provenance(rec));
865
866   jint=json_integer(trp_inforec_get_interval(rec));
867   if(jint==NULL)
868     return TRP_ERROR;
869   json_object_set_new(jrec, "interval", jint);
870
871   return TRP_SUCCESS;
872 }
873
874 static json_t *tr_msg_encode_inforec(TRP_INFOREC *rec)
875 {
876   json_t *jrec=NULL;
877   json_t *jstr=NULL;
878
879   if ((rec==NULL) || (trp_inforec_get_type(rec)==TRP_INFOREC_TYPE_UNKNOWN))
880     return NULL;
881
882   jrec=json_object();
883   if (jrec==NULL)
884     return NULL;
885
886   jstr=json_string(trp_inforec_type_to_string(trp_inforec_get_type(rec)));
887   if (jstr==NULL) {
888     json_decref(jrec);
889     return NULL;
890   }
891   json_object_set_new(jrec, "record_type", jstr);
892
893   switch (rec->type) {
894   case TRP_INFOREC_TYPE_ROUTE:
895     if (TRP_SUCCESS!=tr_msg_encode_inforec_route(jrec, rec)) {
896       json_decref(jrec);
897       return NULL;
898     }
899     break;
900   case TRP_INFOREC_TYPE_COMMUNITY:
901     if (TRP_SUCCESS!=tr_msg_encode_inforec_comm(jrec, rec)) {
902       json_decref(jrec);
903       return NULL;
904     }
905     break;
906   default:
907     json_decref(jrec);
908     return NULL;
909   }
910   return jrec;
911 }
912
913 static TRP_RC tr_msg_decode_trp_inforec_route(json_t *jrecord, TRP_INFOREC *rec)
914 {
915   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
916   TRP_RC rc=TRP_ERROR;
917   char *s=NULL;
918   TR_NAME *name;
919   int port;
920   int num=0;
921
922   /* get the trust router */
923   rc=tr_msg_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
924   if (rc != TRP_SUCCESS)
925     goto cleanup;
926
927   if (0 != tr_parse_hostname_and_port(s, &name, &port)) {
928     rc = TRP_ERROR;
929     goto cleanup;
930   }
931   talloc_free(s); s=NULL;
932
933   if (port == 0)
934     port = TRP_PORT;
935
936   if (TRP_SUCCESS!= trp_inforec_set_trust_router(rec, name, port)) {
937     rc=TRP_ERROR;
938     goto cleanup;
939   }
940
941   /* Now do the next hop. If it's not present, use the trust_router for backward
942    * compatibility */
943   switch(tr_msg_get_json_string(jrecord, "next_hop", &s, tmp_ctx)) {
944     case TRP_SUCCESS:
945       /* we got a next_hop field */
946       if (0 != tr_parse_hostname_and_port(s, &name, &port)) {
947         rc = TRP_ERROR;
948         goto cleanup;
949       }
950       break;
951
952     case TRP_MISSING:
953       /* no next_hop field; use the trust router */
954       name = tr_dup_name(trp_inforec_get_trust_router(rec));
955       if (name == NULL) {
956         rc = TRP_ERROR;
957         goto cleanup;
958       }
959       break;
960
961     default:
962       /* something went wrong */
963       rc = TRP_ERROR;
964       goto cleanup;
965   }
966   talloc_free(s); s=NULL;
967
968   if (port == 0)
969     port = TID_PORT;
970
971   if (TRP_SUCCESS!= trp_inforec_set_next_hop(rec, name, port)) {
972     rc=TRP_ERROR;
973     goto cleanup;
974   }
975
976   rc=tr_msg_get_json_integer(jrecord, "metric", &num);
977   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_metric(rec,num)))
978     goto cleanup;
979
980   rc=tr_msg_get_json_integer(jrecord, "interval", &num);
981   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
982     goto cleanup;
983
984 cleanup:
985   talloc_free(tmp_ctx);
986   return rc;
987 }
988
989 static TRP_RC tr_msg_decode_trp_inforec_comm(json_t *jrecord, TRP_INFOREC *rec)
990 {
991   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
992   TRP_RC rc=TRP_ERROR;
993   char *s=NULL;
994   int num=0;
995   TR_APC *apcs=NULL;
996
997   rc=tr_msg_get_json_string(jrecord, "type", &s, tmp_ctx);
998   if (rc != TRP_SUCCESS)
999     goto cleanup;
1000   if (TRP_SUCCESS!=trp_inforec_set_comm_type(rec, tr_comm_type_from_str(s))) {
1001     rc=TRP_ERROR;
1002     goto cleanup;
1003   }
1004   talloc_free(s); s=NULL;
1005
1006   rc=tr_msg_get_json_string(jrecord, "role", &s, tmp_ctx);
1007   if (rc != TRP_SUCCESS)
1008     goto cleanup;
1009   if (TRP_SUCCESS!=trp_inforec_set_role(rec, tr_realm_role_from_str(s))) {
1010     rc=TRP_ERROR;
1011     goto cleanup;
1012   }
1013   talloc_free(s); s=NULL;
1014
1015   apcs=tr_msg_decode_apcs(rec, json_object_get(jrecord, "apcs"), &rc);
1016   if (rc!=TRP_SUCCESS) {
1017     rc=TRP_ERROR;
1018     goto cleanup;
1019   }
1020   trp_inforec_set_apcs(rec, apcs);
1021
1022   rc=tr_msg_get_json_integer(jrecord, "interval", &num);
1023   tr_debug("tr_msg_decode_trp_inforec_comm: interval=%u", num);
1024   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
1025     goto cleanup;
1026
1027   trp_inforec_set_provenance(rec, json_object_get(jrecord, "provenance"));
1028
1029   /* optional */
1030   rc=tr_msg_get_json_string(jrecord, "owner_realm", &s, tmp_ctx);
1031   if (rc == TRP_SUCCESS) {
1032     if (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_new_name(s))) {
1033       rc=TRP_ERROR;
1034       goto cleanup;
1035     }
1036     if (s!=NULL) {
1037       talloc_free(s);
1038       s=NULL;
1039     }
1040   }
1041
1042   rc=tr_msg_get_json_string(jrecord, "owner_contact", &s, tmp_ctx);
1043   if (rc == TRP_SUCCESS) {
1044     if (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_new_name(s))) {
1045       rc=TRP_ERROR;
1046       goto cleanup;
1047     }
1048     if (s!=NULL) {
1049       talloc_free(s);
1050       s=NULL;
1051     }
1052   }
1053
1054 cleanup:
1055   talloc_free(tmp_ctx);
1056   return rc;
1057 }
1058
1059 /* decode a single record */
1060 static TRP_INFOREC *tr_msg_decode_trp_inforec(TALLOC_CTX *mem_ctx, json_t *jrecord)
1061 {
1062   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1063   TRP_INFOREC_TYPE rectype;
1064   TRP_INFOREC *rec=NULL;
1065   TRP_RC rc=TRP_ERROR;
1066   char *s=NULL;
1067   
1068   if (TRP_SUCCESS!=tr_msg_get_json_string(jrecord, "record_type", &s, tmp_ctx))
1069     goto cleanup;
1070
1071   rectype=trp_inforec_type_from_string(s);
1072   talloc_free(s); s=NULL;
1073
1074   rec=trp_inforec_new(tmp_ctx, rectype);
1075   if (rec==NULL) {
1076     rc=TRP_NOMEM;
1077     goto cleanup;
1078   }
1079
1080   tr_debug("tr_msg_decode_trp_inforec: '%s' record found.", trp_inforec_type_to_string(rec->type));
1081
1082   switch(trp_inforec_get_type(rec)) {
1083   case TRP_INFOREC_TYPE_ROUTE:
1084     rc=tr_msg_decode_trp_inforec_route(jrecord, rec);
1085     break;
1086   case TRP_INFOREC_TYPE_COMMUNITY:
1087     rc=tr_msg_decode_trp_inforec_comm(jrecord, rec);
1088     break;
1089   default:
1090     rc=TRP_UNSUPPORTED;
1091     goto cleanup;
1092   }
1093
1094   talloc_steal(mem_ctx, rec);
1095   rc=TRP_SUCCESS;
1096
1097 cleanup:
1098   if (rc != TRP_SUCCESS) {
1099     trp_inforec_free(rec);
1100     rec=NULL;
1101   }
1102   talloc_free(tmp_ctx);
1103   return rec;
1104 }
1105
1106 /* TRP update msg */
1107 static json_t *tr_msg_encode_trp_upd(TRP_UPD *update)
1108 {
1109   json_t *jupdate=NULL;
1110   json_t *jrecords=NULL;
1111   json_t *jrec=NULL;
1112   json_t *jstr=NULL;
1113   TRP_INFOREC *rec;
1114   char *s=NULL;
1115
1116   if (update==NULL)
1117     return NULL;
1118
1119   jupdate=json_object();
1120   if (jupdate==NULL)
1121     return NULL;
1122
1123   s=tr_name_strdup(trp_upd_get_comm(update));
1124   if (s==NULL) {
1125     json_decref(jupdate);
1126     return NULL;
1127   }
1128   jstr=json_string(s);
1129   free(s);s=NULL;
1130   if(jstr==NULL) {
1131     json_decref(jupdate);
1132     return NULL;
1133   }
1134   json_object_set_new(jupdate, "community", jstr);
1135
1136   s=tr_name_strdup(trp_upd_get_realm(update));
1137   if (s==NULL) {
1138     json_decref(jupdate);
1139     return NULL;
1140   }
1141   jstr=json_string(s);
1142   free(s);s=NULL;
1143   if(jstr==NULL) {
1144     json_decref(jupdate);
1145     return NULL;
1146   }
1147   json_object_set_new(jupdate, "realm", jstr);
1148
1149   jrecords=json_array();
1150   if (jrecords==NULL) {
1151     json_decref(jupdate);
1152     return NULL;
1153   }
1154   json_object_set_new(jupdate, "records", jrecords); /* jrecords now a "borrowed" reference */
1155   for (rec=trp_upd_get_inforec(update); rec!=NULL; rec=trp_inforec_get_next(rec)) {
1156     tr_debug("tr_msg_encode_trp_upd: encoding inforec.");
1157     jrec=tr_msg_encode_inforec(rec);
1158     if (jrec==NULL) {
1159       json_decref(jupdate); /* also decs jrecords and any elements */
1160       return NULL;
1161     }
1162     if (0!=json_array_append_new(jrecords, jrec)) {
1163       json_decref(jupdate); /* also decs jrecords and any elements */
1164       json_decref(jrec); /* this one did not get added so dec explicitly */
1165       return NULL;
1166     }
1167   }
1168
1169   return jupdate;
1170 }
1171
1172 /* Creates a linked list of records in the msg->body talloc context.
1173  * An error will be returned if any unparseable records are encountered. 
1174  */
1175 static TRP_UPD *tr_msg_decode_trp_upd(TALLOC_CTX *mem_ctx, json_t *jupdate)
1176 {
1177   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1178   json_t *jrecords=NULL;
1179   size_t ii=0;
1180   TRP_UPD *update=NULL;
1181   TRP_INFOREC *new_rec=NULL;
1182   TRP_INFOREC *list_tail=NULL;
1183   char *s=NULL;
1184   TR_NAME *name;
1185   TRP_RC rc=TRP_ERROR;
1186
1187   update=trp_upd_new(tmp_ctx);
1188   if (update==NULL) {
1189     rc=TRP_NOMEM;
1190     goto cleanup;
1191   }
1192
1193   rc=tr_msg_get_json_string(jupdate, "community", &s, tmp_ctx);
1194   if (rc != TRP_SUCCESS) {
1195     tr_debug("tr_msg_decode_trp_upd: no community in TRP update message.");
1196     rc=TRP_NOPARSE;
1197     goto cleanup;
1198   }
1199   name=tr_new_name(s);
1200   if (name==NULL) {
1201     tr_debug("tr_msg_decode_trp_upd: could not allocate community name.");
1202     rc=TRP_NOMEM;
1203     goto cleanup;
1204   }
1205   talloc_free(s); s=NULL;
1206   trp_upd_set_comm(update, name);
1207
1208   rc=tr_msg_get_json_string(jupdate, "realm", &s, tmp_ctx);
1209   if (rc != TRP_SUCCESS) {
1210     tr_debug("tr_msg_decode_trp_upd: no realm in TRP update message.");
1211     rc=TRP_NOPARSE;
1212     goto cleanup;
1213   }
1214   name=tr_new_name(s);
1215   if (name==NULL) {
1216     tr_debug("tr_msg_decode_trp_upd: could not allocate realm name.");
1217     rc=TRP_NOMEM;
1218     goto cleanup;
1219   }
1220   talloc_free(s); s=NULL;
1221   trp_upd_set_realm(update, name);
1222
1223   jrecords=json_object_get(jupdate, "records");
1224   if ((jrecords==NULL) || (!json_is_array(jrecords))) {
1225     rc=TRP_NOPARSE;
1226     goto cleanup;
1227   }
1228
1229   tr_debug("tr_msg_decode_trp_upd: found %d records", json_array_size(jrecords));
1230   /* process the array */
1231   for (ii=0; ii<json_array_size(jrecords); ii++) {
1232     new_rec=tr_msg_decode_trp_inforec(update, json_array_get(jrecords, ii));
1233     if (new_rec==NULL) {
1234       rc=TRP_NOPARSE;
1235       goto cleanup;
1236     }
1237
1238     if (list_tail==NULL)
1239       trp_upd_set_inforec(update, new_rec); /* first is a special case */
1240     else
1241       trp_inforec_set_next(list_tail, new_rec);
1242
1243     list_tail=new_rec;
1244   }
1245
1246   /* Succeeded. Move new allocations into the correct talloc context */
1247   talloc_steal(mem_ctx, update);
1248   rc=TRP_SUCCESS;
1249
1250 cleanup:
1251   talloc_free(tmp_ctx);
1252   if (rc!=TRP_SUCCESS)
1253     return NULL;
1254   return update;
1255 }
1256
1257 static json_t *tr_msg_encode_trp_req(TRP_REQ *req)
1258 {
1259   json_t *jbody=NULL;
1260   json_t *jstr=NULL;
1261   char *s=NULL;
1262
1263   if (req==NULL)
1264     return NULL;
1265
1266   jbody=json_object();
1267   if (jbody==NULL)
1268     return NULL;
1269
1270   if ((NULL==trp_req_get_comm(req))
1271      || (NULL==trp_req_get_realm(req))) {
1272     json_decref(jbody);
1273     return NULL;
1274   }
1275
1276   s=tr_name_strdup(trp_req_get_comm(req)); /* ensures null termination */
1277   if (s==NULL) {
1278     json_decref(jbody);
1279     return NULL;
1280   }
1281   jstr=json_string(s);
1282   free(s); s=NULL;
1283   if (jstr==NULL) {
1284     json_decref(jbody);
1285     return NULL;
1286   }
1287   json_object_set_new(jbody, "community", jstr);
1288     
1289   s=tr_name_strdup(trp_req_get_realm(req)); /* ensures null termination */
1290   if (s==NULL) {
1291     json_decref(jbody);
1292     return NULL;
1293   }
1294   jstr=json_string(s);
1295   free(s); s=NULL;
1296   if (jstr==NULL) {
1297     json_decref(jbody);
1298     return NULL;
1299   }
1300   json_object_set_new(jbody, "realm", jstr);
1301
1302   return jbody;
1303 }
1304
1305 static TRP_REQ *tr_msg_decode_trp_req(TALLOC_CTX *mem_ctx, json_t *jreq)
1306 {
1307   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1308   TRP_REQ *req=NULL;
1309   char *s=NULL;
1310   TRP_RC rc=TRP_ERROR;
1311
1312   /* check message type and body type for agreement */
1313   req=trp_req_new(tmp_ctx);
1314   if (req==NULL) {
1315     rc=TRP_NOMEM;
1316     goto cleanup;
1317   }
1318
1319   rc=tr_msg_get_json_string(jreq, "community", &s, tmp_ctx);
1320   if (rc!=TRP_SUCCESS)
1321     goto cleanup;
1322   trp_req_set_comm(req, tr_new_name(s));
1323   talloc_free(s); s=NULL;
1324
1325   rc=tr_msg_get_json_string(jreq, "realm", &s, tmp_ctx);
1326   if (rc!=TRP_SUCCESS)
1327     goto cleanup;
1328   trp_req_set_realm(req, tr_new_name(s));
1329   talloc_free(s); s=NULL;
1330
1331   rc=TRP_SUCCESS;
1332   talloc_steal(mem_ctx, req);
1333
1334 cleanup:
1335   talloc_free(tmp_ctx);
1336   if (rc!=TRP_SUCCESS)
1337     return NULL;
1338   return req;
1339 }
1340
1341 char *tr_msg_encode(TALLOC_CTX *mem_ctx, TR_MSG *msg)
1342 {
1343   json_t *jmsg=NULL;
1344   json_t *jmsg_type=NULL;
1345   char *encoded_tmp=NULL;
1346   char *encoded=NULL;
1347   TID_RESP *tidresp=NULL;
1348   TID_REQ *tidreq=NULL;
1349   TRP_UPD *trpupd=NULL;
1350   TRP_REQ *trpreq=NULL;
1351   MON_REQ *monreq=NULL;
1352   MON_RESP *monresp=NULL;
1353
1354   /* TBD -- add error handling */
1355   jmsg = json_object();
1356
1357   switch (msg->msg_type) {
1358     case TID_REQUEST:
1359       jmsg_type = json_string("tid_request");
1360       json_object_set_new(jmsg, "msg_type", jmsg_type);
1361       tidreq=tr_msg_get_req(msg);
1362       json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidreq(tidreq));
1363       break;
1364
1365     case TID_RESPONSE:
1366       jmsg_type = json_string("tid_response");
1367       json_object_set_new(jmsg, "msg_type", jmsg_type);
1368       tidresp=tr_msg_get_resp(msg);
1369       json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidresp(tidresp));
1370       break;
1371
1372     case TRP_UPDATE:
1373       jmsg_type = json_string("trp_update");
1374       json_object_set_new(jmsg, "msg_type", jmsg_type);
1375       trpupd=tr_msg_get_trp_upd(msg);
1376       json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_upd(trpupd));
1377       break;
1378
1379     case TRP_REQUEST:
1380       jmsg_type = json_string("trp_request");
1381       json_object_set_new(jmsg, "msg_type", jmsg_type);
1382       trpreq=tr_msg_get_trp_req(msg);
1383       json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_req(trpreq));
1384       break;
1385
1386     case MON_REQUEST:
1387       jmsg_type = json_string("mon_request");
1388       json_object_set_new(jmsg, "msg_type", jmsg_type);
1389       monreq=tr_msg_get_mon_req(msg);
1390       json_object_set_new(jmsg, "msg_body", mon_req_encode(monreq));
1391       break;
1392
1393     case MON_RESPONSE:
1394       jmsg_type = json_string("mon_response");
1395       json_object_set_new(jmsg, "msg_type", jmsg_type);
1396       monresp=tr_msg_get_mon_resp(msg);
1397       json_object_set_new(jmsg, "msg_body", mon_resp_encode(monresp));
1398       break;
1399
1400     default:
1401       json_decref(jmsg);
1402       return NULL;
1403   }
1404
1405   /* We should perhaps use json_set_alloc_funcs to automatically use talloc, but for
1406    * now, we'll encode to a malloc'ed buffer, then copy that to a talloc'ed buffer. */
1407   encoded_tmp=json_dumps(jmsg, 0);                // malloc'ed version
1408   json_decref(jmsg);                              // free the JSON structure
1409   encoded = talloc_strdup(mem_ctx, encoded_tmp);  // get the talloc'ed version
1410   free(encoded_tmp);                              // free the malloc'ed version
1411
1412   tr_debug("tr_msg_encode: outgoing msg=%s", encoded);
1413   return encoded;
1414 }
1415
1416 TR_MSG *tr_msg_decode(TALLOC_CTX *mem_ctx, const char *jbuf, size_t buflen)
1417 {
1418   TR_MSG *msg=NULL;
1419   json_t *jmsg = NULL;
1420   json_error_t rc;
1421   json_t *jtype=NULL;
1422   json_t *jbody=NULL;
1423   const char *mtype = NULL;
1424
1425   if (NULL == (jmsg = json_loadb(jbuf, buflen, JSON_DISABLE_EOF_CHECK, &rc))) {
1426     tr_debug("tr_msg_decode(): error loading object");
1427     return NULL;
1428   }
1429
1430   if (!(msg = talloc_zero(mem_ctx, TR_MSG))) {
1431     tr_debug("tr_msg_decode(): Error allocating TR_MSG structure.");
1432     json_decref(jmsg);
1433     return NULL;
1434   }
1435  
1436   if ((NULL == (jtype = json_object_get(jmsg, "msg_type"))) ||
1437       (NULL == (jbody = json_object_get(jmsg, "msg_body")))) {
1438     tr_debug("tr_msg_decode(): Error parsing message header.");
1439     json_decref(jmsg);
1440     tr_msg_free_decoded(msg);
1441     return NULL;
1442   }
1443
1444   mtype = json_string_value(jtype);
1445
1446   if (0 == strcmp(mtype, "tid_request")) {
1447     msg->msg_type = TID_REQUEST;
1448     tr_msg_set_req(msg, tr_msg_decode_tidreq(msg, jbody));
1449   }
1450   else if (0 == strcmp(mtype, "tid_response")) {
1451     msg->msg_type = TID_RESPONSE;
1452     tr_msg_set_resp(msg, tr_msg_decode_tidresp(msg, jbody));
1453   }
1454   else if (0 == strcmp(mtype, "trp_update")) {
1455     msg->msg_type = TRP_UPDATE;
1456     tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(msg, jbody));
1457   }
1458   else if (0 == strcmp(mtype, "trp_request")) {
1459     msg->msg_type = TRP_UPDATE;
1460     tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(msg, jbody));
1461   }
1462   else if (0 == strcmp(mtype, "mon_request")) {
1463     msg->msg_type = MON_REQUEST;
1464     tr_msg_set_mon_req(msg, mon_req_decode(msg, jbody));
1465   }
1466   /* We do not currently handle monitoring responses */
1467   else if (0 == strcmp(mtype, "mon_response")) {
1468     msg->msg_type = MON_RESPONSE;
1469     tr_msg_set_mon_resp(msg, mon_resp_decode(msg, jbody));
1470   }
1471   else {
1472     msg->msg_type = TR_UNKNOWN;
1473     msg->msg_rep = NULL;
1474   }
1475
1476   json_decref(jmsg);
1477
1478   return msg;
1479 }
1480
1481 void tr_msg_free_encoded(char *jmsg)
1482 {
1483   if (jmsg)
1484     talloc_free(jmsg);
1485 }
1486
1487 void tr_msg_free_decoded(TR_MSG *msg)
1488 {
1489   if (msg)
1490     talloc_free(msg);
1491 }