More work on cleanup and the telnet interface
authorHenning Rogge <hrogge@googlemail.com>
Tue, 13 Sep 2011 17:03:21 +0000 (19:03 +0200)
committerHenning Rogge <hrogge@googlemail.com>
Tue, 13 Sep 2011 17:03:21 +0000 (19:03 +0200)
16 files changed:
config.txt
src/CMakeLists.txt
src/config/cfg_delta.c
src/config/cfg_delta.h
src/config/cfg_schema.c
src/core/olsr_logging_cfg.c
src/core/olsr_logging_cfg.h
src/core/olsr_logging_sources.c
src/core/olsr_logging_sources.h
src/core/olsr_stream_socket.c
src/core/olsr_stream_socket.h
src/core/olsr_telnet.c
src/core/olsr_telnet.h
src/olsr.c
src/olsr_setup.c [new file with mode: 0644]
src/olsr_setup.h [new file with mode: 0644]

index a37b2bc..73de432 100644 (file)
@@ -5,6 +5,7 @@
        plugin  test3
 
 [telnet]
-       acl     +10.0.0.0/8
-       acl     default_accept
-       bindto_v4       11.0.0.1
+#      acl     127.0.0.1/8
+#      acl     default_reject
+#      bindto_v4       11.0.0.1
+#      port    2006
index b758004..6b82639 100644 (file)
@@ -24,7 +24,7 @@ IF(BSD)
 ENDIF(BSD)
 
 # add main program
-set(OLSRD_SRCS ${OLSRD_SRCS} olsr.c)
+set(OLSRD_SRCS ${OLSRD_SRCS} olsr.c olsr_setup.c)
 
 # activate symbol export for win32
 IF(WIN32)
index 1f5f2d9..e00b337 100644 (file)
 #include "config/cfg_delta.h"
 
 static void _delta_section(struct cfg_delta *delta,
-    struct cfg_section_type *pre_change, struct cfg_section_type *post_change);
+    struct cfg_section_type *pre_change, struct cfg_section_type *post_change,
+    struct cfg_schema_section *schema);
 static void _handle_namedsection(struct cfg_delta *delta, const char *type,
-    struct cfg_named_section *pre_change, struct cfg_named_section *post_change);
+    struct cfg_named_section *pre_change, struct cfg_named_section *post_change,
+    struct cfg_schema_section *schema_section);
 static bool _setup_filterresults(struct cfg_delta_handler *handler,
-    struct cfg_named_section *pre_change, struct cfg_named_section *post_change);
+    struct cfg_named_section *pre_change, struct cfg_named_section *post_change,
+    struct cfg_schema_section *schema);
 static int _cmp_section_types(struct cfg_section_type *, struct cfg_section_type *);
 static int _cmp_named_section(struct cfg_named_section *, struct cfg_named_section *);
 
