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