Decode and print route_req messages.
[trust_router.git] / trp / trp_msg.c
index c2e6213..ea90cf1 100644 (file)
@@ -1,5 +1,6 @@
 #include <talloc.h>
 
+#include <tr_name.h>
 #include <trp_internal.h>
 #include <tr_debug.h>
 
@@ -7,23 +8,39 @@
 /* static prototypes */
 static void *trp_msg_body_update_new(TALLOC_CTX *mem_ctx);
 static TRP_RC trp_parse_update(TRP_MSG *msg, json_t *jmsg);
+static void trp_msg_body_update_print(void *);
 
 static void *trp_msg_body_route_req_new(TALLOC_CTX *mem_ctx);
 static TRP_RC trp_parse_route_req(TRP_MSG *msg, json_t *jmsg);
+static void trp_msg_body_route_req_print(void *);
 
+static void *trp_msg_info_route_new(TALLOC_CTX *mem_ctx);
+static TRP_RC trp_parse_info_route(TRP_MSG *msg, json_t *jmsg);
+static void trp_msg_info_route_print(void *);
 
 /* table of string names for TMT_MSG_TYPE codes */
-struct trp_msg_type_info {
+struct trp_msg_type_entry {
   const char *name;
   TRP_MSG_TYPE type;
   void *(*allocator)(TALLOC_CTX *);
   TRP_RC (*parser)(TRP_MSG *, json_t *);
+  void (*printer)(void *);
+};
+static struct trp_msg_type_entry trp_msg_type_table[] = {
+  { "update", TRP_MSG_TYPE_UPDATE, trp_msg_body_update_new, trp_parse_update, trp_msg_body_update_print },
+  { "route_req", TRP_MSG_TYPE_ROUTE_REQ, trp_msg_body_route_req_new, trp_parse_route_req, trp_msg_body_route_req_print },
+  { NULL, TRP_MSG_TYPE_UNKNOWN, NULL, NULL, NULL } /* must be the last entry */
 };
 
-static struct trp_msg_type_info trp_msg_type_table[] = {
-  { "update", TRP_MSG_TYPE_UPDATE, trp_msg_body_update_new, trp_parse_update },
-  { "route_req", TRP_MSG_TYPE_ROUTE_REQ, trp_msg_body_route_req_new, trp_parse_route_req },
-  { NULL, TRP_MSG_TYPE_UNKNOWN, NULL, NULL } /* must be the last entry */
+struct trp_msg_info_type_entry {
+  const char *name;
+  TRP_MSG_INFO_TYPE type;
+  void (*printer)(void *);
+};
+static struct trp_msg_info_type_entry trp_msg_info_type_table[] = {
+  { "route_info", TRP_MSG_INFO_TYPE_ROUTE, trp_msg_info_route_print },
+  { "comm_info", TRP_MSG_INFO_TYPE_COMMUNITY, NULL },
+  { NULL, TRP_MSG_INFO_TYPE_UNKNOWN, NULL } /* must be the last entry */
 };
 
 /* Use talloc's dynamic type checking to verify type.
@@ -46,9 +63,9 @@ static void msg_body_type_check(TRP_MSG_TYPE msgtype, void *p)
 }
 
 /* look up an entry in the trp_msg_type_table */
-static struct trp_msg_type_info *get_trp_msg_type_info(TRP_MSG_TYPE msgtype)
+static struct trp_msg_type_entry *get_trp_msg_type_entry(TRP_MSG_TYPE msgtype)
 {
-  struct trp_msg_type_info *entry=trp_msg_type_table;
+  struct trp_msg_type_entry *entry=trp_msg_type_table;
 
   while ((entry->type != TRP_MSG_TYPE_UNKNOWN)
         && (entry->type != msgtype)) {
@@ -57,10 +74,22 @@ static struct trp_msg_type_info *get_trp_msg_type_info(TRP_MSG_TYPE msgtype)
   return entry;
 }
 
+/* look up an entry in the trp_msg_info_type_table */
+static struct trp_msg_info_type_entry *get_trp_msg_info_type_entry(TRP_MSG_INFO_TYPE msgtype)
+{
+  struct trp_msg_info_type_entry *entry=trp_msg_info_type_table;
+
+  while ((entry->type != TRP_MSG_INFO_TYPE_UNKNOWN)
+        && (entry->type != msgtype)) {
+    entry ++;
+  }
+  return entry;
+}
+
 /* translate strings to codes */
 TRP_MSG_TYPE trp_msg_type_from_string(const char *s)
 {
-  struct trp_msg_type_info *entry=trp_msg_type_table;
+  struct trp_msg_type_entry *entry=trp_msg_type_table;
 
   while ((entry->type != TRP_MSG_TYPE_UNKNOWN)
         && (strcmp(s, entry->name)!=0)) {
@@ -68,12 +97,30 @@ TRP_MSG_TYPE trp_msg_type_from_string(const char *s)
   }
   return entry->type;
 }
-
 /* translate codes to strings (do not need to be freed) 
  * Returns NULL on an unknown code */
 const char *trp_msg_type_to_string(TRP_MSG_TYPE msgtype)
 {
-  struct trp_msg_type_info *entry=get_trp_msg_type_info(msgtype);
+  struct trp_msg_type_entry *entry=get_trp_msg_type_entry(msgtype);
+  return entry->name;
+}
+
+/* translate strings to codes */
+TRP_MSG_INFO_TYPE trp_msg_info_type_from_string(const char *s)
+{
+  struct trp_msg_info_type_entry *entry=trp_msg_info_type_table;
+
+  while ((entry->type != TRP_MSG_INFO_TYPE_UNKNOWN)
+        && (strcmp(s, entry->name)!=0)) {
+    entry++;
+  }
+  return entry->type;
+}
+/* translate codes to strings (do not need to be freed) 
+ * Returns NULL on an unknown code */
+const char *trp_msg_info_type_to_string(TRP_MSG_INFO_TYPE msgtype)
+{
+  struct trp_msg_info_type_entry *entry=get_trp_msg_info_type_entry(msgtype);
   return entry->name;
 }
 
@@ -83,7 +130,7 @@ TRP_MSG *trp_msg_new(TALLOC_CTX *mem_ctx)
   TRP_MSG *new_msg=talloc(mem_ctx, TRP_MSG);
 
   if (new_msg != NULL) {
-    new_msg->type=TRP_MSG_TYPE_UNKNOWN;
+    new_msg->type=TRP_MSG_INFO_TYPE_UNKNOWN;
     new_msg->body=NULL;
   }
   return new_msg;
@@ -98,13 +145,7 @@ void trp_msg_destroy(TRP_MSG *msg)
 
 /* JSON helpers */
 /* Read attribute attr from msg as an integer */
-static TRP_RC trp_get_json_integer(json_t *msg, const char *attr, int *dest)
-{
-  return TRP_ERROR;
-}
-
-/* Read attribute attr from msg as a string */
-static TRP_RC trp_get_json_string(json_t *jmsg, const char *attr, const char **dest)
+static TRP_RC trp_get_json_integer(json_t *jmsg, const char *attr, int *dest)
 {
   json_error_t err;
   json_t *obj;
@@ -114,40 +155,176 @@ static TRP_RC trp_get_json_string(json_t *jmsg, const char *attr, const char **d
     return TRP_NOPARSE;
   }
   /* check type */
-  if (!json_is_string(obj)) {
+  if (!json_is_integer(obj)) {
     return TRP_BADTYPE;
   }
 
-  (*dest)=json_string_value(obj);
+  (*dest)=json_integer_value(obj);
   return TRP_SUCCESS;
 }
 
+/* Read attribute attr from msg as a string. Copies string into mem_ctx context so jmsg can
+ * be destroyed safely. */
+static TRP_RC trp_get_json_string(json_t *jmsg, const char *attr, char **dest, TALLOC_CTX *mem_ctx)
+{
+  json_error_t err;
+  json_t *obj;
 
+  obj=json_object_get(jmsg, attr);
+  if (obj == NULL)
+    return TRP_NOPARSE;
 
-static void *trp_msg_body_update_new(TALLOC_CTX *mem_ctx)
+  /* check type */
+  if (!json_is_string(obj))
+    return TRP_BADTYPE;
+
+  *dest=talloc_strdup(mem_ctx, json_string_value(obj));
+  if (*dest==NULL)
+    return TRP_NOMEM;
+
+  return TRP_SUCCESS;
+}
+
+
+/* called by talloc when destroying an update message body */
+static int trp_msg_info_route_destructor(void *object)
 {
-  TRP_MSG_BODY_UPDATE *new_body=talloc(mem_ctx, TRP_MSG_BODY_UPDATE);
+  TRP_MSG_INFO_ROUTE *body=talloc_get_type_abort(object, TRP_MSG_INFO_ROUTE);
+  
+  /* clean up TR_NAME data, which are not managed by talloc */
+  if (body->community != NULL) {
+    tr_free_name(body->community);
+    body->community=NULL;
+    tr_debug("trp_msg_info_route_destructor: freed community");
+  }
+  if (body->realm != NULL) {
+    tr_free_name(body->realm);
+    body->realm=NULL;
+    tr_debug("trp_msg_info_route_destructor: freed realm");
+  }
+  if (body->trust_router != NULL) {
+    tr_free_name(body->trust_router);
+    body->trust_router=NULL;
+    tr_debug("trp_msg_info_route_destructor: freed trust_router");
+  }
 
-  if (new_body != NULL) {
-    new_body->next=NULL;
-    new_body->community=NULL;
-    new_body->realm=NULL;
-    new_body->trust_router=NULL;
-    new_body->metric=TRP_METRIC_INFINITY;
-    new_body->interval=0;
+  return 0;
+}
+
+static void *trp_msg_info_route_new(TALLOC_CTX *mem_ctx)
+{
+  TRP_MSG_INFO_ROUTE *new_rec=talloc(mem_ctx, TRP_MSG_INFO_ROUTE);
+
+  if (new_rec != NULL) {
+    new_rec->next=NULL;
+    new_rec->type=TRP_MSG_INFO_TYPE_UNKNOWN;
+    new_rec->community=NULL;
+    new_rec->realm=NULL;
+    new_rec->trust_router=NULL;
+    new_rec->metric=TRP_METRIC_INFINITY;
+    new_rec->interval=0;
+    talloc_set_destructor((void *)new_rec, trp_msg_info_route_destructor);
   }
-  return new_body;
+  return new_rec;
 }
 
 /* parse a single record */
-static TRP_RC trp_parse_update_record(TRP_MSG_BODY_UPDATE *body, json_t *jrecord)
+static TRP_RC trp_parse_update_record(TRP_MSG_INFO_ROUTE *rec, json_t *jrecord)
 {
-  return TRP_SUCCESS;
+  TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+  TRP_RC rc=TRP_ERROR;
+  char *s=NULL;
+  int num=0;
+
+  rc=trp_get_json_string(jrecord, "record_type", &s, tmp_ctx);
+  if (rc != TRP_SUCCESS)
+    goto cleanup;
+  rec->type=trp_msg_info_type_from_string(s);
+  talloc_free(s); s=NULL;
+  /* We only support route_info records for now*/
+  if (rec->type!=TRP_MSG_INFO_TYPE_ROUTE) {
+    rc=TRP_UNSUPPORTED;
+    goto cleanup;
+  }
+
+  tr_debug("trp_parse_update_record: '%s' record found.", trp_msg_info_type_to_string(rec->type));
+
+  rc=trp_get_json_string(jrecord, "community", &s, tmp_ctx);
+  if (rc != TRP_SUCCESS)
+    goto cleanup;
+  if (NULL==(rec->community=tr_new_name(s)))
+    goto cleanup;
+  talloc_free(s); s=NULL;
+
+  tr_debug("trp_parse_update_record: 'community' is '%.*s'.", rec->community->len, rec->community->buf);
+
+  rc=trp_get_json_string(jrecord, "realm", &s, tmp_ctx);
+  if (rc != TRP_SUCCESS)
+    goto cleanup;
+  if (NULL==(rec->realm=tr_new_name(s)))
+    goto cleanup;
+  talloc_free(s); s=NULL;
+
+  tr_debug("trp_parse_update_record: 'realm' is '%.*s'.", rec->realm->len, rec->realm->buf);
+
+  rc=trp_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
+  if (rc != TRP_SUCCESS)
+    goto cleanup;
+  if (NULL==(rec->trust_router=tr_new_name(s)))
+    goto cleanup;
+  talloc_free(s); s=NULL;
+
+  tr_debug("trp_parse_update_record: 'trust_router' is '%.*s'.", rec->trust_router->len, rec->trust_router->buf);
+
+  rc=trp_get_json_integer(jrecord, "metric", &num);
+  if (rc != TRP_SUCCESS)
+    goto cleanup;
+  rec->metric=num;
+
+  tr_debug("trp_parse_update_record: 'metric' is %d.", rec->metric);
+  
+  rc=trp_get_json_integer(jrecord, "interval", &num);
+  if (rc != TRP_SUCCESS)
+    goto cleanup;
+  rec->interval=num;
+
+  tr_debug("trp_parse_update_record: 'interval' is %d.", rec->interval);
+
+  rc=TRP_SUCCESS;
+
+cleanup:
+  if (rc != TRP_SUCCESS) {
+    /* clean up TR_NAME data, which is not managed by talloc */
+    if (rec->community != NULL) {
+      tr_free_name(rec->community);
+      rec->community=NULL;
+    }
+    if (rec->realm != NULL) {
+      tr_free_name(rec->realm);
+      rec->realm=NULL;
+    }
+    if (rec->trust_router != NULL) {
+      tr_free_name(rec->trust_router);
+      rec->trust_router=NULL;
+    }
+  }
+  
+  talloc_free(tmp_ctx);
+  return rc;
+}
+
+
+
+static void *trp_msg_body_update_new(TALLOC_CTX *mem_ctx)
+{
+  TRP_MSG_BODY_UPDATE *new_body=talloc(mem_ctx, TRP_MSG_BODY_UPDATE);
+
+  if (new_body!=NULL) {
+    new_body->records=NULL;
+  }
 }
 
-/* Parse an update body. Creates a linked list of records as the body, allocating all but the first.
- * Hence, msg->body must be allocated as a TRP_MSG_BODY_UPDATE. All body records will be in the
- * talloc context of msg.
+/* Parse an update body. Creates a linked list of records in the msg->body talloc context.
  *
  * An error will be returned if any unparseable records are encountered. 
  *
@@ -156,17 +333,22 @@ static TRP_RC trp_parse_update(TRP_MSG *msg, json_t *jbody)
 {
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   json_t *jrecords=NULL;
-  json_t *jval=NULL; /* for iteration */
   size_t ii=0;
   size_t nrec=0;
   TRP_MSG_BODY_UPDATE *msg_body=NULL;
-  TRP_MSG_BODY_UPDATE *cur_body=NULL;
+  TRP_MSG_INFO_ROUTE *new_rec=NULL;
+  TRP_MSG_INFO_ROUTE *list_tail=NULL;
   TRP_RC rc=TRP_ERROR;
 
   if (msg->type != TRP_MSG_TYPE_UPDATE) {
     rc=TRP_BADTYPE;
     goto cleanup;
   }
+  msg_body=talloc_get_type(msg->body, TRP_MSG_BODY_UPDATE);
+  if (msg_body==NULL) {
+    rc=TRP_BADTYPE;
+    goto cleanup;
+  }
 
   jrecords=json_object_get(jbody, "records");
   if ((jrecords==NULL) || (!json_is_array(jrecords))) {
@@ -174,48 +356,76 @@ static TRP_RC trp_parse_update(TRP_MSG *msg, json_t *jbody)
     goto cleanup;
   }
 
+  tr_debug("trp_parse_update: found %d records", json_array_size(jrecords));
   /* process the array */
-  /* first body is already allocated by caller. Check that it is expected type */
-  msg_body=talloc_get_type(msg->body, TRP_MSG_BODY_UPDATE);
-  if (msg_body==NULL) {
-    rc=TRP_BADTYPE;
-    goto cleanup;
-  }
-
-  cur_body=msg_body;
-  nrec=json_array_size(jrecords);
-  for (ii=0; ii<nrec; ii++) {
-    jval=json_array_get(jrecords, ii);
-    if (ii>0) {
-      /* on all but the first, need to allocate space */
-      cur_body->next=trp_msg_body_update_new(tmp_ctx);
-      if (cur_body==NULL) {
-        rc=TRP_NOMEM;
-        goto cleanup;
-      }
-      cur_body=cur_body->next;
+  for (ii=0; ii<json_array_size(jrecords); ii++) {
+    new_rec=trp_msg_info_route_new(tmp_ctx);
+    if (new_rec==NULL) {
+      rc=TRP_NOMEM;
+      goto cleanup;
     }
 
-    if (TRP_SUCCESS != trp_parse_update_record(cur_body, jval)) {
+    if (TRP_SUCCESS != trp_parse_update_record(new_rec, json_array_get(jrecords, ii))) {
       rc=TRP_NOPARSE;
       goto cleanup;
     }
+
+    if (list_tail==NULL)
+      msg_body->records=new_rec; /* first is a special case */
+    else
+      list_tail->next=new_rec;
+
+    list_tail=new_rec;
   }
 
   /* Succeeded. Move all of our new allocations into the correct talloc context */
-  for (cur_body=msg_body->next; cur_body != NULL; cur_body=cur_body->next)
-    talloc_steal(msg, cur_body); /* all successfully parsed bodies belong to msg context */
+  for (list_tail=msg_body->records; list_tail != NULL; list_tail=list_tail->next)
+    talloc_steal(msg->body, list_tail); /* all successfully parsed bodies belong to msg context */
+
   rc=TRP_SUCCESS;
 
 cleanup:
   talloc_free(tmp_ctx);
-  if (rc != TRP_SUCCESS)
-    msg_body->next=NULL; /* don't leave this hanging */
+  if ((rc != TRP_SUCCESS) && (msg_body != NULL))
+    msg_body->records=NULL; /* don't leave this hanging */
 
   return rc;
 }
 
+/* pretty print */
+static void trp_msg_info_route_print(void *rec_in)
+{
+  TRP_MSG_INFO_ROUTE *rec=talloc_get_type(rec_in, TRP_MSG_INFO_ROUTE); /* null if wrong type */
+
+  while (rec!=NULL) {
+    printf("    [record_type=%s\n     community=%.*s\n     realm=%.*s\n     trust_router=%.*s\n     metric=%d\n     interval=%d]\n",
+           trp_msg_info_type_to_string(rec->type),
+           rec->community->len, rec->community->buf,
+           rec->realm->len, rec->realm->buf,
+           rec->trust_router->len, rec->trust_router->buf,
+           rec->metric, rec->interval);
+    rec=rec->next;
+  }
+}
+
 
+static int trp_msg_body_route_req_destructor(void *object)
+{
+  TRP_MSG_BODY_ROUTE_REQ *body=talloc_get_type_abort(object, TRP_MSG_BODY_ROUTE_REQ);
+  
+  /* clean up TR_NAME data, which are not managed by talloc */
+  if (body->community != NULL) {
+    tr_free_name(body->community);
+    body->community=NULL;
+    tr_debug("trp_msg_body_route_req_destructor: freed community");
+  }
+  if (body->realm != NULL) {
+    tr_free_name(body->realm);
+    body->realm=NULL;
+    tr_debug("trp_msg_body_route_req_destructor: freed realm");
+  }
+  return 0;
+}
 static void *trp_msg_body_route_req_new(TALLOC_CTX *mem_ctx)
 {
   TRP_MSG_BODY_ROUTE_REQ *new_body=talloc(mem_ctx, TRP_MSG_BODY_ROUTE_REQ);
@@ -224,21 +434,88 @@ static void *trp_msg_body_route_req_new(TALLOC_CTX *mem_ctx)
     new_body->community=NULL;
     new_body->realm=NULL;
   }
+
+  talloc_set_destructor((void *)new_body, trp_msg_body_route_req_destructor);
   return new_body;
 }
 
 static TRP_RC trp_parse_route_req(TRP_MSG *msg, json_t *jbody)
 {
-  return TRP_ERROR;
+  TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+  TRP_MSG_BODY_ROUTE_REQ *msg_body=NULL;
+  char *s=NULL;
+  TRP_RC rc=TRP_ERROR;
+
+  /* check message type and body type for agreement */
+  if (msg->type != TRP_MSG_TYPE_ROUTE_REQ) {
+    rc=TRP_BADTYPE;
+    goto cleanup;
+  }
+  msg_body=talloc_get_type(msg->body, TRP_MSG_BODY_ROUTE_REQ);
+  if (msg_body==NULL) {
+    rc=TRP_BADTYPE;
+    goto cleanup;
+  }
+
+  rc=trp_get_json_string(jbody, "community", &s, tmp_ctx);
+  if (rc!=TRP_SUCCESS)
+    goto cleanup;
+  msg_body->community=tr_new_name(s);
+  talloc_free(s); s=NULL;
+
+  rc=trp_get_json_string(jbody, "realm", &s, tmp_ctx);
+  if (rc!=TRP_SUCCESS)
+    goto cleanup;
+  msg_body->realm=tr_new_name(s);
+  talloc_free(s); s=NULL;
+
+  rc=TRP_SUCCESS;
+cleanup:
+  talloc_free(tmp_ctx);
+  return rc;
+}
+
+static void trp_msg_body_update_print(void *body_in)
+{
+  TRP_MSG_BODY_UPDATE *body=talloc_get_type(body_in, TRP_MSG_BODY_UPDATE); /* null if wrong type */
+
+  if (body!=NULL) {
+    printf("  {records=\n");
+    trp_msg_info_route_print(body->records);
+    printf("  }\n");
+  }
+}
+
+static void trp_msg_body_route_req_print(void *body_in)
+{
+  TRP_MSG_BODY_ROUTE_REQ *body=talloc_get_type(body_in, TRP_MSG_BODY_ROUTE_REQ); /* null if wrong type */
+
+  if (body!=NULL) {
+    printf("  {community=%.*s\n   realm=%.*s}\n",
+           body->community->len, body->community->buf,
+           body->realm->len, body->realm->buf);
+  }
 }
 
+static void trp_msg_body_print(void *body, TRP_MSG_TYPE msgtype)
+{
+  struct trp_msg_type_entry *info=get_trp_msg_type_entry(msgtype);
+  info->printer(body);
+}
 
+void trp_msg_print(TRP_MSG *msg)
+{
+  /* right now just assumes update */
+  printf("{message_type=%s\n", trp_msg_type_to_string(msg->type));
+  trp_msg_body_print(msg->body, msg->type);
+  printf("}\n");
+}
 
 /* returns a pointer to one of the message body types, or NULL on error/unknown type */
 static void *trp_msg_body_new(TALLOC_CTX *mem_ctx, TRP_MSG_TYPE msgtype)
 {
   void *new_body=NULL;
-  struct trp_msg_type_info *info=get_trp_msg_type_info(msgtype);
+  struct trp_msg_type_entry *info=get_trp_msg_type_entry(msgtype);
 
   if (info->type==TRP_MSG_TYPE_UNKNOWN) {
     tr_debug("trp_msg_body_new: Unknown type %d.", info->type);
@@ -253,7 +530,7 @@ static void *trp_msg_body_new(TALLOC_CTX *mem_ctx, TRP_MSG_TYPE msgtype)
 /* call the correct parser */
 static TRP_RC trp_parse_msg_body(TRP_MSG *msg, json_t *jbody)
 {
-  struct trp_msg_type_info *info=get_trp_msg_type_info(msg->type);
+  struct trp_msg_type_entry *info=get_trp_msg_type_entry(msg->type);
 
   if (info->type==TRP_MSG_TYPE_UNKNOWN) {
     tr_debug("trp_msg_body_parse: Unknown type %d.", info->type);
@@ -272,7 +549,7 @@ TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MS
   json_error_t json_err;
   json_t *jmsg=NULL; /* handle for the whole msg */
   json_t *jbody=NULL;
-  const char *s;
+  char *s;
 
   tr_debug("trp_parse_msg: parsing %d bytes", buflen);
 
@@ -291,7 +568,7 @@ TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MS
     goto cleanup;
   }
 
-  switch (trp_get_json_string(jmsg, "message_type", &s)) {
+  switch (trp_get_json_string(jmsg, "message_type", &s, new_msg)) {
   case TRP_SUCCESS:
     break;
   case TRP_NOPARSE:
@@ -341,8 +618,10 @@ TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MS
   (*msg)=new_msg;
   new_msg=NULL;
   talloc_steal(mem_ctx, *msg);
+  msg_rc=TRP_SUCCESS;
 
 cleanup:
   talloc_free(tmp_ctx);
+  json_decref(jmsg);
   return msg_rc;
 }