@@ -153,6 +156,8 @@ cfg_delta_calculate(struct cfg_delta *delta,
   struct cfg_section_type *section_pre = NULL, *section_post = NULL;
   struct cfg_named_section *named, *named_it;
   struct cfg_delta_handler *handler;
+  struct cfg_schema *schema;
+  struct cfg_schema_section *schema_section;
 
   /* cleanup delta handler flags */
   avl_for_each_element(&delta->handler, handler, node) {
@@ -161,6 +166,13 @@ cfg_delta_calculate(struct cfg_delta *delta,
     handler->post = NULL;
   }
 
+  /* initialize section handling */
+  schema = NULL;
+  schema_section = NULL;
+  if (pre_change->schema == post_change->schema) {
+    schema = pre_change->schema;
+  }
+
   /* iterate over section types */
   section_pre = avl_first_element_safe(&pre_change->sectiontypes, section_pre, node);
   section_post = avl_first_element_safe(&post_change->sectiontypes, section_post, node);
@@ -173,19 +185,28 @@ cfg_delta_calculate(struct cfg_delta *delta,
 
     if (cmp_sections < 0) {
       /* handle pre-section */
+      if (schema) {
+        schema_section = cfg_schema_find_section(schema, section_pre->type);
+      }
       CFG_FOR_ALL_SECTION_NAMES(section_pre, named, named_it) {
-        _handle_namedsection(delta, section_pre->type, named, NULL);
+        _handle_namedsection(delta, section_pre->type, named, NULL, schema_section);
       }
     }
     else if (cmp_sections > 0) {
       /* handle post-section */
+      if (schema) {
+        schema_section = cfg_schema_find_section(schema, section_post->type);
+      }
       CFG_FOR_ALL_SECTION_NAMES(section_post, named, named_it) {
-        _handle_namedsection(delta, section_post->type, NULL, named);
+        _handle_namedsection(delta, section_post->type, NULL, named, schema_section);
       }
     }
     else {
       /* type is available in both db's, this might be an change event */
-      _delta_section(delta, section_pre, section_post);
+      if (schema) {
+        schema_section = cfg_schema_find_section(schema, section_pre->type);
+      }
+      _delta_section(delta, section_pre, section_post, schema_section);
     }
 
     if (cmp_sections <= 0) {
@@ -236,7 +257,8 @@ _cmp_named_section(struct cfg_named_section *ptr1, struct cfg_named_section *ptr
  */
 static void
 _delta_section(struct cfg_delta *delta,
-    struct cfg_section_type *pre_change, struct cfg_section_type *post_change) {
+    struct cfg_section_type *pre_change, struct cfg_section_type *post_change,
+    struct cfg_schema_section *schema) {
   struct cfg_named_section *named_pre = NULL, *named_post = NULL;
 
   named_pre = avl_first_element_safe(&pre_change->names, named_pre, node);
@@ -250,15 +272,15 @@ _delta_section(struct cfg_delta *delta,
 
     if (cmp_sections < 0) {
       /* handle pre-named */
-      _handle_namedsection(delta, pre_change->type, named_pre, NULL);
+      _handle_namedsection(delta, pre_change->type, named_pre, NULL, schema);
     }
     else if (cmp_sections > 0) {
       /* handle post-section */
-      _handle_namedsection(delta, post_change->type, NULL, named_post);
+      _handle_namedsection(delta, post_change->type, NULL, named_post, schema);
     }
     else {
       /* named section is available in both db's, we have section change */
-      _handle_namedsection(delta, pre_change->type, named_pre, named_post);
+      _handle_namedsection(delta, pre_change->type, named_pre, named_post, schema);
     }
 
     if (cmp_sections <= 0) {
@@ -280,7 +302,8 @@ _delta_section(struct cfg_delta *delta,
  */
 static void
 _handle_namedsection(struct cfg_delta *delta, const char *type,
-    struct cfg_named_section *pre_change, struct cfg_named_section *post_change) {
+    struct cfg_named_section *pre_change, struct cfg_named_section *post_change,
+    struct cfg_schema_section *schema_section) {
   struct cfg_delta_handler *handler;
 
   avl_for_each_element(&delta->handler, handler, node) {
@@ -289,7 +312,7 @@ _handle_namedsection(struct cfg_delta *delta, const char *type,
     }
 
     if ((handler->_trigger_callback =
-        _setup_filterresults(handler, pre_change, post_change))) {
+        _setup_filterresults(handler, pre_change, post_change, schema_section))) {
       handler->pre = pre_change;
       handler->post = post_change;
 
@@ -315,8 +338,13 @@ _handle_namedsection(struct cfg_delta *delta, const char *type,
  */
 static bool
 _setup_filterresults(struct cfg_delta_handler *handler,
-    struct cfg_named_section *pre_change, struct cfg_named_section *post_change) {
+    struct cfg_named_section *pre_change, struct cfg_named_section *post_change,
+    struct cfg_schema_section *schema) {
+  const char *_EMPTY = "";
   struct cfg_entry *pre, *post;
+  struct cfg_schema_entry *schema_entry;
+  const char *pre_value, *post_value;
+  size_t pre_len, post_len;
   bool change;
   size_t i;
 
@@ -340,24 +368,46 @@ _setup_filterresults(struct cfg_delta_handler *handler,
     handler->filter[i].post = post;
 
     if (pre == NULL && post == NULL) {
-      handler->filter[i].delta = CFG_DELTA_NO_CHANGE;
+      handler->filter[i].changed = false;
+      continue;
     }
-    else if (pre == NULL) {
-      handler->filter[i].delta = CFG_DELTA_ADDED;
-      change = true;
+
+    pre_value = _EMPTY;
+    pre_len = 0;
+    post_value = _EMPTY;
+    post_len = 0;
+
+    if (pre) {
+      /* get value */
+      pre_value = pre->val.value;
+      pre_len = pre->val.length;
     }
-    else if (post == NULL) {
-      handler->filter[i].delta = CFG_DELTA_REMOVED;
-      change = true;
+    else if(schema) {
+      /* look for default value */
+      schema_entry = cfg_schema_find_entry(schema, post->name);
+      if (schema_entry) {
+        pre_value = schema_entry->t_default;
+        pre_len = strlen(pre_value) + 1;
+      }
     }
-    else if (pre->val.length == post->val.length
-        && memcmp(pre->val.value, post->val.value, pre->val.length) == 0) {
-      handler->filter[i].delta = CFG_DELTA_NO_CHANGE;
+
+    if (post) {
+      /* get value */
+      post_value = post->val.value;
+      post_len = post->val.length;
     }
-    else {
-      handler->filter[i].delta = CFG_DELTA_CHANGED;
-      change = true;
+    else if(schema) {
+      /* look for default value */
+      schema_entry = cfg_schema_find_entry(schema, pre->name);
+      if (schema_entry) {
+        post_value = schema_entry->t_default;
+        post_len = strlen(post_value) + 1;
+      }
     }
+
+    handler->filter[i].changed = (pre_len != post_len)
+        || (memcmp(pre_value, post_value, pre_len) != 0);
+    change |= handler->filter[i].changed;
   }
   return change;
 }
index 7b14a97..4fa1d41 100644 (file)
@@ -108,14 +108,6 @@ struct cfg_delta_handler {
   struct cfg_named_section *pre, *post;
 };
 
-/* type of change that happened for a filter */
-enum cfg_delta_event {
-  CFG_DELTA_NO_CHANGE = 0,
-  CFG_DELTA_ADDED     = 1,
-  CFG_DELTA_CHANGED   = 2,
-  CFG_DELTA_REMOVED   = 3,
-};
-
 /**
  * One filter entry for a delta handler filter.
  * Only "k" must be filled by the user.
@@ -124,11 +116,8 @@ struct cfg_delta_filter {
   /* key of the entry this filter matches */
   const char *k;
 
-  /*
-   * defines the change happened for the filters entry,
-   * set by cfg_delta_calculate()
-   */
-  enum cfg_delta_event delta;
+  /* true if parameter was changed */
+  bool changed;
 
   /*
    * Pointer to entry before and after the change.
index 5698920..c62a90a 100644 (file)
@@ -352,7 +352,6 @@ cfg_schema_validate(struct cfg_db *db,
 int
 cfg_schema_tobin(void *target, struct cfg_named_section *named,
     const struct cfg_schema_entry *entries, size_t count) {
-  struct cfg_entry *db_entry;
   char *ptr;
   size_t i;
   struct cfg_stringarray default_array, *value;
@@ -364,15 +363,22 @@ cfg_schema_tobin(void *target, struct cfg_named_section *named,
       continue;
     }
 
-    db_entry = avl_find_element(&named->entries, entries[i].t_name, db_entry, node);
-    if (db_entry) {
-      value = &db_entry->val;
-    }
-    else if (entries[i].t_default == NULL) {
-      /* missing mandatory entry */
-      return -1;
+    /* cleanup pointer */
+    value = NULL;
+
+    if (named) {
+      struct cfg_entry *db_entry;
+      db_entry = avl_find_element(&named->entries, entries[i].t_name, db_entry, node);
+      if (db_entry) {
+        value = &db_entry->val;
+      }
     }
-    else {
+
+    if (value == NULL) {
+      if (entries[i].t_default == NULL) {
+        /* missing mandatory entry */
+        return -1;
+      }
       memcpy(&default_array.value, &entries[i].t_default, sizeof(default_array.value));
       default_array.last_value = default_array.value;
       default_array.length = strlen(default_array.value);
index 71a5441..bea8442 100644 (file)
@@ -115,15 +115,18 @@ OLSR_SUBSYSTEM_STATE(olsr_logcfg_state);
 /**
  * Initialize logging configuration
  * @param debug_lvl_1_ptr array of logging sources for debug level 1
- * @param count number of logging sources in array
  */
 void
-olsr_logcfg_init(enum log_source *debug_lvl_1_ptr, size_t count) {
+olsr_logcfg_init(enum log_source *debug_lvl_1_ptr) {
+  size_t i;
   if (olsr_subsystem_init(&olsr_logcfg_state))
     return;
 
   debug_lvl_1 = debug_lvl_1_ptr;
-  debug_lvl_1_count = count;
+
+  for (i=0; debug_lvl_1_ptr[i] > 0; i++);
+
+  debug_lvl_1_count = i;
 
   memset(&logging_cfg, 0, sizeof(logging_cfg));
 
index 4593799..f24bf6c 100644 (file)
@@ -48,7 +48,7 @@
 
 #include "olsr_logging.h"
 
-void olsr_logcfg_init(enum log_source *debug_lvl_1, size_t count);
+void olsr_logcfg_init(enum log_source *debug_lvl_1);
 void olsr_logcfg_cleanup(void);
 void olsr_logcfg_addschema(struct cfg_schema *schema);
 int olsr_logcfg_apply(struct cfg_db *db) __attribute__((warn_unused_result));
index 2f9a438..f096527 100644 (file)
@@ -58,4 +58,6 @@ const char *LOG_SOURCE_NAMES[LOG_SOURCE_COUNT] = {
   "socket-packet",
   "plugin-loader",
   "telnet",
+
+  /* add you custom logging sources here */
 };
index c2c6223..4631f52 100644 (file)
@@ -60,6 +60,8 @@ enum log_source {
   LOG_PLUGINLOADER,
   LOG_TELNET,
 
+  /* add you custom logging sources here */
+
   /* this one must be the last of the enums ! */
   LOG_SOURCE_COUNT
 };
index 59f44ee..2eb94a1 100644 (file)
@@ -249,6 +249,11 @@ connect_to_error:
   return NULL;
 }
 
+void
+olsr_stream_set_timeout(struct olsr_stream_session *con, uint32_t timeout) {
+  olsr_timer_set(&con->timeout, timeout, 0, con, connection_timeout);
+}
+
 static void
 _parse_request(int fd, void *data, unsigned int flags) {
   struct olsr_stream_socket *comport;
@@ -311,17 +316,17 @@ _create_session(struct olsr_stream_socket *comport,
 
   session->send_first = comport->send_first;
   session->comport = comport;
-  memcpy(&session->peer_addr, &remote_addr, sizeof(session->peer_addr));
+  session->peer_addr = *remote_addr;
 
   if (comport->allowed_sessions-- > 0) {
     /* create active session */
-    session->state = COMPORT_SESSION_ACTIVE;
+    session->state = STREAM_SESSION_ACTIVE;
   } else {
     /* too many sessions */
     if (comport->create_error) {
-      comport->create_error(session, SERVICE_UNAVAILABLE);
+      comport->create_error(session, STREAM_SERVICE_UNAVAILABLE);
     }
-    session->state = COMPORT_SESSION_SEND_AND_QUIT;
+    session->state = STREAM_SESSION_SEND_AND_QUIT;
   }
 
   if (comport->session_timeout) {
@@ -397,12 +402,12 @@ _parse_connection(int fd, void *data,
       if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &value, &value_len)) {
         OLSR_WARN(LOG_SOCKET_STREAM, "getsockopt failed: %s (%d)",
             strerror(errno), errno);
-        session->state = COMPORT_SESSION_CLEANUP;
+        session->state = STREAM_SESSION_CLEANUP;
       }
       else if (value != 0) {
         OLSR_WARN(LOG_SOCKET_STREAM, "Connection to %s failed: %s (%d)",
             netaddr_socket_to_string(&buf, &session->peer_addr), strerror(value), value);
-        session->state = COMPORT_SESSION_CLEANUP;
+        session->state = STREAM_SESSION_CLEANUP;
       }
       else {
         session->wait_for_connect = false;
@@ -415,7 +420,7 @@ _parse_connection(int fd, void *data,
   }
 
   /* read data if necessary */
-  if (session->state == COMPORT_SESSION_ACTIVE && (flags & OLSR_SOCKET_READ)
+  if (session->state == STREAM_SESSION_ACTIVE && (flags & OLSR_SOCKET_READ)
       != 0) {
     len = recv(fd, buffer, sizeof(buffer), 0);
     if (len > 0) {
@@ -423,13 +428,13 @@ _parse_connection(int fd, void *data,
       if (abuf_memcpy(&session->in, buffer, len)) {
         /* out of memory */
         OLSR_WARN(LOG_SOCKET_STREAM, "Out of memory for comport session input buffer");
-        session->state = COMPORT_SESSION_CLEANUP;
+        session->state = STREAM_SESSION_CLEANUP;
       } else if (session->in.len > comport->maximum_input_buffer) {
         /* input buffer overflow */
         if (comport->create_error) {
-          comport->create_error(session, REQUEST_TOO_LARGE);
+          comport->create_error(session, STREAM_REQUEST_TOO_LARGE);
         }
-        session->state = COMPORT_SESSION_SEND_AND_QUIT;
+        session->state = STREAM_SESSION_SEND_AND_QUIT;
       } else {
         /* got new input block, reset timeout */
         olsr_timer_change(session->timeout, comport->session_timeout, 0);
@@ -439,21 +444,21 @@ _parse_connection(int fd, void *data,
       /* error during read */
       OLSR_WARN(LOG_SOCKET_STREAM, "Error while reading from communication stream with %s: %s (%d)\n",
           netaddr_socket_to_string(&buf, &session->peer_addr), strerror(errno), errno);
-      session->state = COMPORT_SESSION_CLEANUP;
+      session->state = STREAM_SESSION_CLEANUP;
     } else if (len == 0) {
       /* external socket closed */
-      session->state = COMPORT_SESSION_SEND_AND_QUIT;
+      session->state = STREAM_SESSION_SEND_AND_QUIT;
     }
   }
 
-  if (session->state == COMPORT_SESSION_ACTIVE && comport->receive_data != NULL
+  if (session->state == STREAM_SESSION_ACTIVE && comport->receive_data != NULL
       && (session->in.len > 0 || session->send_first)) {
     session->state = comport->receive_data(session);
     session->send_first = false;
   }
 
   /* send data if necessary */
-  if (session->state != COMPORT_SESSION_CLEANUP && session->out.len > 0) {
+  if (session->state != STREAM_SESSION_CLEANUP && session->out.len > 0) {
     if (flags & OLSR_SOCKET_WRITE) {
       len = send(fd, session->out.buf, session->out.len, 0);
 
@@ -465,7 +470,7 @@ _parse_connection(int fd, void *data,
           != EWOULDBLOCK) {
         OLSR_WARN(LOG_SOCKET_STREAM, "Error while writing to communication stream with %s: %s (%d)\n",
             netaddr_socket_to_string(&buf, &session->peer_addr), strerror(errno), errno);
-        session->state = COMPORT_SESSION_CLEANUP;
+        session->state = STREAM_SESSION_CLEANUP;
       }
     } else {
       OLSR_DEBUG(LOG_SOCKET_STREAM, "  activating output in scheduler\n");
@@ -477,13 +482,13 @@ _parse_connection(int fd, void *data,
     /* nothing to send anymore */
     OLSR_DEBUG(LOG_SOCKET_STREAM, "  deactivating output in scheduler\n");
     olsr_socket_disable(session->scheduler_entry, OLSR_SOCKET_WRITE);
-    if (session->state == COMPORT_SESSION_SEND_AND_QUIT) {
-      session->state = COMPORT_SESSION_CLEANUP;
+    if (session->state == STREAM_SESSION_SEND_AND_QUIT) {
+      session->state = STREAM_SESSION_CLEANUP;
     }
   }
 
   /* end of connection ? */
-  if (session->state == COMPORT_SESSION_CLEANUP) {
+  if (session->state == STREAM_SESSION_CLEANUP) {
     OLSR_DEBUG(LOG_SOCKET_STREAM, "  cleanup\n");
 
     /* clean up connection by calling cleanup directly */
index a0c0276..f38b3a4 100644 (file)
 #include "olsr_memcookie.h"
 
 enum olsr_stream_session_state {
-  COMPORT_SESSION_ACTIVE,
-  COMPORT_SESSION_SEND_AND_QUIT,
-  COMPORT_SESSION_CLEANUP
+  STREAM_SESSION_ACTIVE,
+  STREAM_SESSION_SEND_AND_QUIT,
+  STREAM_SESSION_CLEANUP
 };
 
 enum olsr_stream_errors {
-  REQUEST_TOO_LARGE = 413,
-  SERVICE_UNAVAILABLE = 503
+  STREAM_REQUEST_TOO_LARGE = 413,
+  STREAM_SERVICE_UNAVAILABLE = 503
 };
 
 /* represents a TCP stream */
@@ -171,4 +171,7 @@ EXPORT struct olsr_stream_session *olsr_stream_connect_to(
     struct olsr_stream_socket *, union netaddr_socket *remote);
 EXPORT void olsr_stream_flush(struct olsr_stream_session *con);
 
+EXPORT void olsr_stream_set_timeout(
+    struct olsr_stream_session *con, uint32_t timeout);
+
 #endif /* OLSR_STREAM_SOCKET_H_ */
index 9006f91..6d4329d 100644 (file)
@@ -6,17 +6,29 @@
  */
 
 #include "common/common_types.h"
+#include "common/avl.h"
 
 #include "config/cfg_delta.h"
 #include "config/cfg_schema.h"
 
 #include "olsr_cfg.h"
 #include "olsr_logging.h"
+#include "olsr_memcookie.h"
 #include "olsr_netaddr_acl.h"
+#include "olsr_stream_socket.h"
+#include "olsr_timer.h"
 #include "olsr.h"
 #include "olsr_telnet.h"
 
-static void _config_changed(void);
+#define _CFG_TELNET_SECTION "telnet"
+
+/* variable definitions */
+enum cfg_telnet_idx {
+  _CFG_TELNET_ACL,
+  _CFG_TELNET_BINDTO_V4,
+  _CFG_TELNET_BINDTO_V6,
+  _CFG_TELNET_PORT,
+};
 
 struct telnet_config {
   struct olsr_netaddr_acl acl;
@@ -25,39 +37,85 @@ struct telnet_config {
   uint16_t port;
 };
 
+/* static function prototypes */
+static void _config_changed(void);
+static int _apply_config(struct cfg_named_section *section);
+static int _setup_socket(struct olsr_stream_socket *sock,
+    struct netaddr *bindto, uint16_t port);
+static void _telnet_init(struct olsr_stream_session *);
+static void _telnet_cleanup(struct olsr_stream_session *);
+static void _telnet_create_error(struct olsr_stream_session *,
+    enum olsr_stream_errors);
+static enum olsr_stream_session_state _telnet_receive_data(
+    struct olsr_stream_session *);
+
+/* global and static variables */
 static struct cfg_schema_section telnet_section = {
-  .t_type = "telnet",
+  .t_type = _CFG_TELNET_SECTION,
   .t_help = "Settings for the telnet interface",
 };
 
 static struct cfg_schema_entry telnet_entries[] = {
-  CFG_MAP_ACL_V46(telnet_config, acl, "127.0.0.1",
+  [_CFG_TELNET_ACL] = CFG_MAP_ACL_V46(telnet_config, acl, "127.0.0.1",
       "Access control list for telnet interface"),
-  CFG_MAP_NETADDR_V4(telnet_config, bindto_v4, "0.0.0.0",
+  [_CFG_TELNET_BINDTO_V4] = CFG_MAP_NETADDR_V4(telnet_config, bindto_v4, "127.0.0.1",
       "Bind ipv4 socket to this address", false),
-  CFG_MAP_NETADDR_V6(telnet_config, bindto_v6, "::",
+  [_CFG_TELNET_BINDTO_V6] = CFG_MAP_NETADDR_V6(telnet_config, bindto_v6, "::1",
       "Bind ipv6 socket to this address", false),
-  CFG_MAP_INT_MINMAX(telnet_config, port, "2006",
+  [_CFG_TELNET_PORT] = CFG_MAP_INT_MINMAX(telnet_config, port, "2006",
       "Network port for telnet interface", 1, 65535),
 };
 
-static struct cfg_delta_handler telnet_handler = {
-  .s_type = "telnet",
-  .callback = _config_changed
-};
+static struct cfg_delta_filter telnet_filter[ARRAYSIZE(telnet_entries) + 1];
+
+static struct cfg_delta_handler telnet_handler;
+
+/* configuration of telnet interface */
+static struct telnet_config _telnet_config;
+static struct olsr_stream_socket _telnet_v4, _telnet_v6;
+static struct olsr_netaddr_acl _telnet_acl;
 
 /* remember if initialized or not */
 OLSR_SUBSYSTEM_STATE(olsr_telnet_state);
 
-void
+/* memcookie for telnet sessions */
+static struct olsr_memcookie_info *_telnet_memcookie;
+
+/* tree of telnet commands */
+struct avl_tree telnet_cmd_tree;
+
+int
 olsr_telnet_init(void) {
+  struct cfg_named_section *section;
   if (olsr_subsystem_init(&olsr_telnet_state))
-    return;
+    return 0;
+
+  _telnet_memcookie = olsr_memcookie_add("telnet session",
+      sizeof(struct olsr_telnet_session));
+  if (_telnet_memcookie == NULL) {
+    return -1;
+  }
 
   cfg_schema_add_section(olsr_cfg_get_schema(), &telnet_section);
   cfg_schema_add_entries(&telnet_section, telnet_entries, ARRAYSIZE(telnet_entries));
 
-  cfg_delta_add_handler(olsr_cfg_get_delta(), &telnet_handler);
+  cfg_delta_add_handler_by_schema(
+      olsr_cfg_get_delta(), _config_changed, 0, &telnet_handler,
+      &telnet_filter[0], &telnet_section, &telnet_entries[0],
+      ARRAYSIZE(telnet_entries));
+
+  memset(&_telnet_config, 0, sizeof(_telnet_config));
+  memset(&_telnet_v4, 0, sizeof(_telnet_v4));
+  memset(&_telnet_v6, 0, sizeof(_telnet_v6));
+
+  section = cfg_db_find_unnamedsection(olsr_cfg_get_rawdb(),
+      _CFG_TELNET_SECTION);
+  if (_apply_config(section)) {
+    olsr_memcookie_remove(_telnet_memcookie);
+    olsr_subsystem_cleanup(&olsr_telnet_state);
+    return -1;
+  }
+  return 0;
 }
 
 void
@@ -65,29 +123,271 @@ olsr_telnet_cleanup(void) {
   if (olsr_subsystem_cleanup(&olsr_telnet_state))
     return;
 
+  olsr_stream_remove(&_telnet_v4);
+  olsr_stream_remove(&_telnet_v6);
+
   cfg_delta_remove_handler(olsr_cfg_get_delta(), &telnet_handler);
   cfg_schema_remove_section(olsr_cfg_get_schema(), &telnet_section);
+
+  olsr_stream_remove(&_telnet_v4);
+  olsr_stream_remove(&_telnet_v6);
+
+  olsr_memcookie_remove(_telnet_memcookie);
 }
 
+int
+olsr_telnet_add(struct olsr_telnet_command *command) {
+  command->node.key = command->command;
+  if (avl_insert(&telnet_cmd_tree, &command->node)) {
+    return -1;
+  }
+
+  /* default for empty acl should be 'accept' */
+  if (command->acl.accept_count + command->acl.reject_count == 0) {
+    command->acl.accept_default = true;
+  }
+  return 0;
+}
+
+void
+olsr_telnet_remove(struct olsr_telnet_command *command) {
+  avl_remove(&telnet_cmd_tree, &command->node);
+}
+
+
+
+
 static void
 _config_changed(void) {
-  struct telnet_config config;
-  struct netaddr_str buf;
-
+  _apply_config(telnet_handler.post);
+}
 
-  if (!telnet_handler.post)
-    return;
+static int
+_apply_config(struct cfg_named_section *section) {
+  struct telnet_config config;
 
+  /* clear old config */
   memset(&config, 0, sizeof(config));
 
-  if (cfg_schema_tobin(&config, telnet_handler.post, telnet_entries, ARRAYSIZE(telnet_entries))) {
+  if (cfg_schema_tobin(&config, section, telnet_entries, ARRAYSIZE(telnet_entries))) {
     // error
     OLSR_WARN(LOG_TELNET, "Cannot map telnet config to binary data");
-    return;
+    return -1;
+  }
+
+  /* copy acl */
+  memcpy(&_telnet_acl, &config.acl, sizeof(_telnet_acl));
+
+  /* refresh sockets */
+  if (_setup_socket(&_telnet_v4, &config.bindto_v4, config.port)) {
+    return -1;
+  }
+  if (_setup_socket(&_telnet_v6, &config.bindto_v6, config.port)) {
+    return -1;
+  }
+  return 0;
+}
+
+static int
+_setup_socket(struct olsr_stream_socket *sock, struct netaddr *bindto, uint16_t port) {
+  union netaddr_socket local;
+  struct netaddr_str buf;
+
+  /* generate local socket data */
+  netaddr_socket_init(&local, bindto, port);
+  OLSR_INFO(LOG_TELNET, "Opening telnet socket %s", netaddr_socket_to_string(&buf, &local));
+
+  /* check if change is really necessary */
+  if (memcmp(&sock->local_socket, &local, sizeof(local)) == 0) {
+    /* nothing to do */
+    return 0;
+  }
+
+  /* free olsr socket resources */
+  olsr_stream_remove(sock);
+
+  /* initialize new socket */
+  if (olsr_stream_add(sock, &local)) {
+    memset(sock, 0, sizeof(*sock));
+    return -1;
+  }
+  sock->session_timeout = 120000; /* 120 seconds */
+  sock->maximum_input_buffer = 4096;
+  sock->allowed_sessions = 3;
+  sock->memcookie = _telnet_memcookie;
+  sock->init = _telnet_init;
+  sock->cleanup = _telnet_cleanup;
+  sock->receive_data = _telnet_receive_data;
+  sock->create_error = _telnet_create_error;
+  return 0;
+}
+
+static void
+_telnet_init(struct olsr_stream_session *session) {
+  struct olsr_telnet_session *telnet_session;
+
+  /* get telnet session pointer */
+  telnet_session = (struct olsr_telnet_session *)session;
+
+  telnet_session->show_echo = true;
+  telnet_session->stop_handler = NULL;
+  telnet_session->timeout_value = 120000;
+}
+
+static void
+_telnet_cleanup(struct olsr_stream_session *session) {
+  struct olsr_telnet_session *telnet_session;
+
+  /* get telnet session pointer */
+  telnet_session = (struct olsr_telnet_session *)session;
+  if (telnet_session->stop_handler) {
+    telnet_session->stop_handler(telnet_session);
+    telnet_session->stop_handler = NULL;
+  }
+}
+
+static void
+_telnet_create_error(struct olsr_stream_session *session,
+    enum olsr_stream_errors error) {
+  switch(error) {
+    case STREAM_REQUEST_TOO_LARGE:
+      abuf_puts(&session->out, "Input buffer overflow, ending connection\n");
+      break;
+    case STREAM_SERVICE_UNAVAILABLE:
+      abuf_puts(&session->out, "Telnet service unavailable, too many sessions\n");
+      break;
+  }
+}
+
+static enum olsr_stream_session_state
+_telnet_receive_data(struct olsr_stream_session *session) {
+  static const char defaultCommand[] = "/link/neigh/topology/hna/mid/routes";
+  static char tmpbuf[128];
+
+  struct olsr_telnet_session *telnet_session;
+  enum olsr_txtcommand_result res;
+  char *eol;
+  int len;
+  bool processedCommand = false, chainCommands = false;
+  uint32_t old_timeout;
+
+  struct netaddr remote;
+  int ret;
+
+  /* get telnet session pointer */
+  telnet_session = (struct olsr_telnet_session *)session;
+
+  /* check ACL */
+  ret = netaddr_from_socket(&remote, &session->peer_addr);
+  if (ret != 0 || !olsr_acl_check_accept(&_telnet_acl, &remote)) {
+    struct netaddr_str buf;
+    OLSR_INFO(LOG_TELNET, "Illegal access from %s",
+        netaddr_socket_to_string(&buf, &session->peer_addr));
+
+    return STREAM_SESSION_SEND_AND_QUIT;
+  }
+
+  old_timeout = session->timeout->timer_period;
+
+  /* loop over input */
+  while (session->in.len > 0 && session->state == STREAM_SESSION_ACTIVE) {
+    char *para = NULL, *cmd = NULL, *next = NULL;
+
+    /* search for end of line */
+    eol = memchr(session->in.buf, '\n', session->in.len);
+
+    if (eol == NULL) {
+      break;
+    }
+
+    /* terminate line with a 0 */
+    if (eol != session->in.buf && eol[-1] == '\r') {
+      eol[-1] = 0;
+    }
+    *eol++ = 0;
+
+    /* handle line */
+    OLSR_DEBUG(LOG_TELNET, "Interactive console: %s\n", session->in.buf);
+    cmd = &session->in.buf[0];
+    processedCommand = true;
+
+    /* apply default command */
+    if (strcmp(cmd, "/") == 0) {
+      strcpy(tmpbuf, defaultCommand);
+      cmd = tmpbuf;
+    }
+
+    if (cmd[0] == '/') {
+      cmd++;
+      chainCommands = true;
+    }
+    while (cmd) {
+      len = session->out.len;
+
+      /* handle difference between multicommand and singlecommand mode */
+      if (chainCommands) {
+        next = strchr(cmd, '/');
+        if (next) {
+          *next++ = 0;
+        }
+      }
+      para = strchr(cmd, ' ');
+      if (para != NULL) {
+        *para++ = 0;
+      }
+
+      /* if we are doing continous output, stop it ! */
+      if (telnet_session->stop_handler) {
+        telnet_session->stop_handler(telnet_session);
+        telnet_session->stop_handler = NULL;
+      }
+
+      if (strlen(cmd) != 0) {
+        res = ACTIVE;
+        // TODO res = olsr_com_handle_txtcommand(con, cmd, para);
+        switch (res) {
+          case ACTIVE:
+            break;
+          case CONTINOUS:
+            break;
+          case ABUF_ERROR:
+            session->out.len = len;
+            abuf_appendf(&session->out,
+                "Error in autobuffer during command '%s'.\n", cmd);
+            break;
+          case UNKNOWN:
+            session->out.len = len;
+            abuf_appendf(&session->out, "Error, unknown command '%s'\n", cmd);
+            break;
+          case QUIT:
+            session->state = STREAM_SESSION_SEND_AND_QUIT;
+            break;
+        }
+        /* put an empty line behind each command */
+        if (telnet_session->show_echo) {
+          abuf_puts(&session->out, "\n");
+        }
+      }
+      cmd = next;
+    }
+
+    /* remove line from input buffer */
+    abuf_pull(&session->in, eol - session->in.buf);
+
+    if (session->in.buf[0] == '/') {
+      /* end of multiple command line */
+      session->state = STREAM_SESSION_SEND_AND_QUIT;
+    }
+  }
+
+  /* reset timeout */
+  olsr_stream_set_timeout(session, telnet_session->timeout_value);
+
+  /* print prompt */
+  if (processedCommand && session->state == STREAM_SESSION_ACTIVE
+      && telnet_session->show_echo) {
+    abuf_puts(&session->out, "> ");
   }
 
-  OLSR_INFO(LOG_TELNET, "Testing %s: %s", netaddr_to_string(&buf, &config.bindto_v4),
-      olsr_acl_check_accept(&config.acl, &config.bindto_v4) ? "true" : "false");
-  OLSR_INFO(LOG_TELNET, "Testing %s: %s", netaddr_to_string(&buf, &config.bindto_v6),
-      olsr_acl_check_accept(&config.acl, &config.bindto_v6) ? "true" : "false");
+  return STREAM_SESSION_ACTIVE;
 }
index 584217b..a56de28 100644 (file)
@@ -9,26 +9,55 @@
 #define OLSR_TELNET_H_
 
 #include "common/common_types.h"
+#include "common/avl.h"
+#include "olsr_netaddr_acl.h"
+#include "olsr_stream_socket.h"
+
+enum olsr_txtcommand_result {
+  ACTIVE,
+  CONTINOUS,
+  QUIT,
+  ABUF_ERROR,
+  UNKNOWN,
+};
+
+struct olsr_telnet_session {
+  struct olsr_stream_session session;
+
+  /* remember if echo mode is active */
+  bool show_echo;
+
+  /* millisecond timeout between commands */
+  uint32_t timeout_value;
 
-typedef enum olsr_txtcommand_result (*olsr_txthandler)
-    (void *con, const char *command, const char *parameter);
+  /* callback and data to stop a continous output txt command */
+  void (*stop_handler)(struct olsr_telnet_session *);
+  void *stop_data[4];
 
-struct olsr_txtcommand {
+};
+
+typedef enum olsr_txtcommand_result (*olsr_telnethandler)
+    (struct olsr_telnet_session *con, const char *command, const char *parameter);
+
+struct olsr_telnet_command {
   struct avl_node node;
   const char *command;
 
   const char *help;
 
-  struct ip_acl *acl;
+  struct olsr_netaddr_acl acl;
 
-  olsr_txthandler handler;
-  olsr_txthandler help_handler;
+  olsr_telnethandler handler;
+  olsr_telnethandler help_handler;
 };
 
-void olsr_telnet_init(void);
+#define FOR_ALL_TELNET_COMMANDS(cmd, ptr) avl_for_each_element_safe(&telnet_cmd_tree, cmd, node, ptr)
+EXPORT struct avl_tree telnet_cmd_tree;
+
+int olsr_telnet_init(void);
 void olsr_telnet_cleanup(void);
 
-//EXPORT int olsr_telnet_add(struct olsr_telnet_command *command);
-//EXPORT void olsr_telnet_remove(struct olsr_telnet_command *command);
+EXPORT int olsr_telnet_add(struct olsr_telnet_command *command);
+EXPORT void olsr_telnet_remove(struct olsr_telnet_command *command);
 
 #endif /* OLSR_TELNET_H_ */
index 3583e17..b005932 100644 (file)
@@ -68,6 +68,7 @@
 #include "olsr_stream_socket.h"
 #include "olsr_telnet.h"
 #include "olsr_timer.h"
+#include "olsr_setup.h"
 #include "olsr.h"
 
 static bool running, reload_config, exit_called;
@@ -96,7 +97,7 @@ static struct option olsr_options[] = {
 
 #if !defined(REMOVE_HELPTEXT)
 static const char *help_text =
-    "Activates OLSR.org routing daemon\n"
+    OLSR_SETUP_HELP_HEADLINE
     "Mandatory arguments to long options are mandatory for short options too.\n"
     "  -h, --help                             Display this help file\n"
     "  -v, --version                          Display the version string and the included static plugins\n"
@@ -124,11 +125,6 @@ static const char *help_text =
 ;
 #endif
 
-/* logging sources included in debug level 1 */
-static enum log_source level_1_sources[] = {
-    LOG_MAIN,
-};
-
 /* name of default configuration file */
 static const char *DEFAULT_CONFIGFILE = OLSRD_GLOBAL_CONF_FILE;
 
@@ -170,8 +166,13 @@ main(int argc, char **argv) {
     goto olsrd_cleanup;
   }
 
+  /* add custom configuration definitions */
+  if (olsr_setup_cfginit()) {
+    goto olsrd_cleanup;
+  }
+
   /* initialize logging to config interface */
-  olsr_logcfg_init(level_1_sources, ARRAYSIZE(level_1_sources));
+  olsr_logcfg_init(olsr_setup_debuglevel1);
   olsr_logcfg_addschema(olsr_cfg_get_schema());
 
   /* load static plugins */
@@ -189,7 +190,7 @@ main(int argc, char **argv) {
 
   /* TODO: check if we are root, otherwise stop */
   if (0 && geteuid()) {
-    OLSR_WARN(LOG_MAIN, "You must be root(uid = 0) to run olsrd!\n");
+    OLSR_WARN(LOG_MAIN, "You must be root(uid = 0) to run "OLSR_SETUP_PROGRAM"!\n");
     goto olsrd_cleanup;
   }
 
@@ -224,7 +225,14 @@ main(int argc, char **argv) {
   if (olsr_stream_init()) {
     goto olsrd_cleanup;
   }
-  olsr_telnet_init();
+  if (olsr_telnet_init()) {
+    goto olsrd_cleanup;
+  }
+
+  /* activate custom additions to framework */
+  if (olsr_setup_init()) {
+    goto olsrd_cleanup;
+  }
 
   /* activate plugins */
   olsr_plugins_init();
@@ -262,6 +270,9 @@ olsrd_cleanup:
   /* free plugins */
   olsr_plugins_cleanup();
 
+  /* free custom framework additions */
+  olsr_setup_cleanup();
+
   /* free framework resources */
   olsr_telnet_cleanup();
   olsr_stream_cleanup();
@@ -272,13 +283,13 @@ olsrd_cleanup:
   olsr_logcfg_cleanup();
 
   /* free configuration resources */
+  olsr_setup_cfgcleanup();
   olsr_cfg_cleanup();
 
   /* free logger resources */
   olsr_log_cleanup();
 
   if (fork_pipe != -1) {
-    fprintf(stderr, "Errorcode: %d\n", return_code);
     /* tell main process that we had a problem */
     daemonize_finish(fork_pipe, return_code);
   }
@@ -319,7 +330,7 @@ mainloop(int argc, char **argv) {
   uint32_t next_interval;
   int exit_code = 0;
 
-  OLSR_INFO(LOG_MAIN, "Starting olsr.org adapter daemon");
+  OLSR_INFO(LOG_MAIN, "Starting "OLSR_SETUP_PROGRAM".");
 
   /* enter main loop */
   while (running) {
@@ -344,6 +355,7 @@ mainloop(int argc, char **argv) {
 
     /* reload configuration if triggered */
     if (reload_config) {
+      OLSR_INFO(LOG_MAIN, "Reloading configuration");
       if (olsr_cfg_create_new_rawdb()) {
         running = false;
       }
@@ -361,7 +373,7 @@ mainloop(int argc, char **argv) {
     exit_code = 1;
   }
 
-  OLSR_INFO(LOG_MAIN, "Ending olsr.org daemon");
+  OLSR_INFO(LOG_MAIN, "Ending "OLSR_SETUP_PROGRAM".");
   return exit_code;
 }
 
diff --git a/src/olsr_setup.c b/src/olsr_setup.c
new file mode 100644 (file)
index 0000000..c25b4e7
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * olsr_setup.c
+ *
+ *  Created on: Sep 13, 2011
+ *      Author: rogge
+ */
+
+#include "common/common_types.h"
+#include "olsr.h"
+#include "olsr_setup.h"
+
+/* define the logging sources that are part of debug level 1 */
+static enum log_source _level_1_sources[] = {
+    LOG_MAIN,
+    0,
+};
+
+enum log_source *olsr_setup_debuglevel1 = _level_1_sources;
+
+/* remember if initialized or not */
+OLSR_SUBSYSTEM_STATE(olsr_setupcfg_state);
+OLSR_SUBSYSTEM_STATE(olsr_setup_state);
+
+
+int
+olsr_setup_cfginit(void) {
+  if (olsr_subsystem_init(&olsr_setupcfg_state))
+    return 0;
+
+  /* add custom configuration setup here */
+
+
+  /* no error happened */
+  return 0;
+}
+
+void
+olsr_setup_cfgcleanup(void) {
+  if (olsr_subsystem_cleanup(&olsr_setupcfg_state))
+    return;
+
+  /* add cleanup for custom configuration setup here */
+}
+
+int
+olsr_setup_init(void) {
+  if (olsr_subsystem_init(&olsr_setup_state))
+    return 0;
+
+  /* add custom service setup here */
+
+
+  /* no error happened */
+  return 0;
+}
+
+void
+olsr_setup_cleanup(void) {
+  if (olsr_subsystem_cleanup(&olsr_setup_state))
+    return;
+
+  /* add cleanup for custom services here */
+}
+
diff --git a/src/olsr_setup.h b/src/olsr_setup.h
new file mode 100644 (file)
index 0000000..b93307f
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * olsr_setup.h
+ *
+ *  Created on: Sep 13, 2011
+ *      Author: rogge
+ */
+
+#ifndef OLSR_SETUP_H_
+#define OLSR_SETUP_H_
+
+#include "common/common_types.h"
+#include "olsr_logging.h"
+
+/* define the first line of the command line help */
+#define OLSR_SETUP_HELP_HEADLINE  "Activates OLSR.org routing daemon\n"
+
+/* define program name */
+#define OLSR_SETUP_PROGRAM        "Olsrd"
+
+enum log_source *olsr_setup_debuglevel1;
+
+int olsr_setup_cfginit(void);
+int olsr_setup_init(void);
+void olsr_setup_cleanup(void);
+void olsr_setup_cfgcleanup(void);
+
+#endif /* OLSR_SETUP_H_ */