From 0d3480b51b1904ba01515d98fefc083c866e825a Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 14 Jun 2016 14:36:09 -0400 Subject: [PATCH] Progress towards parsing update messages. --- include/trp_internal.h | 1 + trp/msgtst.c | 6 +- trp/trp_msg.c | 182 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 167 insertions(+), 22 deletions(-) diff --git a/include/trp_internal.h b/include/trp_internal.h index 0cf6f05..b598f6e 100644 --- a/include/trp_internal.h +++ b/include/trp_internal.h @@ -14,6 +14,7 @@ typedef enum trp_rc { TRP_ERROR, /* generic error */ TRP_NOPARSE, /* parse error */ TRP_NOMEM, /* allocation error */ + TRP_BADTYPE, /* typing error */ } TRP_RC; /*** Messages ***/ diff --git a/trp/msgtst.c b/trp/msgtst.c index 83f5476..9b844ff 100644 --- a/trp/msgtst.c +++ b/trp/msgtst.c @@ -3,6 +3,8 @@ /* compiles with: gcc -o msgtst -I../include msgtst.c trp_msg.c $(pkg-config --cflags --libs glib-2.0) ../common/tr_debug.c -ltalloc -ljansson */ #include +#include + #include #include @@ -10,6 +12,7 @@ int main(int argc, const char *argv[]) { + TALLOC_CTX *main_ctx=talloc_new(NULL); FILE *f; char *buf; size_t buflen; @@ -44,8 +47,9 @@ int main(int argc, const char *argv[]) if (buflen>=MAX_MSG_LEN) printf("Warning: file may exceed maximum message length (%d bytes).\n", MAX_MSG_LEN); - rc=trp_parse_msg(NULL, buf, buflen, &msg); + rc=trp_parse_msg(main_ctx, buf, buflen, &msg); printf("trp_parse_msg returned %d\n\n", rc); + talloc_report_full(main_ctx, stderr); return 0; } diff --git a/trp/trp_msg.c b/trp/trp_msg.c index df8fca5..c2e6213 100644 --- a/trp/trp_msg.c +++ b/trp/trp_msg.c @@ -6,19 +6,24 @@ /* 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_route_req_new(TALLOC_CTX *mem_ctx); +static TRP_RC trp_parse_route_req(TRP_MSG *msg, json_t *jmsg); + /* table of string names for TMT_MSG_TYPE codes */ struct trp_msg_type_info { const char *name; TRP_MSG_TYPE type; void *(*allocator)(TALLOC_CTX *); + TRP_RC (*parser)(TRP_MSG *, json_t *); }; static struct trp_msg_type_info trp_msg_type_table[] = { - { "update", TRP_MSG_TYPE_UPDATE, trp_msg_body_update_new }, - { "route_req", TRP_MSG_TYPE_ROUTE_REQ, trp_msg_body_route_req_new }, - { NULL, TRP_MSG_TYPE_UNKNOWN, NULL } /* must be the last entry */ + { "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 */ }; /* Use talloc's dynamic type checking to verify type. @@ -90,6 +95,35 @@ void trp_msg_destroy(TRP_MSG *msg) talloc_free(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) +{ + json_error_t err; + json_t *obj; + + obj=json_object_get(jmsg, attr); + if (obj == NULL) { + return TRP_NOPARSE; + } + /* check type */ + if (!json_is_string(obj)) { + return TRP_BADTYPE; + } + + (*dest)=json_string_value(obj); + return TRP_SUCCESS; +} + + + static void *trp_msg_body_update_new(TALLOC_CTX *mem_ctx) { TRP_MSG_BODY_UPDATE *new_body=talloc(mem_ctx, TRP_MSG_BODY_UPDATE); @@ -105,12 +139,83 @@ static void *trp_msg_body_update_new(TALLOC_CTX *mem_ctx) return new_body; } -/* placeholder return type */ -static int trp_parse_msg_update(json_t *jmsg) +/* parse a single record */ +static TRP_RC trp_parse_update_record(TRP_MSG_BODY_UPDATE *body, json_t *jrecord) { - + return TRP_SUCCESS; +} + +/* 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. + * + * An error will be returned if any unparseable records are encountered. + * + * TODO: clean up return codes. */ +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_RC rc=TRP_ERROR; + + if (msg->type != TRP_MSG_TYPE_UPDATE) { + rc=TRP_BADTYPE; + goto cleanup; + } + + jrecords=json_object_get(jbody, "records"); + if ((jrecords==NULL) || (!json_is_array(jrecords))) { + rc=TRP_NOPARSE; + goto cleanup; + } + + /* 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; ii0) { + /* 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; + } + + if (TRP_SUCCESS != trp_parse_update_record(cur_body, jval)) { + rc=TRP_NOPARSE; + goto cleanup; + } + } + + /* 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 */ + rc=TRP_SUCCESS; + +cleanup: + talloc_free(tmp_ctx); + if (rc != TRP_SUCCESS) + msg_body->next=NULL; /* don't leave this hanging */ + + return rc; } + 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); @@ -122,6 +227,13 @@ static void *trp_msg_body_route_req_new(TALLOC_CTX *mem_ctx) return new_body; } +static TRP_RC trp_parse_route_req(TRP_MSG *msg, json_t *jbody) +{ + return TRP_ERROR; +} + + + /* 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) { @@ -138,6 +250,19 @@ static void *trp_msg_body_new(TALLOC_CTX *mem_ctx, TRP_MSG_TYPE msgtype) return new_body; } +/* 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); + + if (info->type==TRP_MSG_TYPE_UNKNOWN) { + tr_debug("trp_msg_body_parse: Unknown type %d.", info->type); + return TRP_ERROR; + } + + return info->parser(msg, jbody); +} + TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MSG **msg) { @@ -146,7 +271,8 @@ TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MS TRP_RC msg_rc=TRP_ERROR; json_error_t json_err; json_t *jmsg=NULL; /* handle for the whole msg */ - json_t *jmsgtype=NULL; + json_t *jbody=NULL; + const char *s; tr_debug("trp_parse_msg: parsing %d bytes", buflen); @@ -165,37 +291,51 @@ TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MS goto cleanup; } - jmsgtype=json_object_get(jmsg, "message_type"); - if (jmsgtype == NULL) { + switch (trp_get_json_string(jmsg, "message_type", &s)) { + case TRP_SUCCESS: + break; + case TRP_NOPARSE: + tr_debug("trp_parse_msg: required attribute 'message_type' not present."); msg_rc=TRP_NOPARSE; goto cleanup; - } - - /* get the message type */ - if (!json_is_string(jmsgtype)) { - tr_debug("trp_parse_msg: Parsing error, message_type is not a string."); + case TRP_BADTYPE: + tr_debug("trp_parse_msg: required attribute 'message_type' is not a string."); + msg_rc=TRP_NOPARSE; + goto cleanup; + default: + tr_debug("trp_parse_msg: error parsing 'message_type'."); msg_rc=TRP_NOPARSE; goto cleanup; } - - tr_debug("trp_parse_msg: message_type: %s", json_string_value(jmsgtype)); - - new_msg->type = trp_msg_type_from_string(json_string_value(jmsgtype)); + + tr_debug("trp_parse_msg: 'message_type' is '%s'", s); + new_msg->type = trp_msg_type_from_string(s); if (new_msg->type==TRP_MSG_TYPE_UNKNOWN) { - tr_debug("trp_parse_msg: Parsing error, unknown message_type (%s).", json_string_value(jmsgtype)); + tr_debug("trp_parse_msg: Parsing error, unknown message_type (%s).", s); msg_rc=TRP_NOPARSE; goto cleanup; } - /* next line uses new_msg as the talloc context so body will free along with msg */ new_msg->body=trp_msg_body_new(new_msg, new_msg->type); if (new_msg->body==NULL) { tr_debug("trp_parse_msg: Error allocating message body for message_type %d.", new_msg->type); msg_rc=TRP_NOMEM; goto cleanup; } + jbody=json_object_get(jmsg, "body"); + if (jbody==NULL) { + tr_debug("trp_parse_msg: Message body not found."); + msg_rc=TRP_NOPARSE; + goto cleanup; + } - tr_debug("trp_parse_msg: SUCCESS"); + switch (trp_parse_msg_body(new_msg, jbody)) { + case TRP_SUCCESS: + break; + default: + tr_debug("trp_parse_msg: Error parsing message body."); + goto cleanup; + } /* success! */ (*msg)=new_msg; -- 2.1.4