Merge pull request #50 from painless-security/jennifer/refactoring_tids
[trust_router.git] / tr / tr_main.c
index 4f330ae..8c8202d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, JANET(UK)
+ * Copyright (c) 2012, 2015, JANET(UK)
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 #include <stdio.h>
-#include <jansson.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <event2/event.h>
+#include <talloc.h>
+#include <signal.h>
 
-#include <tr.h>
-#include <trust_router/tid.h>
+#include <tid_internal.h>
+#include <mon_internal.h>
+#include <tr_mon.h>
+#include <tr_tid.h>
+#include <tr_trp.h>
 #include <tr_config.h>
+#include <tr_event.h>
+#include <tr_cfgwatch.h>
+#include <tr.h>
+#include <tr_debug.h>
 
+#define TALLOC_DEBUG_ENABLE 1
 
-static int tids_req_handler (TIDS_INSTANCE * tids,
-                     TID_REQ *req, 
-                     TID_RESP **resp,
-                     void *cookie)
+/***** command-line option handling / setup *****/
+
+static void print_version_info(void)
 {
-  printf("Request received! Realm = %s, Comm = %s\n", req->realm->buf, req->comm->buf);
-  if (tids)
-    tids->req_count++;
+  printf("Moonshot Trust Router %s\n\n", PACKAGE_VERSION);
+}
 
-  return 0;
+/* Strip trailing / from a path name.*/
+static void remove_trailing_slash(char *s) {
+  size_t n;
+
+  n=strlen(s);
+  if(s[n-1]=='/') {
+    s[n-1]='\0';
+  }
+}
+
+/* argp global parameters */
+const char *argp_program_bug_address=PACKAGE_BUGREPORT; /* bug reporting address */
+
+/* doc strings */
+static const char doc[]=PACKAGE_NAME " - Moonshot Trust Router " PACKAGE_VERSION;
+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[] = {
+    { "config-dir", 'c', "DIR", 0, "Specify configuration file location (default is current directory)"},
+    { "config-validate", 'C', NULL, 0, "Validate configuration files and exit"},
+    { "version", 1, NULL, 0, "Print version information and exit"},
+    { NULL }
+};
+
+/* structure for communicating with option parser */
+struct cmdline_args {
+    int version_requested;
+    int validate_config_and_exit;
+    char *config_dir;
+};
+
+/* 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 'c':
+      if (arg == NULL) {
+        /* somehow we got called without an argument */
+        return ARGP_ERR_UNKNOWN;
+      }
+      arguments->config_dir=arg;
+      break;
+
+    case 1:
+      arguments->version_requested=1;
+      break;
+
+    case 'C':
+      arguments->validate_config_and_exit=1;
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+  }
+
+  return 0; /* success */
+}
+
+/* assemble the argp parser */
+static struct argp argp = {cmdline_options, parse_option, arg_doc, doc};
+
+
+/***** talloc error handling *****/
+/* called when talloc tries to abort */
+static void tr_abort(const char *reason)
+{
+  tr_crit("tr_abort: Critical error, talloc aborted. Reason: %s", reason);
+  abort();
+}
+
+#if TALLOC_DEBUG_ENABLE
+static void tr_talloc_log(const char *msg)
+{
+  tr_debug("talloc: %s", msg);
+}
+#endif /* TALLOC_DEBUG_ENABLE */
+
+static void configure_signals(void)
+{
+  sigset_t signals;
+  /* ignore SIGPIPE */
+  sigemptyset(&signals);
+  sigaddset(&signals, SIGPIPE);
+  pthread_sigmask(SIG_BLOCK, &signals, NULL);
 }
 
