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