10f15f5a22a77443fa043147d1d66592dd2e1d1e
[trust_router.git] / trp / trp_msg.c
1 #include <jansson.h>
2 #include <talloc.h>
3
4 #include <tr_name.h>
5 #include <trp_internal.h>
6 #include <tr_debug.h>
7
8
9 /* static prototypes */
10 static void *trp_route_update_new(TALLOC_CTX *mem_ctx);
11 static TRP_RC trp_parse_update(TRP_MSG *msg, json_t *jmsg);
12 static void trp_route_update_print(void *);
13
14 static void *trp_route_req_new(TALLOC_CTX *mem_ctx);
15 static json_t *trp_encode_route_req(void *req_in);
16 static TRP_RC trp_parse_route_req(TRP_MSG *msg, json_t *jmsg);
17 static void trp_route_req_print(void *);
18
19 static void *trp_msg_info_route_new(TALLOC_CTX *mem_ctx);
20 static TRP_RC trp_parse_info_route(TRP_MSG *msg, json_t *jmsg);
21 static void trp_msg_info_route_print(void *);
22
23 /* table of string names for TMT_MSG_TYPE codes */
24 struct trp_msg_type_entry {
25   const char *name;
26   TRP_MSG_TYPE type;
27   void *(*allocate)(TALLOC_CTX *);
28   json_t *(*encode)(void *);
29   TRP_RC (*parse)(TRP_MSG *, json_t *);
30   void (*print)(void *);
31 };
32 static struct trp_msg_type_entry trp_msg_type_table[] = {
33   { "update", TRP_MSG_TYPE_UPDATE, trp_route_update_new, NULL, trp_parse_update, trp_route_update_print },
34   { "route_req", TRP_MSG_TYPE_ROUTE_REQ, trp_route_req_new, trp_encode_route_req, trp_parse_route_req, trp_route_req_print },
35   { NULL, TRP_MSG_TYPE_UNKNOWN, NULL, NULL, NULL, NULL } /* must be the last entry */
36 };
37
38 struct trp_msg_info_type_entry {
39   const char *name;
40   TRP_MSG_INFO_TYPE type;
41   void (*print)(void *);
42 };
43 static struct trp_msg_info_type_entry trp_msg_info_type_table[] = {
44   { "route_info", TRP_MSG_INFO_TYPE_ROUTE, trp_msg_info_route_print },
45   { "comm_info", TRP_MSG_INFO_TYPE_COMMUNITY, NULL },
46   { NULL, TRP_MSG_INFO_TYPE_UNKNOWN, NULL } /* must be the last entry */
47 };
48
49 /* Use talloc's dynamic type checking to verify type.
50  * By default, this will cause program abort, but can be overridden
51  * via talloc_set_abort_fn() if more graceful handling is needed. */
52 static void msg_body_type_check(TRP_MSG_TYPE msgtype, void *p)
53 {
54   switch (msgtype) {
55   case TRP_MSG_TYPE_UPDATE:
56     talloc_get_type_abort(p, TRP_ROUTE_UPDATE);
57     break;
58
59   case TRP_MSG_TYPE_ROUTE_REQ:
60     talloc_get_type_abort(p, TRP_ROUTE_REQ);
61     break;
62
63   default:
64     break;
65   }
66 }
67
68 /* look up an entry in the trp_msg_type_table */
69 static struct trp_msg_type_entry *get_trp_msg_type_entry(TRP_MSG_TYPE msgtype)
70 {
71   struct trp_msg_type_entry *entry=trp_msg_type_table;
72
73   while ((entry->type != TRP_MSG_TYPE_UNKNOWN)
74         && (entry->type != msgtype)) {
75     entry ++;
76   }
77   return entry;
78 }
79
80 /* look up an entry in the trp_msg_info_type_table */
81 static struct trp_msg_info_type_entry *get_trp_msg_info_type_entry(TRP_MSG_INFO_TYPE msgtype)
82 {
83   struct trp_msg_info_type_entry *entry=trp_msg_info_type_table;
84
85   while ((entry->type != TRP_MSG_INFO_TYPE_UNKNOWN)
86         && (entry->type != msgtype)) {
87     entry ++;
88   }
89   return entry;
90 }
91
92 /* translate strings to codes */
93 TRP_MSG_TYPE trp_msg_type_from_string(const char *s)
94 {
95   struct trp_msg_type_entry *entry=trp_msg_type_table;
96
97   while ((entry->type != TRP_MSG_TYPE_UNKNOWN)
98         && (strcmp(s, entry->name)!=0)) {
99     entry++;
100   }
101   return entry->type;
102 }
103 /* translate codes to strings (do not need to be freed) 
104  * Returns NULL on an unknown code */
105 const char *trp_msg_type_to_string(TRP_MSG_TYPE msgtype)
106 {
107   struct trp_msg_type_entry *entry=get_trp_msg_type_entry(msgtype);
108   return entry->name;
109 }
110
111 /* translate strings to codes */
112 TRP_MSG_INFO_TYPE trp_msg_info_type_from_string(const char *s)
113 {
114   struct trp_msg_info_type_entry *entry=trp_msg_info_type_table;
115
116   while ((entry->type != TRP_MSG_INFO_TYPE_UNKNOWN)
117         && (strcmp(s, entry->name)!=0)) {
118     entry++;
119   }
120   return entry->type;
121 }
122 /* translate codes to strings (do not need to be freed) 
123  * Returns NULL on an unknown code */
124 const char *trp_msg_info_type_to_string(TRP_MSG_INFO_TYPE msgtype)
125 {
126   struct trp_msg_info_type_entry *entry=get_trp_msg_info_type_entry(msgtype);
127   return entry->name;
128 }
129
130
131 TRP_MSG *trp_msg_new(TALLOC_CTX *mem_ctx)
132 {
133   TRP_MSG *new_msg=talloc(mem_ctx, TRP_MSG);
134
135   if (new_msg != NULL) {
136     new_msg->type=TRP_MSG_INFO_TYPE_UNKNOWN;
137     new_msg->body=NULL;
138   }
139   return new_msg;
140 }
141
142 void trp_msg_destroy(TRP_MSG *msg)
143 {
144   if (msg)
145     talloc_free(msg);
146 }
147
148
149 /* JSON helpers */
150 /* Read attribute attr from msg as an integer */
151 static TRP_RC trp_get_json_integer(json_t *jmsg, const char *attr, int *dest)
152 {
153   json_error_t err;
154   json_t *obj;
155
156   obj=json_object_get(jmsg, attr);
157   if (obj == NULL) {
158     return TRP_NOPARSE;
159   }
160   /* check type */
161   if (!json_is_integer(obj)) {
162     return TRP_BADTYPE;
163   }
164
165   (*dest)=json_integer_value(obj);
166   return TRP_SUCCESS;
167 }
168
169 /* Read attribute attr from msg as a string. Copies string into mem_ctx context so jmsg can
170  * be destroyed safely. */
171 static TRP_RC trp_get_json_string(json_t *jmsg, const char *attr, char **dest, TALLOC_CTX *mem_ctx)
172 {
173   json_error_t err;
174   json_t *obj;
175
176   obj=json_object_get(jmsg, attr);
177   if (obj == NULL)
178     return TRP_NOPARSE;
179
180   /* check type */
181   if (!json_is_string(obj))
182     return TRP_BADTYPE;
183
184   *dest=talloc_strdup(mem_ctx, json_string_value(obj));
185   if (*dest==NULL)
186     return TRP_NOMEM;
187
188   return TRP_SUCCESS;
189 }
190
191
192 /* called by talloc when destroying an update message body */
193 static int trp_msg_info_route_destructor(void *object)
194 {
195   TRP_MSG_INFO_ROUTE *body=talloc_get_type_abort(object, TRP_MSG_INFO_ROUTE);
196   
197   /* clean up TR_NAME data, which are not managed by talloc */
198   if (body->comm != NULL) {
199     tr_free_name(body->comm);
200     body->comm=NULL;
201     tr_debug("trp_msg_info_route_destructor: freed community");
202   }
203   if (body->realm != NULL) {
204     tr_free_name(body->realm);
205     body->realm=NULL;
206     tr_debug("trp_msg_info_route_destructor: freed realm");
207   }
208   if (body->trust_router != NULL) {
209     tr_free_name(body->trust_router);
210     body->trust_router=NULL;
211     tr_debug("trp_msg_info_route_destructor: freed trust_router");
212   }
213
214   return 0;
215 }
216
217 static void *trp_msg_info_route_new(TALLOC_CTX *mem_ctx)
218 {
219   TRP_MSG_INFO_ROUTE *new_rec=talloc(mem_ctx, TRP_MSG_INFO_ROUTE);
220
221   if (new_rec != NULL) {
222     new_rec->next=NULL;
223     new_rec->type=TRP_MSG_INFO_TYPE_UNKNOWN;
224     new_rec->comm=NULL;
225     new_rec->realm=NULL;
226     new_rec->trust_router=NULL;
227     new_rec->metric=TRP_METRIC_INFINITY;
228     new_rec->interval=0;
229     talloc_set_destructor((void *)new_rec, trp_msg_info_route_destructor);
230   }
231   return new_rec;
232 }
233
234 /* parse a single record */
235 static TRP_RC trp_parse_update_record(TRP_MSG_INFO_ROUTE *rec, json_t *jrecord)
236 {
237   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
238   TRP_RC rc=TRP_ERROR;
239   char *s=NULL;
240   int num=0;
241
242   rc=trp_get_json_string(jrecord, "record_type", &s, tmp_ctx);
243   if (rc != TRP_SUCCESS)
244     goto cleanup;
245   rec->type=trp_msg_info_type_from_string(s);
246   talloc_free(s); s=NULL;
247   /* We only support route_info records for now*/
248   if (rec->type!=TRP_MSG_INFO_TYPE_ROUTE) {
249     rc=TRP_UNSUPPORTED;
250     goto cleanup;
251   }
252
253   tr_debug("trp_parse_update_record: '%s' record found.", trp_msg_info_type_to_string(rec->type));
254
255   rc=trp_get_json_string(jrecord, "community", &s, tmp_ctx);
256   if (rc != TRP_SUCCESS)
257     goto cleanup;
258   if (NULL==(rec->comm=tr_new_name(s)))
259     goto cleanup;
260   talloc_free(s); s=NULL;
261
262   tr_debug("trp_parse_update_record: 'community' is '%.*s'.", rec->comm->len, rec->comm->buf);
263
264   rc=trp_get_json_string(jrecord, "realm", &s, tmp_ctx);
265   if (rc != TRP_SUCCESS)
266     goto cleanup;
267   if (NULL==(rec->realm=tr_new_name(s)))
268     goto cleanup;
269   talloc_free(s); s=NULL;
270
271   tr_debug("trp_parse_update_record: 'realm' is '%.*s'.", rec->realm->len, rec->realm->buf);
272
273   rc=trp_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
274   if (rc != TRP_SUCCESS)
275     goto cleanup;
276   if (NULL==(rec->trust_router=tr_new_name(s)))
277     goto cleanup;
278   talloc_free(s); s=NULL;
279
280   tr_debug("trp_parse_update_record: 'trust_router' is '%.*s'.", rec->trust_router->len, rec->trust_router->buf);
281
282   rc=trp_get_json_integer(jrecord, "metric", &num);
283   if (rc != TRP_SUCCESS)
284     goto cleanup;
285   rec->metric=num;
286
287   tr_debug("trp_parse_update_record: 'metric' is %d.", rec->metric);
288   
289   rc=trp_get_json_integer(jrecord, "interval", &num);
290   if (rc != TRP_SUCCESS)
291     goto cleanup;
292   rec->interval=num;
293
294   tr_debug("trp_parse_update_record: 'interval' is %d.", rec->interval);
295
296   rc=TRP_SUCCESS;
297
298 cleanup:
299   if (rc != TRP_SUCCESS) {
300     /* clean up TR_NAME data, which is not managed by talloc */
301     if (rec->comm != NULL) {
302       tr_free_name(rec->comm);
303       rec->comm=NULL;
304     }
305     if (rec->realm != NULL) {
306       tr_free_name(rec->realm);
307       rec->realm=NULL;
308     }
309     if (rec->trust_router != NULL) {
310       tr_free_name(rec->trust_router);
311       rec->trust_router=NULL;
312     }
313   }
314   
315   talloc_free(tmp_ctx);
316   return rc;
317 }
318
319
320
321 static void *trp_route_update_new(TALLOC_CTX *mem_ctx)
322 {
323   TRP_ROUTE_UPDATE *new_body=talloc(mem_ctx, TRP_ROUTE_UPDATE);
324
325   if (new_body!=NULL) {
326     new_body->records=NULL;
327   }
328 }
329
330 /* Parse an update body. Creates a linked list of records in the msg->body talloc context.
331  *
332  * An error will be returned if any unparseable records are encountered. 
333  *
334  * TODO: clean up return codes. 
335  * TODO: should take a body, not a msg */
336 static TRP_RC trp_parse_update(TRP_MSG *msg, json_t *jbody)
337 {
338   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
339   json_t *jrecords=NULL;
340   size_t ii=0;
341   size_t nrec=0;
342   TRP_ROUTE_UPDATE *msg_body=NULL;
343   TRP_MSG_INFO_ROUTE *new_rec=NULL;
344   TRP_MSG_INFO_ROUTE *list_tail=NULL;
345   TRP_RC rc=TRP_ERROR;
346
347   if (msg->type != TRP_MSG_TYPE_UPDATE) {
348     rc=TRP_BADTYPE;
349     goto cleanup;
350   }
351   msg_body=talloc_get_type(msg->body, TRP_ROUTE_UPDATE);
352   if (msg_body==NULL) {
353     rc=TRP_BADTYPE;
354     goto cleanup;
355   }
356
357   jrecords=json_object_get(jbody, "records");
358   if ((jrecords==NULL) || (!json_is_array(jrecords))) {
359     rc=TRP_NOPARSE;
360     goto cleanup;
361   }
362
363   tr_debug("trp_parse_update: found %d records", json_array_size(jrecords));
364   /* process the array */
365   for (ii=0; ii<json_array_size(jrecords); ii++) {
366     new_rec=trp_msg_info_route_new(tmp_ctx);
367     if (new_rec==NULL) {
368       rc=TRP_NOMEM;
369       goto cleanup;
370     }
371
372     if (TRP_SUCCESS != trp_parse_update_record(new_rec, json_array_get(jrecords, ii))) {
373       rc=TRP_NOPARSE;
374       goto cleanup;
375     }
376
377     if (list_tail==NULL)
378       msg_body->records=new_rec; /* first is a special case */
379     else
380       list_tail->next=new_rec;
381
382     list_tail=new_rec;
383   }
384
385   /* Succeeded. Move all of our new allocations into the correct talloc context */
386   for (list_tail=msg_body->records; list_tail != NULL; list_tail=list_tail->next)
387     talloc_steal(msg->body, list_tail); /* all successfully parsed bodies belong to msg context */
388
389   rc=TRP_SUCCESS;
390
391 cleanup:
392   talloc_free(tmp_ctx);
393   if ((rc != TRP_SUCCESS) && (msg_body != NULL))
394     msg_body->records=NULL; /* don't leave this hanging */
395
396   return rc;
397 }
398
399 /* pretty print */
400 static void trp_msg_info_route_print(void *rec_in)
401 {
402   TRP_MSG_INFO_ROUTE *rec=talloc_get_type(rec_in, TRP_MSG_INFO_ROUTE); /* null if wrong type */
403
404   while (rec!=NULL) {
405     printf("    [record_type=%s\n     community=%.*s\n     realm=%.*s\n     trust_router=%.*s\n     metric=%d\n     interval=%d]\n",
406            trp_msg_info_type_to_string(rec->type),
407            rec->comm->len, rec->comm->buf,
408            rec->realm->len, rec->realm->buf,
409            rec->trust_router->len, rec->trust_router->buf,
410            rec->metric, rec->interval);
411     rec=rec->next;
412   }
413 }
414
415
416 static int trp_route_req_destructor(void *object)
417 {
418   TRP_ROUTE_REQ *body=talloc_get_type_abort(object, TRP_ROUTE_REQ);
419   
420   /* clean up TR_NAME data, which are not managed by talloc */
421   if (body->comm != NULL) {
422     tr_free_name(body->comm);
423     body->comm=NULL;
424     tr_debug("trp_route_req_destructor: freed community");
425   }
426   if (body->realm != NULL) {
427     tr_free_name(body->realm);
428     body->realm=NULL;
429     tr_debug("trp_route_req_destructor: freed realm");
430   }
431   return 0;
432 }
433
434 void *trp_route_req_new(TALLOC_CTX *mem_ctx)
435 {
436   TRP_ROUTE_REQ *new_body=talloc(mem_ctx, TRP_ROUTE_REQ);
437
438   if (new_body != NULL) {
439     new_body->comm=NULL;
440     new_body->realm=NULL;
441   }
442
443   talloc_set_destructor((void *)new_body, trp_route_req_destructor);
444   return new_body;
445 }
446
447 void trp_route_req_set_comm(TRP_ROUTE_REQ *req, TR_NAME *comm)
448 {
449   req->comm=comm;
450 }
451
452 void trp_route_req_set_realm(TRP_ROUTE_REQ *req, TR_NAME *realm)
453 {
454   req->realm=realm;
455 }
456
457 /* TODO: clean up return codes. 
458  * TODO: should take a body, not a msg */
459 static TRP_RC trp_parse_route_req(TRP_MSG *msg, json_t *jbody)
460 {
461   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
462   TRP_ROUTE_REQ *msg_body=NULL;
463   char *s=NULL;
464   TRP_RC rc=TRP_ERROR;
465
466   /* check message type and body type for agreement */
467   if (msg->type != TRP_MSG_TYPE_ROUTE_REQ) {
468     rc=TRP_BADTYPE;
469     goto cleanup;
470   }
471   msg_body=talloc_get_type(msg->body, TRP_ROUTE_REQ);
472   if (msg_body==NULL) {
473     rc=TRP_BADTYPE;
474     goto cleanup;
475   }
476
477   rc=trp_get_json_string(jbody, "community", &s, tmp_ctx);
478   if (rc!=TRP_SUCCESS)
479     goto cleanup;
480   msg_body->comm=tr_new_name(s);
481   talloc_free(s); s=NULL;
482
483   rc=trp_get_json_string(jbody, "realm", &s, tmp_ctx);
484   if (rc!=TRP_SUCCESS)
485     goto cleanup;
486   msg_body->realm=tr_new_name(s);
487   talloc_free(s); s=NULL;
488
489   rc=TRP_SUCCESS;
490 cleanup:
491   talloc_free(tmp_ctx);
492   return rc;
493 }
494
495 static json_t *trp_encode_body(TRP_MSG_TYPE type, void *body)
496 {
497   struct trp_msg_type_entry *msgtype=get_trp_msg_type_entry(type);
498
499   if ((msgtype->type==TRP_MSG_TYPE_UNKNOWN) || (msgtype->encode==NULL))
500     return NULL;
501
502   tr_debug("trp_encode_body: encoding type %s", trp_msg_type_to_string(type));
503
504   return msgtype->encode(body);
505 }
506
507 /* TODO: error checking */
508 char *trp_encode_msg(TRP_MSG *msg)
509 {
510   json_t *jmsg=NULL;
511   json_t *jtype=NULL;
512   json_t *jbody=NULL;
513   char *encoded=NULL;
514
515   jbody=trp_encode_body(msg->type, msg->body);
516   if (jbody!=NULL) {
517     jmsg=json_object();
518
519     jtype=json_string(trp_msg_type_to_string(msg->type));
520     json_object_set_new(jmsg, "message_type", jtype);
521     json_object_set_new(jmsg, "body", jbody);
522
523     encoded=json_dumps(jmsg, 0);
524     json_decref(jmsg);
525   }
526   return encoded;
527 }
528
529 /* TODO: error checking */
530 static json_t *trp_encode_route_req(void *req_in)
531 {
532   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
533   TRP_ROUTE_REQ *req=talloc_get_type(req_in, TRP_ROUTE_REQ); /* null if wrong type */
534   TRP_RC rc=TRP_ERROR;
535   json_t *jbody=NULL;
536   json_t *jstr=NULL;
537   char *s=NULL;
538
539   if (req!=NULL) {
540     jbody=json_object();
541
542     s=talloc_strndup(tmp_ctx, req->comm->buf, req->comm->len); /* ensures null term */
543     if (s==NULL) {
544       tr_debug("trp_encode_route_req: could not allocate community string");
545       json_decref(jbody);
546       jbody=NULL;
547       goto cleanup;
548     }
549     jstr=json_string(s);
550     talloc_free(s);
551     json_object_set_new(jbody, "community", jstr);
552     
553     s=talloc_strndup(tmp_ctx, req->realm->buf, req->realm->len); /* ensures null term */
554     if (s==NULL) {
555       tr_debug("trp_encode_route_req: could not allocate realm string");
556       json_decref(jbody);
557       jbody=NULL;
558       goto cleanup;
559     }
560     jstr=json_string(s);
561     talloc_free(s);
562     json_object_set_new(jbody, "realm", jstr);
563   }
564
565 cleanup:
566   talloc_free(tmp_ctx);
567   return jbody;
568 }
569
570 static void trp_route_update_print(void *body_in)
571 {
572   TRP_ROUTE_UPDATE *body=talloc_get_type(body_in, TRP_ROUTE_UPDATE); /* null if wrong type */
573
574   if (body!=NULL) {
575     printf("  {records=\n");
576     trp_msg_info_route_print(body->records);
577     printf("  }\n");
578   }
579 }
580
581 static void trp_route_req_print(void *body_in)
582 {
583   TRP_ROUTE_REQ *body=talloc_get_type(body_in, TRP_ROUTE_REQ); /* null if wrong type */
584
585   if (body!=NULL) {
586     printf("  {community=%.*s\n   realm=%.*s}\n",
587            body->comm->len, body->comm->buf,
588            body->realm->len, body->realm->buf);
589   }
590 }
591
592 static void trp_msg_body_print(void *body, TRP_MSG_TYPE msgtype)
593 {
594   struct trp_msg_type_entry *info=get_trp_msg_type_entry(msgtype);
595   info->print(body);
596 }
597
598 void trp_msg_print(TRP_MSG *msg)
599 {
600   /* right now just assumes update */
601   printf("{message_type=%s\n", trp_msg_type_to_string(msg->type));
602   trp_msg_body_print(msg->body, msg->type);
603   printf("}\n");
604 }
605
606 /* returns a pointer to one of the message body types, or NULL on error/unknown type */
607 static void *trp_msg_body_new(TALLOC_CTX *mem_ctx, TRP_MSG_TYPE msgtype)
608 {
609   void *new_body=NULL;
610   struct trp_msg_type_entry *info=get_trp_msg_type_entry(msgtype);
611
612   if (info->type==TRP_MSG_TYPE_UNKNOWN) {
613     tr_debug("trp_msg_body_new: Unknown type %d.", info->type);
614     return NULL;
615   }
616
617   new_body=info->allocate(mem_ctx);
618   msg_body_type_check(msgtype, new_body); /* aborts program on type violation */
619   return new_body;
620 }
621
622 /* call the correct parser */
623 static TRP_RC trp_parse_msg_body(TRP_MSG *msg, json_t *jbody)
624 {
625   struct trp_msg_type_entry *info=get_trp_msg_type_entry(msg->type);
626
627   if (info->type==TRP_MSG_TYPE_UNKNOWN) {
628     tr_debug("trp_msg_body_parse: Unknown type %d.", info->type);
629     return TRP_ERROR;
630   }
631
632   return info->parse(msg, jbody);
633 }
634
635
636 TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MSG **msg) 
637 {
638   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
639   TRP_MSG *new_msg=NULL;
640   TRP_RC msg_rc=TRP_ERROR;
641   json_error_t json_err;
642   json_t *jmsg=NULL; /* handle for the whole msg */
643   json_t *jbody=NULL;
644   char *s;
645
646   tr_debug("trp_parse_msg: parsing %d bytes", buflen);
647
648   jmsg=json_loadb(buf, buflen, 0, &json_err);
649   if (jmsg == NULL) {
650     tr_debug("trp_parse_msg: Error parsing message.");
651     msg_rc=TRP_NOPARSE;
652     goto cleanup;
653   }
654
655   /* parse the common part of the message */
656   new_msg=trp_msg_new(tmp_ctx);
657   if (new_msg == NULL) {
658     tr_debug("trp_parse_msg: Error allocating message.");
659     msg_rc=TRP_NOMEM;
660     goto cleanup;
661   }
662
663   switch (trp_get_json_string(jmsg, "message_type", &s, new_msg)) {
664   case TRP_SUCCESS:
665     break;
666   case TRP_NOPARSE:
667     tr_debug("trp_parse_msg: required attribute 'message_type' not present.");
668     msg_rc=TRP_NOPARSE;
669     goto cleanup;
670   case TRP_BADTYPE:
671     tr_debug("trp_parse_msg: required attribute 'message_type' is not a string.");
672     msg_rc=TRP_NOPARSE;
673     goto cleanup;
674   default:
675     tr_debug("trp_parse_msg: error parsing 'message_type'.");
676     msg_rc=TRP_NOPARSE;
677     goto cleanup;
678   }
679   
680   tr_debug("trp_parse_msg: 'message_type' is '%s'", s);
681   new_msg->type = trp_msg_type_from_string(s);
682   if (new_msg->type==TRP_MSG_TYPE_UNKNOWN) {
683     tr_debug("trp_parse_msg: Parsing error, unknown message_type (%s).", s);
684     msg_rc=TRP_NOPARSE;
685     goto cleanup;
686   }  
687
688   new_msg->body=trp_msg_body_new(new_msg, new_msg->type);
689   if (new_msg->body==NULL) {
690     tr_debug("trp_parse_msg: Error allocating message body for message_type %d.", new_msg->type);
691     msg_rc=TRP_NOMEM;
692     goto cleanup;
693   }
694   jbody=json_object_get(jmsg, "body");
695   if (jbody==NULL) {
696     tr_debug("trp_parse_msg: Message body not found.");
697     msg_rc=TRP_NOPARSE;
698     goto cleanup;
699   }
700
701   switch (trp_parse_msg_body(new_msg, jbody)) {
702   case TRP_SUCCESS:
703     break;
704   default:
705     tr_debug("trp_parse_msg: Error parsing message body.");
706     goto cleanup;
707   }
708
709   /* success! */
710   (*msg)=new_msg;
711   new_msg=NULL;
712   talloc_steal(mem_ctx, *msg);
713   msg_rc=TRP_SUCCESS;
714
715 cleanup:
716   talloc_free(tmp_ctx);
717   json_decref(jmsg);
718   return msg_rc;
719 }