-int main (int argc, const char *argv[])
+int main(int argc, char *argv[])
 {
+  TALLOC_CTX *main_ctx=NULL;
+
   TR_INSTANCE *tr = NULL;
-  TIDS_INSTANCE *tids = NULL;
-  struct dirent **cfg_files = NULL;
-  json_t *jcfg = NULL;
-  TR_CFG_RC rc = TR_CFG_SUCCESS;       /* presume success */
-  int err = 0, n = 0;;
+  struct cmdline_args opts;
+  struct event_base *ev_base;
+  struct tr_socket_event tids_ev = {0};
+  struct tr_socket_event mon_ev = {0};
+  struct event *cfgwatch_ev;
+
+  configure_signals();
+
+  /* we're going to be multithreaded, so disable null context tracking */
+  talloc_set_abort_fn(tr_abort);
+  talloc_disable_null_tracking();
+#if TALLOC_DEBUG_ENABLE
+  talloc_set_log_fn(tr_talloc_log);
+#endif /* TALLOC_DEBUG_ENABLE */
+  main_ctx=talloc_new(NULL);
+
+  /* Use standalone logging */
+  tr_log_open();
+
+  /***** parse command-line arguments *****/
+  /* set defaults */
+  opts.version_requested=0;
+  opts.validate_config_and_exit=0;
+  opts.config_dir=".";
+
+  /* parse the command line*/
+  argp_parse(&argp, argc, argv, 0, 0, &opts);
 
-  /* parse command-line arguments -- TBD */
+  /* process options */
+  remove_trailing_slash(opts.config_dir);
 
-  /* create a Trust Router instance */
-  if (NULL == (tr = tr_create())) {
-    fprintf(stderr, "Unable to create Trust Router instance, exiting.\n");
+
+  /***** Print version info *****/
+  print_version_info();
+  if (opts.version_requested)
+    return 0; /* requested that we print version and exit */
+
+  /***** create a Trust Router instance *****/
+  if (NULL == (tr = tr_create(main_ctx))) {
+    tr_crit("Unable to create Trust Router instance, exiting.");
     return 1;
   }
 
-  /* find the configuration files */
-  if (0 == (n = tr_find_config_files(&cfg_files))) {
-    fprintf (stderr, "Can't locate configuration files, exiting.\n");
-    exit(1);
+  /***** initialize the trust path query server instance *****/
+  if (NULL == (tr->tids = tids_new(tr))) {
+    tr_crit("Error initializing Trust Path Query Server instance.");
+    return 1;
   }
 
-  /* read and parse initial configuration */
-  if (NULL == (jcfg = tr_read_config (n, cfg_files))) {
-    fprintf (stderr, "Error reading or parsing configuration files, exiting.\n");
-    exit(1);
+  /***** initialize the trust router protocol server instance *****/
+  if (NULL == (tr->trps = trps_new(tr))) {
+    tr_crit("Error initializing Trust Router Protocol Server instance.");
+    return 1;
   }
-  if (TR_CFG_SUCCESS != tr_parse_config(tr, jcfg)) {
-    fprintf (stderr, "Error decoding configuration information, exiting.\n");
-    exit(1);
+
+  /***** initialize the monitoring interface instance *****/
+  if (NULL == (tr->mons = mons_new(tr))) {
+    tr_crit("Error initializing monitoring interface instance.");
+    return 1;
   }
+  /* Monitor our tids/trps instances */
+  tr->mons->tids = tr->tids;
+  tr->mons->trps = tr->trps;
 
-  /* apply initial configuration */
-  if (TR_CFG_SUCCESS != (rc = tr_apply_new_config(tr))) {
-    fprintf (stderr, "Error applying configuration, rc = %d.\n", rc);
-    exit(1);
+  /***** process configuration *****/
+  tr->cfgwatch=tr_cfgwatch_create(tr);
+  if (tr->cfgwatch == NULL) {
+    tr_crit("Unable to create configuration watcher object, exiting.");
+    return 1;
+  }
+  tr->cfgwatch->config_dir=opts.config_dir;
+  tr->cfgwatch->cfg_mgr=tr->cfg_mgr;
+  tr->cfgwatch->update_cb=tr_config_changed; /* handle configuration changes */
+  tr->cfgwatch->update_cookie=(void *)tr;
+  if (0 != tr_read_and_apply_config(tr->cfgwatch)) {
+    tr_crit("Error reading configuration, exiting.");
+    return 1;
+  }
+
+  /***** Exit here if we are just validating our configuration *****/
+  if (opts.validate_config_and_exit) {
+    printf("Valid configuration found in %s.\n", opts.config_dir);
+    return 0;
+  }
+  /***** Set up the event loop *****/
+  ev_base=tr_event_loop_init(); /* Set up the event loop */
+  if (ev_base==NULL) {
+    tr_crit("Error initializing event loop.");
+    return 1;
+  }
+
+  /* already set config_dir, fstat_list and n_files earlier */
+  if (0 != tr_cfgwatch_event_init(ev_base, tr->cfgwatch, &cfgwatch_ev)) {
+    tr_crit("Error initializing configuration file watcher.");
+    return 1;
   }
 
-  //  printf("Trust Router Configured, max_tree_depth = %d.\n", tr->active_cfg->internal->max_tree_depth);
+  /* install monitoring interface events */
+  tr_debug("Initializing monitoring interface events.");
+  if (0 != tr_mons_event_init(ev_base, tr->mons, tr->cfg_mgr, &mon_ev)) {
+    tr_crit("Error initializing monitoring interface.");
+    return 1;
+  }
 
-  /* initialize the trust path query server instance */
-  if (0 == (tids = tids_create ())) {
-    printf ("Error initializing Trust Path Query Server instance.\n");
+  /* install TID server events */
+  tr_debug("Initializing TID server events.");
+  if (0 != tr_tids_event_init(ev_base,
+                              tr->tids,
+                              tr->cfg_mgr,
+                              tr->trps,
+                             &tids_ev)) {
+    tr_crit("Error initializing Trust Path Query Server instance.");
     return 1;
   }
 
-  /* start the trust path query server, won't return unless error. */
-  if (0 != (err = tids_start(tids, &tids_req_handler, NULL))) {
-    printf ("Error starting Trust Path Query Server, err = %d.\n", err);
-    return err;
+  /* install TRP handler events */
+  tr_debug("Initializing Dynamic Trust Router Protocol events.");
+  if (TRP_SUCCESS != tr_trps_event_init(ev_base, tr)) {
+    tr_crit("Error initializing Trust Path Query Server instance.");
+    return 1;
   }
 
-  tids_destroy(tids);
+  tr_debug("Starting event loop.");
+  tr_event_loop_run(ev_base); /* does not return until we are done */
+
+  tr_destroy(tr); /* thanks to talloc, should destroy everything */
+
+  talloc_free(main_ctx);
   return 0;
 }