Replace static monitor handler tables with dynamic handler registry
authorJennifer Richards <jennifer@painless-security.com>
Wed, 18 Apr 2018 03:38:27 +0000 (23:38 -0400)
committerJennifer Richards <jennifer@painless-security.com>
Wed, 18 Apr 2018 03:38:27 +0000 (23:38 -0400)
  * Keep a list of handlers as part of MONS_INSTANCE
    - each handles a command/opt_type pair
    - registered via mons_register_handler()
  * Scan the list of handlers when servicing a monitoring request
  * Add handlers for version and uptime, registered through tr_main.c
    (probably need to move these, but this works as a demo)

12 files changed:
CMakeLists.txt
Makefile.am
include/mon.h
include/mon_internal.h
include/mons_handlers.h [moved from mon/mons_handlers.h with 85% similarity]
include/tr_mon.h
mon/mon_common.c
mon/mon_req.c
mon/mons.c
mon/mons_handlers.c
mon/mons_handlers_show.c [deleted file]
tr/tr_main.c

index c970f02..f7bff87 100644 (file)
@@ -91,7 +91,7 @@ set(SOURCE_FILES
     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
     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})
 
 # Does not actually build!
 add_executable(trust_router ${SOURCE_FILES})
index 2df06b6..c73c623 100644 (file)
@@ -53,8 +53,7 @@ mon_srcs =                   \
 # monitoring server sources
 mons_srcs = \
     mon/mons.c \
 # 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
 
 check_PROGRAMS = common/t_constraint
 TESTS = common/t_constraint
index 037e717..33b8f4b 100644 (file)
@@ -54,6 +54,8 @@ typedef enum mon_rc MON_RC;
 typedef struct mons_instance MONS_INSTANCE;
 typedef struct monc_instance MONC_INSTANCE;
 
 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 *);
 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 *);
index d2d1572..8e439d2 100644 (file)
@@ -91,6 +91,7 @@ enum mon_resp_code {
 
 enum mon_opt_type {
   OPT_TYPE_UNKNOWN=0,
 
 enum mon_opt_type {
   OPT_TYPE_UNKNOWN=0,
+  OPT_TYPE_ANY,
 
   // System information
   OPT_TYPE_SHOW_VERSION,
 
   // System information
   OPT_TYPE_SHOW_VERSION,
@@ -131,6 +132,7 @@ struct mons_instance {
   MONS_REQ_FUNC *req_handler;
   MONS_AUTH_FUNC *auth_handler;
   void *cookie;
   MONS_REQ_FUNC *req_handler;
   MONS_AUTH_FUNC *auth_handler;
   void *cookie;
+  GPtrArray *handlers;
 };
 
 /* Client instance */
 };
 
 /* Client instance */
similarity index 85%
rename from mon/mons_handlers.h
rename to include/mons_handlers.h
index 03e2847..50bdd43 100644 (file)
 #ifndef TRUST_ROUTER_MONS_HANDLERS_H
 #define TRUST_ROUTER_MONS_HANDLERS_H
 
 #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.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
 
 #endif //TRUST_ROUTER_MONS_HANDLERS_H
index e956db2..15ab640 100644 (file)
@@ -38,6 +38,7 @@
 #include <tr_event.h>
 #include <tr_config.h>
 #include <mon_internal.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,
 
 int tr_mons_event_init(struct event_base *base,
                        MONS_INSTANCE *mons,
index d0317f7..440a277 100644 (file)
@@ -81,6 +81,7 @@ const char *mon_opt_type_to_string(MON_OPT_TYPE opt_type)
 {
   switch(opt_type) {
     case OPT_TYPE_UNKNOWN:
 {
   switch(opt_type) {
     case OPT_TYPE_UNKNOWN:
+    case OPT_TYPE_ANY:
       return NULL;
 
     case OPT_TYPE_SHOW_VERSION:
       return NULL;
 
     case OPT_TYPE_SHOW_VERSION:
index dd9de4d..bffa92e 100644 (file)
@@ -112,3 +112,4 @@ MON_OPT *mon_req_opt_index(MON_REQ *req, size_t index)
   MON_OPT *result = &g_array_index(req->options, MON_OPT, index);
   return result;
 }
   MON_OPT *result = &g_array_index(req->options, MON_OPT, index);
   return result;
 }
+
index 2216f5f..4d638d6 100644 (file)
 
 #include "mons_handlers.h"
 
 
 #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
  *
 /**
  * Allocate a new MONS_INSTANCE
  *
@@ -64,10 +73,20 @@ MONS_INSTANCE *mons_new(TALLOC_CTX *mem_ctx)
     mons->req_handler = NULL;
     mons->auth_handler = NULL;
     mons->cookie = NULL;
     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->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;
     }
   }
   return mons;
index 68abd48..b546b89 100644 (file)
 
 /* Handlers for monitoring requests */
 
 
 /* Handlers for monitoring requests */
 
+#include <gmodule.h>
+
 #include <tr_debug.h>
 #include <mon_internal.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;
   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
  *
 };
 
 /**
  * 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)
 {
  * @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");
 
 
   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;
 }
   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));
+  }
+}
+
diff --git a/mon/mons_handlers_show.c b/mon/mons_handlers_show.c
deleted file mode 100644 (file)
index e4d4d22..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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
index 7fad36f..3c74730 100644 (file)
@@ -38,6 +38,7 @@
 #include <event2/event.h>
 #include <talloc.h>
 #include <signal.h>
 #include <event2/event.h>
 #include <talloc.h>
 #include <signal.h>
+#include <time.h>
 
 #include <tid_internal.h>
 #include <mon_internal.h>
 
 #include <tid_internal.h>
 #include <mon_internal.h>
@@ -144,6 +145,18 @@ static void configure_signals(void)
   pthread_sigmask(SIG_BLOCK, &signals, NULL);
 }
 
   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;
 int main(int argc, char *argv[])
 {
   TALLOC_CTX *main_ctx=NULL;
@@ -155,6 +168,8 @@ int main(int argc, char *argv[])
   struct tr_socket_event mon_ev = {0};
   struct event *cfgwatch_ev;
 
   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 */
   configure_signals();
 
   /* we're going to be multithreaded, so disable null context tracking */
@@ -212,6 +227,10 @@ int main(int argc, char *argv[])
   tr->mons->tids = tr->tids;
   tr->mons->trps = tr->trps;
 
   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) {
   /***** process configuration *****/
   tr->cfgwatch=tr_cfgwatch_create(tr);
   if (tr->cfgwatch == NULL) {