X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=blobdiff_plain;f=common%2Ftr_msg.c;h=50e8bc95fd8239bcefab0b5781e98ae5f50eb53e;hp=cb602929c1f5988f4a7e446be75abfa4f0cda3f2;hb=3c5fb17459ff56d5e23cea059503f46a42150a1e;hpb=fcd7109fa98920f3ffbb7909757f506d8f85db0c diff --git a/common/tr_msg.c b/common/tr_msg.c index cb60292..50e8bc9 100644 --- a/common/tr_msg.c +++ b/common/tr_msg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, JANET(UK) + * Copyright (c) 2012-2014 , JANET(UK) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,31 +31,252 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. * */ - +#include +#include +#include #include #include +#include #include +#include +#include +#include +#include +#include +#include #include -#include +#include +#include +#include +#include + +/* JSON helpers */ +/* Read attribute attr from msg as an integer. Returns nonzero on error. */ +static int tr_msg_get_json_integer(json_t *jmsg, const char *attr, int *dest) +{ + json_t *obj; + + obj=json_object_get(jmsg, attr); + if (obj == NULL) { + return -1; + } + /* check type */ + if (!json_is_integer(obj)) { + return -1; + } + + (*dest)=json_integer_value(obj); + return 0; +} + +/* Read attribute attr from msg as a string. Copies string into mem_ctx context so jmsg can + * be destroyed safely. Returns nonzero on error. */ +static TRP_RC tr_msg_get_json_string(json_t *jmsg, const char *attr, char **dest, TALLOC_CTX *mem_ctx) +{ + json_t *obj; + + obj=json_object_get(jmsg, attr); + if (obj == NULL) + return TRP_ERROR; + + /* check type */ + if (!json_is_string(obj)) + return TRP_ERROR; + + *dest=talloc_strdup(mem_ctx, json_string_value(obj)); + if (*dest==NULL) + return TRP_ERROR; + + return TRP_SUCCESS; +} + +enum msg_type tr_msg_get_msg_type(TR_MSG *msg) +{ + return msg->msg_type; +} + +void tr_msg_set_msg_type(TR_MSG *msg, enum msg_type type) +{ + msg->msg_type = type; +} + +/* NOTE: If you are manipulating messages with these getters/setters, the msg_rep + * objects are *not* put in the talloc context of the msg. If you are allocating + * the message directly with talloc, then you can talloc_steal() the rep into the + * message's context, but this is not handled automatically. */ + +/** + * Get a TID_REQ message payload + * + * @param msg + * @return the message payload, or null if it is not a TID_REQUEST message + */ +TID_REQ *tr_msg_get_req(TR_MSG *msg) +{ + if (msg->msg_type == TID_REQUEST) + return (TID_REQ *)msg->msg_rep; + return NULL; +} + +/** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ +void tr_msg_set_req(TR_MSG *msg, TID_REQ *req) +{ + msg->msg_rep = req; + msg->msg_type = TID_REQUEST; +} + +/** + * Get a TID_RESP message payload + * + * @param msg + * @return the message payload, or null if it is not a TID_RESPONSE message + */ +TID_RESP *tr_msg_get_resp(TR_MSG *msg) +{ + if (msg->msg_type == TID_RESPONSE) + return (TID_RESP *)msg->msg_rep; + return NULL; +} + +/** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ +void tr_msg_set_resp(TR_MSG *msg, TID_RESP *resp) +{ + msg->msg_rep = resp; + msg->msg_type = TID_RESPONSE; +} + +/** + * Get a MON_REQ message payload + * + * @param msg + * @return the message payload, or null if it is not a MON_REQUEST message + */ +MON_REQ *tr_msg_get_mon_req(TR_MSG *msg) +{ + if (msg->msg_type == MON_REQUEST) + return (MON_REQ *)msg->msg_rep; + return NULL; +} + +/** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ +void tr_msg_set_mon_req(TR_MSG *msg, MON_REQ *req) +{ + msg->msg_rep = req; + msg->msg_type = MON_REQUEST; +} + +/** + * Get a MON_RESP message payload + * + * @param msg + * @return the message payload, or null if it is not a MON_RESPONSE message + */ +MON_RESP *tr_msg_get_mon_resp(TR_MSG *msg) +{ + if (msg->msg_type == MON_RESPONSE) + return (MON_RESP *)msg->msg_rep; + return NULL; +} + +/** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ +void tr_msg_set_mon_resp(TR_MSG *msg, MON_RESP *resp) +{ + msg->msg_rep = resp; + msg->msg_type = MON_RESPONSE; +} + +/** + * Get a TRP_UPD message payload + * + * @param msg + * @return the message payload, or null if it is not a TRP_UPDATE message + */ +TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg) +{ + if (msg->msg_type == TRP_UPDATE) + return (TRP_UPD *)msg->msg_rep; + return NULL; +} + +/** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ +void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *update) +{ + msg->msg_rep=update; + msg->msg_type=TRP_UPDATE; +} + +/** + * Get a TRP_REQ message payload + * + * @param msg + * @return the message payload, or null if it is not a TRP_REQUEST message + */ +TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg) +{ + if (msg->msg_type == TRP_REQUEST) + return (TRP_REQ *)msg->msg_rep; + return NULL; +} + +/** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ +void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req) +{ + msg->msg_rep=req; + msg->msg_type=TRP_REQUEST; +} static json_t *tr_msg_encode_dh(DH *dh) { json_t *jdh = NULL; json_t *jbn = NULL; + char *s=NULL; if ((!dh) || (!dh->p) || (!dh->g) || (!dh->pub_key)) return NULL; jdh = json_object(); - jbn = json_string(BN_bn2hex(dh->p)); + jbn = json_string(s=BN_bn2hex(dh->p)); + OPENSSL_free(s); json_object_set_new(jdh, "dh_p", jbn); - jbn = json_string(BN_bn2hex(dh->g)); + jbn = json_string(s=BN_bn2hex(dh->g)); + OPENSSL_free(s); json_object_set_new(jdh, "dh_g", jbn); - jbn = json_string(BN_bn2hex(dh->pub_key)); + jbn = json_string(s=BN_bn2hex(dh->pub_key)); + OPENSSL_free(s); json_object_set_new(jdh, "dh_pub_key", jbn); return jdh; @@ -64,40 +285,32 @@ static json_t *tr_msg_encode_dh(DH *dh) static DH *tr_msg_decode_dh(json_t *jdh) { DH *dh = NULL; - json_error_t rc; json_t *jp = NULL; json_t *jg = NULL; json_t *jpub_key = NULL; - int msize; - if (!(dh = malloc(sizeof(DH)))) { - fprintf (stderr, "tr_msg_decode_dh(): Error allocating DH structure.\n"); + if (!(dh=tr_dh_new())) { + tr_crit("tr_msg_decode_dh(): Error allocating DH structure."); return NULL; } - memset(dh, 0, sizeof(DH)); - /* store required fields from dh object */ - if (((msize = json_object_size(jdh)) < 3) || - (NULL == (jp = json_object_get(jdh, "dh_p"))) || - (!json_is_string(jp)) || + if ((NULL == (jp = json_object_get(jdh, "dh_p"))) || (NULL == (jg = json_object_get(jdh, "dh_g"))) || - (!json_is_string(jg)) || - (NULL == (jpub_key = json_object_get(jdh, "dh_pub_key"))) || - (!json_is_string(jdh))) { - fprintf (stderr, "tr_msg_decode(): Error parsing message.\n"); - free(dh); + (NULL == (jpub_key = json_object_get(jdh, "dh_pub_key")))) { + tr_debug("tr_msg_decode_dh(): Error parsing dh_info."); + tr_dh_destroy(dh); return NULL; } - dh->p = json_string_value(jp); - dh->g = json_string_value(jg); - dh->pub_key = json_string_value(jpub_key); + BN_hex2bn(&(dh->p), json_string_value(jp)); + BN_hex2bn(&(dh->g), json_string_value(jg)); + BN_hex2bn(&(dh->pub_key), json_string_value(jpub_key)); return dh; } -json_t *tr_msg_encode_tidreq(TID_REQ *req) +static json_t * tr_msg_encode_tidreq(TID_REQ *req) { json_t *jreq = NULL; json_t *jstr = NULL; @@ -106,223 +319,1055 @@ json_t *tr_msg_encode_tidreq(TID_REQ *req) return NULL; jreq = json_object(); + assert(jreq); - jstr = json_string(req->rp_realm->buf); + jstr = tr_name_to_json_string(req->rp_realm); json_object_set_new(jreq, "rp_realm", jstr); - jstr = json_string(req->realm->buf); + jstr = tr_name_to_json_string(req->realm); json_object_set_new(jreq, "target_realm", jstr); - jstr = json_string(req->comm->buf); + jstr = tr_name_to_json_string(req->comm); json_object_set_new(jreq, "community", jstr); + if (req->orig_coi) { + jstr = tr_name_to_json_string(req->orig_coi); + json_object_set_new(jreq, "orig_coi", jstr); + } + + if (tid_req_get_request_id(req)) { + jstr = tr_name_to_json_string(tid_req_get_request_id(req)); + json_object_set_new(jreq, "request_id", jstr); + } + json_object_set_new(jreq, "dh_info", tr_msg_encode_dh(req->tidc_dh)); + + if (req->cons) + json_object_set(jreq, "constraints", (json_t *) req->cons); + + if (req->path) + json_object_set(jreq, "path", req->path); + if (req->expiration_interval) + json_object_set_new(jreq, "expiration_interval", + json_integer(req->expiration_interval)); return jreq; } -TID_REQ *tr_msg_decode_tidreq(json_t *jreq) +static TID_REQ *tr_msg_decode_tidreq(TALLOC_CTX *mem_ctx, json_t *jreq) { TID_REQ *treq = NULL; - json_error_t rc; json_t *jrp_realm = NULL; json_t *jrealm = NULL; json_t *jcomm = NULL; json_t *jorig_coi = NULL; + json_t *jrequest_id = NULL; json_t *jdh = NULL; - int msize; + json_t *jpath = NULL; + json_t *jexpire_interval = NULL; - if (!(treq = malloc(sizeof(TID_REQ)))) { - fprintf (stderr, "tr_msg_decode_tidreq(): Error allocating TID_REQ structure.\n"); + if (!(treq =tid_req_new())) { + tr_crit("tr_msg_decode_tidreq(): Error allocating TID_REQ structure."); return NULL; } - - memset(treq, 0, sizeof(TID_REQ)); + talloc_steal(mem_ctx, treq); /* store required fields from request */ - if (((msize = json_object_size(jreq)) < 4) || - (NULL == (jrp_realm = json_object_get(jreq, "rp_realm"))) || - (!json_is_string(jrp_realm)) || - (NULL == (jrealm = json_object_get(jreq, "realm"))) || - (!json_is_string(jrealm)) || - (NULL == (jcomm = json_object_get(jreq, "comm"))) || - (!json_is_string(jcomm)) || - (NULL == (jdh = json_object_get(jreq, "dh_info"))) || - (!json_is_object(jdh))) { - fprintf (stderr, "tr_msg_decode(): Error parsing message.\n"); - free(treq); + if ((NULL == (jrp_realm = json_object_get(jreq, "rp_realm"))) || + (NULL == (jrealm = json_object_get(jreq, "target_realm"))) || + (NULL == (jcomm = json_object_get(jreq, "community")))) { + tr_notice("tr_msg_decode(): Error parsing required fields."); + tid_req_free(treq); return NULL; } - treq->rp_realm->buf = json_string_value(jrp_realm); - treq->rp_realm->len = strlen(treq->rp_realm->buf); - treq->realm->buf = json_string_value(jrealm); - treq->realm->len = strlen(treq->realm->buf); - treq->comm->buf = json_string_value(jcomm); - treq->comm->len = strlen(treq->comm->buf); + jpath = json_object_get(jreq, "path"); + jexpire_interval = json_object_get(jreq, "expiration_interval"); + + treq->rp_realm = tr_new_name(json_string_value(jrp_realm)); + treq->realm = tr_new_name(json_string_value(jrealm)); + treq->comm = tr_new_name(json_string_value(jcomm)); + + /* Get DH Info from the request */ + if (NULL == (jdh = json_object_get(jreq, "dh_info"))) { + tr_debug("tr_msg_decode(): Error parsing dh_info."); + tid_req_free(treq); + return NULL; + } treq->tidc_dh = tr_msg_decode_dh(jdh); /* store optional "orig_coi" field */ - if ((NULL != (jorig_coi = json_object_get(jreq, "orig_coi"))) && - (!json_is_object(jorig_coi))) { - treq->orig_coi->buf = json_string_value(jorig_coi); - treq->orig_coi->len = strlen(treq->orig_coi->buf); + if (NULL != (jorig_coi = json_object_get(jreq, "orig_coi"))) { + treq->orig_coi = tr_new_name(json_string_value(jorig_coi)); } + /* store optional "request_id" field */ + if (NULL != (jrequest_id = json_object_get(jreq, "request_id"))) { + tid_req_set_request_id(treq, tr_new_name(json_string_value(jrequest_id))); + } + + treq->cons = (TR_CONSTRAINT_SET *) json_object_get(jreq, "constraints"); + if (treq->cons) { + if (!tr_constraint_set_validate(treq->cons)) { + tr_debug("Constraint set validation failed"); + tid_req_free(treq); + return NULL; + } + json_incref((json_t *) treq->cons); + tid_req_cleanup_json(treq, (json_t *) treq->cons); + } + if (jpath) { + json_incref(jpath); + treq->path = jpath; + tid_req_cleanup_json(treq, jpath); + } + if (jexpire_interval) + treq->expiration_interval = json_integer_value(jexpire_interval); + return treq; } -json_t *tr_msg_encode_tidresp(TID_RESP *resp) +static json_t *tr_msg_encode_one_server(TID_SRVR_BLK *srvr) +{ + json_t *jsrvr = NULL; + json_t *jstr = NULL; + gchar *time_str = g_time_val_to_iso8601(&srvr->key_expiration); + + tr_debug("Encoding one server."); + + jsrvr = json_object(); + + jstr = json_string(srvr->aaa_server_addr); + json_object_set_new(jsrvr, "server_addr", jstr); + + json_object_set_new(jsrvr, + "key_expiration", json_string(time_str)); + g_free(time_str); + /* Server DH Block */ + jstr = tr_name_to_json_string(srvr->key_name); + json_object_set_new(jsrvr, "key_name", jstr); + json_object_set_new(jsrvr, "server_dh", tr_msg_encode_dh(srvr->aaa_server_dh)); + if (srvr->path) + /* The path is owned by the srvr, so grab an extra ref*/ + json_object_set(jsrvr, "path", (json_t *)(srvr->path)); + return jsrvr; +} + +static int tr_msg_decode_one_server(json_t *jsrvr, TID_SRVR_BLK *srvr) +{ + json_t *jsrvr_addr = NULL; + json_t *jsrvr_kn = NULL; + json_t *jsrvr_dh = NULL; + json_t *jsrvr_expire = NULL; + + if (jsrvr == NULL) + return -1; + + + if ((NULL == (jsrvr_addr = json_object_get(jsrvr, "server_addr"))) || + (NULL == (jsrvr_kn = json_object_get(jsrvr, "key_name"))) || + (NULL == (jsrvr_dh = json_object_get(jsrvr, "server_dh")))) { + tr_notice("tr_msg_decode_one_server(): Error parsing required fields."); + return -1; + } + + srvr->aaa_server_addr=talloc_strdup(srvr, json_string_value(jsrvr_addr)); + srvr->key_name = tr_new_name((char *)json_string_value(jsrvr_kn)); + srvr->aaa_server_dh = tr_msg_decode_dh(jsrvr_dh); + tid_srvr_blk_set_path(srvr, (TID_PATH *) json_object_get(jsrvr, "path")); + jsrvr_expire = json_object_get(jsrvr, "key_expiration"); + if (jsrvr_expire && json_is_string(jsrvr_expire)) { + if (!g_time_val_from_iso8601(json_string_value(jsrvr_expire), + &srvr->key_expiration)) + tr_notice("Key expiration %s cannot be parsed", json_string_value(jsrvr_expire)); + } + + return 0; +} + +static json_t *tr_msg_encode_servers(TID_RESP *resp) +{ + json_t *jservers = NULL; + json_t *jsrvr = NULL; + TID_SRVR_BLK *srvr = NULL; + size_t index; + + jservers = json_array(); + + tid_resp_servers_foreach(resp, srvr, index) { + if ((NULL == (jsrvr = tr_msg_encode_one_server(srvr))) || + (-1 == json_array_append_new(jservers, jsrvr))) { + return NULL; + } + } + + // tr_debug("tr_msg_encode_servers(): servers contains:"); + // tr_debug("%s", json_dumps(jservers, 0)); + return jservers; +} + +static TID_SRVR_BLK *tr_msg_decode_servers(TALLOC_CTX *mem_ctx, json_t *jservers) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TID_SRVR_BLK *servers=NULL; + TID_SRVR_BLK *new_srvr=NULL; + json_t *jsrvr; + size_t i, num_servers; + + num_servers = json_array_size(jservers); + tr_debug("tr_msg_decode_servers(): Number of servers = %u.", (unsigned) num_servers); + + if (0 == num_servers) { + tr_debug("tr_msg_decode_servers(): Server array is empty."); + goto cleanup; + } + + for (i = 0; i < num_servers; i++) { + jsrvr = json_array_get(jservers, i); + + new_srvr=tid_srvr_blk_new(tmp_ctx); + if (new_srvr==NULL) { + servers=NULL; /* it's all in tmp_ctx, so we can just let go */ + goto cleanup; + } + + if (0 != tr_msg_decode_one_server(jsrvr, new_srvr)) { + servers=NULL; /* it's all in tmp_ctx, so we can just let go */ + goto cleanup; + } + + tid_srvr_blk_add(servers, new_srvr); + } + + talloc_steal(mem_ctx, servers); + +cleanup: + talloc_free(tmp_ctx); + return servers; +} + +static json_t * tr_msg_encode_tidresp(TID_RESP *resp) { json_t *jresp = NULL; json_t *jstr = NULL; + json_t *jservers = NULL; - if ((!resp) || (!resp->result) || (!resp->rp_realm) || (!resp->realm) || !(resp->comm)) + if ((!resp) || (!resp->rp_realm) || (!resp->realm) || !(resp->comm)) return NULL; jresp = json_object(); - jstr = json_string(resp->result->buf); - json_object_set_new(jresp, "result", jstr); + if (TID_ERROR == resp->result) { + jstr = json_string("error"); + json_object_set_new(jresp, "result", jstr); + if (resp->err_msg) { + jstr = tr_name_to_json_string(resp->err_msg); + json_object_set_new(jresp, "err_msg", jstr); + } + } + else { + jstr = json_string("success"); + json_object_set_new(jresp, "result", jstr); + } - jstr = json_string(resp->rp_realm->buf); + jstr = tr_name_to_json_string(resp->rp_realm); json_object_set_new(jresp, "rp_realm", jstr); - jstr = json_string(resp->realm->buf); + jstr = tr_name_to_json_string(resp->realm); json_object_set_new(jresp, "target_realm", jstr); - jstr = json_string(resp->comm->buf); + jstr = tr_name_to_json_string(resp->comm); json_object_set_new(jresp, "comm", jstr); if (resp->orig_coi) { - jstr = json_string(resp->orig_coi->buf); + jstr = tr_name_to_json_string(resp->orig_coi); json_object_set_new(jresp, "orig_coi", jstr); } - // TBD -- Encode server info. + if (tid_resp_get_request_id(resp)) { + jstr = tr_name_to_json_string(tid_resp_get_request_id(resp)); + json_object_set_new(jresp, "request_id", jstr); + } + + if (NULL == resp->servers) { + tr_debug("tr_msg_encode_tidresp(): No servers to encode."); + } + else { + jservers = tr_msg_encode_servers(resp); + json_object_set_new(jresp, "servers", jservers); + } + if (resp->error_path) + json_object_set(jresp, "error_path", resp->error_path); + return jresp; } -TID_RESP *tr_msg_decode_tidresp(json_t *jresp) +static TID_RESP *tr_msg_decode_tidresp(TALLOC_CTX *mem_ctx, json_t *jresp) { TID_RESP *tresp = NULL; - json_error_t rc; json_t *jresult = NULL; json_t *jrp_realm = NULL; json_t *jrealm = NULL; json_t *jcomm = NULL; json_t *jorig_coi = NULL; + json_t *jrequest_id = NULL; json_t *jservers = NULL; - int msize; + json_t *jerr_msg = NULL; - if (!(tresp = malloc(sizeof(TID_RESP)))) { - fprintf (stderr, "tr_msg_decode_tidresp(): Error allocating TID_RESP structure.\n"); + if (!(tresp=tid_resp_new(mem_ctx))) { + tr_crit("tr_msg_decode_tidresp(): Error allocating TID_RESP structure."); return NULL; } - - memset(tresp, 0, sizeof(TID_RESP)); - /* store required fields from request */ - if (((msize = json_object_size(jresp)) < 5) || - (NULL == (jresult = json_object_get(jresp, "result"))) || + /* store required fields from response */ + if ((NULL == (jresult = json_object_get(jresp, "result"))) || (!json_is_string(jresult)) || (NULL == (jrp_realm = json_object_get(jresp, "rp_realm"))) || (!json_is_string(jrp_realm)) || - (NULL == (jrealm = json_object_get(jresp, "realm"))) || + (NULL == (jrealm = json_object_get(jresp, "target_realm"))) || (!json_is_string(jrealm)) || (NULL == (jcomm = json_object_get(jresp, "comm"))) || - (!json_is_string(jcomm)) || - (NULL == (jservers = json_object_get(jresp, "servers"))) || - (!json_is_object(jservers))) { - fprintf (stderr, "tr_msg_decode(): Error parsing message.\n"); - free(tresp); + (!json_is_string(jcomm))) { + tr_debug("tr_msg_decode_tidresp(): Error parsing response."); + talloc_free(tresp); return NULL; } - tresp->result->buf = json_string_value(jresult); - tresp->result->len = strlen(tresp->result->buf); - tresp->rp_realm->buf = json_string_value(jrp_realm); - tresp->rp_realm->len = strlen(tresp->rp_realm->buf); - tresp->realm->buf = json_string_value(jrealm); - tresp->realm->len = strlen(tresp->realm->buf); - tresp->comm->buf = json_string_value(jcomm); - tresp->comm->len = strlen(tresp->comm->buf); + if (0 == (strcmp(json_string_value(jresult), "success"))) { + tr_debug("tr_msg_decode_tidresp(): Success! result = %s.", json_string_value(jresult)); + if ((NULL != (jservers = json_object_get(jresp, "servers"))) || + (!json_is_array(jservers))) { + tresp->servers = tr_msg_decode_servers(tresp, jservers); + } + else { + talloc_free(tresp); + return NULL; + } + tresp->result = TID_SUCCESS; + } + else { + tresp->result = TID_ERROR; + tr_debug("tr_msg_decode_tidresp(): Error! result = %s.", json_string_value(jresult)); + if ((NULL != (jerr_msg = json_object_get(jresp, "err_msg"))) || + (!json_is_string(jerr_msg))) { + tresp->err_msg = tr_new_name(json_string_value(jerr_msg)); + } else + tresp->err_msg = tr_new_name("No error message set."); + + if (NULL !=(tresp->error_path = json_object_get(jresp, "error_path"))) + json_incref(tresp->error_path); + } + + tresp->rp_realm = tr_new_name(json_string_value(jrp_realm)); + tresp->realm = tr_new_name(json_string_value(jrealm)); + tresp->comm = tr_new_name(json_string_value(jcomm)); /* store optional "orig_coi" field */ if ((NULL != (jorig_coi = json_object_get(jresp, "orig_coi"))) && - (!json_is_object(jorig_coi))) { - tresp->orig_coi->buf = json_string_value(jorig_coi); - tresp->orig_coi->len = strlen(tresp->orig_coi->buf); + json_is_string(jorig_coi)) { + tresp->orig_coi = tr_new_name(json_string_value(jorig_coi)); + } + + /* store optional "request_id" field */ + if ((NULL != (jrequest_id = json_object_get(jresp, "request_id"))) && + json_is_string(jrequest_id)) { + tid_resp_set_request_id(tresp, tr_new_name(json_string_value(jrequest_id))); } - // Decode server info - // tresp->servers = tr_msg_decode_servers(jservers); - return tresp; } -char *tr_msg_encode(TR_MSG *msg) + +/* Information records for TRP update msg + * requires that jrec already be allocated */ +static TRP_RC tr_msg_encode_inforec_route(json_t *jrec, TRP_INFOREC *rec) +{ + json_t *jstr=NULL; + json_t *jint=NULL; + char *s=NULL; + + if (rec==NULL) + return TRP_BADTYPE; + + if (trp_inforec_get_trust_router(rec)==NULL) + return TRP_ERROR; + + s=tr_name_strdup(trp_inforec_get_trust_router(rec)); + if (s==NULL) + return TRP_NOMEM; + jstr=json_string(s); + free(s);s=NULL; + if(jstr==NULL) + return TRP_ERROR; + json_object_set_new(jrec, "trust_router", jstr); + + jint=json_integer(trp_inforec_get_metric(rec)); + if(jint==NULL) + return TRP_ERROR; + json_object_set_new(jrec, "metric", jint); + + jint=json_integer(trp_inforec_get_interval(rec)); + if(jint==NULL) + return TRP_ERROR; + json_object_set_new(jrec, "interval", jint); + + return TRP_SUCCESS; +} + +/* returns a json array */ +static json_t *tr_msg_encode_apcs(TR_APC *apcs) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_APC_ITER *iter=tr_apc_iter_new(tmp_ctx); + TR_APC *apc=NULL; + json_t *jarray=NULL; + json_t *jid=NULL; + + if (iter==NULL) + goto cleanup; + + jarray=json_array(); + if (jarray==NULL) + goto cleanup; + + for (apc=tr_apc_iter_first(iter, apcs); apc!=NULL; apc=tr_apc_iter_next(iter)) { + jid=tr_name_to_json_string(tr_apc_get_id(apc)); + if ((jid==NULL) || (json_array_append_new(jarray, jid)!=0)) { + json_decref(jarray); + jarray=NULL; + goto cleanup; + } + } + +cleanup: + talloc_free(tmp_ctx); + return jarray; +} + +static TR_APC *tr_msg_decode_apcs(TALLOC_CTX *mem_ctx, json_t *jarray, TRP_RC *rc) { - json_t *jmsg; - json_t *jmsg_type; + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + size_t ii=0; + TR_APC *apc_list=NULL; + TR_APC *new=NULL; + json_t *jstr=NULL; + + *rc=TRP_ERROR; + + for (ii=0; iitype) { + case TRP_INFOREC_TYPE_ROUTE: + if (TRP_SUCCESS!=tr_msg_encode_inforec_route(jrec, rec)) { + json_decref(jrec); + return NULL; + } + break; + case TRP_INFOREC_TYPE_COMMUNITY: + if (TRP_SUCCESS!=tr_msg_encode_inforec_comm(jrec, rec)) { + json_decref(jrec); + return NULL; + } + break; + default: + json_decref(jrec); + return NULL; + } + return jrec; +} + +static TRP_RC tr_msg_decode_trp_inforec_route(json_t *jrecord, TRP_INFOREC *rec) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TRP_RC rc=TRP_ERROR; + char *s=NULL; + int num=0; + + rc=tr_msg_get_json_string(jrecord, "trust_router", &s, tmp_ctx); + if (rc != TRP_SUCCESS) + goto cleanup; + if (TRP_SUCCESS!=trp_inforec_set_trust_router(rec, tr_new_name(s))) { + rc=TRP_ERROR; + goto cleanup; + } + talloc_free(s); s=NULL; + + trp_inforec_set_next_hop(rec, NULL); /* make sure this is null (filled in later) */ + + rc=tr_msg_get_json_integer(jrecord, "metric", &num); + if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_metric(rec,num))) + goto cleanup; + + rc=tr_msg_get_json_integer(jrecord, "interval", &num); + if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num))) + goto cleanup; + +cleanup: + talloc_free(tmp_ctx); + return rc; +} + +static TRP_RC tr_msg_decode_trp_inforec_comm(json_t *jrecord, TRP_INFOREC *rec) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TRP_RC rc=TRP_ERROR; + char *s=NULL; + int num=0; + TR_APC *apcs=NULL; + + rc=tr_msg_get_json_string(jrecord, "type", &s, tmp_ctx); + if (rc != TRP_SUCCESS) + goto cleanup; + if (TRP_SUCCESS!=trp_inforec_set_comm_type(rec, tr_comm_type_from_str(s))) { + rc=TRP_ERROR; + goto cleanup; + } + talloc_free(s); s=NULL; + + rc=tr_msg_get_json_string(jrecord, "role", &s, tmp_ctx); + if (rc != TRP_SUCCESS) + goto cleanup; + if (TRP_SUCCESS!=trp_inforec_set_role(rec, tr_realm_role_from_str(s))) { + rc=TRP_ERROR; + goto cleanup; + } + talloc_free(s); s=NULL; + + apcs=tr_msg_decode_apcs(rec, json_object_get(jrecord, "apcs"), &rc); + if (rc!=TRP_SUCCESS) { + rc=TRP_ERROR; + goto cleanup; + } + trp_inforec_set_apcs(rec, apcs); + + rc=tr_msg_get_json_integer(jrecord, "interval", &num); + tr_debug("tr_msg_decode_trp_inforec_comm: interval=%u", num); + if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num))) + goto cleanup; + + trp_inforec_set_provenance(rec, json_object_get(jrecord, "provenance")); + + /* optional */ + rc=tr_msg_get_json_string(jrecord, "owner_realm", &s, tmp_ctx); + if (rc == TRP_SUCCESS) { + if (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_new_name(s))) { + rc=TRP_ERROR; + goto cleanup; + } + if (s!=NULL) { + talloc_free(s); + s=NULL; + } + } + + rc=tr_msg_get_json_string(jrecord, "owner_contact", &s, tmp_ctx); + if (rc == TRP_SUCCESS) { + if (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_new_name(s))) { + rc=TRP_ERROR; + goto cleanup; + } + if (s!=NULL) { + talloc_free(s); + s=NULL; + } + } + +cleanup: + talloc_free(tmp_ctx); + return rc; +} + +/* decode a single record */ +static TRP_INFOREC *tr_msg_decode_trp_inforec(TALLOC_CTX *mem_ctx, json_t *jrecord) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TRP_INFOREC_TYPE rectype; + TRP_INFOREC *rec=NULL; + TRP_RC rc=TRP_ERROR; + char *s=NULL; + + if (TRP_SUCCESS!=tr_msg_get_json_string(jrecord, "record_type", &s, tmp_ctx)) + goto cleanup; + + rectype=trp_inforec_type_from_string(s); + talloc_free(s); s=NULL; + + rec=trp_inforec_new(tmp_ctx, rectype); + if (rec==NULL) { + rc=TRP_NOMEM; + goto cleanup; + } + + tr_debug("tr_msg_decode_trp_inforec: '%s' record found.", trp_inforec_type_to_string(rec->type)); + + switch(trp_inforec_get_type(rec)) { + case TRP_INFOREC_TYPE_ROUTE: + rc=tr_msg_decode_trp_inforec_route(jrecord, rec); + break; + case TRP_INFOREC_TYPE_COMMUNITY: + rc=tr_msg_decode_trp_inforec_comm(jrecord, rec); + break; + default: + rc=TRP_UNSUPPORTED; + goto cleanup; + } + + talloc_steal(mem_ctx, rec); + rc=TRP_SUCCESS; + +cleanup: + if (rc != TRP_SUCCESS) { + trp_inforec_free(rec); + rec=NULL; + } + talloc_free(tmp_ctx); + return rec; +} + +/* TRP update msg */ +static json_t *tr_msg_encode_trp_upd(TRP_UPD *update) +{ + json_t *jupdate=NULL; + json_t *jrecords=NULL; + json_t *jrec=NULL; + json_t *jstr=NULL; + TRP_INFOREC *rec; + char *s=NULL; + + if (update==NULL) + return NULL; + + jupdate=json_object(); + if (jupdate==NULL) + return NULL; + + s=tr_name_strdup(trp_upd_get_comm(update)); + if (s==NULL) { + json_decref(jupdate); + return NULL; + } + jstr=json_string(s); + free(s);s=NULL; + if(jstr==NULL) { + json_decref(jupdate); + return NULL; + } + json_object_set_new(jupdate, "community", jstr); + + s=tr_name_strdup(trp_upd_get_realm(update)); + if (s==NULL) { + json_decref(jupdate); + return NULL; + } + jstr=json_string(s); + free(s);s=NULL; + if(jstr==NULL) { + json_decref(jupdate); + return NULL; + } + json_object_set_new(jupdate, "realm", jstr); + + jrecords=json_array(); + if (jrecords==NULL) { + json_decref(jupdate); + return NULL; + } + json_object_set_new(jupdate, "records", jrecords); /* jrecords now a "borrowed" reference */ + for (rec=trp_upd_get_inforec(update); rec!=NULL; rec=trp_inforec_get_next(rec)) { + tr_debug("tr_msg_encode_trp_upd: encoding inforec."); + jrec=tr_msg_encode_inforec(rec); + if (jrec==NULL) { + json_decref(jupdate); /* also decs jrecords and any elements */ + return NULL; + } + if (0!=json_array_append_new(jrecords, jrec)) { + json_decref(jupdate); /* also decs jrecords and any elements */ + json_decref(jrec); /* this one did not get added so dec explicitly */ + return NULL; + } + } + + return jupdate; +} + +/* Creates a linked list of records in the msg->body talloc context. + * An error will be returned if any unparseable records are encountered. + */ +static TRP_UPD *tr_msg_decode_trp_upd(TALLOC_CTX *mem_ctx, json_t *jupdate) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + json_t *jrecords=NULL; + size_t ii=0; + TRP_UPD *update=NULL; + TRP_INFOREC *new_rec=NULL; + TRP_INFOREC *list_tail=NULL; + char *s=NULL; + TR_NAME *name; + TRP_RC rc=TRP_ERROR; + + update=trp_upd_new(tmp_ctx); + if (update==NULL) { + rc=TRP_NOMEM; + goto cleanup; + } + + rc=tr_msg_get_json_string(jupdate, "community", &s, tmp_ctx); + if (rc != TRP_SUCCESS) { + tr_debug("tr_msg_decode_trp_upd: no community in TRP update message."); + rc=TRP_NOPARSE; + goto cleanup; + } + name=tr_new_name(s); + if (name==NULL) { + tr_debug("tr_msg_decode_trp_upd: could not allocate community name."); + rc=TRP_NOMEM; + goto cleanup; + } + talloc_free(s); s=NULL; + trp_upd_set_comm(update, name); + + rc=tr_msg_get_json_string(jupdate, "realm", &s, tmp_ctx); + if (rc != TRP_SUCCESS) { + tr_debug("tr_msg_decode_trp_upd: no realm in TRP update message."); + rc=TRP_NOPARSE; + goto cleanup; + } + name=tr_new_name(s); + if (name==NULL) { + tr_debug("tr_msg_decode_trp_upd: could not allocate realm name."); + rc=TRP_NOMEM; + goto cleanup; + } + talloc_free(s); s=NULL; + trp_upd_set_realm(update, name); + + jrecords=json_object_get(jupdate, "records"); + if ((jrecords==NULL) || (!json_is_array(jrecords))) { + rc=TRP_NOPARSE; + goto cleanup; + } + + tr_debug("tr_msg_decode_trp_upd: found %d records", json_array_size(jrecords)); + /* process the array */ + for (ii=0; iimsg_type) - { + switch (msg->msg_type) { case TID_REQUEST: - jmsg_type = json_string("TIDRequest"); + jmsg_type = json_string("tid_request"); json_object_set_new(jmsg, "msg_type", jmsg_type); - json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidreq(msg->tid_req)); + tidreq=tr_msg_get_req(msg); + json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidreq(tidreq)); break; case TID_RESPONSE: - jmsg_type = json_string("TIDResponse"); + jmsg_type = json_string("tid_response"); json_object_set_new(jmsg, "msg_type", jmsg_type); - json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidresp(msg->tid_resp)); + tidresp=tr_msg_get_resp(msg); + json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidresp(tidresp)); break; - /* TBD -- Add TR message types */ + case TRP_UPDATE: + jmsg_type = json_string("trp_update"); + json_object_set_new(jmsg, "msg_type", jmsg_type); + trpupd=tr_msg_get_trp_upd(msg); + json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_upd(trpupd)); + break; + + case TRP_REQUEST: + jmsg_type = json_string("trp_request"); + json_object_set_new(jmsg, "msg_type", jmsg_type); + trpreq=tr_msg_get_trp_req(msg); + json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_req(trpreq)); + break; + + case MON_REQUEST: + jmsg_type = json_string("mon_request"); + json_object_set_new(jmsg, "msg_type", jmsg_type); + monreq=tr_msg_get_mon_req(msg); + json_object_set_new(jmsg, "msg_body", mon_req_encode(monreq)); + break; + + case MON_RESPONSE: + jmsg_type = json_string("mon_response"); + json_object_set_new(jmsg, "msg_type", jmsg_type); + monresp=tr_msg_get_mon_resp(msg); + json_object_set_new(jmsg, "msg_body", mon_resp_encode(monresp)); + break; default: json_decref(jmsg); return NULL; - } - - return(json_dumps(jmsg, 0)); + } + + /* We should perhaps use json_set_alloc_funcs to automatically use talloc, but for + * now, we'll encode to a malloc'ed buffer, then copy that to a talloc'ed buffer. */ + encoded_tmp=json_dumps(jmsg, 0); // malloc'ed version + json_decref(jmsg); // free the JSON structure + encoded = talloc_strdup(mem_ctx, encoded_tmp); // get the talloc'ed version + free(encoded_tmp); // free the malloc'ed version + + tr_debug("tr_msg_encode: outgoing msg=%s", encoded); + return encoded; } -TR_MSG *tr_msg_decode(char *jbuf, size_t buflen) +TR_MSG *tr_msg_decode(TALLOC_CTX *mem_ctx, const char *jbuf, size_t buflen) { - TR_MSG *msg; + TR_MSG *msg=NULL; json_t *jmsg = NULL; json_error_t rc; - size_t msize; - json_t *jtype; - json_t *jbody; + json_t *jtype=NULL; + json_t *jbody=NULL; const char *mtype = NULL; - if (NULL == (jmsg = json_loadb(jbuf, buflen, 0, &rc))) { - fprintf (stderr, "tr_msg_decode(): error loading object, rc = %d.\n", rc); + if (NULL == (jmsg = json_loadb(jbuf, buflen, JSON_DISABLE_EOF_CHECK, &rc))) { + tr_debug("tr_msg_decode(): error loading object"); return NULL; } - if (!(msg = malloc(sizeof(TR_MSG)))) { - fprintf (stderr, "tr_msg_decode(): Error allocating TR_MSG structure.\n"); + if (!(msg = talloc_zero(mem_ctx, TR_MSG))) { + tr_debug("tr_msg_decode(): Error allocating TR_MSG structure."); json_decref(jmsg); return NULL; } - memset(msg, 0, sizeof(TR_MSG)); - - if ((2 != (msize = json_object_size(jmsg))) || - (NULL == (jtype = json_object_get(jmsg, "msg_type"))) || - (!json_is_string(jtype)) || - (NULL == (jbody = json_object_get(jmsg, "msg_body"))) || - (!json_is_object(jbody))) { - fprintf (stderr, "tr_msg_decode(): Error parsing message.\n"); + if ((NULL == (jtype = json_object_get(jmsg, "msg_type"))) || + (NULL == (jbody = json_object_get(jmsg, "msg_body")))) { + tr_debug("tr_msg_decode(): Error parsing message header."); json_decref(jmsg); tr_msg_free_decoded(msg); return NULL; @@ -330,31 +1375,49 @@ TR_MSG *tr_msg_decode(char *jbuf, size_t buflen) mtype = json_string_value(jtype); - if (0 == strcmp(mtype, "TIDRequest")) { + if (0 == strcmp(mtype, "tid_request")) { msg->msg_type = TID_REQUEST; - msg->tid_req = tr_msg_decode_tidreq(jbody); + tr_msg_set_req(msg, tr_msg_decode_tidreq(msg, jbody)); } - else if (0 == strcmp(mtype, "TIDResponse")) { + else if (0 == strcmp(mtype, "tid_response")) { msg->msg_type = TID_RESPONSE; - msg->tid_resp = tr_msg_decode_tidresp(jbody); + tr_msg_set_resp(msg, tr_msg_decode_tidresp(msg, jbody)); + } + else if (0 == strcmp(mtype, "trp_update")) { + msg->msg_type = TRP_UPDATE; + tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(msg, jbody)); + } + else if (0 == strcmp(mtype, "trp_request")) { + msg->msg_type = TRP_UPDATE; + tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(msg, jbody)); + } + else if (0 == strcmp(mtype, "mon_request")) { + msg->msg_type = MON_REQUEST; + tr_msg_set_mon_req(msg, mon_req_decode(msg, jbody)); + } + /* We do not currently handle monitoring responses */ + else if (0 == strcmp(mtype, "mon_response")) { + msg->msg_type = MON_RESPONSE; + tr_msg_set_mon_resp(msg, mon_resp_decode(msg, jbody)); } else { msg->msg_type = TR_UNKNOWN; - msg->tid_req = NULL; + msg->msg_rep = NULL; } + + json_decref(jmsg); + return msg; } void tr_msg_free_encoded(char *jmsg) { if (jmsg) - free (jmsg); + talloc_free(jmsg); } void tr_msg_free_decoded(TR_MSG *msg) { if (msg) - free (msg); + talloc_free(msg); } - -