From: Jennifer Richards Date: Wed, 11 Apr 2018 21:06:29 +0000 (-0400) Subject: Add encoder for monitoring responses X-Git-Tag: 3.4.0~1^2~50^2~1 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=commitdiff_plain;h=36a471285d0cafbbe74f49d736e472dbfe317a38 Add encoder for monitoring responses * add response encoder * add partial test of response encoder * move tr_mon.h to include directory * move code common to req/resp from tr_mon_req.c to tr_mon.c * fix a couple warnings --- diff --git a/CMakeLists.txt b/CMakeLists.txt index c97e39c..a0c2ff6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,14 +90,18 @@ set(SOURCE_FILES trp/trp_rtable.c trp/trp_upd.c trp/trpc.c - trp/trps.c include/tr_name_internal.h mon/tr_mon_req.c mon/tr_mon_req.h mon/tr_mon_req_encode.c mon/tr_mon_req_decode.c) + trp/trps.c include/tr_name_internal.h mon/tr_mon_req.c mon/tr_mon_req_encode.c mon/tr_mon_req_decode.c + mon/tr_mon_resp.c mon/tr_mon.c mon/tr_mon_resp_encode.c) # Does not actually build! add_executable(trust_router ${SOURCE_FILES}) # Test build targets - for debugging -add_executable(test_mon_req_encode mon/tr_mon_req.c mon/tr_mon_req.h mon/tests/test_mon_req_encode.c mon/tr_mon_req_encode.c) +add_executable(test_mon_req_encode mon/tr_mon.c mon/tr_mon_req.c mon/tests/test_mon_req_encode.c mon/tr_mon_req_encode.c) target_link_libraries(test_mon_req_encode jansson talloc glib-2.0) -add_executable(test_mon_req_decode mon/tr_mon_req.c mon/tr_mon_req.h mon/tests/test_mon_req_decode.c mon/tr_mon_req_decode.c) +add_executable(test_mon_req_decode mon/tr_mon.c mon/tr_mon_req.c mon/tests/test_mon_req_decode.c mon/tr_mon_req_decode.c) target_link_libraries(test_mon_req_decode jansson talloc glib-2.0) + +add_executable(test_mon_resp_encode mon/tr_mon.c mon/tr_mon_req.c mon/tr_mon_resp.c mon/tr_mon_resp_encode.c common/tr_name.c mon/tests/test_mon_resp_encode.c) +target_link_libraries(test_mon_resp_encode jansson talloc glib-2.0) diff --git a/Makefile.am b/Makefile.am index 2e27e3f..ddfd8d2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,10 @@ +ACLOCAL_AMFLAGS = -I m4 DISTCHECK_CONFIGURE_FLAGS = \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/tests/tr_dh_test common/tests/mq_test \ common/tests/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/tests/cfg_test \ common/tests/commtest common/tests/name_test common/tests/filt_test mon/tests/test_mon_req_encode \ - mon/tests/test_mon_req_decode + mon/tests/test_mon_req_decode mon/tests/test_mon_resp_encode AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS) AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS) SUBDIRS = gsscon @@ -37,9 +38,12 @@ common/tr_config.c \ common/tr_mq.c mon_srcs = \ + mon/tr_mon.c \ mon/tr_mon_req.c \ mon/tr_mon_req_encode.c \ - mon/tr_mon_req_decode.c + mon/tr_mon_req_decode.c \ + mon/tr_mon_resp.c \ + mon/tr_mon_resp_encode.c check_PROGRAMS = common/t_constraint TESTS = common/t_constraint @@ -171,15 +175,23 @@ common_tests_filt_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread common_tests_filt_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) mon_tests_test_mon_req_encode_SOURCES = mon/tests/test_mon_req_encode.c \ - $(mon_srcs) + $(mon_srcs) \ + common/tr_name.c mon_tests_test_mon_req_encode_LDADD = $(GLIB_LIBS) mon_tests_test_mon_req_encode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) mon_tests_test_mon_req_decode_SOURCES = mon/tests/test_mon_req_decode.c \ - $(mon_srcs) + $(mon_srcs) \ + common/tr_name.c mon_tests_test_mon_req_decode_LDADD = $(GLIB_LIBS) mon_tests_test_mon_req_decode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +mon_tests_test_mon_resp_encode_SOURCES = mon/tests/test_mon_resp_encode.c \ + $(mon_srcs) \ + common/tr_name.c +mon_tests_test_mon_resp_encode_LDADD = $(GLIB_LIBS) +mon_tests_test_mon_resp_encode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + pkginclude_HEADERS = include/trust_router/tid.h include/trust_router/tr_name.h \ include/tr_debug.h include/trust_router/trp.h \ include/trust_router/tr_dh.h \ diff --git a/mon/tr_mon_req.h b/include/tr_mon.h similarity index 80% rename from mon/tr_mon_req.h rename to include/tr_mon.h index d32b262..dc255ba 100644 --- a/mon/tr_mon_req.h +++ b/include/tr_mon.h @@ -39,11 +39,14 @@ #include #include #include +#include /* Typedefs */ typedef struct tr_mon_req TR_MON_REQ; +typedef struct tr_mon_resp TR_MON_RESP; typedef enum tr_mon_cmd TR_MON_CMD; +typedef enum tr_mon_resp_code TR_MON_RESP_CODE; typedef struct tr_mon_opt TR_MON_OPT; typedef enum tr_mon_opt_type TR_MON_OPT_TYPE; @@ -66,6 +69,12 @@ enum tr_mon_cmd { MON_CMD_SHOW }; +/* These should be explicitly numbered because they form part of the public API */ +enum tr_mon_resp_code { + MON_RESP_SUCCESS=0, + MON_RESP_ERROR=1, // generic error +}; + enum tr_mon_opt_type { OPT_TYPE_UNKNOWN=0, @@ -92,25 +101,42 @@ struct tr_mon_req { GArray *options; }; +struct tr_mon_resp { + TR_MON_REQ *req; // request this responds to + TR_MON_RESP_CODE code; + TR_NAME *message; + json_t *payload; +}; + /* Prototypes */ +/* tr_mon.c */ +const char *cmd_to_string(TR_MON_CMD cmd); +TR_MON_CMD cmd_from_string(const char *s); +const char *opt_type_to_string(TR_MON_OPT_TYPE opt_type); +TR_MON_OPT_TYPE opt_type_from_string(const char *s); + +/* tr_mon_req.c */ TR_MON_REQ *tr_mon_req_new(TALLOC_CTX *mem_ctx, TR_MON_CMD cmd); void tr_mon_req_free(TR_MON_REQ *req); TR_MON_RC tr_mon_req_add_option(TR_MON_REQ *req, TR_MON_OPT_TYPE opt_type); size_t tr_mon_req_opt_count(TR_MON_REQ *req); TR_MON_OPT *tr_mon_req_opt_index(TR_MON_REQ *req, size_t index); -const char *cmd_to_string(TR_MON_CMD cmd); -TR_MON_CMD cmd_from_string(const char *s); - -const char *opt_type_to_string(TR_MON_OPT_TYPE opt_type); -TR_MON_OPT_TYPE opt_type_from_string(const char *s); - /* tr_mon_req_encode.c */ json_t *tr_mon_req_encode(TR_MON_REQ *req); /* tr_mon_req_decode.c */ TR_MON_REQ *tr_mon_req_decode(TALLOC_CTX *mem_ctx, const char *req_json); -/* tr_mon_rec_decode.c */ +/* tr_mon_resp.c */ +TR_MON_RESP *tr_mon_resp_new(TALLOC_CTX *mem_ctx, + TR_MON_REQ *req, + TR_MON_RESP_CODE code, + const char *msg, + json_t *payload); +void tr_mon_resp_free(TR_MON_RESP *resp); + +/* tr_mon_resp_encode.c */ +json_t *tr_mon_resp_encode(TR_MON_RESP *resp); #endif //TRUST_ROUTER_TR_MON_REQ_H diff --git a/mon/tests/resp_reconfigure_error.test b/mon/tests/resp_reconfigure_error.test new file mode 100644 index 0000000..3344bb1 --- /dev/null +++ b/mon/tests/resp_reconfigure_error.test @@ -0,0 +1 @@ +{"code": 1, "message": "error"} diff --git a/mon/tests/resp_reconfigure_success.test b/mon/tests/resp_reconfigure_success.test new file mode 100644 index 0000000..392c2e0 --- /dev/null +++ b/mon/tests/resp_reconfigure_success.test @@ -0,0 +1 @@ +{"code": 0, "message": "success"} diff --git a/mon/tests/resp_show_success.test b/mon/tests/resp_show_success.test new file mode 100644 index 0000000..bfbec19 --- /dev/null +++ b/mon/tests/resp_show_success.test @@ -0,0 +1 @@ +{"code": 0, "message": "success", "show": {"version": "1.2.3-4", "serial": 86400, "tid_req_pending": 13, "tid_req_count": 1432}} diff --git a/mon/tests/test_mon_req_decode.c b/mon/tests/test_mon_req_decode.c index 5c1c279..38ee66f 100644 --- a/mon/tests/test_mon_req_decode.c +++ b/mon/tests/test_mon_req_decode.c @@ -8,7 +8,7 @@ #include #include -#include "../tr_mon_req.h" +#include /** * @return reconfigure command diff --git a/mon/tests/test_mon_req_encode.c b/mon/tests/test_mon_req_encode.c index c797cc0..60fe9ca 100644 --- a/mon/tests/test_mon_req_encode.c +++ b/mon/tests/test_mon_req_encode.c @@ -8,7 +8,7 @@ #include #include -#include "../tr_mon_req.h" +#include #define JSON_DUMP_OPTS 0 diff --git a/mon/tests/test_mon_resp_encode.c b/mon/tests/test_mon_resp_encode.c new file mode 100644 index 0000000..9f9a3bb --- /dev/null +++ b/mon/tests/test_mon_resp_encode.c @@ -0,0 +1,130 @@ +// +// Created by jlr on 4/9/18. +// + +#include +#include +#include +#include + +#include + +#define JSON_DUMP_OPTS 0 + +static char *reconfigure(TR_MON_RESP_CODE code, const char *message) +{ + TR_MON_REQ *req = NULL; + TR_MON_RESP *resp = NULL; + json_t *resp_json = NULL; + char *result = NULL; + + req = tr_mon_req_new(NULL, MON_CMD_RECONFIGURE); + assert(req); + + resp = tr_mon_resp_new(NULL, req, code, message, NULL); + assert(resp); + + resp_json = tr_mon_resp_encode(resp); + assert(resp_json); + + result = json_dumps(resp_json, JSON_DUMP_OPTS); + assert(result); + + json_decref(resp_json); + tr_mon_resp_free(resp); + tr_mon_req_free(req); + return result; +} + +static char *reconfigure_success() +{ + return reconfigure(MON_RESP_SUCCESS, "success"); +} + +static char *reconfigure_error() +{ + return reconfigure(MON_RESP_ERROR, "error"); +} + +static char *show_success() +{ + TR_MON_REQ *req = NULL; + TR_MON_RESP *resp = NULL; + json_t *resp_json = NULL; + json_t *payload = NULL; + char *result = NULL; + + req = tr_mon_req_new(NULL, MON_CMD_SHOW); + // Only need the command to be set in req, don't actually need the options + assert(req); + + payload = json_object(); + assert(payload); + assert(! json_object_set_new(payload, + opt_type_to_string(OPT_TYPE_SHOW_VERSION), + json_string("1.2.3-4"))); + assert(! json_object_set_new(payload, + opt_type_to_string(OPT_TYPE_SHOW_SERIAL), + json_integer(1234567890))); + assert(! json_object_set_new(payload, + opt_type_to_string(OPT_TYPE_SHOW_SERIAL), + json_integer(86400))); + assert(! json_object_set_new(payload, + opt_type_to_string(OPT_TYPE_SHOW_TID_REQ_PENDING), + json_integer(13))); + assert(! json_object_set_new(payload, + opt_type_to_string(OPT_TYPE_SHOW_TID_REQ_COUNT), + json_integer(1432))); + + resp = tr_mon_resp_new(NULL, req, MON_RESP_SUCCESS, "success", payload); + assert(resp); + + resp_json = tr_mon_resp_encode(resp); + assert(resp_json); + + result = json_dumps(resp_json, JSON_DUMP_OPTS); + assert(result); + + json_decref(resp_json); + tr_mon_resp_free(resp); + tr_mon_req_free(req); + return result; +} + +static char *read_file(const char *filename) +{ + FILE *f = fopen(filename, "r"); + char *s = NULL; + size_t nn = 0; + ssize_t n = getline(&s, &nn, f); + fclose(f); + + if( (n > 0) && (s[n-1] == '\n')) + s[n-1] = 0; + + return s; +} + +int run_test(const char *filename, char *(generator)()) +{ + char *s = NULL; + char *expected = NULL; + + // Test reconfigure command + s = generator(); + expected = read_file(filename); + assert(expected); + assert(strcmp(expected, s) == 0); + free(s); + free(expected); + + return 1; +} + +int main(void) +{ + assert(run_test("resp_reconfigure_success.test", reconfigure_success)); + assert(run_test("resp_reconfigure_error.test", reconfigure_error)); + assert(run_test("resp_show_success.test", show_success)); + return 0; +} diff --git a/mon/tr_mon.c b/mon/tr_mon.c new file mode 100644 index 0000000..6c613c9 --- /dev/null +++ b/mon/tr_mon.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2018, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include +#include + +#include + +// Monitoring common code + +/** + * This method defines the command strings + */ +const char *cmd_to_string(TR_MON_CMD cmd) +{ + switch(cmd) { + case MON_CMD_UNKNOWN: + return NULL; + + case MON_CMD_RECONFIGURE: + return "reconfigure"; + + case MON_CMD_SHOW: + return "show"; + } + return NULL; +} + +// Helper macro for the cmd_from_string method +#define return_if_matches(s, cmd) \ + do { \ + if (strcmp((s), cmd_to_string(cmd))==0) \ + return (cmd); \ + } while(0) + +TR_MON_CMD cmd_from_string(const char *s) +{ + return_if_matches(s, MON_CMD_RECONFIGURE); + return_if_matches(s, MON_CMD_SHOW); + return MON_CMD_UNKNOWN; +} +#undef return_if_matches + +/** + * This method defines the option type strings + */ +const char *opt_type_to_string(TR_MON_OPT_TYPE opt_type) +{ + switch(opt_type) { + case OPT_TYPE_UNKNOWN: + return NULL; + + case OPT_TYPE_SHOW_VERSION: + return "version"; + + case OPT_TYPE_SHOW_SERIAL: + return "serial"; + + case OPT_TYPE_SHOW_UPTIME: + return "uptime"; + + case OPT_TYPE_SHOW_TID_REQ_COUNT: + return "tid_req_count"; + + case OPT_TYPE_SHOW_TID_REQ_PENDING: + return "tid_req_pending"; + + case OPT_TYPE_SHOW_ROUTES: + return "routes"; + + case OPT_TYPE_SHOW_COMMUNITIES: + return "communities"; + } + return NULL; +} + +// Helper macro for the opt_type_from_string method +#define return_if_matches(s, cmd) \ + do { \ + if (strcmp((s), opt_type_to_string(cmd))==0) \ + return (cmd); \ + } while(0) + +TR_MON_OPT_TYPE opt_type_from_string(const char *s) +{ + return_if_matches(s, OPT_TYPE_SHOW_VERSION); + return_if_matches(s, OPT_TYPE_SHOW_SERIAL); + return_if_matches(s, OPT_TYPE_SHOW_UPTIME); + return_if_matches(s, OPT_TYPE_SHOW_TID_REQ_COUNT); + return_if_matches(s, OPT_TYPE_SHOW_TID_REQ_PENDING); + return_if_matches(s, OPT_TYPE_SHOW_ROUTES); + return_if_matches(s, OPT_TYPE_SHOW_COMMUNITIES); + return OPT_TYPE_UNKNOWN; +} +#undef return_if_matches diff --git a/mon/tr_mon_req.c b/mon/tr_mon_req.c index 3adb2a3..1660ca4 100644 --- a/mon/tr_mon_req.c +++ b/mon/tr_mon_req.c @@ -35,9 +35,8 @@ #include #include -#include -#include "tr_mon_req.h" +#include // Monitoring request message common code @@ -110,92 +109,6 @@ size_t tr_mon_req_opt_count(TR_MON_REQ *req) TR_MON_OPT *tr_mon_req_opt_index(TR_MON_REQ *req, size_t index) { - TR_MON_OPT *result = (TR_MON_OPT *) &g_array_index(req->options, TR_MON_OPT, index); + TR_MON_OPT *result = &g_array_index(req->options, TR_MON_OPT, index); return result; } - -/** - * This method defines the command strings - */ -const char *cmd_to_string(TR_MON_CMD cmd) -{ - switch(cmd) { - case MON_CMD_UNKNOWN: - return NULL; - - case MON_CMD_RECONFIGURE: - return "reconfigure"; - - case MON_CMD_SHOW: - return "show"; - } - return NULL; -} - -// Helper macro for the cmd_from_string method -#define return_if_matches(s, cmd) \ - do { \ - if (strcmp((s), cmd_to_string(cmd))==0) \ - return (cmd); \ - } while(0) - -TR_MON_CMD cmd_from_string(const char *s) -{ - return_if_matches(s, MON_CMD_RECONFIGURE); - return_if_matches(s, MON_CMD_SHOW); - return MON_CMD_UNKNOWN; -} -#undef return_if_matches - -/** - * This method defines the option type strings - */ -const char *opt_type_to_string(TR_MON_OPT_TYPE opt_type) -{ - switch(opt_type) { - case OPT_TYPE_UNKNOWN: - return NULL; - - case OPT_TYPE_SHOW_VERSION: - return "version"; - - case OPT_TYPE_SHOW_SERIAL: - return "serial"; - - case OPT_TYPE_SHOW_UPTIME: - return "uptime"; - - case OPT_TYPE_SHOW_TID_REQ_COUNT: - return "tid_req_count"; - - case OPT_TYPE_SHOW_TID_REQ_PENDING: - return "tid_req_pending"; - - case OPT_TYPE_SHOW_ROUTES: - return "routes"; - - case OPT_TYPE_SHOW_COMMUNITIES: - return "communities"; - } - return NULL; -} - -// Helper macro for the opt_type_from_string method -#define return_if_matches(s, cmd) \ - do { \ - if (strcmp((s), opt_type_to_string(cmd))==0) \ - return (cmd); \ - } while(0) - -TR_MON_OPT_TYPE opt_type_from_string(const char *s) -{ - return_if_matches(s, OPT_TYPE_SHOW_VERSION); - return_if_matches(s, OPT_TYPE_SHOW_SERIAL); - return_if_matches(s, OPT_TYPE_SHOW_UPTIME); - return_if_matches(s, OPT_TYPE_SHOW_TID_REQ_COUNT); - return_if_matches(s, OPT_TYPE_SHOW_TID_REQ_PENDING); - return_if_matches(s, OPT_TYPE_SHOW_ROUTES); - return_if_matches(s, OPT_TYPE_SHOW_COMMUNITIES); - return OPT_TYPE_UNKNOWN; -} -#undef return_if_matches diff --git a/mon/tr_mon_req_decode.c b/mon/tr_mon_req_decode.c index 1c441de..ed97a24 100644 --- a/mon/tr_mon_req_decode.c +++ b/mon/tr_mon_req_decode.c @@ -1,4 +1,4 @@ -#include "tr_mon_req.h"/* +/* * Copyright (c) 2018, JANET(UK) * All rights reserved. * @@ -36,7 +36,7 @@ #include #include -#include "tr_mon_req.h" +#include // Monitoring request decoders diff --git a/mon/tr_mon_req_encode.c b/mon/tr_mon_req_encode.c index 3346b5f..4239b12 100644 --- a/mon/tr_mon_req_encode.c +++ b/mon/tr_mon_req_encode.c @@ -37,7 +37,7 @@ #include #include -#include "tr_mon_req.h" +#include // Monitoring request encoders diff --git a/mon/tr_mon_resp.c b/mon/tr_mon_resp.c new file mode 100644 index 0000000..a8c8f9d --- /dev/null +++ b/mon/tr_mon_resp.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include + +#include + +// Monitoring request message common code + +/** + * Destructor used by talloc to ensure proper cleanup + */ +static int tr_mon_resp_destructor(void *object) +{ + TR_MON_RESP *resp = talloc_get_type_abort(object, TR_MON_RESP); + /* free the message */ + if (resp->message) { + tr_free_name(resp->message); + } + /* free the payload */ + if (resp->payload) { + json_decref(resp->payload); + } + return 0; +} + +/** + * Allocate a new monitoring response + * + * Caller must free using tr_mon_resp_free(). + * + * Makes its own copy of the message, so caller can dispose of + * that after allocating the response. + * + * Steals the reference to the payload JSON object. Does not modify the + * object. Caller should not modify it after allocating the response or + * undefined behavior will result. If allocation fails, the stolen reference + * will be released --- if you need to keep a reference, use incref before + * calling this. + * + * @param mem_ctx talloc context for allocation + * @param req TR_MON_REQ this response corresponds to + * @param code numeric response code + * @param msg string description of response code + * @param payload JSON object to be send as payload, or null for no payload + * @return response allocated in the requested talloc context, null on failure + */ +TR_MON_RESP *tr_mon_resp_new(TALLOC_CTX *mem_ctx, + TR_MON_REQ *req, + TR_MON_RESP_CODE code, + const char *msg, + json_t *payload) +{ + TR_MON_RESP *resp = talloc(mem_ctx, TR_MON_RESP); + if (resp) { + resp->req = req; + resp->code = code; + resp->message = tr_new_name(msg); + resp->payload = payload; + talloc_set_destructor((void *)resp, tr_mon_resp_destructor); + if (resp->message == NULL) { + talloc_free(resp); // destructor will be called + resp = NULL; + } + } + return resp; +} + +/** + * Free a monitoring response + * + * @param resp request to free, must not be null + */ +void tr_mon_resp_free(TR_MON_RESP *resp) +{ + talloc_free(resp); +} diff --git a/mon/tr_mon_resp_encode.c b/mon/tr_mon_resp_encode.c new file mode 100644 index 0000000..19af8c0 --- /dev/null +++ b/mon/tr_mon_resp_encode.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +/* Helper for encoding. Adds a newly allocated JSON object to + * jobj. If the allocation or setting fails, returns NULL after + * cleaning up. */ +#define object_set_or_free_and_return(jobj, tmp_jval, key, jval) \ + do { \ + (tmp_jval) = (jval); \ + if ( (tmp_jval) == NULL) { \ + json_decref(jobj); \ + return NULL; \ + } \ + if (json_object_set_new((jobj), (key), (tmp_jval)) == -1) { \ + json_decref(tmp_jval); \ + json_decref(jobj); \ + return NULL; \ + } \ + } while(0) + +/** + * Encode a monitoring response as a JSON object + * + * Caller must ensure json_decref() is used to free the return value. + * + * @param resp response to encode + * @return response as a newly allocated JSON object + */ +json_t *tr_mon_resp_encode(TR_MON_RESP *resp) +{ + json_t *resp_json = NULL; + json_t *jval = NULL; + const char *cmd_str = NULL; + + /* Get a JSON object */ + resp_json = json_object(); + if (resp_json == NULL) + return NULL; + + /* Add properties, cleaning up and returning NULL on failure */ + object_set_or_free_and_return(resp_json, jval, "code", json_integer(resp->code)); + object_set_or_free_and_return(resp_json, jval, "message", tr_name_to_json_string(resp->message)); + + /* If we have a payload, add it */ + if (resp->payload) { + cmd_str = cmd_to_string(resp->req->command); // key for the response payload + object_set_or_free_and_return(resp_json, jval, cmd_str, resp->payload); + } + + return resp_json; +}