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