trp/trp_upd.c
trp/trpc.c
trp/trps.c include/tr_name_internal.h mon/mon_req.c mon/mon_req_encode.c mon/mon_req_decode.c
- mon/mon_resp.c mon/mon_common.c mon/mon_resp_encode.c mon/mon_resp_decode.c tr/tr_mon.c mon/mons.c include/tr_socket.h common/tr_gss.c include/tr_gss.h common/tr_config_internal.c mon/mons_handlers.c mon/mons_handlers.h mon/mons_handlers_show.c)
+ mon/mon_resp.c mon/mon_common.c mon/mon_resp_encode.c mon/mon_resp_decode.c tr/tr_mon.c mon/mons.c include/tr_socket.h common/tr_gss.c include/tr_gss.h common/tr_config_internal.c mon/mons_handlers.c include/mons_handlers.h)
# Does not actually build!
add_executable(trust_router ${SOURCE_FILES})
# monitoring server sources
mons_srcs = \
mon/mons.c \
- mon/mons_handlers.c \
- mon/mons_handlers_show.c
+ mon/mons_handlers.c
check_PROGRAMS = common/t_constraint
TESTS = common/t_constraint
typedef struct mons_instance MONS_INSTANCE;
typedef struct monc_instance MONC_INSTANCE;
+typedef struct mons_dispatch_table_entry MONS_DISPATCH_TABLE_ENTRY;
+
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 *);
enum mon_opt_type {
OPT_TYPE_UNKNOWN=0,
+ OPT_TYPE_ANY,
// System information
OPT_TYPE_SHOW_VERSION,
MONS_REQ_FUNC *req_handler;
MONS_AUTH_FUNC *auth_handler;
void *cookie;
+ GPtrArray *handlers;
};
/* Client instance */
#ifndef TRUST_ROUTER_MONS_HANDLERS_H
#define TRUST_ROUTER_MONS_HANDLERS_H
+typedef json_t *(MONS_HANDLER_FUNC)(void *);
+
+struct mons_dispatch_table_entry {
+ MON_CMD command;
+ MON_OPT_TYPE opt_type;
+ MONS_HANDLER_FUNC *handler;
+ void *cookie;
+};
+
/* mons_handlers.c */
MON_RESP *mons_handle_request(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req);
-
-/* mons_handlers_show.c */
-MON_RESP *mons_handle_show(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req);
+MON_RC mons_register_handler(MONS_INSTANCE *mons, MON_CMD cmd, MON_OPT_TYPE opt_type, MONS_HANDLER_FUNC *f, void *cookie);
#endif //TRUST_ROUTER_MONS_HANDLERS_H
#include <tr_event.h>
#include <tr_config.h>
#include <mon_internal.h>
+#include <mons_handlers.h>
int tr_mons_event_init(struct event_base *base,
MONS_INSTANCE *mons,
{
switch(opt_type) {
case OPT_TYPE_UNKNOWN:
+ case OPT_TYPE_ANY:
return NULL;
case OPT_TYPE_SHOW_VERSION:
MON_OPT *result = &g_array_index(req->options, MON_OPT, index);
return result;
}
+
#include "mons_handlers.h"
+static int mons_destructor(void *object)
+{
+ MONS_INSTANCE *mons = talloc_get_type_abort(object, MONS_INSTANCE);
+ if (mons->handlers) {
+ g_ptr_array_unref(mons->handlers);
+ }
+ return 0;
+}
+
/**
* Allocate a new MONS_INSTANCE
*
mons->req_handler = NULL;
mons->auth_handler = NULL;
mons->cookie = NULL;
+
+ /* Before any steps that may fail, install the destructor */
+ talloc_set_destructor((void *)mons, mons_destructor);
+
mons->authorized_gss_names = tr_gss_names_new(mons);
if (mons->authorized_gss_names == NULL) {
talloc_free(mons);
- mons = NULL;
+ return NULL;
+ }
+
+ mons->handlers = g_ptr_array_new();
+ if (mons->handlers == NULL) {
+ talloc_free(mons);
+ return NULL;
}
}
return mons;
/* Handlers for monitoring requests */
+#include <gmodule.h>
+
#include <tr_debug.h>
#include <mon_internal.h>
-#include "mons_handlers.h"
-
-typedef MON_RESP *(MONS_HANDLER_FUNC)(TALLOC_CTX *, MONS_INSTANCE *, MON_REQ *);
+#include <mons_handlers.h>
-/* Prototypes for the dispatch table */
-static MON_RESP *mons_handle_reconfigure(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req);
+/* Static Prototypes */
+static int dispatch_entry_matches(MONS_DISPATCH_TABLE_ENTRY *e, MON_CMD command, MON_OPT_TYPE opt_type);
+static MONS_HANDLER_FUNC *mons_find_handler(MONS_INSTANCE *mons, MON_CMD cmd, MON_OPT_TYPE opt_type);
+static void request_helper(void *element, void *data);
-struct dispatch_table_entry {
+struct request_helper_data {
MON_CMD command;
- MONS_HANDLER_FUNC *handler;
-};
-
-static struct dispatch_table_entry dispatch_table[] = {
- {MON_CMD_SHOW, mons_handle_show},
- {MON_CMD_RECONFIGURE, mons_handle_reconfigure},
- {MON_CMD_UNKNOWN} /* Must be the last entry in the table */
+ MON_OPT_TYPE opt_type;
+ json_t *payload;
};
/**
* Call the appropriate handler for a request
*
+ * TODO: report errors from handlers
+ *
* @return a MON_RESP structure or null if there was a processing error
*/
MON_RESP *mons_handle_request(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req)
{
- struct dispatch_table_entry *entry = dispatch_table;
+ MON_RESP *resp = NULL;
+ json_t *payload = NULL;
+ struct request_helper_data cookie;
+ size_t ii = 0;
tr_debug("mons_handle_request: Handling a request");
- /* Find the handler */
- while ((entry->command != req->command) && (entry->command != MON_CMD_UNKNOWN)) {
- entry++;
+ /* Start off by allocating our response with a generic error message */
+ resp = mon_resp_new(mem_ctx,
+ MON_RESP_ERROR,
+ "Error processing show request",
+ NULL);
+ if (resp == NULL) {
+ /* we can't respond, just return */
+ tr_crit("mons_handle_request: Error allocating response structure.");
+ goto cleanup;
+ }
+
+ /* Now get a JSON object for our return payload */
+ payload = json_object();
+ if (payload == NULL) {
+ tr_crit("mons_handle_request: Error allocating response payload.");
+ goto cleanup; /* This will return the generic error message set earlier */
+ }
+
+ /* Now call handlers */
+ cookie.command = req->command;
+ cookie.payload = payload; /* borrowed reference */
+
+ if (mon_req_opt_count(req) == 0) {
+ /* call every handler that matches the command */
+ cookie.opt_type = OPT_TYPE_ANY;
+ g_ptr_array_foreach(mons->handlers, request_helper, &cookie);
+ } else {
+ /* call only those handlers that match an option */
+ for (ii=0; ii < mon_req_opt_count(req); ii++) {
+ cookie.opt_type = mon_req_opt_index(req, ii)->type;
+ /* Loop over all handlers - we know we can only have one match for each opt type */
+ g_ptr_array_foreach(mons->handlers, request_helper, &cookie);
+ }
+ }
+
+ /* If we get here, then we successfully processed the request. Return a successful reply. */
+ if (mon_resp_set_message(resp, "success") == 0) {
+ /* Failed to set the response message to success - fail ironically */
+ tr_crit("mons_handle_request: Error setting response message to 'success'.");
+ goto cleanup;
+ }
+
+ /* Attach the accumulated payload to the response */
+ if (json_object_size(payload) > 0)
+ mon_resp_set_payload(resp, payload);
+
+ resp->code = MON_RESP_SUCCESS; /* at last... */
+ tr_debug("mons_handle_request: Successfully processed request.");
+
+cleanup:
+ if (payload)
+ json_decref(payload);
+ return resp;
+}
+
+/**
+ * Register a handler for a command/option combination
+ *
+ * @param mons
+ * @param cmd
+ * @param opt_type
+ * @param f
+ * @param cookie
+ * @return
+ */
+MON_RC mons_register_handler(MONS_INSTANCE *mons,
+ MON_CMD cmd,
+ MON_OPT_TYPE opt_type,
+ MONS_HANDLER_FUNC *f,
+ void *cookie)
+{
+ MONS_DISPATCH_TABLE_ENTRY *entry = NULL;
+
+ if (mons_find_handler(mons, cmd, opt_type) != NULL) {
+ return MON_ERROR;
}
- /* See if we found a handler */
- if (entry->command == MON_CMD_UNKNOWN) {
- tr_info("mons_handle_request: Unknown or unsupported monitoring request received");
- return NULL;
+ /* Put these in the mons talloc context so we don't have to muck about with
+ * a free function for the GPtrArray */
+ entry = talloc(mons, MONS_DISPATCH_TABLE_ENTRY);
+ if (entry == NULL) {
+ return MON_NOMEM;
}
+ entry->command = cmd;
+ entry->opt_type = opt_type;
+ entry->handler = f;
+ entry->cookie = cookie;
- /* Call the handler */
- tr_debug("mons_handle_request: Calling handler for %s command", mon_cmd_to_string(entry->command));
- return entry->handler(mem_ctx, mons, req);
+ g_ptr_array_add(mons->handlers, entry);
+ return MON_SUCCESS;
}
-static MON_RESP *mons_handle_reconfigure(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req)
+/**
+ * Two table entries match if none of the commands or opt_types are unknown,
+ * if the commands match, and if the opt types either match or at least one is
+ * OPT_TYPE_ANY.
+ *
+ * No comparison of the handler pointer is included.
+ *
+ * @return 1 if the two match, 0 if not
+ */
+static int dispatch_entry_matches(MONS_DISPATCH_TABLE_ENTRY *e,
+ MON_CMD command,
+ MON_OPT_TYPE opt_type)
+{
+ if ((command == MON_CMD_UNKNOWN) || (opt_type == OPT_TYPE_UNKNOWN))
+ return 0; /* request is invalid */
+
+ if ((e->command == MON_CMD_UNKNOWN) || (e->opt_type == OPT_TYPE_UNKNOWN))
+ return 0; /* e1 is invalid */
+
+ if (e->command != command)
+ return 0; /* commands do not match */
+
+ if (e->opt_type == opt_type)
+ return 1; /* exact match */
+
+ if ( (e->opt_type == OPT_TYPE_ANY) || (opt_type == OPT_TYPE_ANY) )
+ return 1; /* one is a wildcard */
+
+ return 0; /* commands matched but opt_types did not */
+}
+
+static MONS_HANDLER_FUNC *mons_find_handler(MONS_INSTANCE *mons, MON_CMD cmd, MON_OPT_TYPE opt_type)
{
+ guint index;
+
+ for (index=0; index < mons->handlers->len; index++) {
+ if (dispatch_entry_matches(g_ptr_array_index(mons->handlers, index), cmd, opt_type))
+ return g_ptr_array_index(mons->handlers, index);
+ }
return NULL;
}
+
+/**
+ * This calls every request handler that matches a command/opt_type,
+ * gathering their results.
+ *
+ * @param element
+ * @param data
+ */
+static void request_helper(void *element, void *data)
+{
+ MONS_DISPATCH_TABLE_ENTRY *entry = talloc_get_type_abort(element, MONS_DISPATCH_TABLE_ENTRY);
+ struct request_helper_data *helper_data = data;
+
+ if (dispatch_entry_matches(entry, helper_data->command, helper_data->opt_type)) {
+ json_object_set(helper_data->payload,
+ mon_opt_type_to_string(entry->opt_type),
+ entry->handler(entry->cookie));
+ }
+}
+
+++ /dev/null
-/*
- * 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.
- *
- */
-
-/* Handlers for monitoring "show" requests */
-
-#include <jansson.h>
-#include <talloc.h>
-
-#include <tr_debug.h>
-#include <mon_internal.h>
-#include "mons_handlers.h"
-
-typedef json_t *(MONS_SHOW_FUNC)(MONS_INSTANCE *mons);
-
-/* prototypes for the dispatch table */
-static json_t *handle_show_version(MONS_INSTANCE *mons);
-
-struct dispatch_table_entry {
- MON_OPT_TYPE opt_type;
- MONS_SHOW_FUNC *handler;
-};
-
-struct dispatch_table_entry dispatch_table[] = {
- {OPT_TYPE_SHOW_VERSION, handle_show_version},
- {OPT_TYPE_SHOW_SERIAL, NULL},
- {OPT_TYPE_SHOW_UPTIME, NULL},
- {OPT_TYPE_SHOW_TID_REQ_COUNT, NULL},
- {OPT_TYPE_SHOW_TID_REQ_PENDING, NULL},
- {OPT_TYPE_SHOW_ROUTES, NULL},
- {OPT_TYPE_SHOW_COMMUNITIES, NULL},
- {OPT_TYPE_UNKNOWN} /* must be the last entry */
-};
-
-/**
- * Should we include this opt_type in our response to this request?
- *
- * Returns 1 if the opt_type is in the options list, or if the options list
- * is empty.
- *
- * @param opt_type
- * @param req
- * @return 1 if the opt_type should be included, else 0
- */
-static int opt_requested(MON_OPT_TYPE opt_type, MON_REQ *req)
-{
- size_t ii;
-
- /* empty options list is a wildcard - return everything */
- if (mon_req_opt_count(req) == 0)
- return 1;
-
- /* check whether this opt_type is in the list */
- for (ii=0; ii<mon_req_opt_count(req); ii++) {
- if (opt_type == mon_req_opt_index(req, ii)->type)
- return 1;
- }
- return 0;
-}
-
-MON_RESP *mons_handle_show(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req)
-{
- struct dispatch_table_entry *entry = NULL;
- MON_RESP *resp = NULL;
- json_t *payload = NULL; /* entire payload */
- json_t *payload_item = NULL; /* payload for a single option */
-
- tr_debug("mons_handle_show: Handling a request");
-
- /* Start off by allocating our response with a generic error message */
- resp = mon_resp_new(mem_ctx,
- MON_RESP_ERROR,
- "Error processing show request",
- NULL);
- if (resp == NULL) {
- /* we can't respond, just return */
- tr_crit("mons_handle_show: Error allocating response structure.");
- goto cleanup;
- }
-
- /* Now get a JSON object for our return payload */
- payload = json_object();
- if (payload == NULL) {
- tr_crit("mons_handle_show: Error allocating response payload.");
- goto cleanup; /* This will return the generic error message set earlier */
- }
-
- tr_debug("mons_handle_show: Processing options");
-
- /* Now step through the dispatch table. Call each requested option type. */
- for (entry = dispatch_table; entry->opt_type != OPT_TYPE_UNKNOWN; entry++) {
- if (! opt_requested(entry->opt_type, req)) {
- tr_debug("mons_handle_show: Not including %s in response",
- mon_opt_type_to_string(entry->opt_type));
- } else {
- /* This option is needed. Add its response to our payload. */
- if (entry->handler == NULL) {
- tr_debug("mons_handle_show: Would include %s in response, but its handler is null",
- mon_opt_type_to_string(entry->opt_type));
- continue;
- }
-
- tr_debug("mons_handle_show: Including %s in response",
- mon_opt_type_to_string(entry->opt_type));
-
- payload_item = entry->handler(mons);
- if (payload_item == NULL) {
- tr_err("mons_handle_show: Error processing option %s", mon_opt_type_to_string(entry->opt_type));
- goto cleanup;
- }
- /* this steals the reference to payload_item */
- json_object_set_new(payload,
- mon_opt_type_to_string(entry->opt_type),
- payload_item);
- }
- }
-
- /* If we get here, then we successfully processed the request. Return a successful reply. */
- if (mon_resp_set_message(resp, "success") == 0) {
- /* Failed to set the response message to success - fail ironically */
- tr_crit("mons_handle_show: Error setting response message to 'success'");
- goto cleanup;
- }
-
- /* Attach the accumulated payload to the response */
- if (json_object_size(payload) > 0)
- mon_resp_set_payload(resp, payload);
-
- resp->code = MON_RESP_SUCCESS; /* at last... */
-
-cleanup:
- if (payload)
- json_decref(payload);
- return resp;
-}
-
-
-static json_t *handle_show_version(MONS_INSTANCE *mons)
-{
- return json_string(PACKAGE_VERSION);
-}
\ No newline at end of file
#include <event2/event.h>
#include <talloc.h>
#include <signal.h>
+#include <time.h>
#include <tid_internal.h>
#include <mon_internal.h>
pthread_sigmask(SIG_BLOCK, &signals, NULL);
}
+/* TODO move this function */
+static json_t *tr_mon_handle_version(void *cookie)
+{
+ return json_string(PACKAGE_VERSION);
+}
+
+static json_t *tr_mon_handle_uptime(void *cookie)
+{
+ time_t *start_time = cookie;
+ return json_integer(time(NULL) - (*start_time));
+}
+
int main(int argc, char *argv[])
{
TALLOC_CTX *main_ctx=NULL;
struct tr_socket_event mon_ev = {0};
struct event *cfgwatch_ev;
+ time_t start_time = time(NULL); /* TODO move this? */
+
configure_signals();
/* we're going to be multithreaded, so disable null context tracking */
tr->mons->tids = tr->tids;
tr->mons->trps = tr->trps;
+ /* TODO do this more systematically */
+ mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_VERSION, tr_mon_handle_version, NULL);
+ mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_UPTIME, tr_mon_handle_uptime, &start_time);
+
/***** process configuration *****/
tr->cfgwatch=tr_cfgwatch_create(tr);
if (tr->cfgwatch == NULL) {