5 #include <trp_internal.h>
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 *);
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 *);
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 *);
23 /* table of string names for TMT_MSG_TYPE codes */
24 struct trp_msg_type_entry {
27 void *(*allocate)(TALLOC_CTX *);
28 json_t *(*encode)(void *);
29 TRP_RC (*parse)(TRP_MSG *, json_t *);
30 void (*print)(void *);
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 */
38 struct trp_msg_info_type_entry {
40 TRP_MSG_INFO_TYPE type;
41 void (*print)(void *);
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 */
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)
55 case TRP_MSG_TYPE_UPDATE:
56 talloc_get_type_abort(p, TRP_ROUTE_UPDATE);
59 case TRP_MSG_TYPE_ROUTE_REQ:
60 talloc_get_type_abort(p, TRP_ROUTE_REQ);
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)
71 struct trp_msg_type_entry *entry=trp_msg_type_table;
73 while ((entry->type != TRP_MSG_TYPE_UNKNOWN)
74 && (entry->type != msgtype)) {
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)
83 struct trp_msg_info_type_entry *entry=trp_msg_info_type_table;
85 while ((entry->type != TRP_MSG_INFO_TYPE_UNKNOWN)
86 && (entry->type != msgtype)) {
92 /* translate strings to codes */
93 TRP_MSG_TYPE trp_msg_type_from_string(const char *s)
95 struct trp_msg_type_entry *entry=trp_msg_type_table;
97 while ((entry->type != TRP_MSG_TYPE_UNKNOWN)
98 && (strcmp(s, entry->name)!=0)) {
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)
107 struct trp_msg_type_entry *entry=get_trp_msg_type_entry(msgtype);
111 /* translate strings to codes */
112 TRP_MSG_INFO_TYPE trp_msg_info_type_from_string(const char *s)
114 struct trp_msg_info_type_entry *entry=trp_msg_info_type_table;
116 while ((entry->type != TRP_MSG_INFO_TYPE_UNKNOWN)
117 && (strcmp(s, entry->name)!=0)) {
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)
126 struct trp_msg_info_type_entry *entry=get_trp_msg_info_type_entry(msgtype);
131 TRP_MSG *trp_msg_new(TALLOC_CTX *mem_ctx)
133 TRP_MSG *new_msg=talloc(mem_ctx, TRP_MSG);
135 if (new_msg != NULL) {
136 new_msg->type=TRP_MSG_INFO_TYPE_UNKNOWN;
142 void trp_msg_destroy(TRP_MSG *msg)
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)
156 obj=json_object_get(jmsg, attr);
161 if (!json_is_integer(obj)) {
165 (*dest)=json_integer_value(obj);
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)
176 obj=json_object_get(jmsg, attr);
181 if (!json_is_string(obj))
184 *dest=talloc_strdup(mem_ctx, json_string_value(obj));
192 /* called by talloc when destroying an update message body */
193 static int trp_msg_info_route_destructor(void *object)
195 TRP_MSG_INFO_ROUTE *body=talloc_get_type_abort(object, TRP_MSG_INFO_ROUTE);
197 /* clean up TR_NAME data, which are not managed by talloc */
198 if (body->comm != NULL) {
199 tr_free_name(body->comm);
201 tr_debug("trp_msg_info_route_destructor: freed community");
203 if (body->realm != NULL) {
204 tr_free_name(body->realm);
206 tr_debug("trp_msg_info_route_destructor: freed realm");
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");
217 static void *trp_msg_info_route_new(TALLOC_CTX *mem_ctx)
219 TRP_MSG_INFO_ROUTE *new_rec=talloc(mem_ctx, TRP_MSG_INFO_ROUTE);
221 if (new_rec != NULL) {
223 new_rec->type=TRP_MSG_INFO_TYPE_UNKNOWN;
226 new_rec->trust_router=NULL;
227 new_rec->metric=TRP_METRIC_INFINITY;
229 talloc_set_destructor((void *)new_rec, trp_msg_info_route_destructor);
234 /* parse a single record */
235 static TRP_RC trp_parse_update_record(TRP_MSG_INFO_ROUTE *rec, json_t *jrecord)
237 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
242 rc=trp_get_json_string(jrecord, "record_type", &s, tmp_ctx);
243 if (rc != TRP_SUCCESS)
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) {
253 tr_debug("trp_parse_update_record: '%s' record found.", trp_msg_info_type_to_string(rec->type));
255 rc=trp_get_json_string(jrecord, "community", &s, tmp_ctx);
256 if (rc != TRP_SUCCESS)
258 if (NULL==(rec->comm=tr_new_name(s)))
260 talloc_free(s); s=NULL;
262 tr_debug("trp_parse_update_record: 'community' is '%.*s'.", rec->comm->len, rec->comm->buf);
264 rc=trp_get_json_string(jrecord, "realm", &s, tmp_ctx);
265 if (rc != TRP_SUCCESS)
267 if (NULL==(rec->realm=tr_new_name(s)))
269 talloc_free(s); s=NULL;
271 tr_debug("trp_parse_update_record: 'realm' is '%.*s'.", rec->realm->len, rec->realm->buf);
273 rc=trp_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
274 if (rc != TRP_SUCCESS)
276 if (NULL==(rec->trust_router=tr_new_name(s)))
278 talloc_free(s); s=NULL;
280 tr_debug("trp_parse_update_record: 'trust_router' is '%.*s'.", rec->trust_router->len, rec->trust_router->buf);
282 rc=trp_get_json_integer(jrecord, "metric", &num);
283 if (rc != TRP_SUCCESS)
287 tr_debug("trp_parse_update_record: 'metric' is %d.", rec->metric);
289 rc=trp_get_json_integer(jrecord, "interval", &num);
290 if (rc != TRP_SUCCESS)
294 tr_debug("trp_parse_update_record: 'interval' is %d.", rec->interval);
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);
305 if (rec->realm != NULL) {
306 tr_free_name(rec->realm);
309 if (rec->trust_router != NULL) {
310 tr_free_name(rec->trust_router);
311 rec->trust_router=NULL;
315 talloc_free(tmp_ctx);
321 static void *trp_route_update_new(TALLOC_CTX *mem_ctx)
323 TRP_ROUTE_UPDATE *new_body=talloc(mem_ctx, TRP_ROUTE_UPDATE);
325 if (new_body!=NULL) {
326 new_body->records=NULL;
330 /* Parse an update body. Creates a linked list of records in the msg->body talloc context.
332 * An error will be returned if any unparseable records are encountered.
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)
338 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
339 json_t *jrecords=NULL;
342 TRP_ROUTE_UPDATE *msg_body=NULL;
343 TRP_MSG_INFO_ROUTE *new_rec=NULL;
344 TRP_MSG_INFO_ROUTE *list_tail=NULL;
347 if (msg->type != TRP_MSG_TYPE_UPDATE) {
351 msg_body=talloc_get_type(msg->body, TRP_ROUTE_UPDATE);
352 if (msg_body==NULL) {
357 jrecords=json_object_get(jbody, "records");
358 if ((jrecords==NULL) || (!json_is_array(jrecords))) {
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);
372 if (TRP_SUCCESS != trp_parse_update_record(new_rec, json_array_get(jrecords, ii))) {
378 msg_body->records=new_rec; /* first is a special case */
380 list_tail->next=new_rec;
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 */
392 talloc_free(tmp_ctx);
393 if ((rc != TRP_SUCCESS) && (msg_body != NULL))
394 msg_body->records=NULL; /* don't leave this hanging */
400 static void trp_msg_info_route_print(void *rec_in)
402 TRP_MSG_INFO_ROUTE *rec=talloc_get_type(rec_in, TRP_MSG_INFO_ROUTE); /* null if wrong type */
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);
416 static int trp_route_req_destructor(void *object)
418 TRP_ROUTE_REQ *body=talloc_get_type_abort(object, TRP_ROUTE_REQ);
420 /* clean up TR_NAME data, which are not managed by talloc */
421 if (body->comm != NULL) {
422 tr_free_name(body->comm);
424 tr_debug("trp_route_req_destructor: freed community");
426 if (body->realm != NULL) {
427 tr_free_name(body->realm);
429 tr_debug("trp_route_req_destructor: freed realm");
434 void *trp_route_req_new(TALLOC_CTX *mem_ctx)
436 TRP_ROUTE_REQ *new_body=talloc(mem_ctx, TRP_ROUTE_REQ);
438 if (new_body != NULL) {
440 new_body->realm=NULL;
443 talloc_set_destructor((void *)new_body, trp_route_req_destructor);
447 void trp_route_req_set_comm(TRP_ROUTE_REQ *req, TR_NAME *comm)
452 void trp_route_req_set_realm(TRP_ROUTE_REQ *req, TR_NAME *realm)
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)
461 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
462 TRP_ROUTE_REQ *msg_body=NULL;
466 /* check message type and body type for agreement */
467 if (msg->type != TRP_MSG_TYPE_ROUTE_REQ) {
471 msg_body=talloc_get_type(msg->body, TRP_ROUTE_REQ);
472 if (msg_body==NULL) {
477 rc=trp_get_json_string(jbody, "community", &s, tmp_ctx);
480 msg_body->comm=tr_new_name(s);
481 talloc_free(s); s=NULL;
483 rc=trp_get_json_string(jbody, "realm", &s, tmp_ctx);
486 msg_body->realm=tr_new_name(s);
487 talloc_free(s); s=NULL;
491 talloc_free(tmp_ctx);
495 static json_t *trp_encode_body(TRP_MSG_TYPE type, void *body)
497 struct trp_msg_type_entry *msgtype=get_trp_msg_type_entry(type);
499 if ((msgtype->type==TRP_MSG_TYPE_UNKNOWN) || (msgtype->encode==NULL))
502 tr_debug("trp_encode_body: encoding type %s", trp_msg_type_to_string(type));
504 return msgtype->encode(body);
507 /* TODO: error checking */
508 char *trp_encode_msg(TRP_MSG *msg)
515 jbody=trp_encode_body(msg->type, msg->body);
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);
523 encoded=json_dumps(jmsg, 0);
529 /* TODO: error checking */
530 static json_t *trp_encode_route_req(void *req_in)
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 */
542 s=talloc_strndup(tmp_ctx, req->comm->buf, req->comm->len); /* ensures null term */
544 tr_debug("trp_encode_route_req: could not allocate community string");
551 json_object_set_new(jbody, "community", jstr);
553 s=talloc_strndup(tmp_ctx, req->realm->buf, req->realm->len); /* ensures null term */
555 tr_debug("trp_encode_route_req: could not allocate realm string");
562 json_object_set_new(jbody, "realm", jstr);
566 talloc_free(tmp_ctx);
570 static void trp_route_update_print(void *body_in)
572 TRP_ROUTE_UPDATE *body=talloc_get_type(body_in, TRP_ROUTE_UPDATE); /* null if wrong type */
575 printf(" {records=\n");
576 trp_msg_info_route_print(body->records);
581 static void trp_route_req_print(void *body_in)
583 TRP_ROUTE_REQ *body=talloc_get_type(body_in, TRP_ROUTE_REQ); /* null if wrong type */
586 printf(" {community=%.*s\n realm=%.*s}\n",
587 body->comm->len, body->comm->buf,
588 body->realm->len, body->realm->buf);
592 static void trp_msg_body_print(void *body, TRP_MSG_TYPE msgtype)
594 struct trp_msg_type_entry *info=get_trp_msg_type_entry(msgtype);
598 void trp_msg_print(TRP_MSG *msg)
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);
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)
610 struct trp_msg_type_entry *info=get_trp_msg_type_entry(msgtype);
612 if (info->type==TRP_MSG_TYPE_UNKNOWN) {
613 tr_debug("trp_msg_body_new: Unknown type %d.", info->type);
617 new_body=info->allocate(mem_ctx);
618 msg_body_type_check(msgtype, new_body); /* aborts program on type violation */
622 /* call the correct parser */
623 static TRP_RC trp_parse_msg_body(TRP_MSG *msg, json_t *jbody)
625 struct trp_msg_type_entry *info=get_trp_msg_type_entry(msg->type);
627 if (info->type==TRP_MSG_TYPE_UNKNOWN) {
628 tr_debug("trp_msg_body_parse: Unknown type %d.", info->type);
632 return info->parse(msg, jbody);
636 TRP_RC trp_parse_msg(TALLOC_CTX *mem_ctx, const char *buf, size_t buflen, TRP_MSG **msg)
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 */
646 tr_debug("trp_parse_msg: parsing %d bytes", buflen);
648 jmsg=json_loadb(buf, buflen, 0, &json_err);
650 tr_debug("trp_parse_msg: Error parsing message.");
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.");
663 switch (trp_get_json_string(jmsg, "message_type", &s, new_msg)) {
667 tr_debug("trp_parse_msg: required attribute 'message_type' not present.");
671 tr_debug("trp_parse_msg: required attribute 'message_type' is not a string.");
675 tr_debug("trp_parse_msg: error parsing 'message_type'.");
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);
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);
694 jbody=json_object_get(jmsg, "body");
696 tr_debug("trp_parse_msg: Message body not found.");
701 switch (trp_parse_msg_body(new_msg, jbody)) {
705 tr_debug("trp_parse_msg: Error parsing message body.");
712 talloc_steal(mem_ctx, *msg);
716 talloc_free(tmp_ctx);