From 884dfb4e2fa13d09a0c84d4da0febfdfb75e1bf6 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 13 Apr 2018 17:02:18 -0400 Subject: [PATCH] First pass at a trmon command-line interface; fix a few bugs At this point, if you hack tr_mons_auth_handler() to always return 0 (success), then trmon can connect to the trust router's monitoring port and retrieve a test message. That counts as first contact, I guess. Actual functionality is still to come. * Create basic trmon utility based closely on tidc * Temporarily use void pointers for trps/tids handles in the MON_INSTANCE structure - there is a header file cycle that prevents compliation. Need to sort that out, but this works for the moment. * Fill in tr_msg handlers for monitoring message encoders/decoders * Revert to the monitoring msg decoder working from json, not a string, since that is what we need. This breaks the test programs for now. --- CMakeLists.txt | 2 + Makefile.am | 12 ++- common/tr_msg.c | 90 +++++++++++++++++---- include/mon_internal.h | 27 ++++++- include/tr_msg.h | 10 ++- mon/mon_req_decode.c | 21 +++-- mon/monc.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++ tr/trmon_main.c | 178 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 517 insertions(+), 33 deletions(-) create mode 100644 mon/monc.c create mode 100644 tr/trmon_main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fe9749..2256e88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,8 @@ set(SOURCE_FILES # Does not actually build! add_executable(trust_router ${SOURCE_FILES}) +add_executable(trmon mon/monc.c tr/trmon_main.c) + # Test build targets - for debugging add_executable(test_mon_req_encode mon/mon_common.c mon/mon_req.c mon/tests/test_mon_req_encode.c mon/mon_req_encode.c) target_link_libraries(test_mon_req_encode jansson talloc glib-2.0) diff --git a/Makefile.am b/Makefile.am index 49bf774..2d94db2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ DISTCHECK_CONFIGURE_FLAGS = \ 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_resp_encode + mon/tests/test_mon_req_decode mon/tests/test_mon_resp_encode tr/trmon AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS) AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS) SUBDIRS = gsscon @@ -41,6 +41,7 @@ common/tr_mq.c mon_srcs = \ mon/mons.c \ + mon/monc.c \ mon/mon_common.c \ mon/mon_req.c \ mon/mon_req_encode.c \ @@ -99,6 +100,15 @@ $(common_srcs) tr_trpc_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) tr_trpc_LDFLAGS = $(AM_LDFLAGS) -pthread +tr_trmon_SOURCES = tr/trmon_main.c \ +common/tr_gss.c \ +$(tid_srcs) \ +$(trp_srcs) \ +$(mon_srcs) \ +$(common_srcs) +tr_trmon_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) +tr_trmon_LDFLAGS = $(AM_LDFLAGS) -pthread + trp_msgtst_SOURCES = trp/msgtst.c \ $(common_srcs) \ trp/trp_req.c \ diff --git a/common/tr_msg.c b/common/tr_msg.c index e0e406a..8d792cb 100644 --- a/common/tr_msg.c +++ b/common/tr_msg.c @@ -44,9 +44,10 @@ #include #include +#include +#include #include #include -#include #include #include #include @@ -127,6 +128,32 @@ void tr_msg_set_resp(TR_MSG *msg, TID_RESP *resp) msg->msg_type = TID_RESPONSE; } +MON_REQ *tr_msg_get_mon_req(TR_MSG *msg) +{ + if (msg->msg_type == MON_REQUEST) + return (MON_REQ *)msg->msg_rep; + return NULL; +} + +void tr_msg_set_mon_req(TR_MSG *msg, MON_REQ *req) +{ + msg->msg_rep = req; + msg->msg_type = MON_REQUEST; +} + +MON_RESP *tr_msg_get_mon_resp(TR_MSG *msg) +{ + if (msg->msg_type == MON_RESPONSE) + return (MON_RESP *)msg->msg_rep; + return NULL; +} + +void tr_msg_set_mon_resp(TR_MSG *msg, MON_RESP *resp) +{ + msg->msg_rep = resp; + msg->msg_type = MON_RESPONSE; +} + TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg) { if (msg->msg_type == TRP_UPDATE) @@ -1154,6 +1181,8 @@ char *tr_msg_encode(TALLOC_CTX *mem_ctx, TR_MSG *msg) TID_REQ *tidreq=NULL; TRP_UPD *trpupd=NULL; TRP_REQ *trpreq=NULL; + MON_REQ *monreq=NULL; + MON_RESP *monresp=NULL; /* TBD -- add error handling */ jmsg = json_object(); @@ -1174,21 +1203,35 @@ char *tr_msg_encode(TALLOC_CTX *mem_ctx, TR_MSG *msg) json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidresp(tidresp)); break; - 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; - - default: + 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; } @@ -1252,6 +1295,15 @@ TR_MSG *tr_msg_decode(const char *jbuf, size_t buflen) msg->msg_type = TRP_UPDATE; tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(NULL, jbody)); /* null talloc context for now */ } + else if (0 == strcmp(mtype, "mon_request")) { + msg->msg_type = MON_REQUEST; + tr_msg_set_mon_req(msg, mon_req_decode(NULL, 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(NULL, jbody)); +// } else { msg->msg_type = TR_UNKNOWN; msg->msg_rep = NULL; @@ -1286,6 +1338,12 @@ void tr_msg_free_decoded(TR_MSG *msg) trp_req_free(tr_msg_get_trp_req(msg)); default: break; + case MON_REQUEST: + mon_req_free(tr_msg_get_mon_req(msg)); + break; + case MON_RESPONSE: + mon_resp_free(tr_msg_get_mon_resp(msg)); + break; } } free (msg); diff --git a/include/mon_internal.h b/include/mon_internal.h index 171ce18..189695f 100644 --- a/include/mon_internal.h +++ b/include/mon_internal.h @@ -40,10 +40,11 @@ #include #include #include -#include +//#include #include #include #include +#include /* Typedefs */ typedef struct mon_req MON_REQ; @@ -58,9 +59,11 @@ typedef enum mon_opt_type MON_OPT_TYPE; typedef enum mon_rc MON_RC; typedef struct mons_instance MONS_INSTANCE; +typedef struct monc_instance MONC_INSTANCE; typedef int (MONS_REQ_FUNC)(MONS_INSTANCE *, MON_REQ *, MON_RESP *, void *); typedef int (MONS_AUTH_FUNC)(gss_name_t client_name, TR_NAME *display_name, void *cookie); +typedef int (MONC_RESP_FUNC)(MONS_INSTANCE *, MON_REQ *, MON_RESP *, void *); /* Struct and enum definitions */ enum mon_rc { @@ -121,13 +124,18 @@ struct mons_instance { const char *hostname; unsigned int port; TR_GSS_NAMES *authorized_gss_names; - TIDS_INSTANCE *tids; - TRPS_INSTANCE *trps; + void *tids; // TODO sort out header file cycles and use typed pointers + void *trps; // TODO sort out header file cycles and use typed pointers MONS_REQ_FUNC *req_handler; MONS_AUTH_FUNC *auth_handler; void *cookie; }; +/* Monitoring client instance */ +struct monc_instance { + DH *client_dh; +}; + /* Prototypes */ /* tr_mon.c */ const char *mon_cmd_to_string(MON_CMD cmd); @@ -146,7 +154,7 @@ MON_OPT *mon_req_opt_index(MON_REQ *req, size_t index); json_t *mon_req_encode(MON_REQ *req); /* mon_req_decode.c */ -MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, const char *req_json); +MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, json_t *req_json); /* mon_resp.c */ MON_RESP *mon_resp_new(TALLOC_CTX *mem_ctx, @@ -165,4 +173,15 @@ int mons_get_listener(MONS_INSTANCE *mons, MONS_REQ_FUNC *req_handler, MONS_AUTH unsigned int port, void *cookie, int *fd_out, size_t max_fd); int mons_accept(MONS_INSTANCE *mons, int listen); +/* monc.c */ +MONC_INSTANCE *monc_create(void); +void monc_destroy(MONC_INSTANCE *monc); +int monc_open_connection (MONC_INSTANCE *monc, const char *server, unsigned int port, gss_ctx_id_t *gssctx); +int monc_send_request (MONC_INSTANCE *monc, int conn, gss_ctx_id_t gssctx, MONC_RESP_FUNC *resp_handler, + void *cookie); +int monc_fwd_request(MONC_INSTANCE *monc, int conn, gss_ctx_id_t gssctx, MON_REQ *mon_req, + MONC_RESP_FUNC *resp_handler, void *cookie); +DH * monc_get_dh(MONC_INSTANCE *inst); +DH *monc_set_dh(MONC_INSTANCE *inst, DH *dh); + #endif //TRUST_ROUTER_MON_REQ_H diff --git a/include/tr_msg.h b/include/tr_msg.h index 59b7cf7..17979c1 100644 --- a/include/tr_msg.h +++ b/include/tr_msg.h @@ -38,6 +38,8 @@ #include #include #include +#include + typedef struct tr_msg TR_MSG; enum msg_type { @@ -45,7 +47,9 @@ enum msg_type { TID_REQUEST, TID_RESPONSE, TRP_UPDATE, - TRP_REQUEST + TRP_REQUEST, + MON_REQUEST, + MON_RESPONSE }; /* Union of TR message types to hold message of any type. */ @@ -65,6 +69,10 @@ TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg); void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *req); TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg); void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req); +MON_REQ *tr_msg_get_mon_req(TR_MSG *msg); +void tr_msg_set_mon_req(TR_MSG *msg, MON_REQ *req); +MON_RESP *tr_msg_get_mon_resp(TR_MSG *msg); +void tr_msg_set_mon_resp(TR_MSG *msg, MON_RESP *resp); /* Encoders/Decoders */ diff --git a/mon/mon_req_decode.c b/mon/mon_req_decode.c index c1eeed1..66763a2 100644 --- a/mon/mon_req_decode.c +++ b/mon/mon_req_decode.c @@ -106,14 +106,14 @@ static MON_RC mon_options_decode(json_t *opts_json, MON_REQ *req) /** * Parse JSON for a request */ -static json_t *mon_req_parse(const char *input) -{ - json_t *parsed_json = NULL; - json_error_t json_error; - - parsed_json = json_loads(input, JSON_REJECT_DUPLICATES, &json_error); - return parsed_json; -} +//static json_t *mon_req_parse(const char *input) +//{ +// json_t *parsed_json = NULL; +// json_error_t json_error; +// +// parsed_json = json_loads(input, JSON_REJECT_DUPLICATES, &json_error); +// return parsed_json; +//} /** * Decode a JSON request @@ -132,16 +132,15 @@ static json_t *mon_req_parse(const char *input) * @param req_json reference to JSON request object * @return decoded request struct or NULL on failure */ -MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, const char *req_str) +MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, json_t *req_json) //const char *req_str) { TALLOC_CTX *tmp_ctx = talloc_new(NULL); MON_REQ *req = NULL; - json_t *req_json = NULL; json_t *jval = NULL; json_t *opts_json = NULL; MON_CMD cmd = MON_CMD_UNKNOWN; - req_json = mon_req_parse(req_str); // TODO: Check errors + //req_json = mon_req_parse(req_str); // TODO: Check errors if (! json_is_object(req_json)) goto cleanup; diff --git a/mon/monc.c b/mon/monc.c new file mode 100644 index 0000000..3e567ce --- /dev/null +++ b/mon/monc.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2012, 2014-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 +#include +#include +#include +#include + + +static int monc_destructor(void *obj) +{ + MONC_INSTANCE *monc=talloc_get_type_abort(obj, MONC_INSTANCE); + if (NULL!=monc) { + if (NULL!=monc->client_dh) + tr_destroy_dh_params(monc->client_dh); + } + return 0; +} + +/* creates struct in talloc null context */ +MONC_INSTANCE *monc_create(void) +{ + MONC_INSTANCE *monc=talloc(NULL, MONC_INSTANCE); + if (monc!=NULL) { + monc->client_dh=NULL; + talloc_set_destructor((void *)monc, monc_destructor); + } + return monc; +} + +void monc_destroy(MONC_INSTANCE *monc) +{ + talloc_free(monc); +} + +int monc_open_connection (MONC_INSTANCE *monc, + const char *server, + unsigned int port, + gss_ctx_id_t *gssctx) +{ + int err = 0; + int conn = -1; + + tr_debug("monc_open_connection: opening monc connection to %s:%d", server, port); + err = gsscon_connect(server, port, "trustmonitor", &conn, gssctx); + + if (!err) + return conn; + else + return -1; +} + +int monc_send_request (MONC_INSTANCE *monc, + int conn, + gss_ctx_id_t gssctx, + MONC_RESP_FUNC *resp_handler, + void *cookie) +{ + MON_REQ *mon_req = NULL; + int rc; + + /* Create and populate a MON req structure */ + if (!(mon_req = mon_req_new(NULL, MON_CMD_SHOW))) // TODO accept command as a parameter + goto error; + + rc = monc_fwd_request(monc, conn, gssctx, mon_req, resp_handler, cookie); + goto cleanup; +error: + rc = -1; +cleanup: + mon_req_free(mon_req); + return rc; +} + +int monc_fwd_request(MONC_INSTANCE *monc, + int conn, + gss_ctx_id_t gssctx, + MON_REQ *mon_req, + MONC_RESP_FUNC *resp_handler, + void *cookie) +{ + char *req_buf = NULL; + char *resp_buf = NULL; + size_t resp_buflen = 0; + TR_MSG *msg = NULL; + TR_MSG *resp_msg = NULL; + int err; + int rc = 0; + + /* Create and populate a MON msg structure */ + if (!(msg = talloc_zero(mon_req, TR_MSG))) + goto error; + + msg->msg_type = MON_REQUEST; + tr_msg_set_mon_req(msg, mon_req); + + /* store the response function and cookie */ + // mon_req->resp_func = resp_handler; + // mon_req->cookie = cookie; + + + /* Encode the request into a json string */ + if (!(req_buf = tr_msg_encode(NULL, msg))) { + tr_err("monc_fwd_request: Error encoding MON request.\n"); + goto error; + } + + tr_debug( "monc_fwd_request: Sending MON request:\n"); + tr_debug( "%s\n", req_buf); + + /* Send the request over the connection */ + err = gsscon_write_encrypted_token (conn, gssctx, req_buf, strlen(req_buf)); + if (err) { + tr_err( "monc_fwd_request: Error sending request over connection.\n"); + goto error; + } + + /* TBD -- queue request on instance, read resps in separate thread */ + + /* Read the response from the connection */ + /* TBD -- timeout? */ + if (err = gsscon_read_encrypted_token(conn, gssctx, &resp_buf, &resp_buflen)) { + if (resp_buf) + free(resp_buf); + goto error; + } + + tr_debug( "monc_fwd_request: Response Received (%u bytes).\n", (unsigned) resp_buflen); + tr_debug( "%s\n", resp_buf); + +// if (NULL == (resp_msg = tr_msg_decode(resp_buf, resp_buflen))) { +// tr_err( "monc_fwd_request: Error decoding response.\n"); +// goto error; +// } +// +// /* TBD -- Check if this is actually a valid response */ +// if (MON_RESPONSE != tr_msg_get_msg_type(resp_msg)) { +// tr_err( "monc_fwd_request: Error, no response in the response!\n"); +// goto error; +// } +// +// if (resp_handler) { +// /* Call the caller's response function. It must copy any data it needs before returning. */ +// tr_debug("monc_fwd_request: calling response callback function."); +// (*resp_handler)(monc, mon_req, tr_msg_get_resp(resp_msg), cookie); +// } + + goto cleanup; + +error: + rc = -1; +cleanup: + if (msg) + talloc_free(msg); + if (req_buf) + free(req_buf); + if (resp_buf) + free(resp_buf); + if (resp_msg) + tr_msg_free_decoded(resp_msg); + return rc; +} + + +DH * monc_get_dh(MONC_INSTANCE *inst) +{ + return inst->client_dh; +} + +DH *monc_set_dh(MONC_INSTANCE *inst, DH *dh) +{ + inst->client_dh = dh; + return dh; +} diff --git a/tr/trmon_main.c b/tr/trmon_main.c new file mode 100644 index 0000000..507bf34 --- /dev/null +++ b/tr/trmon_main.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2012-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 +#include + +#include +#include +#include +#include + + +/* command-line option setup */ + +/* argp global parameters */ +const char *argp_program_bug_address=PACKAGE_BUGREPORT; /* bug reporting address */ + +/* doc strings */ +static const char doc[]=PACKAGE_NAME " - TR Monitoring Client"; +static const char arg_doc[]=" []"; /* string describing arguments, if any */ + +/* define the options here. Fields are: + * { long-name, short-name, variable name, options, help description } */ +static const struct argp_option cmdline_options[] = { + { "repeat", 'r', "N", OPTION_ARG_OPTIONAL, "Repeat message until terminated, or N times." }, + {NULL} +}; + +/* structure for communicating with option parser */ +struct cmdline_args { + char *msg; + char *server; + int port; /* optional */ + int repeat; /* how many times to repeat, or -1 for infinite */ +}; + +/* parser for individual options - fills in a struct cmdline_args */ +static error_t parse_option(int key, char *arg, struct argp_state *state) +{ + /* get a shorthand to the command line argument structure, part of state */ + struct cmdline_args *arguments=state->input; + + switch (key) { + case 'r': + if (arg==NULL) + arguments->repeat=-1; + else + arguments->repeat=strtol(arg, NULL, 10); + break; + + case ARGP_KEY_ARG: /* handle argument (not option) */ + switch (state->arg_num) { + case 0: + arguments->msg=arg; + break; + + case 1: + arguments->server=arg; + break; + + case 2: + arguments->port=strtol(arg, NULL, 10); /* optional */ + break; + + default: + /* too many arguments */ + argp_usage(state); + } + break; + + case ARGP_KEY_END: /* no more arguments */ + if (state->arg_num < 2) { + /* not enough arguments encountered */ + argp_usage(state); + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; /* success */ +} + + +/* assemble the argp parser */ +static struct argp argp = {cmdline_options, parse_option, arg_doc, doc}; + +int main (int argc, + char *argv[]) +{ + TALLOC_CTX *main_ctx=talloc_new(NULL); + MONC_INSTANCE *monc=NULL; + struct cmdline_args opts; + int rc; + int conn; + gss_ctx_id_t gssctx; + + /* parse the command line*/ + /* set defaults */ + opts.msg=NULL; + opts.server=NULL; + opts.port=TRP_PORT; + opts.repeat=1; + + argp_parse(&argp, argc, argv, 0, 0, &opts); + + /* Use standalone logging */ + tr_log_open(); + + /* set logging levels */ + talloc_set_log_stderr(); + tr_log_threshold(LOG_CRIT); + tr_console_threshold(LOG_DEBUG); + + printf("TR Monitor:\nServer = %s, port = %i\n", opts.server, opts.port); + + /* Create a MON client instance & the client DH */ + monc = monc_create(); + if (NULL == (monc->client_dh = tr_create_dh_params(main_ctx, 0))) { + printf("Error creating client DH params.\n"); + return 1; + } + + /* Set-up MON connection */ + if (-1 == (conn = monc_open_connection(monc, opts.server, opts.port, &gssctx))) { + /* Handle error */ + printf("Error in monc_open_connection.\n"); + return 1; + }; + + /* Send a MON request */ + if (0 > (rc = monc_send_request(monc, conn, gssctx, NULL, NULL))) { + /* Handle error */ + printf("Error in monc_send_request, rc = %d.\n", rc); + return 1; + } + + /* Clean-up the MON client instance, and exit */ + monc_destroy(monc); + talloc_free(main_ctx); + return 0; +} + -- 2.1.4