Initial framework commit initial-framework
authorHenning Rogge <hrogge@googlemail.com>
Tue, 19 Jul 2011 19:03:03 +0000 (21:03 +0200)
committerHenning Rogge <hrogge@googlemail.com>
Tue, 19 Jul 2011 19:03:03 +0000 (21:03 +0200)
88 files changed:
CMake.config [new file with mode: 0644]
CMake.flags [new file with mode: 0644]
CMake.os [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
Makefile [new file with mode: 0644]
lib/CMakeLists.txt [new file with mode: 0644]
lib/cfgparser_compact/CMakeLists.txt [new file with mode: 0644]
lib/cfgparser_compact/Makefile [new file with mode: 0644]
lib/cfgparser_compact/README_CFGPARSER_COMPACT [new file with mode: 0644]
lib/cfgparser_compact/src/cfgparser_compact.c [new file with mode: 0644]
lib/plugin.cmake [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/builddata/CMakeLists.txt [new file with mode: 0644]
src/builddata/data.c.in [new file with mode: 0644]
src/builddata/data.h [new file with mode: 0644]
src/builddata/generate_builddata.cmake [new file with mode: 0755]
src/builddata/generate_static_loader.cmake [new file with mode: 0755]
src/builddata/plugin_static.h [new file with mode: 0644]
src/common/CMakeLists.txt [new file with mode: 0644]
src/common/autobuf.c [new file with mode: 0644]
src/common/autobuf.h [new file with mode: 0644]
src/common/avl.c [new file with mode: 0644]
src/common/avl.h [new file with mode: 0644]
src/common/avl_comp.c [new file with mode: 0644]
src/common/avl_comp.h [new file with mode: 0644]
src/common/common_types.h [new file with mode: 0644]
src/common/container_of.h [new file with mode: 0644]
src/common/daemonize.c [new file with mode: 0644]
src/common/daemonize.h [new file with mode: 0644]
src/common/list.h [new file with mode: 0644]
src/common/netaddr.c [new file with mode: 0644]
src/common/netaddr.h [new file with mode: 0644]
src/common/string.c [new file with mode: 0644]
src/common/string.h [new file with mode: 0644]
src/common/template.c [new file with mode: 0644]
src/common/template.h [new file with mode: 0644]
src/config/CMakeLists.txt [new file with mode: 0644]
src/config/cfg.c [new file with mode: 0644]
src/config/cfg.h [new file with mode: 0644]
src/config/cfg_cmd.c [new file with mode: 0644]
src/config/cfg_cmd.h [new file with mode: 0644]
src/config/cfg_db.c [new file with mode: 0644]
src/config/cfg_db.h [new file with mode: 0644]
src/config/cfg_delta.c [new file with mode: 0644]
src/config/cfg_delta.h [new file with mode: 0644]
src/config/cfg_io.c [new file with mode: 0644]
src/config/cfg_io.h [new file with mode: 0644]
src/config/cfg_memory.c [new file with mode: 0644]
src/config/cfg_memory.h [new file with mode: 0644]
src/config/cfg_parser.c [new file with mode: 0644]
src/config/cfg_parser.h [new file with mode: 0644]
src/config/cfg_schema.c [new file with mode: 0644]
src/config/cfg_schema.h [new file with mode: 0644]
src/config/io/cfg_io_file.c [new file with mode: 0644]
src/config/io/cfg_io_file.h [new file with mode: 0644]
src/config/parser/cfg_parser_compact.c [new file with mode: 0644]
src/config/parser/cfg_parser_compact.h [new file with mode: 0644]
src/core/interface.h [new file with mode: 0644]
src/core/olsr.c [new file with mode: 0644]
src/core/olsr.h [new file with mode: 0644]
src/core/olsr_cfg.c [new file with mode: 0644]
src/core/olsr_cfg.h [new file with mode: 0644]
src/core/olsr_clock.c [new file with mode: 0644]
src/core/olsr_clock.h [new file with mode: 0644]
src/core/olsr_logging.c [new file with mode: 0644]
src/core/olsr_logging.h [new file with mode: 0644]
src/core/olsr_logging_cfg.c [new file with mode: 0644]
src/core/olsr_logging_cfg.h [new file with mode: 0644]
src/core/olsr_logging_sources.c [new file with mode: 0644]
src/core/olsr_logging_sources.h [new file with mode: 0644]
src/core/olsr_memcookie.c [new file with mode: 0644]
src/core/olsr_memcookie.h [new file with mode: 0644]
src/core/olsr_packet_socket.c [new file with mode: 0644]
src/core/olsr_packet_socket.h [new file with mode: 0644]
src/core/olsr_plugins.c [new file with mode: 0644]
src/core/olsr_plugins.h [new file with mode: 0644]
src/core/olsr_socket.c [new file with mode: 0644]
src/core/olsr_socket.h [new file with mode: 0644]
src/core/olsr_stream_socket.c [new file with mode: 0644]
src/core/olsr_stream_socket.h [new file with mode: 0644]
src/core/olsr_timer.c [new file with mode: 0644]
src/core/olsr_timer.h [new file with mode: 0644]
src/core/os_net.h [new file with mode: 0644]
src/core/os_net_generic.c [new file with mode: 0644]
src/core/os_system.h [new file with mode: 0644]
src/core/os_time.h [new file with mode: 0644]
src/linux/os_net_linux.c [new file with mode: 0644]
src/linux/os_net_linux.h [new file with mode: 0644]

diff --git a/CMake.config b/CMake.config
new file mode 100644 (file)
index 0000000..5fbab57
--- /dev/null
@@ -0,0 +1,11 @@
+# set OLSRD version (e.g. 0.7.0)
+set (OLSRD_VERSION 0.7.0)
+
+# set static plugins (space separated list of plugin names)
+set (OLSRD_STATIC_PLUGINS cfgparser_compact)
+
+# allow removal of Logging levels from code
+set (OLSRD_REMOVE_DEBUG_LOGGING false)
+set (OLSRD_REMOVE_INFO_LOGGING  false)
+set (OLSRD_REMOVE_WARN_LOGGING  false)
+set (OLSRD_REMOVE_ERROR_LOGGING false)
diff --git a/CMake.flags b/CMake.flags
new file mode 100644 (file)
index 0000000..9fff7bc
--- /dev/null
@@ -0,0 +1,46 @@
+include(CheckCCompilerFlag)
+
+# define a function that checks if a certain compiler flag is available
+# use it if it is available, display a warning if not
+
+function(add_compiler_flag flag)
+    check_c_compiler_flag(${flag} test${flag})
+    if (${test${flag}})
+        ADD_DEFINITIONS(${flag})
+    endif()
+endfunction(add_compiler_flag)
+
+add_compiler_flag(-finline-functions-called-once)
+add_compiler_flag(-funit-at-a-time)
+add_compiler_flag(-fearly-inlining)
+add_compiler_flag(-fno-strict-aliasing)
+add_compiler_flag(-finline-limit=350)
+add_compiler_flag(-Wstrict-overflow=5)
+add_compiler_flag(-fvisibility=hidden)
+
+add_compiler_flag(-Wall)
+add_compiler_flag(-Wextra)
+add_compiler_flag(-Wold-style-definition)
+add_compiler_flag(-Wdeclaration-after-statement)
+add_compiler_flag(-Wmissing-prototypes)
+add_compiler_flag(-Wstrict-prototypes)
+add_compiler_flag(-Wmissing-declarations)
+add_compiler_flag(-Wsign-compare)
+add_compiler_flag(-Waggregate-return)
+add_compiler_flag(-Wmissing-noreturn)
+add_compiler_flag(-Wmissing-format-attribute)
+add_compiler_flag(-Wno-multichar)
+add_compiler_flag(-Wno-deprecated-declarations)
+add_compiler_flag(-Wendif-labels)
+add_compiler_flag(-Wwrite-strings)
+add_compiler_flag(-Wbad-function-cast)
+add_compiler_flag(-Wpointer-arith)
+add_compiler_flag(-Wno-cast-qual)
+add_compiler_flag(-Wshadow)
+add_compiler_flag(-Wsequence-point)
+add_compiler_flag(-Wpointer-arith)
+add_compiler_flag(-Wnested-externs)
+add_compiler_flag(-Winline)
+add_compiler_flag(-Wdisabled-optimization)
+add_compiler_flag(-Wformat)
+add_compiler_flag(-Wformat-security)
diff --git a/CMake.os b/CMake.os
new file mode 100644 (file)
index 0000000..8175ab5
--- /dev/null
+++ b/CMake.os
@@ -0,0 +1,37 @@
+# detect operation system and add compiler hints
+STRING(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME)
+
+IF (UNIX)
+    ADD_DEFINITIONS(-DOS_UNIX)
+ENDIF (UNIX)
+
+IF (${SYSTEM_NAME} MATCHES "linux")
+    message("Linux detected")
+    ADD_DEFINITIONS(-DOS_LINUX)
+    SET(LINUX true)
+ENDIF (${SYSTEM_NAME} MATCHES "linux")
+
+IF (${SYSTEM_NAME} MATCHES "android" OR ANDROID)
+    message("Android detected")
+    ADD_DEFINITIONS(-DOS_ANDROID -DOS_LINUX)
+    SET(LINUX true)
+    SET(ANDROID true)
+    SET(UNIX true)
+ENDIF (${SYSTEM_NAME} MATCHES "android" OR ANDROID)
+
+IF (${SYSTEM_NAME} MATCHES "bsd")
+    message("BSD detected")
+    ADD_DEFINITIONS(-DOS_BSD)
+    SET(BSD true)
+ENDIF (${SYSTEM_NAME} MATCHES "bsd")
+
+IF (APPLE)
+    message("Mac OS detected")
+    ADD_DEFINITIONS(-DOS_APPLE -DOS_BSD)
+    set(BSD true)
+ENDIF (APPLE)
+
+IF (WIN32)
+    message("Win32 detected")
+    ADD_DEFINITIONS(-DOS_WIN32)
+ENDIF (WIN32)
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..14f74f5
--- /dev/null
@@ -0,0 +1,70 @@
+project(olsrd C)
+cmake_minimum_required(VERSION 2.8)
+
+include(./CMake.os)
+include(./CMake.config)
+
+# create all data inside the build directory
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+
+# set release specific compiler options
+set(CMAKE_C_FLAGS "-g")
+set(CMAKE_C_FLAGS_DEBUG "-g")
+set(CMAKE_C_FLAGS_RELEASE "-O2 -g0 -DNDEBUG")
+set(CMAKE_C_FLAGS_MINSIZEREL "-Os -g0 -DNDEBUG")
+
+# add generic compiler options
+ADD_DEFINITIONS(-Werror)
+include(./CMake.flags)
+
+IF (OLSRD_REMOVE_DEBUG_LOGGING)
+    ADD_DEFINITIONS(-DREMOVE_LOG_DEBUG)
+ENDIF (OLSRD_REMOVE_DEBUG_LOGGING)
+IF (OLSRD_REMOVE_INFO_LOGGING)
+    ADD_DEFINITIONS(-DREMOVE_LOG_INFO)
+ENDIF (OLSRD_REMOVE_INFO_LOGGING)
+IF (OLSRD_REMOVE_WARN_LOGGING)
+    ADD_DEFINITIONS(-DREMOVE_LOG_WARN)
+ENDIF (OLSRD_REMOVE_WARN_LOGGING)
+IF (OLSRD_REMOVE_ERROR_LOGGING)
+    ADD_DEFINITIONS(-DREMOVE_LOG_ERROR)
+ENDIF (OLSRD_REMOVE_ERROR_LOGGING)
+
+# OS-specific settings
+IF(ANDROID OR WIN32)
+    # Android and windows don't compile well with c99
+    ADD_DEFINITIONS(-std=gnu99)
+ELSE(ANDROID OR WIN32)
+    # everything else does
+    ADD_DEFINITIONS(-std=c99 -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D__BSD_VISIBLE -D_DARWIN_C_SOURCE -D__KERNEL_STRICT_NAMES)
+ENDIF (ANDROID OR WIN32)
+
+# overwrite OLSRd default config file for win32
+IF(WIN32)
+    ADD_DEFINITIONS(-DOLSRD_GLOBAL_CONF_FILE="olsrd.conf")
+ENDIF(WIN32)
+
+# add some necessary additions for win32
+IF (WIN32)
+    ADD_DEFINITIONS(-D_WIN32_WINNT=0x0502)
+    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--enable-auto-import")
+ENDIF(WIN32)
+
+# set include directories
+include_directories(src)
+include_directories(src/core)
+
+# TODO: get rid of this
+IF(WIN32)
+    include_directories(src/win32)
+ENDIF(WIN32)
+
+IF(ANDROID)
+    include_directories(src/android)
+ENDIF(ANDROID)
+
+# start compiling core and plugins
+add_subdirectory(src)
+add_subdirectory(lib)
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..8824945
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+BUILD_DIR=build
+
+
+.ONESHELL:
+all: default_target FORCE
+       @make -s -C $(BUILD_DIR) all
+
+clean: default_target FORCE
+       @make -s -C $(BUILD_DIR) clean
+
+autotest:
+       @./test_all.sh
+
+default_target:
+       @test -d ${BUILD_DIR} || sh -c "mkdir $(BUILD_DIR) ; cd $(BUILD_DIR) ;  cmake .."
+
+FORCE:
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7c37f1e
--- /dev/null
@@ -0,0 +1,2 @@
+# add subdirectories
+add_subdirectory(cfgparser_compact)
diff --git a/lib/cfgparser_compact/CMakeLists.txt b/lib/cfgparser_compact/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e7bff36
--- /dev/null
@@ -0,0 +1,6 @@
+# set library name
+SET (libname "cfgparser_compact")
+SET (source "${CMAKE_CURRENT_SOURCE_DIR}/src/cfgparser_compact.c")
+
+# use generic plugin cmake file
+include (../plugin.cmake)
diff --git a/lib/cfgparser_compact/Makefile b/lib/cfgparser_compact/Makefile
new file mode 100644 (file)
index 0000000..62514a0
--- /dev/null
@@ -0,0 +1,56 @@
+# The olsr.org Optimized Link-State Routing daemon(olsrd)
+# Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of olsr.org, olsrd 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 OWNER 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.
+#
+# Visit http://www.olsr.org for more information.
+#
+# If you find this software useful feel free to make a donation
+# to the project. For more information see the website or contact
+# the copyright holders.
+#
+
+OLSRD_PLUGIN = true
+PLUGIN_NAME =  olsrd_txtinfo
+PLUGIN_VER =   0.2
+
+TOPDIR =       ../..
+include $(TOPDIR)/Makefile.inc
+
+default_target: $(PLUGIN_FULLNAME)
+
+$(PLUGIN_FULLNAME): $(OBJS) version-script.txt
+               $(CC) $(LDFLAGS) -o $(PLUGIN_FULLNAME) $(OBJS) $(LIBS)
+
+install:       $(PLUGIN_FULLNAME)
+               $(STRIP) $(PLUGIN_FULLNAME)
+               $(INSTALL_LIB)
+
+clean:
+               rm -f $(OBJS) $(SRCS:%.c=%.d) $(PLUGIN_FULLNAME)
diff --git a/lib/cfgparser_compact/README_CFGPARSER_COMPACT b/lib/cfgparser_compact/README_CFGPARSER_COMPACT
new file mode 100644 (file)
index 0000000..3c9a539
--- /dev/null
@@ -0,0 +1,35 @@
+   PLUGIN CONFIGURATION
+==========================
+
+The plugin accepts all parameters for an OLSRD "access
+control list". See README-acl for details.
+
+There are no futher parameters.
+
+   A configuration example
+-----------------------------
+
+LoadPlugin "olsrd_txtinfo.so.0.2"
+{
+    PlParam     "checkfirst"    "reject"
+    PlParam     "defaultpolicy" "reject"
+    PlParam     "accept"   "10.0.0.0/8"
+    PlParam     "reject"   "10.0.1.123"
+}
+
+This will allow access from the network
+10.0.0.0/8, but not from 10.0.1.123.
+access is always allowed from 127.0.0.1(localhost).
+
+
+   PLUGIN USAGE
+==================
+
+The plugin commands are "link", "neigh", "routes",
+"topology", "hna" and "mid". All commands support
+both normal and csv mode.
+
+The plugin commands are used through the normal OLSR
+telnet server. See README-http-txt-services for details.
+
+- Henning Rogge
diff --git a/lib/cfgparser_compact/src/cfgparser_compact.c b/lib/cfgparser_compact/src/cfgparser_compact.c
new file mode 100644 (file)
index 0000000..05d830f
--- /dev/null
@@ -0,0 +1,300 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+/*
+ * Dynamic linked library for the olsr.org olsr daemon
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+#include "common/string.h"
+#include "config/cfg_db.h"
+#include "config/cfg_parser.h"
+#include "config/cfg.h"
+#include "olsr_plugins.h"
+
+#include <stdio.h>
+
+static int _plugin_load(void);
+static int _plugin_unload(void);
+
+static struct cfg_db *_compact_parse(
+    char *src, size_t len, struct autobuf *log);
+static int _compact_serialize(
+    struct autobuf *dst, struct cfg_db *src, struct autobuf *log);
+static int _parse_line(struct cfg_db *db, char *line,
+    char *section, size_t section_size,
+    char *name, size_t name_size,
+    struct autobuf *log);
+
+OLSR_PLUGIN6() {
+  .descr = "OLSRD compact configuration format plugin",
+  .author = "Henning Rogge",
+  .load = _plugin_load,
+  .unload = _plugin_unload,
+};
+
+const char *CFG_PARSER_COMPACT = "compact";
+struct cfg_parser cfg_parser_compact = {
+  .name = "compact",
+  .parse = _compact_parse,
+  .serialize = _compact_serialize,
+  .def = true
+};
+
+/**
+ * Constructor of plugin, called before parameters are initialized
+ */
+static int
+_plugin_load(void)
+{
+  cfg_parser_add(&cfg_parser_compact);
+  return 0;
+}
+
+/**
+ * Destructor of plugin
+ */
+static int
+_plugin_unload(void)
+{
+  cfg_parser_remove(&cfg_parser_compact);
+  return 0;
+}
+
+
+/*
+ * Defintion of the 'compact' configuration parser.
+ *
+ * This parser/serializer use a line oriented text format.
+ * All lines beginning with '#' will be ignored as comments.
+ * All leading and trailing whitespaces will be ignored.
+ *
+ * Sections are defined as '[<section-typ>]'.
+ * Named sections are defined as '[<section-type>=<section-name>]'.
+ * Entrys are defined as 'key value'.
+ *
+ * No entry must be put before the first section.
+ */
+/**
+ * Parse a buffer into a configuration database
+ * @param src pointer to text buffer
+ * @param len length of buffer
+ * @param log autobuffer for logging output
+ * @return pointer to configuration database, NULL if an error happened
+ */
+static struct cfg_db *
+_compact_parse(char *src, size_t len, struct autobuf *log) {
+  char section[128];
+  char name[128];
+  struct cfg_db *db;
+  char *eol, *line;
+
+  db = cfg_db_add();
+
+  memset(section, 0, sizeof(section));
+  memset(name, 0, sizeof(name));
+
+  line = src;
+  while (line < src + len) {
+    /* find end of line */
+    eol = line;
+    while (*eol != 0 && *eol != '\n') {
+      eol++;
+    }
+
+    /* termiate line with zero byte */
+    *eol = 0;
+    if (eol > line && eol[-1] == '\r') {
+      /* handle \r\n line ending */
+      eol[-1] = 0;
+    }
+
+    if (_parse_line(db, line, section, sizeof(section),
+        name, sizeof(name), log)) {
+      cfg_db_remove(db);
+      return NULL;
+    }
+
+    line = eol+1;
+  }
+
+  return db;
+}
+
+/**
+ * Serialize a configuration database into a buffer
+ * @param dst target buffer
+ * @param src source configuration database
+ * @param log autbuffer for logging
+ * @return 0 if database was serialized, -1 otherwise
+ */
+static int
+_compact_serialize(struct autobuf *dst, struct cfg_db *src,
+    struct autobuf *log __attribute__ ((unused))) {
+  struct cfg_section_type *section, *s_it;
+  struct cfg_named_section *name, *n_it;
+  struct cfg_entry *entry, *e_it;
+
+  OLSR_FOR_ALL_CFG_SECTION_TYPES(src, section, s_it) {
+    OLSR_FOR_ALL_CFG_SECTION_NAMES(section, name, n_it) {
+      if (cfg_db_is_named_section(name)) {
+        abuf_appendf(dst, "[%s=%s]\n", section->type, name->name);
+      }
+      else {
+        abuf_appendf(dst, "[%s]\n", section->type);
+      }
+
+      OLSR_FOR_ALL_CFG_ENTRIES(name, entry, e_it) {
+        abuf_appendf(dst, "\t%s %s\n", entry->name, entry->value);
+      }
+    }
+  }
+  return 0;
+}
+
+/**
+ * Parse a single line of the compact format
+ * @param db pointer to configuration database
+ * @param line pointer to line to be parsed (will be modified
+ *   during parsing)
+ * @param section pointer to array with current section type
+ *   (might be modified during parsing)
+ * @param section_size number of bytes for section type
+ * @param name pointer to array with current section name
+ *   (might be modified during parsing)
+ * @param name_size number of bytes for section name
+ * @param log autobuffer for logging output
+ * @return 0 if line was parsed successfully, -1 otherwise
+ */
+static int
+_parse_line(struct cfg_db *db, char *line,
+    char *section, size_t section_size,
+    char *name, size_t name_size,
+    struct autobuf *log) {
+  char *first, *ptr;
+
+  /* trim leading and trailing whitespaces */
+  first = line;
+  str_trim(&first);
+
+  if (*first == 0 || *first == '#') {
+    /* empty line or comment */
+    return 0;
+  }
+
+  if (*first == '[') {
+    first++;
+    ptr = strchr(first, ']');
+    if (ptr == NULL) {
+      cfg_append_printable_line(log,
+          "Section syntax error in line: '%s'", line);
+      return -1;
+    }
+    *ptr = 0;
+
+    ptr = strchr(first, '=');
+    if (ptr) {
+      /* trim section name */
+      *ptr++ = 0;
+      str_trim(&ptr);
+    }
+
+    /* trim section name */
+    str_trim(&first);
+    if (*first == 0) {
+      cfg_append_printable_line(log,
+          "Section syntax error, no section type found");
+      return -1;
+    }
+
+    /* copy section type */
+    strscpy(section, first, section_size);
+
+    /* copy section name */
+    if (ptr) {
+      strscpy(name, ptr, name_size);
+    }
+    else {
+      *name = 0;
+    }
+
+    /* add section to db */
+    _cfg_db_add_section(db, section, *name ? name : NULL);
+    return 0;
+  }
+
+  if (*section == 0) {
+    cfg_append_printable_line(log,
+        "Entry before first section is not allowed in this format");
+    return -1;
+  }
+
+  ptr = first;
+
+  /* look for separator */
+  while (!isspace(*ptr)) {
+    ptr++;
+  }
+
+  *ptr++ = 0;
+
+  /* trim second token */
+  str_trim(&ptr);
+
+  if (*ptr == 0) {
+    cfg_append_printable_line(log,
+        "No second token found in line '%s'",  line);
+    return -1;
+  }
+
+  /* found two tokens */
+  cfg_db_add_entry(db, section, *name ? name : NULL, first, ptr);
+  return 0;
+}
diff --git a/lib/plugin.cmake b/lib/plugin.cmake
new file mode 100644 (file)
index 0000000..7c03cb6
--- /dev/null
@@ -0,0 +1,14 @@
+# generic plugin cmake-file
+ADD_DEFINITIONS(-DPLUGIN_FULLNAME=${libname})
+
+ADD_LIBRARY(static_${libname} STATIC ${source})
+ADD_LIBRARY(olsrd_${libname} SHARED ${source})
+
+IF(WIN32)
+    TARGET_LINK_LIBRARIES(olsrd_${libname} ws2_32 iphlpapi olsrd)
+ENDIF(WIN32)
+
+SET_TARGET_PROPERTIES(olsrd_${libname} PROPERTIES SOVERSION ${OLSRD_VERSION})
+
+UNSET(source)
+UNSET(libname)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..37154af
--- /dev/null
@@ -0,0 +1,50 @@
+# add static libraries
+add_subdirectory(common)
+add_subdirectory(config)
+add_subdirectory(builddata)
+
+# add source files of core directory
+FILE(GLOB SRCS "core/*.c")    
+set(OLSRD_SRCS ${OLSRD_SRCS} ${SRCS})
+
+# add os_specific source files
+IF(WIN32)
+    FILE(GLOB SRCS "win32/*.c")    
+    set(OLSRD_SRCS ${OLSRD_SRCS} ${SRCS})
+ENDIF(WIN32)
+
+IF(UNIX)
+    FILE(GLOB SRCS "unix/*.c")    
+    set(OLSRD_SRCS ${OLSRD_SRCS} ${SRCS})
+ENDIF(UNIX)
+
+IF(LINUX)
+    FILE(GLOB SRCS "linux/*.c")    
+    set(OLSRD_SRCS ${OLSRD_SRCS} ${SRCS})
+ENDIF(LINUX)
+
+IF(BSD)
+    FILE(GLOB SRCS "bsd/*.c")    
+    set(OLSRD_SRCS ${OLSRD_SRCS} ${SRCS})
+ENDIF(BSD)
+
+# activate symbol export for win32
+IF(WIN32)
+    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--export-all-symbols")
+ENDIF(WIN32)
+
+# create executable
+ADD_EXECUTABLE(olsrd ${OLSRD_SRCS})
+TARGET_LINK_LIBRARIES(olsrd OlsrdCommon OlsrdConfig OlsrdBuildData)
+TARGET_LINK_LIBRARIES(olsrd ${CMAKE_DL_LIBS})
+
+# link extra win32 libs
+IF(WIN32)
+    SET_TARGET_PROPERTIES(olsrd PROPERTIES ENABLE_EXPORTS true)
+    TARGET_LINK_LIBRARIES(olsrd ws2_32 iphlpapi)
+ENDIF(WIN32)
+
+# link static plugins
+FOREACH(plugin ${OLSRD_STATIC_PLUGINS})
+    TARGET_LINK_LIBRARIES(olsrd static_${plugin})
+ENDFOREACH(plugin)
diff --git a/src/builddata/CMakeLists.txt b/src/builddata/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8c5fee3
--- /dev/null
@@ -0,0 +1,27 @@
+# generate full version string and initialization for static plugins
+SET(GEN_DATA_C           ${PROJECT_BINARY_DIR}/data.c)
+SET(GEN_PLUGIN_STATIC_C  ${PROJECT_BINARY_DIR}/plugin_static.c)
+
+ADD_CUSTOM_TARGET(OlsrdCleanData ALL
+    COMMAND ${CMAKE_COMMAND} -E remove ${GEN_BUILDDATA_H} ${GEN_PLUGIN_STATIC_C}
+    COMMENT "Remove old builddata"
+)
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT ${GEN_DATA_C} ${GEN_PLUGIN_STATIC_C}
+    COMMAND ${CMAKE_COMMAND}
+        -DSRC=${CMAKE_CURRENT_SOURCE_DIR}/data.c.in
+        -DDST=${GEN_DATA_C}
+        -DGIT=${PROJECT_SOURCE_DIR}/.git
+        -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_builddata.cmake
+    COMMAND ${CMAKE_COMMAND}
+        -DDST=${GEN_PLUGIN_STATIC_C}
+        -DPLUGINS="${OLSRD_STATIC_PLUGINS}"
+        -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_static_loader.cmake
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    COMMENT "Create new builddata"
+)
+
+# create static library with the generated data
+ADD_LIBRARY(OlsrdBuildData STATIC ${GEN_DATA_C} ${GEN_PLUGIN_STATIC_C})
+ADD_DEPENDENCIES(OlsrdBuildData OlsrdCleanData)
diff --git a/src/builddata/data.c.in b/src/builddata/data.c.in
new file mode 100644 (file)
index 0000000..294d7d7
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * builddata.c
+ *
+ *  Created on: May 10, 2011
+ *      Author: rogge
+ */
+
+#include "builddata/data.h"
+
+static const char olsrd_version[] = "${OLSRD_VERSION}";
+static const char olsrd_git[] = "${OLSRD_SRC_GIT}";
+static const char olsrd_change[] = "${OLSRD_SRC_CHANGE}";
+static const char build_date[] = __DATE__" "__TIME__;
+static const char build_host[] = "${OLSRD_SYSTEM}";
+
+const char *
+get_olsrd_version(void) {
+  return olsrd_version;
+}
+
+const char *
+get_olsrd_git_commit(void) {
+  return olsrd_git;
+}
+
+const char *
+get_olsrd_git_change(void) {
+  return olsrd_change;
+}
+
+const char *
+get_olsrd_builddate(void) {
+  return build_date;
+}
+
+const char *
+get_olsrd_buildsystem(void) {
+  return build_host;
+}
diff --git a/src/builddata/data.h b/src/builddata/data.h
new file mode 100644 (file)
index 0000000..cafe159
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * builddata.h
+ *
+ *  Created on: Jun 9, 2011
+ *      Author: rogge
+ */
+
+#ifndef BUILDDATA_H_
+#define BUILDDATA_H_
+
+#include "common/common_types.h"
+
+EXPORT const char *get_olsrd_version(void);
+EXPORT const char *get_olsrd_git_commit(void);
+EXPORT const char *get_olsrd_git_change(void);
+EXPORT const char *get_olsrd_builddate(void);
+EXPORT const char *get_olsrd_buildsystem(void);
+
+#endif /* BUILDDATA_H_ */
diff --git a/src/builddata/generate_builddata.cmake b/src/builddata/generate_builddata.cmake
new file mode 100755 (executable)
index 0000000..7d65620
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/cmake
+
+# look for git executable 
+find_program(found_git git)
+
+IF(${found_git} STREQUAL "found_git-NOTFOUND" OR NOT EXISTS ${GIT})
+    # git executable or repository (.git) is not available
+    SET(OLSRD_SRC_GIT "cannot read git repository")
+    SET(OLSRD_SRC_CHANGE "")
+ELSE()
+    # everything is fine, read commit and diff stat
+    execute_process(COMMAND git describe --tags 
+        OUTPUT_VARIABLE OLSRD_SRC_GIT OUTPUT_STRIP_TRAILING_WHITESPACE)
+    execute_process(COMMAND git diff --shortstat HEAD ./src/ ./lib 
+        OUTPUT_VARIABLE OLSRD_SRC_CHANGE OUTPUT_STRIP_TRAILING_WHITESPACE)
+ENDIF()
+
+# create builddata file
+configure_file (${SRC} ${DST})
diff --git a/src/builddata/generate_static_loader.cmake b/src/builddata/generate_static_loader.cmake
new file mode 100755 (executable)
index 0000000..ae97778
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/cmake
+
+# replace spaces with string to convert into list
+IF (${PLUGIN_LIST})
+    string(REPLACE " " ";" "${PLUGIN_LIST}" ${PLUGINS})
+ENDIF (${PLUGIN_LIST})
+
+# create C file which would call the static plugin constructors 
+file(WRITE  ${DST} "#include \"builddata/plugin_static.h\"\n")
+file(APPEND ${DST} "\n")
+
+IF (${PLUGIN_LIST})
+    FOREACH(plugin ${PLUGIN_LIST})
+        file(APPEND ${DST} "void hookup_plugin_${plugin}(void);\n")
+    ENDFOREACH(plugin)
+ENDIF (${PLUGIN_LIST})
+
+file(APPEND ${DST} "\n")
+file(APPEND ${DST} "void\n")
+file(APPEND ${DST} "olsr_plugins_load_static(void) {\n")
+
+IF (${PLUGIN_LIST})
+    FOREACH(plugin ${PLUGIN_LIST})
+        file(APPEND ${DST} "  hookup_plugin_${plugin}();\n")
+    ENDFOREACH(plugin)
+ENDIF (${PLUGIN_LIST})
+
+file(APPEND ${DST} "}\n")
diff --git a/src/builddata/plugin_static.h b/src/builddata/plugin_static.h
new file mode 100644 (file)
index 0000000..469757d
--- /dev/null
@@ -0,0 +1,47 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+#ifndef PLUGIN_STATIC_H_
+#define PLUGIN_STATIC_H_
+
+/* Prototype for automatically generated function */
+void olsr_plugins_load_static(void);
+
+#endif /* PLUGIN_STATIC_H_ */
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5147ccb
--- /dev/null
@@ -0,0 +1,12 @@
+SET(OLSRD_COMMON_SRCS autobuf.c
+                      avl_comp.c
+                      avl.c
+                      daemonize.c
+                      netaddr.c
+                      string.c
+                      template.c)
+
+ADD_LIBRARY(OlsrdCommon ${OLSRD_COMMON_SRCS})
+IF(WIN32)
+    TARGET_LINK_LIBRARIES(OlsrdCommon ws2_32 iphlpapi)
+ENDIF(WIN32)
diff --git a/src/common/autobuf.c b/src/common/autobuf.c
new file mode 100644 (file)
index 0000000..3c1dbe9
--- /dev/null
@@ -0,0 +1,369 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include "common/autobuf.h"
+
+/**
+ * @param val original size
+ * @param pow2 power of 2 (1024, 4096, ...)
+ * @return multiple of pow2 which larger or equal val
+ */
+static INLINE size_t
+ROUND_UP_TO_POWER_OF_2(size_t val, size_t pow2) {
+  return (val + pow2 - 1) & ~(pow2 - 1);
+}
+
+static int _autobuf_enlarge(struct autobuf *autobuf, size_t new_size);
+static void *_malloc(size_t size);
+
+static void *(*autobuf_malloc)(size_t) = _malloc;
+static void *(*autobuf_realloc)(void *, size_t) = realloc;
+static void (*autobuf_free)(void *) = free;
+
+/**
+ * Allows to overwrite the memory handler functions for autobufs
+ * @param custom_malloc overwrites malloc handler, NULL restores default one
+ * @param custom_realloc overwrites realloc handler, NULL restores default one
+ * @param custom_free overwrites free handler, NULL restores default one
+ */
+void
+abuf_set_memory_handler(
+    void *(*custom_malloc)(size_t),
+    void *(*custom_realloc)(void *, size_t),
+    void (*custom_free)(void *)) {
+  autobuf_malloc = custom_malloc ? custom_malloc : _malloc;
+  autobuf_realloc = custom_realloc ? custom_realloc : realloc;
+  autobuf_free = custom_free ? custom_free : free;
+}
+
+/**
+ * Initialize an autobuffer and allocate a chunk of memory
+ * @param autobuf pointer to autobuf object
+ * @param initial_size size of allocated memory, might be 0
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+int
+abuf_init(struct autobuf *autobuf, size_t initial_size)
+{
+  autobuf->len = 0;
+  if (initial_size <= 0) {
+    autobuf->size = AUTOBUFCHUNK;
+  }
+  else {
+    autobuf->size = ROUND_UP_TO_POWER_OF_2(initial_size, AUTOBUFCHUNK);
+  }
+  autobuf->buf = autobuf_malloc(autobuf->size);
+  if (autobuf->buf == NULL) {
+    autobuf->size = 0;
+    return -1;
+  }
+  *autobuf->buf = '\0';
+  return 0;
+}
+
+/**
+ * Free all currently used memory of an autobuffer.
+ * The buffer can still be used afterwards !
+ * @param autobuf pointer to autobuf object
+ */
+void
+abuf_free(struct autobuf *autobuf)
+{
+  autobuf_free(autobuf->buf);
+  autobuf->buf = NULL;
+  autobuf->len = 0;
+  autobuf->size = 0;
+}
+
+/**
+ * vprintf()-style function that appends the output to an autobuffer
+ * @param autobuf pointer to autobuf object
+ * @param format printf format string
+ * @param ap variable argument list pointer
+ * @return -1 if an out-of-memory error happened,
+ *   otherwise it returns the number of written characters
+ *   (excluding the \0)
+ */
+int
+abuf_vappendf(struct autobuf *autobuf,
+    const char *format, va_list ap)
+{
+  int rc;
+  size_t min_size;
+  va_list ap2;
+
+  if (autobuf == NULL) return 0;
+
+  va_copy(ap2, ap);
+  rc = vsnprintf(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, ap);
+  va_end(ap);
+  min_size = autobuf->len + (size_t)rc;
+  if (min_size >= autobuf->size) {
+    if (_autobuf_enlarge(autobuf, min_size) < 0) {
+      autobuf->buf[autobuf->len] = '\0';
+      return -1;
+    }
+    vsnprintf(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, ap2);
+  }
+  va_end(ap2);
+  autobuf->len = min_size;
+  return rc;
+}
+
+/**
+ * printf()-style function that appends the output to an autobuffer.
+ * The function accepts a variable number of arguments based on the format string.
+ * @param autobuf pointer to autobuf object
+ * @param format printf format string
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+int
+abuf_appendf(struct autobuf *autobuf, const char *fmt, ...)
+{
+  int rv;
+  va_list ap;
+
+  if (autobuf == NULL) return 0;
+
+  va_start(ap, fmt);
+  rv = abuf_vappendf(autobuf, fmt, ap);
+  va_end(ap);
+  return rv;
+}
+
+/**
+ * Appends a null-terminated string to an autobuffer
+ * @param autobuf pointer to autobuf object
+ * @param s string to append to the buffer
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+int
+abuf_puts(struct autobuf *autobuf, const char *s)
+{
+  size_t len;
+
+  if (s == NULL) return 0;
+  if (autobuf == NULL) return 0;
+
+  len  = strlen(s);
+  if (_autobuf_enlarge(autobuf, autobuf->len + len + 1) < 0) {
+    return -1;
+  }
+  strcpy(autobuf->buf + autobuf->len, s);
+  autobuf->len += len;
+  return 0;
+}
+
+/**
+ * Appends a formatted time string to an autobuffer
+ * @param autobuf pointer to autobuf object
+ * @param format strftime() format string
+ * @param tm pointer to time data
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+int
+abuf_strftime(struct autobuf *autobuf, const char *format, const struct tm *tm)
+{
+  size_t rc;
+
+  if (autobuf == NULL) return 0;
+
+  rc = strftime(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, tm);
+  if (rc == 0) {
+    /* we had an error! Probably the buffer too small. So we add some bytes. */
+    if (_autobuf_enlarge(autobuf, autobuf->size + AUTOBUFCHUNK) < 0) {
+      autobuf->buf[autobuf->len] = '\0';
+      return -1;
+    }
+    rc = strftime(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, tm);
+  }
+  autobuf->len += rc;
+  return rc == 0 ? -1 : 0;
+}
+
+/**
+ * Copies a binary buffer to the end of an autobuffer.
+ * @param autobuf pointer to autobuf object
+ * @param p pointer to memory block to be copied
+ * @param len length of memory block
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+int
+abuf_memcpy(struct autobuf *autobuf, const void *p, const size_t len)
+{
+  if (autobuf == NULL) return 0;
+
+  if (_autobuf_enlarge(autobuf, autobuf->len + len) < 0) {
+    return -1;
+  }
+  memcpy(autobuf->buf + autobuf->len, p, len);
+  autobuf->len += len;
+
+  /* null-terminate autobuf */
+  autobuf->buf[autobuf->len] = 0;
+
+  return 0;
+}
+
+/**
+ * Append a memory block to the beginning of an autobuffer.
+ * @param autobuf pointer to autobuf object
+ * @param p pointer to memory block to be copied as a prefix
+ * @param len length of memory block
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+int
+abuf_memcpy_prepend(struct autobuf *autobuf,
+    const void *p, const size_t len)
+{
+  if (autobuf == NULL) return 0;
+
+  if (_autobuf_enlarge(autobuf, autobuf->len + len) < 0) {
+    return -1;
+  }
+  memmove(&autobuf->buf[len], autobuf->buf, autobuf->len);
+  memcpy(autobuf->buf, p, len);
+  autobuf->len += len;
+
+  /* null-terminate autobuf */
+  autobuf->buf[autobuf->len] = 0;
+
+  return 0;
+}
+
+/**
+ * Remove a prefix from an autobuffer. This function can be used
+ * to create an autobuffer based fifo.
+ * @param autobuf pointer to autobuf object
+ * @param len number of bytes to be removed
+ */
+void
+abuf_pull(struct autobuf * autobuf, size_t len) {
+  char *p;
+  size_t newsize;
+
+  if (autobuf == NULL) return;
+
+  if (len != autobuf->len) {
+    memmove(autobuf->buf, &autobuf->buf[len], autobuf->len - len);
+  }
+  autobuf->len -= len;
+
+  newsize = ROUND_UP_TO_POWER_OF_2(autobuf->len + 1, AUTOBUFCHUNK);
+  if (newsize + 2*AUTOBUFCHUNK >= autobuf->size) {
+    /* only reduce buffer size if difference is larger than two chunks */
+    return;
+  }
+
+  /* generate smaller buffer */
+  p = autobuf_realloc(autobuf->buf, newsize);
+  if (p == NULL) {
+    /* keep the longer buffer if we cannot get a smaller one */
+    return;
+  }
+  autobuf->buf = p;
+  autobuf->size = newsize;
+  return;
+}
+
+
+/**
+ * Enlarge an autobuffer if necessary
+ * @param autobuf pointer to autobuf object
+ * @param new_size number of bytes necessary in autobuffer
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+static int
+_autobuf_enlarge(struct autobuf *autobuf, size_t new_size)
+{
+  char *p;
+  size_t roundUpSize;
+
+  new_size++;
+  if (new_size > autobuf->size) {
+    roundUpSize = ROUND_UP_TO_POWER_OF_2(new_size+1, AUTOBUFCHUNK);
+    p = autobuf_realloc(autobuf->buf, roundUpSize);
+    if (p == NULL) {
+#ifdef WIN32
+      WSASetLastError(ENOMEM);
+#else
+      errno = ENOMEM;
+#endif
+      return -1;
+    }
+    autobuf->buf = p;
+
+    memset(&autobuf->buf[autobuf->size], 0, roundUpSize - autobuf->size);
+    autobuf->size = roundUpSize;
+  }
+  return 0;
+}
+
+/**
+ * Internal implementation of malloc that clears buffer.
+ * Maps to calloc(size, 1).
+ * @param size number of bytes to be allocated
+ * @return pointer to allocated memory, NULL if out of memory
+ */
+static void *
+_malloc(size_t size) {
+  return calloc(size, 1);
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * style: linux
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/common/autobuf.h b/src/common/autobuf.h
new file mode 100644 (file)
index 0000000..40a11f0
--- /dev/null
@@ -0,0 +1,140 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef _COMMON_AUTOBUF_H
+#define _COMMON_AUTOBUF_H
+
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+#include "common/common_types.h"
+
+static const size_t AUTOBUFCHUNK = 4096;
+
+/**
+ * Auto-sized buffer handler, mostly used for generation of
+ * large string buffers.
+ */
+struct autobuf {
+  /* total number of bytes allocated in the buffer */
+  size_t size;
+
+  /* currently number of used bytes */
+  size_t len;
+
+  /* pointer to allocated memory */
+  char *buf;
+};
+
+EXPORT void abuf_set_memory_handler(
+    void *(*custom_malloc)(size_t),
+    void *(*custom_realloc)(void *, size_t),
+    void (*custom_free)(void *));
+
+EXPORT int abuf_init(struct autobuf *autobuf, size_t initial_size);
+EXPORT void abuf_free(struct autobuf *autobuf);
+EXPORT int abuf_vappendf(struct autobuf *autobuf, const char *fmt,
+    va_list ap) __attribute__ ((format(printf, 2, 0)));
+EXPORT int abuf_appendf(struct autobuf *autobuf, const char *fmt,
+    ...) __attribute__ ((format(printf, 2, 3)));
+EXPORT int abuf_puts(struct autobuf * autobuf, const char *s);
+EXPORT int abuf_strftime(struct autobuf * autobuf,
+    const char *format, const struct tm * tm);
+EXPORT int abuf_memcpy(struct autobuf * autobuf,
+    const void *p, const size_t len);
+EXPORT int abuf_memcpy_prepend(struct autobuf *autobuf,
+    const void *p, const size_t len);
+EXPORT void abuf_pull(struct autobuf * autobuf, size_t len);
+
+/**
+ * Clears the content of an autobuf
+ * @param autobuf
+ */
+static INLINE void
+abuf_clear(struct autobuf *autobuf) {
+  autobuf->len = 0;
+  memset(autobuf->buf, 0, autobuf->size);
+}
+
+/**
+ * Append a single byte to an autobuffer
+ * @param autobuf
+ * @param c byte to append
+ * @return -1 if an error happened, 0 otherwise
+ */
+static INLINE int
+abuf_append_uint8(struct autobuf *autobuf, const uint8_t c) {
+  return abuf_memcpy(autobuf, &c, 1);
+}
+
+/**
+ * Append a uint16 to an autobuffer
+ * @param autobuf
+ * @param s uint16 to append
+ * @return -1 if an error happened, 0 otherwise
+ */
+static INLINE int
+abuf_append_uint16(struct autobuf *autobuf, const uint16_t s) {
+  return abuf_memcpy(autobuf, &s, 2);
+}
+
+/**
+ * Append a uint32 to an autobuffer
+ * @param autobuf
+ * @param l uint32 to append
+ * @return -1 if an error happened, 0 otherwise
+ */
+static INLINE int
+abuf_append_uint32(struct autobuf *autobuf, const uint32_t l) {
+  return abuf_memcpy(autobuf, &l, 4);
+}
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: c
+ * style: linux
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/common/avl.c b/src/common/avl.c
new file mode 100644 (file)
index 0000000..3792d40
--- /dev/null
@@ -0,0 +1,789 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <stddef.h>
+#include <time.h>
+#include <string.h>
+
+#include "common/common_types.h"
+#include "common/list.h"
+#include "common/avl.h"
+
+static struct avl_node *_avl_find_rec(struct avl_node *node,
+    const void *key, avl_tree_comp comp, void *ptr, int *cmp_result);
+static void _avl_insert_before(struct avl_tree *tree,
+    struct avl_node *pos_node, struct avl_node *node);
+static void _avl_insert_after(struct avl_tree *tree,
+    struct avl_node *pos_node, struct avl_node *node);
+static void _post_insert(struct avl_tree *tree, struct avl_node *node);
+static void _avl_remove_worker(struct avl_tree *tree, struct avl_node *node);
+static void _avl_remove(struct avl_tree *tree, struct avl_node *node);
+static void _avl_rotate_right(struct avl_tree *tree, struct avl_node *node);
+static void _avl_rotate_left(struct avl_tree *tree, struct avl_node *node);
+static void _avl_post_remove(struct avl_tree *tree, struct avl_node *node);
+static struct avl_node *_avl_local_min(struct avl_node *node);
+
+/**
+ * Initialize a new avl_tree struct
+ * @param tree pointer to avl-tree
+ * @param comp pointer to comparator for the tree
+ * @param allow_dups true if the tree allows multiple
+ *   elements with the same
+ * @param ptr custom parameter for comparator
+ */
+void
+avl_init(struct avl_tree *tree, avl_tree_comp comp, bool allow_dups, void *ptr)
+{
+  list_init_head(&tree->list_head);
+  tree->root = NULL;
+  tree->count = 0;
+  tree->comp = comp;
+  tree->allow_dups = allow_dups;
+  tree->cmp_ptr = ptr;
+}
+
+/**
+ * Finds a node in an avl-tree with a certain key
+ * @param tree pointer to avl-tree
+ * @param key pointer to key
+ * @return pointer to avl-node with key, NULL if no node with
+ *    this key exists.
+ */
+struct avl_node *
+avl_find(const struct avl_tree *tree, const void *key)
+{
+  struct avl_node *node;
+  int diff;
+
+  if (tree->root == NULL)
+    return NULL;
+
+  node = _avl_find_rec(tree->root, key, tree->comp, tree->cmp_ptr, &diff);
+
+  return diff == 0 ? node : NULL;
+}
+
+/**
+ * Finds the last node in an avl-tree with a key less or equal
+ * than the specified key
+ * @param tree pointer to avl-tree
+ * @param key pointer to specified key
+ * @return pointer to avl-node, NULL if no node with
+ *    key less or equal specified key exists.
+ */
+struct avl_node *
+avl_find_lessequal(const struct avl_tree *tree, const void *key) {
+  struct avl_node *node, *next;
+  int diff;
+
+  if (tree->root == NULL)
+    return NULL;
+
+  node = _avl_find_rec(tree->root, key, tree->comp, tree->cmp_ptr, &diff);
+
+  /* go left as long as key<node.key */
+  while (diff < 0) {
+    if (list_is_first(&tree->list_head, &node->list)) {
+      return NULL;
+    }
+
+    node = (struct avl_node *)node->list.prev;
+    diff = (*tree->comp) (key, node->key, tree->cmp_ptr);
+  }
+
+  /* go right as long as key>=next_node.key */
+  next = node;
+  while (diff >= 0) {
+    node = next;
+    if (list_is_last(&tree->list_head, &node->list)) {
+      break;
+    }
+
+    next = (struct avl_node *)node->list.next;
+    diff = (*tree->comp) (key, next->key, tree->cmp_ptr);
+  }
+  return node;
+}
+
+/**
+ * Finds the first node in an avl-tree with a key greater or equal
+ * than the specified key
+ * @param tree pointer to avl-tree
+ * @param key pointer to specified key
+ * @return pointer to avl-node, NULL if no node with
+ *    key greater or equal specified key exists.
+ */
+struct avl_node *
+avl_find_greaterequal(const struct avl_tree *tree, const void *key) {
+  struct avl_node *node, *next;
+  int diff;
+
+  if (tree->root == NULL)
+    return NULL;
+
+  node = _avl_find_rec(tree->root, key, tree->comp, tree->cmp_ptr, &diff);
+
+  /* go right as long as key>node.key */
+  while (diff > 0) {
+    if (list_is_last(&tree->list_head, &node->list)) {
+      return NULL;
+    }
+
+    node = (struct avl_node *)node->list.next;
+    diff = (*tree->comp) (key, node->key, tree->cmp_ptr);
+  }
+
+  /* go left as long as key<=next_node.key */
+  next = node;
+  while (diff <= 0) {
+    node = next;
+    if (list_is_first(&tree->list_head, &node->list)) {
+      break;
+    }
+
+    next = (struct avl_node *)node->list.prev;
+    diff = (*tree->comp) (key, next->key, tree->cmp_ptr);
+  }
+  return node;
+}
+
+/**
+ * Inserts an avl_node into a tree
+ * @param tree pointer to tree
+ * @param new pointer to node
+ * @return 0 if node was inserted successfully, -1 if it was not inserted
+ *   because of a key collision
+ */
+int
+avl_insert(struct avl_tree *tree, struct avl_node *new)
+{
+  struct avl_node *node, *next, *last;
+  int diff;
+
+  new->parent = NULL;
+
+  new->left = NULL;
+  new->right = NULL;
+
+  new->balance = 0;
+  new->leader = true;
+
+  if (tree->root == NULL) {
+    list_add_head(&tree->list_head, &new->list);
+    tree->root = new;
+    tree->count = 1;
+    return 0;
+  }
+
+  node = _avl_find_rec(tree->root, new->key, tree->comp, tree->cmp_ptr, &diff);
+
+  last = node;
+
+  while (!list_is_last(&tree->list_head, &last->list)) {
+    next = list_next_element(last, list);
+    if (next->leader) {
+      break;
+    }
+    last = next;
+  }
+
+  diff = (*tree->comp) (new->key, node->key, tree->cmp_ptr);
+
+  if (diff == 0) {
+    if (!tree->allow_dups)
+      return -1;
+
+    new->leader = 0;
+
+    _avl_insert_after(tree, last, new);
+    return 0;
+  }
+
+  if (node->balance == 1) {
+    _avl_insert_before(tree, node, new);
+
+    node->balance = 0;
+    new->parent = node;
+    node->left = new;
+    return 0;
+  }
+
+  if (node->balance == -1) {
+    _avl_insert_after(tree, last, new);
+
+    node->balance = 0;
+    new->parent = node;
+    node->right = new;
+    return 0;
+  }
+
+  if (diff < 0) {
+    _avl_insert_before(tree, node, new);
+
+    node->balance = -1;
+    new->parent = node;
+    node->left = new;
+    _post_insert(tree, node);
+    return 0;
+  }
+
+  _avl_insert_after(tree, last, new);
+
+  node->balance = 1;
+  new->parent = node;
+  node->right = new;
+  _post_insert(tree, node);
+  return 0;
+}
+
+/**
+ * Remove a node from an avl tree
+ * @param tree pointer to tree
+ * @param node pointer to node
+ */
+void
+avl_remove(struct avl_tree *tree, struct avl_node *node)
+{
+  struct avl_node *next;
+  struct avl_node *parent;
+  struct avl_node *left;
+  struct avl_node *right;
+  if (node->leader) {
+    if (tree->allow_dups
+        && !list_is_last(&tree->list_head, &node->list)
+        && !(next = list_next_element(node, list))->leader) {
+      next->leader = true;
+      next->balance = node->balance;
+
+      parent = node->parent;
+      left = node->left;
+      right = node->right;
+
+      next->parent = parent;
+      next->left = left;
+      next->right = right;
+
+      if (parent == NULL)
+        tree->root = next;
+
+      else {
+        if (node == parent->left)
+          parent->left = next;
+
+        else
+          parent->right = next;
+      }
+
+      if (left != NULL)
+        left->parent = next;
+
+      if (right != NULL)
+        right->parent = next;
+    }
+
+    else
+      _avl_remove_worker(tree, node);
+  }
+
+  _avl_remove(tree, node);
+}
+
+/**
+ * Finds a record in an avl_tree corresponding (or close)
+ * to a supplied key.
+ * @param node pointer to avl_node to start tree lookup
+ * @param key pointer to key
+ * @param comp pointer to key comparator
+ * @param cmp_ptr pointer to key comparator custom data
+ * @param cmp_result pointer to an integer to store the final key comparison
+ * @return pointer to result of the lookup (avl_node)
+ */
+static struct avl_node *
+_avl_find_rec(struct avl_node *node, const void *key, avl_tree_comp comp, void *cmp_ptr, int *cmp_result)
+{
+  int diff;
+
+  diff = (*comp) (key, node->key, cmp_ptr);
+  *cmp_result = diff;
+
+  if (diff < 0) {
+    if (node->left != NULL)
+      return _avl_find_rec(node->left, key, comp, cmp_ptr, cmp_result);
+
+    return node;
+  }
+
+  if (diff > 0) {
+    if (node->right != NULL)
+      return _avl_find_rec(node->right, key, comp, cmp_ptr, cmp_result);
+
+    return node;
+  }
+
+  return node;
+}
+
+/**
+ * Rotate an avl_node to the right inside a avl_tree
+ * @param tree pointer to tree
+ * @param node pointer to node
+ */
+static void
+_avl_rotate_right(struct avl_tree *tree, struct avl_node *node)
+{
+  struct avl_node *left, *parent;
+
+  left = node->left;
+  parent = node->parent;
+
+  left->parent = parent;
+  node->parent = left;
+
+  if (parent == NULL)
+    tree->root = left;
+
+  else {
+    if (parent->left == node)
+      parent->left = left;
+
+    else
+      parent->right = left;
+  }
+
+  node->left = left->right;
+  left->right = node;
+
+  if (node->left != NULL)
+    node->left->parent = node;
+
+  //node->balance += 1 - _avl_min(left->balance, 0);
+  //left->balance += 1 + _avl_max(node->balance, 0);
+  node->balance++;
+  if (left->balance < 0) {
+    node->balance = (signed char)(node->balance - left->balance);
+  }
+
+  left->balance++;
+  if (node->balance > 0) {
+    left->balance = (signed char)(left->balance + node->balance);
+  }
+}
+
+/**
+ * Rotate an avl_node to the left inside a avl_tree
+ * @param tree pointer to tree
+ * @param node pointer to node
+ */
+static void
+_avl_rotate_left(struct avl_tree *tree, struct avl_node *node)
+{
+  struct avl_node *right, *parent;
+
+  right = node->right;
+  parent = node->parent;
+
+  right->parent = parent;
+  node->parent = right;
+
+  if (parent == NULL)
+    tree->root = right;
+
+  else {
+    if (parent->left == node)
+      parent->left = right;
+
+    else
+      parent->right = right;
+  }
+
+  node->right = right->left;
+  right->left = node;
+
+  if (node->right != NULL)
+    node->right->parent = node;
+
+  //node->balance -= 1 + _avl_max(right->balance, 0);
+  //right->balance -= 1 - _avl_min(node->balance, 0);
+  node->balance--;
+  if (right->balance > 0) {
+    node->balance = (signed char)(node->balance - right->balance);
+  }
+  right->balance--;
+  if (node->balance < 0) {
+    right->balance = (signed char)(right->balance + node->balance);
+  }
+}
+
+/**
+ * Rebalance the avl_tree after an insert
+ * @param tree pointer to avl_tree
+ * @param node pointer to inserted node
+ */
+static void
+_post_insert(struct avl_tree *tree, struct avl_node *node)
+{
+  struct avl_node *parent = node->parent;
+
+  if (parent == NULL)
+    return;
+
+  if (node == parent->left) {
+    parent->balance--;
+
+    if (parent->balance == 0)
+      return;
+
+    if (parent->balance == -1) {
+      _post_insert(tree, parent);
+      return;
+    }
+
+    if (node->balance == -1) {
+      _avl_rotate_right(tree, parent);
+      return;
+    }
+
+    _avl_rotate_left(tree, node);
+    _avl_rotate_right(tree, node->parent->parent);
+    return;
+  }
+
+  parent->balance++;
+
+  if (parent->balance == 0)
+    return;
+
+  if (parent->balance == 1) {
+    _post_insert(tree, parent);
+    return;
+  }
+
+  if (node->balance == 1) {
+    _avl_rotate_left(tree, parent);
+    return;
+  }
+
+  _avl_rotate_right(tree, node);
+  _avl_rotate_left(tree, node->parent->parent);
+}
+
+/**
+ * Add an avl_node into the linked list before another node and
+ * fix the object count of the tree
+ * @param tree pointer to avl_tree
+ * @param pos_node pointer to reference node
+ * @param node pointer to node to be inserted
+ */
+static void
+_avl_insert_before(struct avl_tree *tree, struct avl_node *pos_node, struct avl_node *node)
+{
+  list_add_before(&pos_node->list, &node->list);
+  tree->count++;
+}
+
+/**
+ * Add an avl_node into the linked list after another node and
+ * fix the object count of the tree
+ * @param tree pointer to avl_tree
+ * @param pos_node pointer to reference node
+ * @param node pointer to node to be inserted
+ */
+static void
+_avl_insert_after(struct avl_tree *tree, struct avl_node *pos_node, struct avl_node *node)
+{
+  list_add_after(&pos_node->list, &node->list);
+  tree->count++;
+}
+
+/**
+ * Remove an avl_node from the linked list and
+ * fix the object count of the tree
+ * @param tree pointer to avl_tre
+ * @param node pointer to avl_node to be removed
+ */
+static void
+_avl_remove(struct avl_tree *tree, struct avl_node *node)
+{
+  list_remove(&node->list);
+  tree->count--;
+}
+
+/**
+ * Rebalance the avl_tree after a remove operation
+ * @param tree pointer to avl_tree
+ * @param node pointer to node which childs have to be
+ *   rebalanced.
+ */static void
+_avl_post_remove(struct avl_tree *tree, struct avl_node *node)
+{
+  struct avl_node *parent;
+
+  if ((parent = node->parent) == NULL)
+    return;
+
+  if (node == parent->left) {
+    parent->balance++;
+
+    if (parent->balance == 0) {
+      _avl_post_remove(tree, parent);
+      return;
+    }
+
+    if (parent->balance == 1)
+      return;
+
+    if (parent->right->balance == 0) {
+      _avl_rotate_left(tree, parent);
+      return;
+    }
+
+    if (parent->right->balance == 1) {
+      _avl_rotate_left(tree, parent);
+      _avl_post_remove(tree, parent->parent);
+      return;
+    }
+
+    _avl_rotate_right(tree, parent->right);
+    _avl_rotate_left(tree, parent);
+    _avl_post_remove(tree, parent->parent);
+    return;
+  }
+
+  parent->balance--;
+
+  if (parent->balance == 0) {
+    _avl_post_remove(tree, parent);
+    return;
+  }
+
+  if (parent->balance == -1)
+    return;
+
+  if (parent->left->balance == 0) {
+    _avl_rotate_right(tree, parent);
+    return;
+  }
+
+  if (parent->left->balance == -1) {
+    _avl_rotate_right(tree, parent);
+    _avl_post_remove(tree, parent->parent);
+    return;
+  }
+
+  _avl_rotate_left(tree, parent->left);
+  _avl_rotate_right(tree, parent);
+  _avl_post_remove(tree, parent->parent);
+}
+
+/**
+ * Iterate down the the left-most node of a tree
+ * @param node pointer to node to start iterate with
+ * @return left-most child of reference node
+ */
+static struct avl_node *
+_avl_local_min(struct avl_node *node)
+{
+  while (node->left != NULL)
+    node = node->left;
+
+  return node;
+}
+
+#if 0
+static struct avl_node *
+avl_local_max(struct avl_node *node)
+{
+  while (node->right != NULL)
+    node = node->right;
+
+  return node;
+}
+#endif
+
+/**
+ * Remove a node from a tree and rebalance it
+ * @param tree pointer to tree
+ * @param node pointer to node to be removed
+ */
+static void
+_avl_remove_worker(struct avl_tree *tree, struct avl_node *node)
+{
+  struct avl_node *parent, *min;
+
+  parent = node->parent;
+
+  if (node->left == NULL && node->right == NULL) {
+    if (parent == NULL) {
+      tree->root = NULL;
+      return;
+    }
+
+    if (parent->left == node) {
+      parent->left = NULL;
+      parent->balance++;
+
+      if (parent->balance == 1)
+        return;
+
+      if (parent->balance == 0) {
+        _avl_post_remove(tree, parent);
+        return;
+      }
+
+      if (parent->right->balance == 0) {
+        _avl_rotate_left(tree, parent);
+        return;
+      }
+
+      if (parent->right->balance == 1) {
+        _avl_rotate_left(tree, parent);
+        _avl_post_remove(tree, parent->parent);
+        return;
+      }
+
+      _avl_rotate_right(tree, parent->right);
+      _avl_rotate_left(tree, parent);
+      _avl_post_remove(tree, parent->parent);
+      return;
+    }
+
+    if (parent->right == node) {
+      parent->right = NULL;
+      parent->balance--;
+
+      if (parent->balance == -1)
+        return;
+
+      if (parent->balance == 0) {
+        _avl_post_remove(tree, parent);
+        return;
+      }
+
+      if (parent->left->balance == 0) {
+        _avl_rotate_right(tree, parent);
+        return;
+      }
+
+      if (parent->left->balance == -1) {
+        _avl_rotate_right(tree, parent);
+        _avl_post_remove(tree, parent->parent);
+        return;
+      }
+
+      _avl_rotate_left(tree, parent->left);
+      _avl_rotate_right(tree, parent);
+      _avl_post_remove(tree, parent->parent);
+      return;
+    }
+  }
+
+  if (node->left == NULL) {
+    if (parent == NULL) {
+      tree->root = node->right;
+      node->right->parent = NULL;
+      return;
+    }
+
+    node->right->parent = parent;
+
+    if (parent->left == node)
+      parent->left = node->right;
+
+    else
+      parent->right = node->right;
+
+    _avl_post_remove(tree, node->right);
+    return;
+  }
+
+  if (node->right == NULL) {
+    if (parent == NULL) {
+      tree->root = node->left;
+      node->left->parent = NULL;
+      return;
+    }
+
+    node->left->parent = parent;
+
+    if (parent->left == node)
+      parent->left = node->left;
+
+    else
+      parent->right = node->left;
+
+    _avl_post_remove(tree, node->left);
+    return;
+  }
+
+  min = _avl_local_min(node->right);
+  _avl_remove_worker(tree, min);
+  parent = node->parent;
+
+  min->balance = node->balance;
+  min->parent = parent;
+  min->left = node->left;
+  min->right = node->right;
+
+  if (min->left != NULL)
+    min->left->parent = min;
+
+  if (min->right != NULL)
+    min->right->parent = min;
+
+  if (parent == NULL) {
+    tree->root = min;
+    return;
+  }
+
+  if (parent->left == node) {
+    parent->left = min;
+    return;
+  }
+
+  parent->right = min;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/common/avl.h b/src/common/avl.h
new file mode 100644 (file)
index 0000000..60250d3
--- /dev/null
@@ -0,0 +1,580 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef _AVL_H
+#define _AVL_H
+
+#include <stddef.h>
+
+#include "common/common_types.h"
+#include "list.h"
+#include "container_of.h"
+
+/**
+ * This element is a member of a avl-tree. It must be contained in all
+ * larger structs that should be put into a tree.
+ */
+struct avl_node {
+  /**
+   * Linked list node for supporting easy iteration and multiple
+   * elments with the same key.
+   *
+   * this must be the first element of an avl_node to
+   * make casting for lists easier
+   */
+  struct list_entity list;
+
+  /**
+   * Pointer to parent node in tree, NULL if root node
+   */
+  struct avl_node *parent;
+
+  /**
+   * Pointer to left child
+   */
+  struct avl_node *left;
+
+  /**
+   * Pointer to right child
+   */
+  struct avl_node *right;
+
+  /**
+   * pointer to key of node
+   */
+  const void *key;
+
+  /**
+   * balance state of AVL tree (0,-1,+1)
+   */
+  signed char balance;
+
+  /**
+   * true if first of a series of nodes with same key
+   */
+  bool leader;
+};
+
+/**
+ * Prototype for avl comparators
+ * @param k1 first key
+ * @param k2 second key
+ * @param ptr custom data for tree comparator
+ * @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
+ */
+typedef int (*avl_tree_comp) (const void *k1, const void *k2, void *ptr);
+
+/**
+ * This struct is the central management part of an avl tree.
+ * One of them is necessary for each avl_tree.
+ */
+struct avl_tree {
+  /**
+   * Head of linked list node for supporting easy iteration
+   * and multiple elments with the same key.
+   */
+  struct list_entity list_head;
+
+  /**
+   * pointer to the root node of the avl tree, NULL if tree is empty
+   */
+  struct avl_node *root;
+
+  /**
+   * number of nodes in the avl tree
+   */
+  uint32_t count;
+
+  /**
+   * true if multiple nodes with the same key are
+   * allowed in the tree, false otherwise
+   */
+  bool allow_dups;
+
+  /**
+   * pointer to the tree comparator
+   *
+   * First two parameters are keys to compare,
+   * third parameter is a copy of cmp_ptr
+   */
+  avl_tree_comp comp;
+
+  /**
+   * custom pointer delivered to the tree comparator
+   */
+  void *cmp_ptr;
+};
+
+EXPORT void avl_init(struct avl_tree *, avl_tree_comp, bool, void *);
+EXPORT struct avl_node *avl_find(const struct avl_tree *, const void *);
+EXPORT struct avl_node *avl_find_greaterequal(const struct avl_tree *tree, const void *key);
+EXPORT struct avl_node *avl_find_lessequal(const struct avl_tree *tree, const void *key);
+EXPORT int avl_insert(struct avl_tree *, struct avl_node *);
+EXPORT void avl_remove(struct avl_tree *, struct avl_node *);
+
+/**
+ * @param tree pointer to avl-tree
+ * @param node pointer to node of the tree
+ * @return true if node is the first one of the tree, false otherwise
+ */
+static INLINE bool
+avl_is_first(struct avl_tree *tree, struct avl_node *node) {
+  return tree->list_head.next == &node->list;
+}
+
+/**
+ * @param tree pointer to avl-tree
+ * @param node pointer to node of the tree
+ * @return true if node is the last one of the tree, false otherwise
+ */
+static INLINE bool
+avl_is_last(struct avl_tree *tree, struct avl_node *node) {
+  return tree->list_head.prev == &node->list;
+}
+
+/**
+ * @param tree pointer to avl-tree
+ * @return true if the tree is empty, false otherwise
+ */
+static INLINE bool
+avl_is_empty(struct avl_tree *tree) {
+  return tree->count == 0;
+}
+
+/**
+ * Legacy function for code that still use the old avl_delete
+ * function instead of the new avl_remove one.
+ *
+ * Use avl_remove() !
+ *
+ * Remove a node from an avl tree
+ * @param tree pointer to tree
+ * @param node pointer to node
+ */
+static INLINE void __attribute__((deprecated("Use avl_remove instead of avl_delete")))
+avl_delete(struct avl_tree *tree, struct avl_node *node) {
+  avl_remove(tree, node);
+}
+
+/**
+ * @param tree pointer to avl-tree
+ * @param key pointer to key
+ * @param element pointer to a node element
+ *    (don't need to be initialized)
+ * @param node_element name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to tree element with the specified key,
+ *    NULL if no element was found
+ */
+#define avl_find_element(tree, key, element, node_element) \
+  container_of_if_notnull(avl_find(tree, key), typeof(*(element)), node_element)
+
+/**
+ * @param tree pointer to avl-tree
+ * @param key pointer to specified key
+ * @param element pointer to a node element
+ *    (don't need to be initialized)
+ * @param node_element name of the avl_node element inside the
+ *    larger struct
+ * return pointer to last tree element with less or equal key than specified key,
+ *    NULL if no element was found
+ */
+#define avl_find_le_element(tree, key, element, node_element) \
+  container_of_if_notnull(avl_find_lessequal(tree, key), typeof(*(element)), node_element)
+
+/**
+ * @param tree pointer to avl-tree
+ * @param key pointer to specified key
+ * @param element pointer to a node element
+ *    (don't need to be initialized)
+ * @param node_element name of the avl_node element inside the
+ *    larger struct
+ * return pointer to first tree element with greater or equal key than specified key,
+ *    NULL if no element was found
+ */
+#define avl_find_ge_element(tree, key, element, node_element) \
+  container_of_if_notnull(avl_find_greaterequal(tree, key), typeof(*(element)), node_element)
+
+/**
+ * This function must not be called for an empty tree
+ *
+ * @param tree pointer to avl-tree
+ * @param element pointer to a node element
+ *    (don't need to be initialized)
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to the first element of the avl_tree
+ *    (automatically converted to type 'element')
+ */
+#define avl_first_element(tree, element, node_member) \
+  container_of((tree)->list_head.next, typeof(*(element)), node_member)
+
+/**
+ * @param tree pointer to avl-tree
+ * @param element pointer to a node element
+ *    (don't need to be initialized)
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to the first element of the avl_tree
+ *    (automatically converted to type 'element'),
+ *    NULL if tree is empty
+ */
+#define avl_first_element_safe(tree, element, node_member) \
+  (avl_is_empty(tree) ? NULL : avl_first_element(tree, element, node_member))
+
+/**
+ * This function must not be called for an empty tree
+ *
+ * @param tree pointer to tree
+ * @param element pointer to a node struct that contains the avl_node
+ *    (don't need to be initialized)
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to the last element of the avl_tree
+ *    (automatically converted to type 'element')
+ */
+#define avl_last_element(tree, element, node_member) \
+  container_of((tree)->list_head.prev, typeof(*(element)), node_member)
+
+/**
+ * @param tree pointer to tree
+ * @param element pointer to a node struct that contains the avl_node
+ *    (don't need to be initialized)
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to the last element of the avl_tree
+ *    (automatically converted to type 'element'),
+ *    NULL if tree is empty
+ */
+#define avl_last_element_safe(tree, element, node_member) \
+  (avl_is_empty(tree) ? NULL : avl_last_element(tree, element, node_member))
+
+/**
+ * This function must not be called for the last element of
+ * an avl tree
+ *
+ * @param element pointer to a node of the tree
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to the node after 'element'
+ *    (automatically converted to type 'element')
+ */
+#define avl_next_element(element, node_member) \
+  container_of((&(element)->node_member.list)->next, typeof(*(element)), node_member)
+
+/**
+ * @param element pointer to a node of the tree
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to the node after 'element'
+ *    (automatically converted to type 'element'),
+ *    NULL if there is no element after 'element' or
+ *    'element' is NULL
+ */
+#define avl_next_element_safe(tree, element, node_member) \
+  ((element) == NULL || avl_is_last(tree, &(element)->node_member) ? NULL : avl_next_element(element, node_member))
+
+/**
+ * This function must not be called for the first element of
+ * an avl tree
+ *
+ * @param element pointer to a node of the tree
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to the node before 'element'
+ *    (automatically converted to type 'element')
+ */
+#define avl_prev_element(element, node_member) \
+  container_of((&(element)->node_member.list)->prev, typeof(*(element)), node_member)
+
+/**
+ * @param element pointer to a node of the tree
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @return pointer to the node before 'element'
+ *    (automatically converted to type 'element'),
+ *    NULL if there is no element before 'element' or
+ *    'element' is NULL
+ */
+#define avl_prev_element_safe(tree, element, node_member) \
+  ((element) == NULL || avl_is_first(tree, &(element)->node_member) ? NULL : avl_prev_element(element, node_member))
+
+
+/**
+ * Loop over a block of elements of a tree, used similar to a for() command.
+ * This loop should not be used if elements are removed from the tree during
+ * the loop.
+ *
+ * @param first pointer to first element of loop
+ * @param last pointer to last element of loop
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the list during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ */
+#define avl_for_element_range(first, last, element, node_member) \
+  for (element = (first); \
+       element->node_member.list.prev != &(last)->node_member.list; \
+       element = avl_next_element(element, node_member))
+
+/**
+ * Loop over a block of elements of a tree backwards, used similar to a for() command.
+ * This loop should not be used if elements are removed from the tree during
+ * the loop.
+ *
+ * @param first pointer to first element of loop
+ * @param last pointer to last element of loop
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the list during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ */
+#define avl_for_element_range_reverse(first, last, element, node_member) \
+  for (element = (last); \
+       element->node_member.list.next != &(first)->node_member.list; \
+       element = avl_prev_element(element, node_member))
+
+/**
+ * Loop over all elements of an avl_tree, used similar to a for() command.
+ * This loop should not be used if elements are removed from the tree during
+ * the loop.
+ *
+ * @param tree pointer to avl-tree
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the tree during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ */
+#define avl_for_each_element(tree, element, node_member) \
+  avl_for_element_range(avl_first_element(tree, element, node_member), \
+                        avl_last_element(tree, element,  node_member), \
+                        element, node_member)
+
+/**
+ * Loop over all elements of an avl_tree backwards, used similar to a for() command.
+ * This loop should not be used if elements are removed from the tree during
+ * the loop.
+ *
+ * @param tree pointer to avl-tree
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the tree during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ */
+#define avl_for_each_element_reverse(tree, element, node_member) \
+  avl_for_element_range_reverse(avl_first_element(tree, element, node_member), \
+                                avl_last_element(tree, element,  node_member), \
+                                element, node_member)
+
+/**
+ * Loop over a block of elements of a tree, used similar to a for() command.
+ * This loop should not be used if elements are removed from the tree during
+ * the loop.
+ * The loop runs from the element 'first' to the end of the tree.
+ *
+ * @param tree pointer to avl-tree
+ * @param first pointer to first element of loop
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the list during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ */
+#define avl_for_element_to_last(tree, first, element, node_member) \
+  avl_for_element_range(first, avl_last_element(tree, element, node_member), element, node_member)
+
+
+/**
+ * Loop over a block of elements of a tree backwards, used similar to a for() command.
+ * This loop should not be used if elements are removed from the tree during
+ * the loop.
+ * The loop runs from the element 'first' to the end of the tree.
+ *
+ * @param tree pointer to avl-tree
+ * @param first pointer to first element of loop
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the list during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ */
+#define avl_for_element_to_last_reverse(tree, first, element, node_member) \
+  avl_for_element_range_reverse(first, avl_last_element(tree, element, node_member), element, node_member)
+
+/**
+ * Loop over a block of elements of a tree, used similar to a for() command.
+ * This loop should not be used if elements are removed from the tree during
+ * the loop.
+ * The loop runs from the start of the tree to the element 'last'.
+ *
+ * @param tree pointer to avl-tree
+ * @param last pointer to last element of loop
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the list during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ */
+#define avl_for_first_to_element(tree, last, element, node_member) \
+  avl_for_element_range(avl_first_element(tree, element, node_member), last, element, node_member)
+
+
+/**
+ * Loop over a block of elements of a tree backwards, used similar to a for() command.
+ * This loop should not be used if elements are removed from the tree during
+ * the loop.
+ * The loop runs from the start of the tree to the element 'last'.
+ *
+ * @param tree pointer to avl-tree
+ * @param last pointer to last element of loop
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the list during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ */
+#define avl_for_first_to_element_reverse(tree, last, element, node_member) \
+  avl_for_element_range_reverse(avl_first_element(tree, element, node_member), last, element, node_member)
+
+/**
+ * Loop over a block of nodes of a tree, used similar to a for() command.
+ * This loop can be used if the current element might be removed from
+ * the tree during the loop. Other elements should not be removed during
+ * the loop.
+ *
+ * @param first_element first element of loop
+ * @param last_element last element of loop
+ * @param element iterator pointer to tree element struct
+ * @param node_member name of avl_node within tree element struct
+ * @param ptr pointer to tree element struct which is used to store
+ *    the next node during the loop
+ */
+#define avl_for_element_range_safe(first_element, last_element, element, node_member, ptr) \
+  for (element = (first_element), ptr = avl_next_element(first_element, node_member); \
+       element->node_member.list.prev != &(last_element)->node_member.list; \
+       element = ptr, ptr = avl_next_element(ptr, node_member))
+
+/**
+ * Loop over a block of elements of a tree backwards, used similar to a for() command.
+ * This loop can be used if the current element might be removed from
+ * the tree during the loop. Other elements should not be removed during
+ * the loop.
+ *
+ * @param first_element first element of range (will be last returned by the loop)
+ * @param last_element last element of range (will be first returned by the loop)
+ * @param element iterator pointer to node element struct
+ * @param node_member name of avl_node within node element struct
+ * @param ptr pointer to node element struct which is used to store
+ *    the previous node during the loop
+ */
+#define avl_for_element_range_reverse_safe(first_element, last_element, element, node_member, ptr) \
+  for (element = (last_element), ptr = avl_prev_element(last_element, node_member); \
+       element->node_member.list.next != &(first_element)->node_member.list; \
+       element = ptr, ptr = avl_prev_element(ptr, node_member))
+
+/**
+ * Loop over all elements of an avl_tree, used similar to a for() command.
+ * This loop can be used if the current element might be removed from
+ * the tree during the loop. Other elements should not be removed during
+ * the loop.
+ *
+ * @param tree pointer to avl-tree
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the tree during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @param ptr pointer to a tree element which is used to store
+ *    the next node during the loop
+ */
+#define avl_for_each_element_safe(tree, element, node_member, ptr) \
+  avl_for_element_range_safe(avl_first_element(tree, element, node_member), \
+                             avl_last_element(tree, element, node_member), \
+                             element, node_member, ptr)
+
+/**
+ * Loop over all elements of an avl_tree backwards, used similar to a for() command.
+ * This loop can be used if the current element might be removed from
+ * the tree during the loop. Other elements should not be removed during
+ * the loop.
+ *
+ * @param tree pointer to avl-tree
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the tree during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @param ptr pointer to a tree element which is used to store
+ *    the next node during the loop
+ */
+#define avl_for_each_element_reverse_safe(tree, element, node_member, ptr) \
+  avl_for_element_range_reverse_safe(avl_first_element(tree, element, node_member), \
+                                     avl_last_element(tree, element, node_member), \
+                                     element, node_member, ptr)
+
+/**
+ * A special loop that removes all elements of the tree and cleans up the tree
+ * root. The loop body is responsible to free the node elements of the tree.
+ *
+ * This loop is faster than a normal one for clearing the tree because it
+ * does not rebalance the tree after each removal. Do NOT use a break command
+ * inside.
+ * You can free the memory of the elements within the loop.
+ * Do NOT call avl_delete() on the elements within the loop,
+ *
+ * @param tree pointer to avl-tree
+ * @param element pointer to a node of the tree, this element will
+ *    contain the current node of the tree during the loop
+ * @param node_member name of the avl_node element inside the
+ *    larger struct
+ * @param ptr pointer to a tree element which is used to store
+ *    the next node during the loop
+ */
+#define avl_remove_all_elements(tree, element, node_member, ptr) \
+  for (element = avl_first_element(tree, element, node_member), \
+       ptr = avl_next_element(element, node_member), \
+       list_init_head(&(tree)->list_head), \
+       (tree)->root = NULL; \
+       (tree)->count > 0; \
+       element = ptr, ptr = avl_next_element(ptr, node_member), (tree)->count--)
+
+#endif /* _AVL_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/common/avl_comp.c b/src/common/avl_comp.c
new file mode 100644 (file)
index 0000000..8c7e9f3
--- /dev/null
@@ -0,0 +1,143 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <string.h>
+#include <strings.h>
+
+#include "common/avl_comp.h"
+#include "common/string.h"
+
+/**
+ * AVL tree comparator for unsigned 32 bit integers
+ * Custom pointer is not used.
+ * @param k1 pointer to key 1
+ * @param k2 pointer to key 2
+ * @param ptr custom pointer for avl comparater (unused)
+ * @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
+ */
+int
+avl_comp_uint32(const void *k1, const void *k2, void *ptr __attribute__ ((unused)))
+{
+  const uint32_t *u1 = k1;
+  const uint32_t *u2 = k2;
+
+  if (*u1 > *u2) {
+    return 1;
+  }
+  if (*u2 > *u1) {
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * AVL tree comparator for unsigned 16 bit integers
+ * Custom pointer is not used.
+ * @param k1 pointer to key 1
+ * @param k2 pointer to key 2
+ * @param ptr custom pointer for avl comparater (unused)
+ * @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
+ */
+int
+avl_comp_uint16(const void *k1, const void *k2, void *ptr __attribute__ ((unused)))
+{
+  const uint16_t *u1 = k1;
+  const uint16_t *u2 = k2;
+
+  if (*u1 > *u2) {
+    return 1;
+  }
+  if (*u2 > *u1) {
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * AVL tree comparator for unsigned 8 bit integers
+ * Custom pointer is not used
+ * @param k1 pointer to key 1
+ * @param k2 pointer to key 2
+ * @param ptr custom pointer for avl comparater (unused)
+ * @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
+ */
+int
+avl_comp_uint8(const void *k1, const void *k2, void *ptr __attribute__ ((unused)))
+{
+  const uint8_t *u1 = k1;
+  const uint8_t *u2 = k2;
+
+  if (*u1 > *u2) {
+    return 1;
+  }
+  if (*u2 > *u1) {
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * AVL tree comparator for arbitrary memory blocks.
+ * Custom pointer is the length of the memory to compare.
+ * @param k1 pointer to key 1
+ * @param k2 pointer to key 2
+ * @param ptr length of memory blocks to compare (size_t)
+ * @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
+ */
+int
+avl_comp_mem(const void *k1, const void *k2, void *ptr) {
+  const size_t length = (const size_t)ptr;
+  return memcmp(k1, k2, length);
+}
+
+/**
+ * AVL tree comparator for case insensitive strings.
+ * Custom pointer is the length of the memory to compare.
+ * @param k1 pointer to string 1
+ * @param k2 pointer to string 2
+ * @param ptr custom pointer for avl comparater (unused)
+ * @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
+ */
+int
+avl_comp_strcasecmp(const void *txt1, const void *txt2,
+    void *ptr __attribute__ ((unused))) {
+  return strcasecmp(txt1, txt2);
+}
diff --git a/src/common/avl_comp.h b/src/common/avl_comp.h
new file mode 100644 (file)
index 0000000..5b3074e
--- /dev/null
@@ -0,0 +1,53 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef AVL_COMP_H_
+#define AVL_COMP_H_
+
+#include "common/common_types.h"
+
+EXPORT int avl_comp_uint32(const void *k1, const void *k2, void *ptr);
+EXPORT int avl_comp_uint16(const void *k1, const void *k2, void *ptr);
+EXPORT int avl_comp_uint8(const void *k1, const void *k2, void *ptr);
+EXPORT int avl_comp_mem(const void *k1, const void *k2, void *ptr);
+EXPORT int avl_comp_strcasecmp(const void *, const void *, void *);
+
+#endif /* AVL_COMP_H_ */
diff --git a/src/common/common_types.h b/src/common/common_types.h
new file mode 100644 (file)
index 0000000..03a4ead
--- /dev/null
@@ -0,0 +1,99 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef COMMON_TYPES_H_
+#define COMMON_TYPES_H_
+
+/* support EXPORT macro of OLSR */
+#ifndef EXPORT
+#  define EXPORT __attribute__((visibility ("default")))
+#endif
+
+/*
+ * This force gcc to always inline, which prevents errors
+ * with option -Os
+ */
+#ifndef INLINE
+#ifdef __GNUC__
+#define INLINE inline __attribute__((always_inline))
+#else
+#define INLINE inline
+#endif
+#endif
+
+/*
+ * This include file creates stdint/stdbool datatypes for
+ * visual studio, because microsoft does not support C99
+ */
+
+/* types */
+#ifdef _MSC_VER
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+
+/* we have a C99 environment */
+#include <stdbool.h>
+#elif defined __GNUC__
+
+/* we simulate a C99 environment */
+#define bool _Bool
+#define true 1
+#define false 0
+#define __bool_true_false_are_defined 1
+#endif
+
+/* add some safe-gaurds */
+#ifndef _MSC_VER
+#if !defined bool || !defined true || !defined false || !defined __bool_true_false_are_defined
+#error You have no C99-like boolean types. Please extend src/olsr_type.h!
+#endif
+#endif
+
+#endif /* COMMON_TYPES_H_ */
diff --git a/src/common/container_of.h b/src/common/container_of.h
new file mode 100644 (file)
index 0000000..8e07eca
--- /dev/null
@@ -0,0 +1,81 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CONTAINER_OF_H_
+#define CONTAINER_OF_H_
+
+#include <stddef.h>
+#include "common/common_types.h"
+
+/* allow compilation with c99 mode */
+#ifndef typeof
+#define typeof(x) __typeof__(x)
+#endif
+
+/**
+ * casts an embedded node of a list/tree into the surrounding struct
+ * this macro returns bad results if ptr is NULL
+ * @param ptr pointer to node
+ * @param type data type of surrounding struct
+ * @param member name of node inside struct
+ * @return pointer to surrounding struct
+ */
+#define container_of(ptr, type, member) ((type *)( (char *)(ptr) - offsetof(type,member) ))
+
+/**
+ * Helper function for NULL safe container_of macro
+ */
+static INLINE void *
+__container_of_if_notnull(void *ptr, size_t offset) {
+  return ptr == NULL ? NULL : (((char *)ptr) - offset);
+}
+
+/**
+ * casts an embedded node of a list/tree into the surrounding struct
+ * this macro returns bad results if ptr is NULL
+ * @param ptr pointer to node
+ * @param type data type of surrounding struct
+ * @param member name of node inside struct
+ * @return pointer to surrounding struct
+ */
+#define container_of_if_notnull(ptr, type, member) ((type *)__container_of_if_notnull(ptr, offsetof(type, member)))
+
+#endif /* CONTAINER_OF_H_ */
diff --git a/src/common/daemonize.c b/src/common/daemonize.c
new file mode 100644 (file)
index 0000000..677d71d
--- /dev/null
@@ -0,0 +1,133 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/daemonize.h"
+
+#ifndef WIN32
+/**
+ * Prepare the start of a daemon. Fork into background,
+ * but keep stdin/out/err open and a pipe connected to
+ * the parent. Parent will wait for the exit_code
+ * send by the child.
+ * @return filedescriptor of pipe, -1 if an error happened
+ */
+int
+daemonize_prepare(void) {
+  int fork_pipe[2];
+  int ret;
+  int exit_code = -1;
+
+  if (pipe(fork_pipe)) {
+    /* error during pipe creation */
+    return -1;
+  }
+
+  ret = fork();
+  if (ret == -1) {
+    /* first fork() failed */
+    return -1;
+  }
+
+  if (ret != 0) {
+    /* parent of first fork() */
+
+    /* wait for exit_code from daemonized part */
+    if (read(fork_pipe[0], &exit_code, sizeof(exit_code)) != sizeof(exit_code)) {
+      exit_code = -1;
+    }
+    close (fork_pipe[1]);
+    close (fork_pipe[0]);
+    exit(exit_code);
+  }
+
+  /* child of first fork() */
+
+  ret = fork();
+  if (ret == -1) {
+    /* second fork() failed */
+    exit_code = -1;
+    if (write(fork_pipe[1], &exit_code, sizeof(exit_code)) != sizeof(exit_code)) {
+      /* there is nothing we can do here */
+    }
+    exit(0);
+  }
+
+  if (ret != 0) {
+    /* parent of second fork(), exit to detach child */
+    exit(0);
+  }
+
+  /* child is up, but keep pipe alive to transmit exit code later */
+  return fork_pipe[1];
+}
+
+/**
+ * Finalize the fork of the daemon, call the parent and
+ * tell it to exit.
+ * @param pipe_fd returned file desriptor of daemonize_prepare
+ * @param exit_code exit code for parent
+ */
+void
+daemonize_finish(int pipe_fd, int exit_code) {
+  if (pipe_fd == 0) {
+    /* ignore call if pipe not set */
+    return;
+  }
+
+  /* tell parent to shut down with defined exit_code */
+  if (write(pipe_fd, &exit_code, sizeof(exit_code)) != sizeof(exit_code)) {
+    /* there is nothing we can do here */
+  }
+
+  /* shut down stdin/out/err */
+  close (STDIN_FILENO);
+  close (STDOUT_FILENO);
+  close (STDERR_FILENO);
+}
+
+#endif
diff --git a/src/common/daemonize.h b/src/common/daemonize.h
new file mode 100644 (file)
index 0000000..dacac71
--- /dev/null
@@ -0,0 +1,63 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef DAEMONIZE_H_
+#define DAEMONIZE_H_
+
+#include "common/common_types.h"
+
+#ifndef WIN32
+EXPORT int daemonize_prepare(void);
+EXPORT void daemonize_finish(int pipe_fd, int exitcode);
+#else
+
+static INLINE int
+daemonize_prepare(void) {
+  return -1;
+}
+static INLINE void
+daemonize_finish(int pipe_fd __attribute__((unused)),
+    int exitcode __attribute__((unused))) {
+  return;
+}
+#endif
+
+#endif /* DAEMONIZE_H_ */
diff --git a/src/common/list.h b/src/common/list.h
new file mode 100644 (file)
index 0000000..3cbb261
--- /dev/null
@@ -0,0 +1,476 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef LIST_H_
+#define LIST_H_
+
+#include <stddef.h>
+
+#include "common/container_of.h"
+#include "common/common_types.h"
+
+/**
+ * this struct is used as list head and list elements.
+ * the list-nodes and the list-head contain two rings of
+ * pointers (one forward, one backward), the first/last node
+ * have a link to the head, no NULL element.
+ */
+struct list_entity {
+  /**
+   * Pointer to next element in list or to list head if last element
+   */
+  struct list_entity *next;
+
+  /**
+   * Pointer to previous element in list or list head if first element
+   */
+  struct list_entity *prev;
+};
+
+/**
+ * initialize a list-head
+ * @param pointer to list-head
+ */
+static INLINE void
+list_init_head(struct list_entity *head) {
+  head->next = head->prev = head;
+}
+
+/**
+ * initialize a list-node
+ * @param pointer to list-node
+ */
+static INLINE void
+list_init_node(struct list_entity *entity) {
+  entity->next = entity->prev = NULL;
+}
+
+/**
+ * internal function to add a new node between two other nodes.
+ * @param prev node before the insertion point
+ * @param next node after the insertion point
+ * @param new node which will be added to the list between 'prev' and 'next'
+ */
+static INLINE void
+__list_add(struct list_entity *prev, struct list_entity *next, struct list_entity *new) {
+  new->next = next;
+  new->prev = prev;
+  next->prev = new;
+  prev->next = new;
+}
+
+/**
+ * adds a node at the beginning of a list
+ * @param head pointer to list head
+ * @param new node which will be added to the list
+ */
+static INLINE void
+list_add_head(struct list_entity *head, struct list_entity *new) {
+  __list_add(head, head->next, new);
+}
+
+/**
+ * adds a node at the end of a list
+ * @param head pointer to list head
+ * @param new node which will be added to the list
+ */
+static INLINE void
+list_add_tail(struct list_entity *head, struct list_entity *new) {
+  __list_add(head->prev, head, new);
+}
+
+/**
+ * adds a node before another node
+ * @param before reference node in the list
+ * @param new node which will be added to the list
+ */
+static INLINE void
+list_add_before(struct list_entity *before, struct list_entity *new) {
+  __list_add(before->prev, before, new);
+}
+
+/**
+ * adds a node after another node
+ * @param before reference node in the list
+ * @param new node which will be added to the list
+ */
+static INLINE void
+list_add_after(struct list_entity *after, struct list_entity *new) {
+  __list_add(after, after->next, new);
+}
+
+/**
+ * internal function that removes the nodes between two other nodes.
+ * @param prev node before the removed part of the list
+ * @param next node after the removed part of the list
+ */
+static INLINE void
+__list_remove(struct list_entity *prev, struct list_entity *next) {
+  prev->next = next;
+  next->prev = prev;
+}
+
+/**
+ * removes a node from a list and clears node pointers
+ * @param entity node to remove from the list
+ */
+static INLINE void
+list_remove(struct list_entity *entity) {
+  __list_remove(entity->prev, entity->next);
+  entity->prev = entity->next = NULL;
+}
+
+/**
+ * checks if list is empty
+ * @param head pointer to list head
+ * @return true if list is empty, false otherwise
+ */
+static INLINE bool
+list_is_empty(struct list_entity *head) {
+  return head->next == head && head->prev == head;
+}
+
+/**
+ * checks if node has been added to a list
+ * @param node pointer to node
+ * @return true if both pointers of the node are initialized,
+ *   false otherwise
+ */
+static INLINE bool
+list_node_added(struct list_entity *node) {
+  return node->next != NULL && node->prev != NULL;
+}
+
+/**
+ * checks if a node is the first element of a list
+ * @param head pointer to list head
+ * @param entity pointer to node
+ * @return true if node is first element of list, false otherwise
+ */
+static INLINE bool
+list_is_first(const struct list_entity *head, const struct list_entity *entity) {
+  return head->next == entity;
+}
+
+/**
+ * checks if node is the last element of a list
+ * @param head pointer to list head
+ * @param entity pointer to node
+ * @return true if node is last element of list, false otherwise
+ */
+static INLINE bool
+list_is_last(const struct list_entity *head, const struct list_entity *entity) {
+  return head->prev == entity;
+}
+
+/**
+ * Merge two lists and clear the second head
+ * @param add_to head of the list which will contain all elements
+ * @param remove_from head of the list which elements will be added after the elements
+ *   of the first one
+ */
+static INLINE void
+list_merge(struct list_entity *add_to, struct list_entity *remove_from) {
+  if (list_is_empty(remove_from)) {
+    return;
+  }
+
+  add_to->next->prev = remove_from->prev;
+  remove_from->prev->next = add_to->next;
+  add_to->next = remove_from->next;
+  remove_from->next->prev = add_to;
+
+  list_init_head(remove_from);
+}
+
+/**
+ * @param head pointer to list-head
+ * @param element pointer to a node element
+ *    (don't need to be initialized)
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ * @return pointer to the first element of the list
+ *    (automatically converted to type 'element')
+ */
+#define list_first_element(head, element, list_member) \
+    container_of((head)->next, typeof(*(element)), list_member)
+
+/**
+ * @param head pointer to list-head
+ * @param element pointer to a node element
+ *    (don't need to be initialized)
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ * @return pointer to the last element of the list
+ *    (automatically converted to type 'element')
+ */
+#define list_last_element(head, element, list_member) \
+    container_of((head)->prev, typeof(*(element)), list_member)
+
+/**
+ * This function must not be called for the last element of
+ * a list
+ *
+ * @param element pointer to a node of the list
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ * @return pointer to the node after 'element'
+ *    (automatically converted to type 'element')
+ */
+#define list_next_element(element, list_member) \
+  container_of((&(element)->list_member)->next, typeof(*(element)), list_member)
+
+/**
+ * This function must not be called for the first element of
+ * a list
+ *
+ * @param element pointer to a node of the list
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ * @return pointer to the node before 'element'
+ *    (automatically converted to type 'element')
+ */
+#define list_prev_element(element, list_member) \
+  container_of((&(element)->list_member)->prev, typeof(*(element)), list_member)
+
+/**
+ * Loop over a block of elements of a list, used similar to a for() command.
+ * This loop should not be used if elements are removed from the list during
+ * the loop.
+ *
+ * @param first_element first element of loop
+ * @param last_element last element of loop
+ * @param element iterator pointer to list element struct
+ * @param list_member name of list_entity within list element struct
+ */
+#define list_for_element_range(first_element, last_element, element, list_member) \
+  for (element = (first_element); \
+       element->list_member.prev != &(last_element)->list_member; \
+       element = list_next_element(element, list_member))
+
+/**
+ * Loop over a block of elements of a list backwards, used similar to a for() command.
+ * This loop should not be used if elements are removed from the list during
+ * the loop.
+ *
+ * @param first_element first element of range (will be last returned by the loop)
+ * @param last_element last element of range (will be first returned by the loop)
+ * @param element iterator pointer to list element struct
+ * @param list_member name of list_entity within list element struct
+ */
+#define list_for_element_range_reverse(first_element, last_element, element, list_member) \
+  for (element = (last_element); \
+       element->list_member.next != &(first_element)->list_member; \
+       element = list_prev_element(element, list_member))
+
+/**
+ * Loop over all elements of a list, used similar to a for() command.
+ * This loop should not be used if elements are removed from the list during
+ * the loop.
+ *
+ * @param head pointer to list-head
+ * @param element pointer to a node of the list, this element will
+ *    contain the current node of the list during the loop
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ */
+#define list_for_each_element(head, element, list_member) \
+  list_for_element_range(list_first_element(head, element, list_member), \
+                         list_last_element(head, element, list_member), \
+                         element, list_member)
+
+/**
+ * Loop over all elements of a list backwards, used similar to a for() command.
+ * This loop should not be used if elements are removed from the list during
+ * the loop.
+ *
+ * @param head pointer to list-head
+ * @param element pointer to a node of the list, this element will
+ *    contain the current node of the list during the loop
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ */
+#define list_for_each_element_reverse(head, element, list_member) \
+  list_for_element_range_reverse(list_first_element(head, element, list_member), \
+                                 list_last_element(head, element, list_member), \
+                                 element, list_member)
+
+/**
+ * Loop over a block of elements of a list, used similar to a for() command.
+ * This loop should not be used if elements are removed from the list during
+ * the loop.
+ * The loop runs from the element 'first' to the end of the list.
+ *
+ * @param head pointer to head of list
+ * @param first pointer to first element of loop
+ * @param element pointer to a node of the list, this element will
+ *    contain the current node of the list during the loop
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ */
+#define list_for_element_to_last(head, first, element, list_member) \
+  list_for_element_range(first, list_last_element(head, element, list_member), element, list_member)
+
+/**
+ * Loop over a block of elements of a list backwards, used similar to a for() command.
+ * This loop should not be used if elements are removed from the list during
+ * the loop.
+ * The loop runs from the end of the list to the element 'first'.
+ *
+ * @param head pointer to head of list
+ * @param first pointer to first element of loop
+ * @param element pointer to a node of the list, this element will
+ *    contain the current node of the list during the loop
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ */
+#define list_for_element_to_last_reverse(head, first, element, list_member) \
+  list_for_element_range_reverse(first, list_last_element(head, element, list_member), element, list_member)
+
+/**
+ * Loop over a block of elements of a list, used similar to a for() command.
+ * This loop should not be used if elements are removed from the list during
+ * the loop.
+ * The loop runs from the start of the list to the element 'last'.
+ *
+ * @param head pointer to head of list
+ * @param last pointer to last element of loop
+ * @param element pointer to a node of the list, this element will
+ *    contain the current node of the list during the loop
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ */
+#define list_for_first_to_element(head, last, element, list_member) \
+  list_for_element_range(list_first_element(head, element, list_member), last, element, list_member)
+
+/**
+ * Loop over a block of elements of a list backwards, used similar to a for() command.
+ * This loop should not be used if elements are removed from the list during
+ * the loop.
+ * The loop runs from the element 'last' to the start of the list.
+ *
+ * @param head pointer to head of list
+ * @param last pointer to last element of loop
+ * @param element pointer to a node of the list, this element will
+ *    contain the current node of the list during the loop
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ * @param loop_ptr pointer to an list_entity which is used as the
+ *    internal iterator
+ */
+#define list_for_first_to_element_reverse(head, last, element, list_member) \
+  list_for_element_range_reverse(list_first_element(head, element, list_member), last, element, list_member)
+
+/**
+ * Loop over a block of elements of a list, used similar to a for() command.
+ * This loop can be used if the current element might be removed from
+ * the list during the loop. Other elements should not be removed during
+ * the loop.
+ *
+ * @param first_element first element of loop
+ * @param last_element last element of loop
+ * @param element iterator pointer to list element struct
+ * @param list_member name of list_entity within list element struct
+ * @param ptr pointer to list element struct which is used to store
+ *    the next node during the loop
+ */
+#define list_for_element_range_safe(first_element, last_element, element, list_member, ptr) \
+  for (element = (first_element), ptr = list_next_element(first_element, list_member); \
+       element->list_member.prev != &(last_element)->list_member; \
+       element = ptr, ptr = list_next_element(ptr, list_member))
+
+/**
+ * Loop over a block of elements of a list backwards, used similar to a for() command.
+ * This loop can be used if the current element might be removed from
+ * the list during the loop. Other elements should not be removed during
+ * the loop.
+ *
+ * @param first_element first element of range (will be last returned by the loop)
+ * @param last_element last element of range (will be first returned by the loop)
+ * @param element iterator pointer to list element struct
+ * @param list_member name of list_entity within list element struct
+ * @param ptr pointer to list element struct which is used to store
+ *    the previous node during the loop
+ */
+#define list_for_element_range_reverse_safe(first_element, last_element, element, list_member, ptr) \
+  for (element = (last_element), ptr = list_prev_element(last_element, list_member); \
+       element->list_member.next != &(first_element)->list_member; \
+       element = ptr, ptr = list_prev_element(ptr, list_member))
+
+/**
+ * Loop over all elements of a list, used similar to a for() command.
+ * This loop can be used if the current element might be removed from
+ * the list during the loop. Other elements should not be removed during
+ * the loop.
+ *
+ * @param head pointer to list-head
+ * @param element pointer to a node of the list, this element will
+ *    contain the current node of the list during the loop
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ * @param ptr pointer to an list element struct which is used to store
+ *    the next node during the loop
+ */
+#define list_for_each_element_safe(head, element, list_member, ptr) \
+  list_for_element_range_safe(list_first_element(head, element, list_member), \
+                              list_last_element(head, element, list_member), \
+                              element, list_member, ptr)
+
+/**
+ * Loop over all elements of a list backwards, used similar to a for() command.
+ * This loop can be used if the current element might be removed from
+ * the list during the loop. Other elements should not be removed during
+ * the loop.
+ *
+ * @param head pointer to list-head
+ * @param element pointer to a node of the list, this element will
+ *    contain the current node of the list during the loop
+ * @param list_member name of the list_entity element inside the
+ *    larger struct
+ * @param ptr pointer to an list element struct which is used to store
+ *    the next node during the loop
+ */
+#define list_for_each_element_reverse_safe(head, element, list_member, ptr) \
+  list_for_element_range_reverse_safe(list_first_element(head, element, list_member), \
+                                      list_last_element(head, element, list_member), \
+                                      element, list_member, ptr)
+
+#endif /* LIST_H_ */
diff --git a/src/common/netaddr.c b/src/common/netaddr.c
new file mode 100644 (file)
index 0000000..47a2bdf
--- /dev/null
@@ -0,0 +1,847 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/common_types.h"
+#include "common/string.h"
+#include "common/netaddr.h"
+
+static const uint32_t _zero_addr[4] = { 0,0,0,0 };
+
+static char *_mac_to_string(char *dst, const void *bin, size_t dst_size,
+    size_t bin_size, char separator);
+static int _mac_from_string(void *bin, size_t bin_size,
+    const char *src, char separator);
+static int _subnetmask_to_prefixlen(const char *src);
+static int _read_hexdigit(const char c);
+static bool _binary_is_in_subnet(const struct netaddr *subnet,
+    const void *bin);
+/**
+ * Read the binary representation of an address into a netaddr object
+ * @param dst pointer to netaddr object
+ * @param binary source pointer
+ * @param len length of source buffer
+ * @param addr_type address type of source
+ * @return 0 if successful read binary data, -1 otherwise
+ */
+int
+netaddr_from_binary(struct netaddr *dst, void *binary, size_t len, uint8_t addr_type) {
+  memset(dst->addr, 0, sizeof(dst->addr));
+  if (addr_type == AF_INET && len >= 4) {
+    /* ipv4 */
+    memcpy(dst->addr, binary, 4);
+    dst->prefix_len = 32;
+  }
+  else if (addr_type == AF_INET6 && len >= 16){
+    /* ipv6 */
+    memcpy(dst->addr, binary, 16);
+    dst->prefix_len = 128;
+  }
+  else if (addr_type == AF_MAC48 && len >= 6) {
+    /* mac48 */
+    memcpy(&dst->addr, binary, 6);
+    dst->prefix_len = 48;
+  }
+  else if (addr_type == AF_EUI64 && len >= 8) {
+    /* eui 64 */
+    memcpy(dst->addr, binary, 8);
+    dst->prefix_len = 64;
+  }
+  else {
+    /* unknown address type */
+    return -1;
+  }
+
+  /* copy address type */
+  dst->type = addr_type;
+
+  return 0;
+}
+
+/**
+ * Writes a netaddr object into a binary buffer
+ * @param dst binary buffer
+ * @param src netaddr source
+ * @param len length of destination buffer
+ * @return 0 if successful read binary data, -1 otherwise
+ */
+int
+netaddr_to_binary(void *dst, struct netaddr *src, size_t len) {
+  if (src->type == AF_INET && len >= 4) {
+    /* ipv4 */
+    memcpy(dst, src->addr, 4);
+  }
+  else if (src->type == AF_INET6 && len >= 16) {
+    /* ipv6 */
+    memcpy(dst, src->addr, 16);
+  }
+  else if (src->type == AF_MAC48 && len >= 6) {
+    /* 48 bit MAC address */
+    memcpy(dst, src->addr, 6);
+  }
+  else if (src->type == AF_EUI64 && len >= 8) {
+    /* 64 bit EUI */
+    memcpy(dst, src->addr, 8);
+  }
+  else {
+    /* unknown address type */
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * Reads the address and address-type part of an
+ * netaddr_socket into a netaddr object
+ * @param dst netaddr object
+ * @param src netaddr_socket source
+ * @return 0 if successful read binary data, -1 otherwise
+ */
+int
+netaddr_from_socket(struct netaddr *dst, union netaddr_socket *src) {
+  memset(dst->addr, 0, sizeof(dst->addr));
+  if (src->std.sa_family == AF_INET) {
+    /* ipv4 */
+    memcpy(dst->addr, &src->v4.sin_addr, 4);
+    dst->prefix_len = 32;
+  }
+  else if (src->std.sa_family == AF_INET6){
+    /* ipv6 */
+    memcpy(dst->addr, &src->v6.sin6_addr, 16);
+    dst->prefix_len = 128;
+  }
+  else {
+    /* unknown address type */
+    return -1;
+  }
+  dst->type = (uint8_t)src->std.sa_family;
+  return 0;
+}
+
+/**
+ * Writes the address and address-type of a netaddr object
+ * into a netaddr_socket.
+ * @param dst pointer to netaddr_socket
+ * @param src netaddr source
+ * @return 0 if successful read binary data, -1 otherwise
+ */
+int
+netaddr_to_socket(union netaddr_socket *dst, struct netaddr *src) {
+  /* copy address type */
+  dst->std.sa_family = src->type;
+
+  if (src->type == AF_INET) {
+    /* ipv4 */
+    memcpy(&dst->v4.sin_addr, src->addr, 4);
+  }
+  else if (src->type == AF_INET6) {
+    /* ipv6 */
+    memcpy(&dst->v6.sin6_addr, src->addr, 16);
+  }
+  else {
+    /* unknown address type */
+    return -1;
+  }
+
+  /* copy address type */
+  dst->std.sa_family= src->type;
+  return 0;
+}
+
+
+int
+netaddr_to_autobuf(struct autobuf *abuf, struct netaddr *src) {
+  switch (src->type) {
+    case AF_INET:
+      /* ipv4 */
+      return abuf_memcpy(abuf, src->addr, 4);
+
+    case AF_INET6:
+      /* ipv6 */
+      return abuf_memcpy(abuf, src->addr, 16);
+
+    case AF_MAC48:
+      /* 48 bit MAC address */
+      return abuf_memcpy(abuf, src->addr, 6);
+
+    case AF_EUI64:
+      /* 64 bit EUI */
+      return abuf_memcpy(abuf, src->addr, 8);
+
+    default:
+      /* unknown address type */
+      return -1;
+  }
+}
+
+/**
+ * Initialize a netaddr_socket with a netaddr and a port number
+ * @param combined pointer to netaddr_socket to be initialized
+ * @param addr pointer to netaddr source
+ * @param port port number for socket
+ * @return 0 if successful read binary data, -1 otherwise
+ */
+int
+netaddr_socket_init(union netaddr_socket *combined, struct netaddr *addr, uint16_t port) {
+  /* initialize memory block */
+  memset(combined, 0, sizeof(*combined));
+
+  if (addr->type == AF_INET) {
+    /* ipv4 */
+    memcpy(&combined->v4.sin_addr, addr->addr, 4);
+    combined->v4.sin_port = htons(port);
+  }
+  else if (addr->type == AF_INET6) {
+    /* ipv6 */
+    memcpy(&combined->v6.sin6_addr, addr->addr, 16);
+    combined->v6.sin6_port = htons(port);
+  }
+  else {
+    /* unknown address type */
+    return -1;
+  }
+
+  /* copy address type */
+  combined->std.sa_family = addr->type;
+  return 0;
+}
+
+/**
+ * @param sock pointer to netaddr_socket
+ * @return port of socket
+ */
+uint16_t
+netaddr_socket_get_port(union netaddr_socket *sock) {
+  switch (sock->std.sa_family) {
+    case AF_INET:
+      return ntohs(sock->v4.sin_port);
+    case AF_INET6:
+      return ntohs(sock->v6.sin6_port);
+    default:
+      return 0;
+  }
+}
+
+/**
+ * Converts a netaddr into a string
+ * @param dst target string buffer
+ * @param src netaddr source
+ * @param forceprefix true if a prefix should be appended even with maximum
+ *   prefix length, false if only shorter prefixes should be appended
+ * @return pointer to target buffer, NULL if an error happened
+ */
+const char *
+netaddr_to_prefixstring(struct netaddr_str *dst,
+    const struct netaddr *src, bool forceprefix) {
+  const char *result = NULL;
+  int maxprefix;
+
+  if (src->type == AF_INET) {
+    result = inet_ntop(AF_INET, src->addr, dst->buf, sizeof(*dst));
+    maxprefix = 32;
+  }
+  else if (src->type == AF_INET6) {
+    result = inet_ntop(AF_INET6, src->addr, dst->buf, sizeof(*dst));
+    maxprefix = 128;
+  }
+  else if (src->type == AF_MAC48) {
+    result = _mac_to_string(dst->buf, src->addr, sizeof(*dst), 6, ':');
+    maxprefix = 48;
+  }
+  else if (src->type == AF_EUI64) {
+    result = _mac_to_string(dst->buf, src->addr, sizeof(*dst), 8, '-');
+    maxprefix = 64;
+  }
+
+  if (result != NULL && (forceprefix || src->prefix_len < maxprefix)) {
+    /* append prefix */
+    snprintf(dst->buf + strlen(result), 5, "/%d", src->prefix_len);
+  }
+  return result;
+}
+
+/**
+ * Generates a netaddr from a string.
+ * @param dst pointer to netaddr object
+ * @param src pointer to input string
+ * @return -1 if an error happened because of an unknown string,
+ *   0 otherwise
+ */
+int
+netaddr_from_string(struct netaddr *dst, const char *src) {
+  struct netaddr_str buf;
+  unsigned int colon_count, minus_count;
+  int result;
+  int prefix_len;
+  bool has_coloncolon, has_point;
+  bool last_was_colon;
+  char *ptr1, *ptr2, *ptr3;
+
+  colon_count = 0;
+  minus_count = 0;
+  has_coloncolon = false;
+  has_point = false;
+
+  last_was_colon = false;
+
+  result = -1;
+  prefix_len = -1;
+
+  /* copy input string in temporary buffer */
+  strscpy(buf.buf, src, sizeof(buf));
+  ptr1 = buf.buf;
+
+  str_trim(&ptr1);
+
+  ptr2 = ptr1;
+  while (*ptr2 != 0 && !isspace(*ptr2) && *ptr2 != '/') {
+    switch (*ptr2) {
+      case ':':
+        if (last_was_colon) {
+          has_coloncolon = true;
+        }
+        colon_count++;
+        break;
+
+      case '.':
+        has_point = true;
+        break;
+
+      case '-':
+        minus_count++;
+        break;
+
+      default:
+        break;
+    }
+    last_was_colon = *ptr2++ == ':';
+  }
+
+  memset(dst, 0, sizeof(*dst));
+  if (*ptr2) {
+    /* split strings */
+    while (isspace(*ptr2)) *ptr2++ = 0;
+    if (*ptr2 == '/') {
+      *ptr2++ = 0;
+    }
+    while (isspace(*ptr2)) *ptr2++ = 0;
+
+    if (*ptr2 == 0) {
+      /* prefixlength is missing */
+      return -1;
+    }
+
+    /* try to read numeric prefix length */
+    prefix_len = (int)strtoul(ptr2, &ptr3, 10);
+    if (ptr3 && *ptr3) {
+      /* not a numeric prefix length */
+      prefix_len = -1;
+    }
+  }
+
+  /* use dst->prefix_len as storage for maximum prefixlen */
+  if ((colon_count == 5 || minus_count == 5)
+      && (colon_count == 0 || minus_count == 0)
+      && !has_point && !has_coloncolon) {
+    dst->type = AF_MAC48;
+    dst->prefix_len = 48;
+    if (colon_count > 0) {
+      result = _mac_from_string(dst->addr, 6, ptr1, ':');
+    }
+    else {
+      result = _mac_from_string(dst->addr, 6, ptr1, '-');
+    }
+  }
+  else if (colon_count == 0 && !has_point && minus_count == 7) {
+    dst->type = AF_EUI64;
+    dst->prefix_len = 64;
+    dst->addr[7] = 2;
+    result = _mac_from_string(dst->addr, 8, ptr1, '-');
+  }
+  else if (colon_count == 0 && has_point && minus_count == 0) {
+    dst->type = AF_INET;
+    dst->prefix_len = 32;
+    result = inet_pton(AF_INET, ptr1, dst->addr) == 1 ? 0 : -1;
+
+    if (result == 0 && *ptr2 && prefix_len == -1) {
+      /* we need a prefix length, but its not a numerical one */
+      prefix_len = _subnetmask_to_prefixlen(ptr2);
+    }
+  }
+  else if ((has_coloncolon || colon_count == 7) && minus_count == 0) {
+    dst->type = AF_INET6;
+    dst->prefix_len = 128;
+    result = inet_pton(AF_INET6, ptr1, dst->addr) == 1 ? 0 : -1;
+  }
+
+  /* stop if an error happened */
+  if (result) {
+    return -1;
+  }
+
+  if (*ptr2) {
+    if (prefix_len < 0 || prefix_len > dst->prefix_len) {
+      /* prefix is too long */
+      return -1;
+    }
+
+    /* store real prefix length */
+    dst->prefix_len = (uint8_t)prefix_len;
+  }
+  return result;
+}
+
+/**
+ * Converts a netaddr_socket into a string
+ * @param dst target string buffer
+ * @param src netaddr_socket source
+ * @return pointer to target buffer, NULL if an error happened
+ */
+const char *
+netaddr_socket_to_string(struct netaddr_str *dst, union netaddr_socket *src) {
+  struct netaddr_str buf;
+
+  if (src->std.sa_family == AF_INET) {
+    snprintf(dst->buf, sizeof(*dst), "%s:%d",
+        inet_ntop(AF_INET, &src->v4.sin_addr, buf.buf, sizeof(buf)),
+        ntohs(src->v4.sin_port));
+  }
+  else if (src->std.sa_family == AF_INET6) {
+    snprintf(dst->buf, sizeof(*dst), "[%s]:%d",
+        inet_ntop(AF_INET6, &src->v6.sin6_addr, buf.buf, sizeof(buf)),
+        ntohs(src->v6.sin6_port));
+  }
+  else {
+    /* unknown address type */
+    return NULL;
+  }
+
+  return dst->buf;
+}
+
+/**
+ * Compares two addresses in network byte order.
+ * Address type will be compared last.
+ *
+ * This function is compatible with the avl comparator
+ * prototype.
+ * @param k1 address 1
+ * @param k2 address 2
+ * @return >0 if k1>k2, <0 if k1<k2, 0 otherwise
+ */
+int
+netaddr_avlcmp(const void *k1, const void *k2, void *ptr __attribute__((unused))) {
+  return netaddr_cmp(k1, k2);
+}
+
+/**
+ * Compares an netaddr object with the address part of
+ * a netaddr_socket.
+ * @param a1 address
+ * @param a2 socket
+ * @return >0 if k1>k2, <0 if k1<k2, 0 otherwise
+ */
+int
+netaddr_cmp_to_socket(const struct netaddr *a1, const union netaddr_socket *a2) {
+  int result = 0;
+
+  result = (int)a1->type - (int)a2->std.sa_family;
+  if (result) {
+    return result;
+  }
+
+  if (a1->type == AF_INET) {
+    result = memcmp(a1->addr, &a2->v4.sin_addr, 4);
+  }
+  else if (a1->type == AF_INET6) {
+    /* ipv6 */
+    result = memcmp(a1->addr, &a2->v6.sin6_addr, 16);
+  }
+
+  if (result) {
+    return result;
+  }
+
+  return (int)a1->prefix_len - (a1->type == AF_INET ? 32 : 128);
+}
+
+/**
+ * Calculates if a binary address is equals to a netaddr one.
+ * @param addr netaddr pointer
+ * @param bin pointer to binary address
+ * @param len length of binary address
+ * @param af family of binary address
+ * @param prefix_len prefix length of binary address
+ * @return true if matches, false otherwise
+ */
+bool
+netaddr_isequal_binary(const struct netaddr *addr,
+    const void *bin, size_t len, uint16_t af, uint8_t prefix_len) {
+  if (addr->type != af || addr->prefix_len != prefix_len) {
+    return false;
+  }
+
+  if (af == AF_INET && len == 4) {
+    return memcmp(addr->addr, bin, 4) == 0;
+  }
+  if (af == AF_INET6 && len == 16) {
+    return memcmp(addr->addr, bin, 16) == 0;
+  }
+  if (af == AF_MAC48 && len == 6) {
+    return memcmp(addr->addr, bin, 6) == 0;
+  }
+  if (af == AF_EUI64 && len == 8) {
+    return memcmp(addr->addr, bin, 8) == 0;
+  }
+  return false;
+}
+
+/**
+ * Checks if a binary address is part of a netaddr prefix.
+ * @param addr netaddr prefix
+ * @param bin pointer to binary address
+ * @param len length of binary address
+ * @param af address family of binary address
+ * @return true if part of the prefix, false otherwise
+ */
+bool
+netaddr_binary_is_in_subnet(const struct netaddr *subnet,
+    const void *bin, size_t len, uint8_t af_family) {
+  if (subnet->type != af_family
+      || netaddr_get_maxprefix(subnet) != len * 8) {
+    return false;
+  }
+  return _binary_is_in_subnet(subnet, bin);
+}
+
+/**
+ * Checks if a netaddr object is part of another netaddr
+ * prefix.
+ * @param subnet netaddr prefix
+ * @param addr netaddr object that might be inside the prefix
+ * @return true if addr is part of subnet, false otherwise
+ */
+bool
+netaddr_is_in_subnet(const struct netaddr *subnet,
+    const struct netaddr *addr) {
+  if (subnet->type != addr->type
+      || subnet->prefix_len > addr->prefix_len) {
+    return false;
+  }
+
+  return _binary_is_in_subnet(subnet, addr->addr);
+}
+
+/**
+ * Calculates the maximum prefix length of an address type
+ * @param af_type address family type
+ * @return prefix length, 0 if unknown address family
+ */
+uint8_t
+netaddr_get_maxprefix(const struct netaddr *addr) {
+  switch (addr->type) {
+    case AF_INET:
+      return 32;
+      break;
+    case AF_INET6:
+      return 128;
+    case AF_MAC48:
+      return 48;
+      break;
+    case AF_EUI64:
+      return 64;
+      break;
+
+    default:
+      return 0;
+  }
+}
+
+#ifdef WIN32
+/**
+ * Helper function for windows
+ * @param dst
+ * @param bin
+ * @param dst_size
+ * @param bin_size
+ * @param separator
+ * @return
+ */
+const char *
+inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
+{
+  if (af == AF_INET) {
+    struct sockaddr_in in;
+    memset(&in, 0, sizeof(in));
+    in.sin_family = AF_INET;
+    memcpy(&in.sin_addr, src, sizeof(struct in_addr));
+    getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in),
+        dst, cnt, NULL, 0, NI_NUMERICHOST);
+    return dst;
+  }
+  else if (af == AF_INET6) {
+    struct sockaddr_in6 in;
+    memset(&in, 0, sizeof(in));
+    in.sin6_family = AF_INET6;
+    memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
+    getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6),
+        dst, cnt, NULL, 0, NI_NUMERICHOST);
+    return dst;
+  }
+  return NULL;
+}
+
+/**
+ * Helper function for windows
+ * @param dst
+ * @param bin
+ * @param dst_size
+ * @param bin_size
+ * @param separator
+ * @return
+ */
+int
+inet_pton(int af, const char *src, void *dst)
+{
+  struct addrinfo hints, *res;
+  union netaddr_socket *sock;
+
+  if (af != AF_INET && af != AF_INET6) {
+    return -1;
+  }
+
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = af;
+  hints.ai_flags = AI_NUMERICHOST;
+
+  if (getaddrinfo(src, NULL, &hints, &res) != 0)
+  {
+    return -1;
+  }
+
+  if (res == NULL) {
+    return 0;
+  }
+
+  sock = (union netaddr_socket *)res->ai_addr;
+  if (af == AF_INET) {
+    memcpy(dst, &sock->v4.sin_addr, 4);
+  }
+  else {
+    memcpy(dst, &sock->v6.sin6_addr, 16);
+  }
+
+  freeaddrinfo(res);
+  return 1;
+}
+
+#endif
+
+/**
+ * Converts a binary mac address into a string representation
+ * @param dst pointer to target string buffer
+ * @param bin pointer to binary source buffer
+ * @param dst_size size of string buffer
+ * @param bin_size size of binary buffer
+ * @param separator character for separating hexadecimal octets
+ * @return pointer to target buffer, NULL if an error happened
+ */
+static char *
+_mac_to_string(char *dst, const void *bin, size_t dst_size,
+    size_t bin_size, char separator) {
+  static const char hex[] = "0123456789abcdef";
+  char *last_separator, *_dst;
+  const uint8_t *_bin;
+
+  _bin = bin;
+  _dst = dst;
+  last_separator = dst;
+
+  if (dst_size == 0) {
+    return NULL;
+  }
+
+  while (bin_size > 0 && dst_size >= 3) {
+    *_dst++ = hex[(*_bin) >> 4];
+    *_dst++ = hex[(*_bin) & 15];
+
+    /* copy pointer to separator */
+    last_separator = _dst;
+
+    /* write separator */
+    *_dst++ = separator;
+
+    /* advance source pointer and decrease remaining length of buffer*/
+    _bin++;
+    bin_size--;
+
+    /* calculate remaining destination size */
+    dst_size-=3;
+  }
+
+  *last_separator = 0;
+  return dst;
+}
+
+/**
+ * Convert a string mac address into a binary representation
+ * @param bin pointer to target binary buffer
+ * @param bin_size pointer to size of target buffer
+ * @param src pointer to source string
+ * @param separator character used to separate octets in source string
+ * @return 0 if sucessfully converted, -1 otherwise
+ */
+static int
+_mac_from_string(void *bin, size_t bin_size, const char *src, char separator) {
+  uint8_t *_bin;
+  int num, digit_2;
+
+  _bin = bin;
+
+  while (bin_size > 0) {
+    num = _read_hexdigit(*src++);
+    if (num == -1) {
+      return -1;
+    }
+    digit_2 = _read_hexdigit(*src);
+    if (digit_2 >= 0) {
+      num = (num << 4) + digit_2;
+      src++;
+    }
+    *_bin++ = (uint8_t) num;
+
+    bin_size--;
+
+    if (*src == 0) {
+      return bin_size ? -1 : 0;
+    }
+    if (*src++ != separator) {
+      return -1;
+    }
+  }
+  return -1;
+}
+
+/**
+ * Reads a single hexadecimal digit
+ * @param c digit to be read
+ * @return integer value (0-15) of digit,
+ *   -1 if not a hexadecimal digit
+ */
+static int
+_read_hexdigit(const char c) {
+  if (c >= '0' && c <= '9') {
+    return c - '0';
+  }
+  if (c >= 'a' && c <= 'f') {
+    return c - 'a' + 10;
+  }
+  if (c >= 'A' && c <= 'F') {
+    return c - 'A' + 10;
+  }
+  return -1;
+}
+
+/**
+ * Converts a ipv4 subnet mask into a prefix length.
+ * @param src string representation of subnet mask
+ * @return prefix length, -1 if source was not a wellformed
+ *   subnet mask
+ */
+static int
+_subnetmask_to_prefixlen(const char *src) {
+  uint32_t v4, shift;
+  int len;
+
+  if (inet_pton(AF_INET, src, &v4) != 1) {
+    return -1;
+  }
+
+  /* transform into host byte order */
+  v4 = ntohl(v4);
+
+  shift = 0xffffffff;
+  for (len = 31; len >= 0; len--) {
+    if (v4 == shift) {
+      return len;
+    }
+    shift <<= 1;
+  }
+
+  /* not wellformed */
+  return -1;
+}
+
+/**
+ * Calculates if a binary address is part of a netaddr prefix.
+ * It will assume that the length of the binary address and its
+ * address family makes sense.
+ * @param addr netaddr prefix
+ * @param bin pointer to binary address
+ * @return true if part of the prefix, false otherwise
+ */
+static bool
+_binary_is_in_subnet(const struct netaddr *subnet, const void *bin) {
+  size_t byte_length, bit_length;
+  const uint8_t *_bin;
+
+  _bin = bin;
+
+  /* split prefix length into whole bytes and bit rest */
+  byte_length = subnet->prefix_len / 8;
+  bit_length = subnet->prefix_len % 8;
+
+  /* compare whole bytes */
+  if (memcmp(subnet->addr, bin, byte_length) != 0) {
+    return false;
+  }
+
+  /* compare bits if necessary */
+  if (bit_length != 0) {
+    return (subnet->addr[byte_length] >> (8 - bit_length))
+        == (_bin[byte_length] >> (8 - bit_length));
+  }
+  return true;
+}
diff --git a/src/common/netaddr.h b/src/common/netaddr.h
new file mode 100644 (file)
index 0000000..f06656a
--- /dev/null
@@ -0,0 +1,163 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef NETADDR_H_
+#define NETADDR_H_
+
+#ifndef WIN32
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+#include <netinet/ip.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+
+
+#define AF_MAC48 ((AF_MAX) + 1)
+#define AF_EUI64 ((AF_MAX) + 2)
+
+/**
+ * Representation of an address including address type
+ * At the moment we support AF_INET, AF_INET6 and AF_MAC48
+ */
+struct netaddr {
+  /* 16 bytes of memory for address */
+  uint8_t addr[16];
+
+  /* address type */
+  uint8_t type;
+
+  /* address prefix length */
+  uint8_t prefix_len;
+};
+
+/**
+ * Representation of a sockaddr object. Allows access
+ * to all variants without casting and compiler warnings.
+ */
+union netaddr_socket {
+  struct sockaddr_in v4;
+  struct sockaddr_in6 v6;
+  struct sockaddr std;
+  struct sockaddr_storage storage;
+};
+
+/**
+ * Buffer for writing string representation of netaddr
+ * and netaddr_socket objects
+ */
+struct netaddr_str {
+  char buf[INET6_ADDRSTRLEN+16];
+};
+
+EXPORT int netaddr_from_binary(struct netaddr *dst, void *binary, size_t len, uint8_t addr_type);
+EXPORT int netaddr_to_binary(void *dst, struct netaddr *src, size_t len);
+EXPORT int netaddr_from_socket(struct netaddr *dst, union netaddr_socket *src);
+EXPORT int netaddr_to_socket(union netaddr_socket *dst, struct netaddr *src);
+EXPORT int netaddr_to_autobuf(struct autobuf *, struct netaddr *src);
+
+EXPORT int netaddr_socket_init(union netaddr_socket *combined, struct netaddr *addr, uint16_t port);
+EXPORT uint16_t netaddr_socket_get_port(union netaddr_socket *sock);
+
+EXPORT const char *netaddr_to_prefixstring(
+    struct netaddr_str *dst, const struct netaddr *src, bool forceprefix);
+EXPORT int netaddr_from_string(struct netaddr *, const char *) __attribute__((warn_unused_result));
+EXPORT const char *netaddr_socket_to_string(struct netaddr_str *, union netaddr_socket *);
+
+EXPORT int netaddr_cmp_to_socket(const struct netaddr *, const union netaddr_socket *);
+EXPORT bool netaddr_isequal_binary(const struct netaddr *addr,
+    const void *bin, size_t len, uint16_t af, uint8_t prefix_len);
+EXPORT bool netaddr_is_in_subnet(const struct netaddr *subnet, const struct netaddr *addr);
+EXPORT bool netaddr_binary_is_in_subnet(const struct netaddr *subnet,
+    const void *bin, size_t len, uint8_t af_family);
+EXPORT int netaddr_avlcmp(const void *, const void *, void *);
+
+EXPORT uint8_t netaddr_get_maxprefix(const struct netaddr *);
+
+#ifdef WIN32
+EXPORT const char *inet_ntop(int af, const void* src, char* dst, int cnt);
+EXPORT int inet_pton(int af, const char *cp, void * buf);
+#endif
+
+/**
+ * Converts a netaddr object into a string.
+ * Prefix will be added if necessary.
+ * @param dst target buffer
+ * @param src netaddr source
+ * @return pointer to target buffer, NULL if an error happened
+ */
+static INLINE const char *
+netaddr_to_string(struct netaddr_str *dst, const struct netaddr *src) {
+  return netaddr_to_prefixstring(dst, src, false);
+}
+
+
+/**
+ * Compares two addresses.
+ * Address type will be compared last.
+ * @param a1 address 1
+ * @param a2 address 2
+ * @return >0 if a1>a2, <0 if a1<a2, 0 otherwise
+ */
+static INLINE int
+netaddr_cmp(const struct netaddr *a1, const struct netaddr *a2) {
+  return memcmp(a1, a2, sizeof(*a1));
+}
+
+/**
+ * Compares two sockets.
+ * @param a1 address 1
+ * @param a2 address 2
+ * @return >0 if a1>a2, <0 if a1<a2, 0 otherwise
+ */
+static INLINE int
+netaddr_socket_cmp(const union netaddr_socket *s1, const union netaddr_socket *s2) {
+  return memcmp(s1, s2, sizeof(*s1));
+}
+
+#endif /* NETADDR_H_ */
diff --git a/src/common/string.c b/src/common/string.c
new file mode 100644 (file)
index 0000000..8bb36e5
--- /dev/null
@@ -0,0 +1,140 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "common/string.h"
+
+/**
+ * A safer version of strncpy that ensures that the
+ * destination string will be null-terminated if its
+ * length is greater than 0.
+ * @param dest target string buffer
+ * @param src source string buffer
+ * @param size size of target buffer
+ * @return pointer to target buffer
+ */
+char *
+strscpy(char *dest, const char *src, size_t size)
+{
+  if (dest == NULL || src == NULL || size == 0) {
+    return dest;
+  }
+
+  /* src does not need to be null terminated */
+  strncpy(dest, src, size-1);
+  dest[size-1] = 0;
+
+  return dest;
+}
+
+/**
+ * A safer version of strncat that ensures that
+ * the target buffer will be null-terminated if
+ * its size is greater than zero.
+ *
+ * If the target buffer is already full, it will
+ * not be changed.
+ * @param dest target string buffer
+ * @param src source string buffer
+ * @param size size of target buffer
+ * @return pointer to target buffer
+ */
+char *
+strscat(char *dest, const char *src, size_t size)
+{
+  size_t l;
+
+  if (dest == NULL || src == NULL || size == 0 || *src == 0) {
+    return dest;
+  }
+
+  l = strlen(dest);
+  if (l < size) {
+    strscpy(dest + l, src, size - l);
+  }
+  return dest;
+}
+
+/**
+ * Removes leading and trailing whitespaces from a string.
+ * Instead of moving characters around, it will change the
+ * pointer to the beginning of the buffer.
+ * @param ptr pointer to string-pointer
+ */
+void
+str_trim (char **ptr) {
+  char *string, *end;
+
+  if (ptr == NULL || *ptr == NULL) {
+    return;
+  }
+
+  string = *ptr;
+
+  /* skip leading whitespaces */
+  while (isspace(*string)) {
+    string++;
+  }
+
+  /* get end of string */
+  end = string;
+  while (*end) {
+    end++;
+  }
+  end--;
+
+  /* remove trailing whitespaces */
+  while (end > string && isspace(*end)) {
+    *end-- = 0;
+  }
+
+  *ptr = string;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/common/string.h b/src/common/string.h
new file mode 100644 (file)
index 0000000..dd149af
--- /dev/null
@@ -0,0 +1,63 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef COMMON_STRING_H_
+#define COMMON_STRING_H_
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include "common/common_types.h"
+
+EXPORT char *strscpy (char *dest, const char *src, size_t size);
+EXPORT char *strscat (char *dest, const char *src, size_t size);
+EXPORT void str_trim (char **ptr);
+
+#endif
+
+/*
+ * Local Variables:
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/common/template.c b/src/common/template.c
new file mode 100644 (file)
index 0000000..f4473f7
--- /dev/null
@@ -0,0 +1,167 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+#include "common/template.h"
+
+static int abuf_find_template(const char **keys, size_t tmplLength,
+    const char *txt, size_t txtLength);
+
+/**
+ * Initialize an index table for a template engine.
+ * Each usage of a key in the format has to be %key%.
+ * The existing keys (start, end, key-number) will be recorded
+ * in the integer array the user provided, so the template
+ * engine can replace them with the values later.
+ *
+ * @param keys array of keys for the template engine
+ * @param tmplLength number of keys
+ * @param format format string of the template
+ * @param indexTable pointer to an template_storage array with a minimum
+ *   length equals to the number of keys used in the format string
+ * @param indexLength length of the size_t array
+ * @return number of indices written into index table,
+ *   -1 if an error happened
+ */
+int
+abuf_template_init (const char **keys, size_t tmplLength, const char *format,
+    struct abuf_template_storage *indexTable, size_t indexLength) {
+  size_t pos = 0, indexCount = 0;
+  size_t start = 0;
+  int i = 0;
+  bool escape = false;
+  bool no_open_format = true;
+
+  while (format[pos]) {
+    if (!escape && format[pos] == '%') {
+      if (no_open_format) {
+        start = pos++;
+        no_open_format = false;
+        continue;
+      }
+      if (pos - start > 1) {
+        if (indexCount + 3 > indexLength) {
+          return -1;
+        }
+
+        i = abuf_find_template(keys, tmplLength, &format[start+1], pos-start-1);
+        if (i != -1) {
+          indexTable[indexCount].start = start;
+          indexTable[indexCount].end = pos+1;
+          indexTable[indexCount].key_index = (size_t)i;
+
+          indexCount++;
+        }
+      }
+      no_open_format = true;
+    }
+    else if (format[pos] == '\\') {
+      /* handle "\\" and "\%" in text */
+      escape = !escape;
+    }
+    else {
+      escape = false;
+    }
+
+    pos++;
+  }
+  return (int)indexCount;
+}
+
+/**
+ * Append the result of a template engine into an autobuffer.
+ * Each usage of a key will be replaced with the corresponding
+ * value.
+ * @param autobuf pointer to autobuf object
+ * @param format format string (as supplied to abuf_template_init()
+ * @param values array of values (same number as keys)
+ * @param indexTable pointer to index table initialized by abuf_template_init()
+ * @param indexCount length of index table as returned by abuf_template_init()
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+int
+abuf_templatef (struct autobuf *autobuf, const char *format,
+    char **values, struct abuf_template_storage *indexTable, size_t indexCount) {
+  size_t i, last = 0;
+
+  if (autobuf == NULL) return 0;
+
+  for (i=0; i<indexCount; i++) {
+    /* copy prefix text */
+    if (last < indexTable[i].start) {
+      if (abuf_memcpy(autobuf, &format[last], indexTable[i].start - last) < 0) {
+        return -1;
+      }
+    }
+    if (abuf_puts(autobuf, values[indexTable[i].key_index]) < 0) {
+      return -1;
+    }
+    last = indexTable[i].end;
+  }
+
+  if (last < strlen(format)) {
+    if (abuf_puts(autobuf, &format[last]) < 0) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+/**
+ * Find the position of one member of a string array in a text.
+ * @param keys pointer to string array
+ * @param tmplLength number of strings in array
+ * @param txt pointer to text to search in
+ * @param txtLength length of text to search in
+ * @return index in array found in text, -1 if no string matched
+ */
+static int
+abuf_find_template(const char **keys, size_t tmplLength, const char *txt, size_t txtLength) {
+  size_t i;
+
+  for (i=0; i<tmplLength; i++) {
+    if (strncmp(keys[i], txt, txtLength) == 0 && keys[i][txtLength] == 0) {
+      return (int)i;
+    }
+  }
+  return -1;
+}
diff --git a/src/common/template.h b/src/common/template.h
new file mode 100644 (file)
index 0000000..269eacf
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * template.h
+ *
+ *  Created on: Jul 19, 2011
+ *      Author: rogge
+ */
+
+#ifndef TEMPLATE_H_
+#define TEMPLATE_H_
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+
+struct abuf_template_storage {
+  size_t start;
+  size_t end;
+  size_t key_index;
+};
+EXPORT int abuf_template_init(const char **keys, size_t length,
+    const char *format, struct abuf_template_storage *indexTable, size_t indexLength);
+EXPORT int abuf_templatef(struct autobuf *autobuf, const char *format,
+    char **values, struct abuf_template_storage *indexTable, size_t indexLength);
+
+#endif /* TEMPLATE_H_ */
diff --git a/src/config/CMakeLists.txt b/src/config/CMakeLists.txt
new file mode 100644 (file)
index 0000000..18c475f
--- /dev/null
@@ -0,0 +1,15 @@
+SET(OLSRD_CONFIG_SRCS io/cfg_io_file.c
+#                      parser/cfg_parser_compact.c
+                      cfg_cmd.c
+                      cfg_db.c
+                      cfg_delta.c
+                      cfg_io.c
+                      cfg_memory.c
+                      cfg_parser.c
+                      cfg_schema.c
+                      cfg.c)
+
+ADD_LIBRARY(OlsrdConfig STATIC ${OLSRD_CONFIG_SRCS})
+IF(WIN32)
+    TARGET_LINK_LIBRARIES(OlsrdConfig ws2_32 iphlpapi)
+ENDIF(WIN32)
diff --git a/src/config/cfg.c b/src/config/cfg.c
new file mode 100644 (file)
index 0000000..00f3433
--- /dev/null
@@ -0,0 +1,170 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <strings.h>
+
+#include "common/autobuf.h"
+#include "common/common_types.h"
+#include "config/cfg.h"
+
+const char *CFGLIST_BOOL_TRUE[] = { "true", "1", "on", "yes" };
+const char *CFGLIST_BOOL[] = { "true", "1", "on", "yes", "false", "0", "off", "no" };
+
+/**
+ * Appends a single line to an autobuffer.
+ * The function replaces all non-printable characters with '.'
+ * and will append a newline at the end
+ * @param autobuf pointer to autobuf object
+ * @param format printf format string
+ * @return -1 if an out-of-memory error happened, 0 otherwise
+ */
+int
+cfg_append_printable_line(struct autobuf *autobuf, const char *fmt, ...) {
+  unsigned char *_value;
+  size_t len;
+  int rv;
+  va_list ap;
+
+  if (autobuf == NULL) return 0;
+
+  _value = (unsigned char *)autobuf->buf + autobuf->len;
+  len = autobuf->len;
+
+  va_start(ap, fmt);
+  rv = abuf_vappendf(autobuf, fmt, ap);
+  va_end(ap);
+
+  if (rv < 0) {
+    return rv;
+  }
+
+  /* convert everything non-printable to '.' */
+  while (*_value && len++ < autobuf->len) {
+    if (*_value < 32 || *_value == 127 || *_value == 255) {
+      *_value = '.';
+    }
+    _value++;
+  }
+  abuf_append_uint8(autobuf, '\n');
+  return 0;
+}
+
+/**
+ * Printable is defined as all ascii characters >= 32 except
+ * 127 and 255.
+ * @param value stringpointer
+ * @return true if string only contains printable characters,
+ *   false otherwise
+ */
+bool
+cfg_is_printable(const char *value) {
+  const unsigned char *_value;
+
+  _value = (const unsigned char *)value;
+
+  while (*_value) {
+    if (*_value < 32 || *_value == 127 || *_value == 255) {
+      return false;
+    }
+    _value++;
+  }
+  return true;
+}
+
+/**
+ * Tests on the pattern [a-zA-Z_][a-zA-Z0-9_]*
+ * @param key section_type/name or entry name
+ * @return true if input string is valid for this parser,
+ *   false otherwise
+ */
+bool
+cfg_is_allowed_key(const char *key) {
+  static const char *valid = "_0123456789"
+      "abcdefghijklmnopqrstuvwxyz"
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  /* test for [a-zA-Z_][a-zA-Z0-9_]* */
+  if (*key >= '0' && *key <= '9') {
+    return false;
+  }
+
+  return key[strspn(key, valid)] == 0;
+}
+
+/**
+ * Null-pointer safe avl compare function for keys implementation.
+ * NULL is considered a string greater than all normal strings.
+ * @param p1 pointer to key 1
+ * @param p2 pointer to key 2
+ * @return similar to strcmp()
+ */
+int
+cfg_avlcmp_keys(const void *p1, const void *p2, void *unused __attribute__((unused))) {
+  const char *str1 = p1;
+  const char *str2 = p2;
+
+  if (str1 == NULL) {
+    return str2 == NULL ? 0 : 1;
+  }
+  if (str2 == NULL) {
+    return -1;
+  }
+
+  return strcasecmp(str1, str2);
+}
+
+/**
+ * Looks up the index of a string within a string array
+ * @param key pointer to string to be looked up in the array
+ * @param array pointer to string pointer array
+ * @param array_size number of strings in array
+ * @return index of the string inside the array, -1 if not found
+ */
+int
+cfg_get_choice_index(const char *key, const char **array, size_t array_size) {
+  size_t i;
+
+  for (i=0; i<array_size; i++) {
+    if (strcasecmp(key, array[i]) == 0) {
+      return (int) i;
+    }
+  }
+  return -1;
+}
diff --git a/src/config/cfg.h b/src/config/cfg.h
new file mode 100644 (file)
index 0000000..3280bba
--- /dev/null
@@ -0,0 +1,86 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_H_
+#define CFG_H_
+
+#include <ctype.h>
+
+#include "common/autobuf.h"
+#include "common/common_types.h"
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a)  (sizeof(a) / sizeof(*(a)))
+#endif
+
+EXPORT int cfg_append_printable_line(struct autobuf *autobuf, const char *fmt, ...)
+  __attribute__ ((format(printf, 2, 3)));
+EXPORT bool cfg_is_printable(const char *value);
+EXPORT bool cfg_is_allowed_key(const char *key);
+EXPORT int cfg_avlcmp_keys(const void *p1, const void *p2, void *unused);
+EXPORT int cfg_get_choice_index(const char *value, const char **array, size_t array_size);
+
+EXPORT const char *CFGLIST_BOOL_TRUE[4];
+EXPORT const char *CFGLIST_BOOL[8];
+
+/**
+ * Compares to keys/names of two section types/names or entry names.
+ * A NULL pointer is considered larger than any valid string.
+ * @param str1 first key
+ * @param str2 second key
+ * @return similar to strcmp()
+ */
+static INLINE int
+cfg_cmp_keys(const char *str1, const char *str2) {
+  return cfg_avlcmp_keys(str1, str2, NULL);
+}
+
+/**
+ * Checks if a string value represents a positive boolean value
+ * @param pointer to string
+ * @return boolean value of the string representation
+ */
+static INLINE bool
+cfg_get_bool(const char *value) {
+  return cfg_get_choice_index(value, CFGLIST_BOOL_TRUE, ARRAYSIZE(CFGLIST_BOOL_TRUE)) >= 0;
+}
+
+#endif /* CFG_H_ */
diff --git a/src/config/cfg_cmd.c b/src/config/cfg_cmd.c
new file mode 100644 (file)
index 0000000..6c52ce6
--- /dev/null
@@ -0,0 +1,465 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef WIN32
+#include <alloca.h>
+#else
+#include <malloc.h>
+#endif
+#include <regex.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "common/autobuf.h"
+#include "common/common_types.h"
+#include "config/cfg_io.h"
+#include "config/cfg_cmd.h"
+
+struct _parsed_argument {
+  char *type;
+  char *name;
+  char *key;
+  char *value;
+};
+
+static int _do_parse_arg(struct cfg_cmd_state *state,
+    char *arg, struct _parsed_argument *pa, struct autobuf *log);
+
+/**
+ * Initialize a command line parser state
+ * @param state pointer to state
+ */
+void
+cfg_cmd_add(struct cfg_cmd_state *state) {
+  memset(state, 0, sizeof(*state));
+}
+
+/**
+ * Cleans up a command line parser state
+ * @param state pointer to state
+ */
+void
+cfg_cmd_remove(struct cfg_cmd_state *state) {
+  free(state->format);
+  free(state->section_name);
+  free(state->section_type);
+  memset(state, 0, sizeof(*state));
+}
+
+/**
+ * Implements the 'set' command for the command line
+ * @param db pointer to cfg_db to be modified
+ * @param state pointer to parser state
+ * @param arg argument of command
+ * @param log pointer for logging
+ * @return 0 if succeeded, -1 otherwise
+ */
+int
+cfg_cmd_handle_set(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log) {
+  struct _parsed_argument pa;
+  char *ptr;
+
+  ptr = alloca(strlen(arg)+1);
+  strcpy(ptr, arg);
+
+  if (_do_parse_arg(state, ptr, &pa, log)) {
+    return -1;
+  }
+
+  if (pa.value != NULL) {
+    if (NULL == cfg_db_set_entry(db, state->section_type, state->section_name, pa.key, pa.value, true)) {
+      cfg_append_printable_line(log, "Cannot create entry: '%s'\n", arg);
+      return -1;
+    }
+    return 0;
+  }
+
+  if (pa.key != NULL) {
+    cfg_append_printable_line(log, "Key without value is not allowed for set command: %s", arg);
+    return -1;
+  }
+
+  /* set section */
+  if (NULL == _cfg_db_add_section(db, state->section_type, state->section_name)) {
+    cfg_append_printable_line(log, "Cannot create section: '%s'\n", arg);
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * Implements the 'remove' command for the command line
+ * @param db pointer to cfg_db to be modified
+ * @param state pointer to parser state
+ * @param arg argument of command
+ * @param log pointer for logging
+ * @return 0 if succeeded, -1 otherwise
+ */
+int
+cfg_cmd_handle_remove(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log) {
+  struct _parsed_argument pa;
+  char *ptr;
+
+  ptr = alloca(strlen(arg)+1);
+  strcpy(ptr, arg);
+
+  if (_do_parse_arg(state, ptr, &pa, log)) {
+    return -1;
+  }
+
+  if (pa.value != NULL) {
+    cfg_append_printable_line(log, "Value is not allowed for remove command: %s", arg);
+    return -1;
+  }
+
+  if (pa.key != NULL) {
+    if (cfg_db_remove_entry(db, state->section_type, state->section_name, pa.key)) {
+      cfg_append_printable_line(log, "Cannot remove entry: '%s'\n", arg);
+      return -1;
+    }
+    return 0;
+  }
+
+  if (state->section_name) {
+    if (cfg_db_remove_namedsection(db, state->section_type, state->section_name)) {
+      cfg_append_printable_line(log, "Cannot remove section: '%s'\n", arg);
+      return -1;
+    }
+  }
+
+  if (state->section_type) {
+    if (cfg_db_remove_sectiontype(db, state->section_type)) {
+      cfg_append_printable_line(log, "Cannot remove section: '%s'\n", arg);
+      return -1;
+    }
+  }
+  return 0;
+}
+
+/**
+ * Implements the 'view' command for the command line
+ * @param db pointer to cfg_db to be modified
+ * @param state pointer to parser state
+ * @param arg argument of command
+ * @param log pointer for logging
+ * @return 0 if succeeded, -1 otherwise
+ */
+int
+cfg_cmd_handle_get(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log) {
+  struct cfg_section_type *type, *type_it;
+  struct cfg_named_section *named, *named_it;
+  struct cfg_entry *entry, *entry_it;
+  struct _parsed_argument pa;
+  char *ptr;
+
+  if (arg == NULL || *arg == 0) {
+    cfg_append_printable_line(log, "Section types in database:");
+
+    OLSR_FOR_ALL_CFG_SECTION_TYPES(db, type, type_it) {
+      cfg_append_printable_line(log, "%s", type->type);
+    }
+    return 0;
+  }
+
+  ptr = alloca(strlen(arg)+1);
+  strcpy(ptr, arg);
+
+  if (_do_parse_arg(state, ptr, &pa, log)) {
+    return -1;
+  }
+
+  if (pa.value != NULL) {
+    cfg_append_printable_line(log, "Value is not allowed for view command: %s", arg);
+    return -1;
+  }
+
+  if (pa.key != NULL) {
+    if (NULL == (entry = cfg_db_find_entry(db, state->section_type, state->section_name, pa.key))) {
+      cfg_append_printable_line(log, "Cannot find data for entry: '%s'\n", arg);
+      return -1;
+    }
+
+    cfg_append_printable_line(log, "Key '%s' has value:", arg);
+    OLSR_FOR_ALL_CFG_LIST_ENTRIES(entry, ptr) {
+      cfg_append_printable_line(log, "%s", ptr);
+    }
+    return 0;
+  }
+
+  if (pa.name == NULL) {
+    type = cfg_db_find_sectiontype(db, pa.type);
+    if (type == NULL || type->names.count == 0) {
+      cfg_append_printable_line(log, "Cannot find data for section type: %s", arg);
+      return -1;
+    }
+
+    named = avl_first_element(&type->names, named, node);
+    if (cfg_db_is_named_section(named)) {
+      cfg_append_printable_line(log, "Named sections in section type: %s", pa.type);
+      OLSR_FOR_ALL_CFG_SECTION_NAMES(type, named, named_it) {
+        cfg_append_printable_line(log, "%s", named->name);
+      }
+      return 0;
+    }
+  }
+
+  named = cfg_db_find_namedsection(db, pa.type, pa.name);
+  if (named == NULL) {
+    cfg_append_printable_line(log, "Cannot find data for section: %s", arg);
+    return -1;
+  }
+
+  cfg_append_printable_line(log, "Entry keys for section '%s':", arg);
+  OLSR_FOR_ALL_CFG_ENTRIES(named, entry, entry_it) {
+    cfg_append_printable_line(log, "%s", entry->name);
+  }
+  return 0;
+}
+
+/**
+ * Implements the 'load' command for the command line
+ * @param db pointer to cfg_db to be modified
+ * @param state pointer to parser state
+ * @param arg argument of command
+ * @param log pointer for logging
+ * @return 0 if succeeded, -1 otherwise
+ */
+int
+cfg_cmd_handle_load(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log) {
+  struct cfg_db *temp_db;
+
+  temp_db = cfg_io_load_parser(arg, state->format, log);
+  if (temp_db != NULL) {
+    cfg_db_copy(db, temp_db);
+    cfg_db_remove(temp_db);
+  }
+  return temp_db != NULL ? 0 : -1;
+}
+
+/**
+ * Implements the 'save' command for the command line
+ * @param db pointer to cfg_db to be modified
+ * @param state pointer to parser state
+ * @param arg argument of command
+ * @param log pointer for logging
+ * @return 0 if succeeded, -1 otherwise
+ */
+int
+cfg_cmd_handle_save(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log) {
+  return cfg_io_save_parser(arg, state->format, db, log);
+}
+
+/**
+ * Implements the 'format' command for the command line
+ * @param db pointer to cfg_db to be modified
+ * @param state pointer to parser state
+ * @param arg argument of command
+ * @param log pointer for logging
+ * @return 0 if succeeded, -1 otherwise
+ */
+int
+cfg_cmd_handle_format(struct cfg_db *db __attribute((unused)),
+    struct cfg_cmd_state *state, const char *arg,
+    struct autobuf *log __attribute((unused))) {
+  free (state->format);
+
+  if (strcasecmp(arg, "auto") == 0) {
+    state->format = NULL;
+  }
+  else {
+    state->format = strdup(arg);
+  }
+  return 0;
+}
+
+/**
+ * Implements the 'schema' command for the configuration system
+ * @param db pointer to cfg_db to be modified
+ * @param state pointer to parser state
+ * @param arg argument of command
+ * @param log pointer for logging
+ * @return 0 if succeeded, -1 otherwise
+ */
+int
+cfg_cmd_handle_schema(struct cfg_db *db,
+    struct cfg_cmd_state *state __attribute((unused)),
+    const char *arg, struct autobuf *log) {
+  struct cfg_schema_section *s_section, *s_section_it;
+  struct cfg_schema_entry *s_entry, *s_entry_it;
+  char *copy, *ptr;
+
+  if (db->schema == NULL) {
+    abuf_puts(log, "Internal error, database not connected to schema\n");
+    return 1;
+  }
+
+  if (arg == NULL) {
+    abuf_puts(log, "List of section types:\n"
+        "(use this command with the types as parameter for more information)\n");
+
+    OLSR_FOR_ALL_CFG_SCHEMA_SECTIONS(db->schema, s_section, s_section_it) {
+      cfg_append_printable_line(log, "    %s%s%s%s%s",
+          s_section->t_type,
+          s_section->t_named ? " (named)" : "",
+          s_section->t_mandatory ? " (mandatory)" : "",
+          s_section->t_help ? ": " : "",
+          s_section->t_help ? s_section->t_help : "");
+    }
+    return 0;
+  }
+
+  /* copy string */
+  copy = alloca(strlen(arg) + 1);
+  strcpy(copy, arg);
+
+  ptr = strchr(copy, '.');
+  if (ptr) {
+    *ptr++ = 0;
+  }
+
+  s_section = avl_find_element(&db->schema->sections, copy, s_section, node);
+  if (s_section == NULL) {
+    cfg_append_printable_line(log, "Unknown section type '%s'", copy);
+    return 1;
+  }
+
+  if (ptr == NULL) {
+    cfg_append_printable_line(log, "List of entries in section type '%s':", copy);
+    abuf_puts(log, "(use this command with 'type.name' as parameter for more information)\n");
+    OLSR_FOR_ALL_CFG_SCHEMA_ENTRIES(s_section, s_entry, s_entry_it) {
+      cfg_append_printable_line(log, "    %s%s%s%s%s",
+          s_entry->t_name,
+          s_entry->t_default == NULL ? " (mandatory)" : "",
+          s_entry->t_list ? " (list)" : "",
+          s_entry->t_help ? ": " : "",
+          s_entry->t_help ? s_entry->t_help : "");
+    }
+    return 0;
+  }
+
+  s_entry = avl_find_element(&s_section->entries, ptr, s_entry, node);
+  if (s_entry == NULL) {
+    cfg_append_printable_line(log, "Unknown entry name '%s' in section type '%s'",
+        ptr, copy);
+    return 1;
+  }
+
+  cfg_append_printable_line(log, "%s.%s%s%s%s%s",
+      s_section->t_type,
+      s_entry->t_name,
+      s_entry->t_default == NULL ? " (mandatory)" : "",
+      s_entry->t_list ? " (list)" : "",
+      s_entry->t_help ? ": " : "",
+      s_entry->t_help ? s_entry->t_help : "");
+
+  if (s_entry->t_default) {
+    cfg_append_printable_line(log, "    Default value: '%s'", s_entry->t_default);
+  }
+  if (s_entry->t_validate) {
+    s_entry->t_validate(s_entry, NULL, NULL, log);
+  }
+  return 0;
+}
+
+/**
+ * Parse the parameter string for most commands
+ * @param db pointer to cfg_db to be modified
+ * @param state pointer to parser state
+ * @param arg argument of command
+ * @param set true if command should set a new entry
+ * @param remove true if command should remove an existing value
+ * @param log pointer for logging
+ * @return 0 if succeeded, negative otherwise
+ */
+static int
+_do_parse_arg(struct cfg_cmd_state *state,
+    char *arg, struct _parsed_argument *pa, struct autobuf *log) {
+  static const char *pattern = "^(([a-zA-Z_][a-zA-Z_0-9]*)(\\[([a-zA-Z_][a-zA-Z_0-9]*)\\])?\\.)?([a-zA-Z_][a-zA-Z_0-9]*)?(=(.*))?$";
+  regex_t regexp;
+  regmatch_t matchers[8];
+
+  if (regcomp(&regexp, pattern, REG_EXTENDED)) {
+    /* error in regexp implementation */
+    cfg_append_printable_line(log, "Error while formatting regular expression for parsing.");
+    return -2;
+  }
+
+  if (regexec(&regexp, arg, ARRAYSIZE(matchers), matchers, 0)) {
+    cfg_append_printable_line(log, "Illegal input for command: %s", arg);
+    regfree(&regexp);
+    return -1;
+  }
+
+  memset(pa, 0, sizeof(*pa));
+  if (matchers[2].rm_so != -1) {
+    pa->type = &arg[matchers[2].rm_so];
+    arg[matchers[2].rm_eo] = 0;
+
+    free (state->section_type);
+    state->section_type = strdup(pa->type);
+
+    /* remove name */
+    free (state->section_name);
+    state->section_name = NULL;
+  }
+  if (matchers[4].rm_so != -1) {
+    pa->name = &arg[matchers[4].rm_so];
+    arg[matchers[4].rm_eo] = 0;
+
+    /* name has already been deleted by section type code */
+    state->section_name = strdup(pa->name);
+  }
+  if (matchers[5].rm_so != -1) {
+    pa->key = &arg[matchers[5].rm_so];
+    arg[matchers[5].rm_eo] = 0;
+  }
+  if (matchers[7].rm_so != -1) {
+    pa->value = &arg[matchers[7].rm_so];
+  }
+
+  regfree(&regexp);
+  return 0;
+}
diff --git a/src/config/cfg_cmd.h b/src/config/cfg_cmd.h
new file mode 100644 (file)
index 0000000..c37faff
--- /dev/null
@@ -0,0 +1,78 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_CMD_H_
+#define CFG_CMD_H_
+
+#include "common/common_types.h"
+#include "config/cfg_db.h"
+#include "config/cfg.h"
+
+/* state for parsing a command line */
+struct cfg_cmd_state {
+  /* currently selected parser, NULL for 'auto' */
+  char *format;
+
+  /* last used section type */
+  char *section_type;
+
+  /* last used section name, NULL for unnamed section */
+  char *section_name;
+};
+
+EXPORT void cfg_cmd_add(struct cfg_cmd_state *state);
+EXPORT void cfg_cmd_remove(struct cfg_cmd_state *state);
+EXPORT int cfg_cmd_handle_set(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log);
+EXPORT int cfg_cmd_handle_remove(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log);
+EXPORT int cfg_cmd_handle_get(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log);
+EXPORT int cfg_cmd_handle_load(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log);
+EXPORT int cfg_cmd_handle_save(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log);
+EXPORT int cfg_cmd_handle_format(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log);
+EXPORT int cfg_cmd_handle_schema(struct cfg_db *db,
+    struct cfg_cmd_state *state, const char *arg, struct autobuf *log);
+
+#endif /* CFG_CMD_H_ */
diff --git a/src/config/cfg_db.c b/src/config/cfg_db.c
new file mode 100644 (file)
index 0000000..9878037
--- /dev/null
@@ -0,0 +1,562 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "common/string.h"
+
+#include "config/cfg.h"
+#include "config/cfg_schema.h"
+#include "config/cfg_memory.h"
+#include "config/cfg_db.h"
+
+
+static struct cfg_section_type *_alloc_section(struct cfg_db *, const char *);
+static void _free_sectiontype(struct cfg_section_type *);
+
+static struct cfg_named_section *_alloc_namedsection(
+    struct cfg_section_type *, const char *);
+static void _free_namedsection(struct cfg_named_section *);
+
+static struct cfg_entry *_alloc_entry(
+    struct cfg_named_section *, const char *);
+static void _free_entry(struct cfg_entry *);
+
+/**
+ * @return new configuration database without entries,
+ *   NULL if no memory left
+ */
+struct cfg_db *
+cfg_db_add(void) {
+  struct cfg_db *db;
+
+  db = calloc(1, sizeof(*db));
+  if (db) {
+    avl_init(&db->sectiontypes, cfg_avlcmp_keys, false, NULL);
+    cfg_memory_add(&db->memory);
+  }
+  return db;
+}
+
+/**
+ * Removes a configuration database including all data from memory
+ * @param db pointer to configuration database
+ */
+void
+cfg_db_remove(struct cfg_db *db) {
+  struct cfg_section_type *section, *section_it;
+
+  OLSR_FOR_ALL_CFG_SECTION_TYPES(db, section, section_it) {
+    _free_sectiontype(section);
+  }
+
+  cfg_memory_remove(&db->memory);
+  free(db);
+}
+
+/**
+ * Copy parts of a db into a new db
+ * @param dst pointer to target db
+ * @param src
+ * @param section_type
+ * @param section_name
+ * @param entry_name
+ */
+void
+_cfg_db_append(struct cfg_db *dst, struct cfg_db *src,
+    const char *section_type, const char *section_name, const char *entry_name) {
+  struct cfg_section_type *section, *section_it;
+  struct cfg_named_section *named, *named_it;
+  struct cfg_entry *entry, *entry_it;
+  char *ptr;
+
+  OLSR_FOR_ALL_CFG_SECTION_TYPES(src, section, section_it) {
+    if (section_type != NULL && cfg_cmp_keys(section->type, section_type) != 0) {
+      continue;
+    }
+
+    OLSR_FOR_ALL_CFG_SECTION_NAMES(section, named, named_it) {
+      if (section_name != NULL && cfg_cmp_keys(named->name, section_name) != 0) {
+        continue;
+      }
+
+      _cfg_db_add_section(dst, section->type, named->name);
+
+      OLSR_FOR_ALL_CFG_ENTRIES(named, entry, entry_it) {
+        if (entry_name != NULL && cfg_cmp_keys(entry->name, entry_name) != 0) {
+          continue;
+        }
+
+        OLSR_FOR_ALL_CFG_LIST_ENTRIES(entry, ptr) {
+          cfg_db_set_entry(dst, section->type, named->name, entry->name, ptr, true);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Adds a named section to a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed one
+ * @return pointer to named section, NULL if an error happened
+ */
+struct cfg_named_section *
+_cfg_db_add_section(struct cfg_db *db, const char *section_type,
+    const char *section_name) {
+  struct cfg_section_type *section;
+  struct cfg_named_section *named;
+
+  /* consistency check */
+  assert (section_type);
+
+  /* get section */
+  section = avl_find_element(&db->sectiontypes, section_type, section, node);
+  if (section == NULL) {
+    section = _alloc_section(db, section_type);
+  }
+
+  /* get named section */
+  named = avl_find_element(&section->names, section_name, named, node);
+  if (named == NULL) {
+    named = _alloc_namedsection(section, section_name);
+  }
+
+  return named;
+}
+
+/**
+ * Removes a section type (including all namedsections and entries of it)
+ * from a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @return -1 if section type did not exist, 0 otherwise
+ */
+int
+cfg_db_remove_sectiontype(struct cfg_db *db, const char *section_type) {
+  struct cfg_section_type *section;
+
+  /* find section */
+  section = cfg_db_find_sectiontype(db, section_type);
+  if (section == NULL) {
+    return -1;
+  }
+
+  _free_sectiontype(section);
+  return 0;
+}
+
+/**
+ * Finds a named section object inside a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed section
+ * @return pointer to named section, NULL if not found
+ */
+struct cfg_named_section *
+cfg_db_find_namedsection(
+    struct cfg_db *db, const char *section_type, const char *section_name) {
+  struct cfg_section_type *section;
+  struct cfg_named_section *named = NULL;
+
+  section = cfg_db_find_sectiontype(db, section_type);
+  if (section != NULL) {
+    named = avl_find_element(&section->names, section_name, named, node);
+  }
+  return named;
+}
+
+/**
+ * Removes a section type (including all entries of it)
+ * from a configuration database.
+ * If the section_type below is empty afterwards, you might
+ * want to delete it too.
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed section
+ * @return -1 if section type did not exist, 0 otherwise
+ */
+int
+cfg_db_remove_namedsection(struct cfg_db *db, const char *section_type,
+    const char *section_name) {
+  struct cfg_named_section *named;
+
+  named = cfg_db_find_namedsection(db, section_type, section_name);
+  if (named == NULL) {
+    return -1;
+  }
+
+  /* only free named section */
+  _free_namedsection(named);
+  return 0;
+}
+
+/**
+ * Changes an entry to a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed one
+ * @param entry_name entry name
+ * @param value entry value
+ * @param append true if the value should be appended to a list,
+ *   false if it should overwrite all old values
+ * @return pointer to cfg_entry, NULL if an error happened
+ */
+struct cfg_entry *
+cfg_db_set_entry(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name, const char *value,
+    bool append) {
+  struct cfg_entry *entry;
+  struct cfg_named_section *named;
+  char *old = NULL;
+  size_t old_size = 0, new_size = 0;
+
+  new_size = strlen(value) + 1;
+
+  /* create section */
+  named = _cfg_db_add_section(db, section_type, section_name);
+
+  /* get entry */
+  entry = avl_find_element(&named->entries, entry_name, entry, node);
+  if (entry == NULL) {
+    entry = _alloc_entry(named, entry_name);
+  }
+
+  /* copy old values */
+  old = entry->value;
+  if (entry->value != NULL && append) {
+    old_size = entry->length;
+  }
+
+  entry->length = old_size + new_size;
+  entry->value = cfg_memory_alloc_string(&db->memory, entry->length);
+
+  if (old_size) {
+    memcpy(entry->value, old, old_size);
+  }
+  memcpy(entry->value + old_size, value, new_size);
+  entry->last_value = entry->value + old_size;
+
+  cfg_memory_free_string(&db->memory, old);
+  return entry;
+}
+
+/**
+ * Finds a specific entry inside a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed section
+ * @param entry_name name of the entry
+ * @return pointer to configuration entry, NULL if not found
+ */
+struct cfg_entry *
+cfg_db_find_entry(struct cfg_db *db,
+    const char *section_type, const char *section_name, const char *entry_name) {
+  struct cfg_named_section *named;
+  struct cfg_entry *entry = NULL;
+
+  /* get named section */
+  named = cfg_db_find_namedsection(db, section_type, section_name);
+  if (named != NULL) {
+    entry = avl_find_element(&named->entries, entry_name, entry, node);
+  }
+  return entry;
+}
+
+/**
+ * Removes an entry from a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed one
+ * @param entry_name entry name
+ * @return -1 if the entry did not exist, 0 if it was removed
+ */
+int
+cfg_db_remove_entry(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name) {
+  struct cfg_entry *entry;
+
+  /* get entry */
+  entry = cfg_db_find_entry(db, section_type, section_name, entry_name);
+  if (entry == NULL) {
+    /* entry not there */
+    return -1;
+  }
+
+  _free_entry(entry);
+  return 0;
+}
+
+/**
+ * Accessor function to read the string value of a single entry
+ * from a configuration database.
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed section
+ * @param entry_name name of the entry
+ * @return string value, NULL if not found or list of values
+ */
+const char *
+cfg_db_get_entry_value(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name) {
+  struct cfg_entry *entry;
+  struct cfg_schema_section *s_section;
+  struct cfg_schema_entry *s_entry;
+
+  entry = cfg_db_find_entry(db, section_type, section_name, entry_name);
+  if (entry != NULL) {
+    return entry->last_value;
+  }
+
+  if (db->schema == NULL) {
+    return NULL;
+  }
+
+  /* look for default value */
+  s_section = cfg_schema_find_section(db->schema, section_type);
+  if (s_section == NULL) {
+    return NULL;
+  }
+
+  s_entry = cfg_schema_find_entry(s_section, entry_name);
+  if (s_entry) {
+    return s_entry->t_default;
+  }
+  return NULL;
+}
+
+/**
+ * Removes an element from a configuration entry list
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed one
+ * @param entry_name entry name
+ * @param value value to be removed from the list
+ * @return 0 if the element was removes, -1 if it wasn't there
+ */
+int
+cfg_db_remove_element(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name, const char *value) {
+  struct cfg_entry *entry;
+  char *ptr, *last_ptr;
+
+  /* find entry */
+  entry = cfg_db_find_entry(db, section_type, section_name, entry_name);
+  if (entry == NULL) {
+    return -1;
+  }
+
+  if (entry->last_value == entry->value) {
+    /* only a single element in list */
+    if (strcmp(value, entry->value) == 0) {
+      _free_entry(entry);
+      return 0;
+    }
+    return -1;
+  }
+
+  last_ptr = NULL;
+  OLSR_FOR_ALL_CFG_LIST_ENTRIES(entry, ptr) {
+    if (strcmp(ptr, value) == 0) {
+      size_t value_len = strlen(value) + 1;
+
+      entry->length -= value_len;
+
+      if (entry->last_value != ptr) {
+        /* not the last element */
+        size_t offset = (size_t)(ptr - entry->value);
+        memmove(ptr, ptr + value_len, entry->length - offset);
+        entry->last_value -= value_len;
+      }
+      else {
+        /* last element */
+        entry->last_value = last_ptr;
+      }
+      return 0;
+    }
+    last_ptr = ptr;
+  }
+
+  /* element not in list */
+  return -1;
+}
+
+
+/**
+ * Counts the number of list items of an entry
+ * @param entry pointer to entry
+ * @return number of items in the entries value
+ */
+size_t
+cfg_db_entry_get_listsize(struct cfg_entry *entry) {
+  char *ptr;
+  size_t cnt = 1;
+
+  for (ptr = entry->value; ptr < entry->last_value; ptr++) {
+    if (*ptr == 0) {
+      cnt++;
+    }
+  }
+  return cnt;
+}
+
+/**
+ * Creates a section type in a configuration database
+ * @param db pointer to configuration database
+ * @param type type of section
+ * @return pointer to section type
+ */
+static struct cfg_section_type *
+_alloc_section(struct cfg_db *db, const char *type) {
+  struct cfg_section_type *section;
+
+  section = cfg_memory_alloc(&db->memory, sizeof(*section));
+  section->type = cfg_memory_strdup(&db->memory, type);
+
+  section->node.key = section->type;
+  avl_insert(&db->sectiontypes, &section->node);
+
+  section->db = db;
+
+  avl_init(&section->names, cfg_avlcmp_keys, false, NULL);
+  return section;
+}
+
+/**
+ * Removes a section type from a configuration database
+ * including its named section and entries.
+ * @param section pointer to section
+ */
+static void
+_free_sectiontype(struct cfg_section_type *section) {
+  struct cfg_named_section *named, *named_it;
+
+  /* remove all named sections */
+  OLSR_FOR_ALL_CFG_SECTION_NAMES(section, named, named_it) {
+    _free_namedsection(named);
+  }
+
+  avl_remove(&section->db->sectiontypes, &section->node);
+  cfg_memory_free_string(&section->db->memory, section->type);
+  cfg_memory_free(&section->db->memory, section, sizeof(*section));
+}
+
+/**
+ * Creates a named section in a configuration database.
+ * @param section pointer to section type
+ * @param name name of section (may not be NULL)
+ * @return pointer to named section
+ */
+static struct cfg_named_section *
+_alloc_namedsection(struct cfg_section_type *section,
+    const char *name) {
+  struct cfg_named_section *named;
+
+  named = cfg_memory_alloc(&section->db->memory, sizeof(*section));
+  named->name = cfg_memory_strdup(&section->db->memory, name);
+
+  named->node.key = named->name;
+  avl_insert(&section->names, &named->node);
+
+  named->section_type = section;
+  avl_init(&named->entries, cfg_avlcmp_keys, false, NULL);
+  return named;
+}
+
+/**
+ * Removes a named section from a database including entries.
+ * @param named pointer to named section.
+ */
+static void
+_free_namedsection(struct cfg_named_section *named) {
+  struct cfg_entry *entry, *entry_it;
+
+  /* remove all entries first */
+  OLSR_FOR_ALL_CFG_ENTRIES(named, entry, entry_it) {
+    _free_entry(entry);
+  }
+
+  avl_remove(&named->section_type->names, &named->node);
+  cfg_memory_free_string(&named->section_type->db->memory, named->name);
+  cfg_memory_free(&named->section_type->db->memory, named, sizeof(*named));
+}
+
+/**
+ * Creates an entry in a configuration database.
+ * It will not initialize the value.
+ * @param named pointer to named section
+ * @param name name of entry
+ * @return pointer to configuration entry
+ */
+static struct cfg_entry *
+_alloc_entry(struct cfg_named_section *named,
+    const char *name) {
+  struct cfg_entry *entry;
+
+  entry = cfg_memory_alloc(&named->section_type->db->memory, sizeof(*entry));
+
+  entry->name = cfg_memory_strdup(&named->section_type->db->memory, name);
+  entry->node.key = entry->name;
+  avl_insert(&named->entries, &entry->node);
+
+  entry->named_section = named;
+  return entry;
+}
+
+/**
+ * Removes a configuration entry from a database
+ * @param entry pointer to configuration entry
+ */
+static void
+_free_entry(struct cfg_entry *entry) {
+  struct cfg_db *db;
+  avl_remove(&entry->named_section->entries, &entry->node);
+
+  db = entry->named_section->section_type->db;
+  cfg_memory_free_string(&db->memory, entry->name);
+  cfg_memory_free_string(&db->memory, entry->value);
+  cfg_memory_free(&db->memory, entry, sizeof(*entry));
+}
diff --git a/src/config/cfg_db.h b/src/config/cfg_db.h
new file mode 100644 (file)
index 0000000..b8238cf
--- /dev/null
@@ -0,0 +1,387 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_DB_H_
+#define CFG_DB_H_
+
+struct cfg_db;
+struct cfg_section_type;
+struct cfg_named_section;
+struct cfg_entry;
+
+#include "common/avl.h"
+#include "common/common_types.h"
+#include "config/cfg.h"
+#include "config/cfg_memory.h"
+#include "config/cfg_schema.h"
+
+/* Represents a single database with configuration entries */
+struct cfg_db {
+  /* tree of all sections of this db */
+  struct avl_tree sectiontypes;
+
+  /* string memory handling for db */
+  struct cfg_memory memory;
+
+  /* linked schema of db */
+  struct cfg_schema *schema;
+};
+
+/* Represents a section type in a configuration database */
+struct cfg_section_type {
+  /* node for tree in database */
+  struct avl_node node;
+
+  /* name of type */
+  char *type;
+
+  /* backpointer to database */
+  struct cfg_db *db;
+
+  /* tree of named sections */
+  struct avl_tree names;
+};
+
+/* Represents a named section in a configuration database */
+struct cfg_named_section {
+  /* node for tree in section type */
+  struct avl_node node;
+
+  /* name of named section */
+  char *name;
+
+  /* backpointer to section type */
+  struct cfg_section_type *section_type;
+
+  /* tree of entries */
+  struct avl_tree entries;
+};
+
+/* Represents a configuration entry */
+struct cfg_entry {
+  /* node for tree in named section */
+  struct avl_node node;
+
+  /* name of entry */
+  char *name;
+
+  /* value of entry, might contain multiple strings */
+  char *value;
+
+  /* pointer to last string in value */
+  char *last_value;
+
+  /* length of value in bytes including 0-bytes */
+  size_t length;
+
+  /* backpointer to named section */
+  struct cfg_named_section *named_section;
+};
+
+#define OLSR_FOR_ALL_CFG_SECTION_TYPES(db, s_type, iterator) avl_for_each_element_safe(&db->sectiontypes, s_type, node, iterator)
+#define OLSR_FOR_ALL_CFG_SECTION_NAMES(s_type, s_name, iterator) avl_for_each_element_safe(&s_type->names, s_name, node, iterator)
+#define OLSR_FOR_ALL_CFG_ENTRIES(s_name, entry, iterator) avl_for_each_element_safe(&s_name->entries, entry, node, iterator)
+
+#define OLSR_FOR_ALL_CFG_LIST_ENTRIES(entry, charptr) for (charptr = (entry)->value; charptr <= (entry)->last_value; charptr += strlen(charptr) + 1)
+
+EXPORT struct cfg_db *cfg_db_add(void);
+EXPORT void cfg_db_remove(struct cfg_db *);
+EXPORT void _cfg_db_append(struct cfg_db *dst, struct cfg_db *src,
+    const char *section_type, const char *section_name, const char *entry_name);
+
+EXPORT struct cfg_named_section *_cfg_db_add_section(
+    struct cfg_db *, const char *section_type, const char *section_name);
+
+EXPORT int cfg_db_remove_sectiontype(struct cfg_db *, const char *section_type);
+
+EXPORT struct cfg_named_section *cfg_db_find_namedsection(
+    struct cfg_db *, const char *section_type, const char *section_name);
+EXPORT int cfg_db_remove_namedsection(struct cfg_db *db, const char *section_type,
+    const char *section_name);
+
+EXPORT struct cfg_entry *cfg_db_set_entry(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name, const char *value, bool append);
+
+EXPORT struct cfg_entry *cfg_db_find_entry(struct cfg_db *db,
+    const char *section_type, const char *section_name, const char *entry_name);
+EXPORT int cfg_db_remove_entry(struct cfg_db *, const char *section_type,
+    const char *section_name, const char *entry_name);
+EXPORT const char *cfg_db_get_entry_value(struct cfg_db *db,
+    const char *section_type, const char *section_name, const char *entry_name);
+
+EXPORT int cfg_db_remove_element(struct cfg_db *, const char *section_type,
+    const char *section_name, const char *entry_name, const char *value);
+EXPORT size_t cfg_db_entry_get_listsize(struct cfg_entry *entry);
+
+/**
+ * Link a configuration schema to a database
+ * @param db pointer to database
+ * @param schema pointer to schema
+ */
+static INLINE void
+cfg_db_link_schema(struct cfg_db *db, struct cfg_schema *schema) {
+  db->schema = schema;
+}
+
+/**
+ * Creates a copy of a configuration database
+ * @param src original database
+ * @return pointer to the copied database, NULL if out of memory
+ */
+static INLINE struct cfg_db *
+cfg_db_duplicate(struct cfg_db *src) {
+  struct cfg_db *dst;
+
+  dst = cfg_db_add();
+  if (dst) {
+    _cfg_db_append(dst, src, NULL, NULL, NULL);
+  }
+  return dst;
+}
+
+/**
+ * Copy all settings from one configuration database to
+ * a second one.
+ * @param dst destination database which will hold the values of
+ *   both databases after the copy
+ * @param src source of the append process
+ */
+static INLINE void
+cfg_db_copy(struct cfg_db *dst, struct cfg_db *src) {
+  _cfg_db_append(dst, src, NULL, NULL, NULL);
+}
+
+/**
+ * Copy a section_type from one configuration database to
+ * a second one.
+ * @param dst destination database which will hold the values of
+ *   both databases after the copy
+ * @param src source of the append process
+ * @param section_type type of section to be copied
+ */
+static INLINE void
+cfg_db_copy_sectiontype(struct cfg_db *dst, struct cfg_db *src,
+    const char *section_type) {
+  _cfg_db_append(dst, src, section_type, NULL, NULL);
+}
+
+/**
+ * Copy a named section from one configuration database to
+ * a second one.
+ * @param dst destination database which will hold the values of
+ *   both databases after the copy
+ * @param src source of the append process
+ * @param section_type type of section to be copied
+ * @param section_name name of section to be copied
+ */
+static INLINE void
+cfg_db_copy_namedsection(struct cfg_db *dst, struct cfg_db *src,
+    const char *section_type, const char *section_name) {
+  _cfg_db_append(dst, src, section_type, section_name, NULL);
+}
+
+/**
+ * Copy a named section from one configuration database to
+ * a second one.
+ * @param dst destination database which will hold the values of
+ *   both databases after the copy
+ * @param src source of the append process
+ * @param section_type type of section to be copied
+ * @param section_name name of section to be copied
+ */
+static INLINE void
+cfg_db_copy_entry(struct cfg_db *dst, struct cfg_db *src,
+    const char *section_type, const char *section_name, const char *entry_name) {
+  _cfg_db_append(dst, src, section_type, section_name, entry_name);
+}
+
+/**
+ * Finds a section object inside a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @return pointer to section type , NULL if not found
+ */
+static INLINE struct cfg_section_type *
+cfg_db_get_sectiontype(struct cfg_db *db, const char *section_type) {
+  struct cfg_section_type *section;
+
+  /* get section */
+  return avl_find_element(&db->sectiontypes, section_type, section, node);
+}
+
+/**
+ * Finds a (named) section inside a section type
+ * @param type pointer to section type
+ * @param name name of section
+ * @return pointer to section, NULL if not found
+ */
+static INLINE struct cfg_named_section *
+cfg_db_get_named_section(struct cfg_section_type *type, const char *name) {
+  struct cfg_named_section *named;
+  return avl_find_element(&type->names, name, named, node);
+}
+
+/**
+ * Finds an entry object inside a (named) section.
+ * @param named pointer to section
+ * @param key name of entry
+ * @return pointer to entry, NULL if not found
+ */
+static INLINE struct cfg_entry *
+cfg_db_get_entry(struct cfg_named_section *named, const char *key) {
+  struct cfg_entry *entry;
+  return avl_find_element(&named->entries, key, entry, node);
+}
+
+/**
+ * Alias for cfg_db_get_sectiontype
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @return pointer to section type , NULL if not found
+ */
+static INLINE struct cfg_section_type *
+cfg_db_find_sectiontype(struct cfg_db *db, const char *section_type) {
+  return cfg_db_get_sectiontype(db, section_type);
+}
+
+/**
+ * Finds an unnamed section inside a section type
+ * @param type pointer to section type
+ * @return pointer to section, NULL if not found
+ */
+static INLINE struct cfg_named_section *
+cfg_db_find_unnamedsection(struct cfg_db *db, const char *section_type) {
+  return cfg_db_find_namedsection(db, section_type, NULL);
+}
+
+/**
+ * @param named pointer to named section
+ * @return true if named sections has a name, false if its an 'unnamed' one.
+ */
+static INLINE bool
+cfg_db_is_named_section(struct cfg_named_section *named) {
+  return named->name != NULL;
+}
+
+/**
+ * @param pointer to section type
+ * @return pointer to named section element of unnamed section type,
+ *   NULL if not an unnamed section or named entry is missing.
+ */
+static INLINE struct cfg_named_section *
+cfg_db_get_unnamed_section(struct cfg_section_type *stype) {
+  struct cfg_named_section *named;
+
+  if (avl_is_empty(&stype->names)) {
+    return NULL;
+  }
+
+  named = avl_first_element(&stype->names, named, node);
+  if (named != NULL && !cfg_db_is_named_section(named)) {
+    return named;
+  }
+  return NULL;
+}
+
+/**
+ * Adds a named section to a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section
+ * @return pointer to named section, NULL if an error happened
+ */
+static INLINE struct cfg_named_section *
+cfg_db_add_namedsection(
+    struct cfg_db *db, const char *section_type, const char *section_name) {
+  return _cfg_db_add_section(db, section_type, section_name);
+}
+
+/**
+ * Adds an unnamed section to a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @return pointer to named section, NULL if an error happened
+ */
+static INLINE struct cfg_named_section *
+cfg_db_add_unnamedsection(
+    struct cfg_db *db, const char *section_type) {
+  return _cfg_db_add_section(db, section_type, NULL);
+}
+
+
+/**
+ * Adds an entry to a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed one
+ * @param entry_name entry name
+ * @param value entry value
+ */
+static INLINE void
+cfg_db_overwrite_entry(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name, const char *value) {
+  cfg_db_set_entry(db, section_type, section_name, entry_name, value, false);
+}
+
+/**
+ * Appends an entry to a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed one
+ * @param entry_name entry name
+ * @param value entry value
+ */
+static INLINE void
+cfg_db_add_entry(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name, const char *value) {
+  cfg_db_set_entry(db, section_type, section_name, entry_name, value, true);
+}
+
+/**
+ * @param entry pointer to configuration entry
+ * @return true if entry has multiple values, false otherwise
+ */
+static INLINE bool
+cfg_db_is_multipart_entry(struct cfg_entry *entry) {
+  return entry->value != entry->last_value;
+}
+
+#endif /* CFG_DB_H_ */
diff --git a/src/config/cfg_delta.c b/src/config/cfg_delta.c
new file mode 100644 (file)
index 0000000..fcca761
--- /dev/null
@@ -0,0 +1,325 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <assert.h>
+
+#include "common/avl.h"
+#include "common/avl_comp.h"
+
+#include "config/cfg.h"
+#include "config/cfg_db.h"
+#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);
+static void _handle_namedsection(struct cfg_delta *delta, const char *type,
+    struct cfg_named_section *pre_change, struct cfg_named_section *post_change);
+static bool _setup_filterresults(struct cfg_delta_handler *handler,
+    struct cfg_named_section *pre_change, struct cfg_named_section *post_change);
+
+/**
+ * Initialize the root of a delta handler list
+ * @param delta pointer to cfg_delta object
+ */
+void
+cfg_delta_add(struct cfg_delta *delta) {
+  list_init_head(&delta->handler);
+  list_init_head(&delta->all_types_handler);
+}
+
+/**
+ * Cleans up a cfg_delta object, will remove
+ * all hooked up handlers from the internal lists
+ * @param delta pointer to cfg_delta object
+ */
+void
+cfg_delta_remove(struct cfg_delta *delta) {
+  struct cfg_delta_handler *handler, *iterator;
+
+  list_for_each_element_safe(&delta->handler, handler, node, iterator) {
+    cfg_delta_remove_handler(handler);
+  }
+  list_for_each_element_safe(&delta->all_types_handler, handler, node, iterator) {
+    cfg_delta_remove_handler(handler);
+  }
+}
+
+/**
+ * Adds a handler to a cfg_delta list
+ * Some fields of the handler have to be initialized before this
+ * call, see header file for description
+ *
+ * @param delta pointer to cfg_delta object
+ * @param handler pointer to handler
+ */
+void
+cfg_delta_add_handler(struct cfg_delta *delta, struct cfg_delta_handler *handler) {
+  assert(handler->callback);
+
+  if (handler->s_type) {
+    list_add_tail(&delta->handler, &handler->node);
+  }
+  else {
+    list_add_tail(&delta->all_types_handler, &handler->node);
+  }
+}
+
+/**
+ * Removes a handler from a cfg_delta list
+ * @param handler pointer to delta handler
+ */
+void
+cfg_delta_remove_handler(struct cfg_delta_handler *handler) {
+  list_remove(&handler->node);
+}
+
+/**
+ * Adds a delta handler by copying a schema section and entries
+ * @param delta base pointer for delta calculation
+ * @param callback callback for delta handling
+ * @param d_handler pointer to uninitialized cfg_delta_handler
+ * @param d_filter pointer to uninitialized array of cfg_delta_filter
+ * @param s_section pointer to initialized schema_section
+ * @param s_entries pointer to initialized array of schema_entry
+ * @param count number of schema_entry and cfg_delta_filter in array
+ */
+void
+cfg_delta_add_handler_by_schema(
+    struct cfg_delta *delta, cfg_delta_callback *callback,
+    struct cfg_delta_handler *d_handler, struct cfg_delta_filter *d_filter,
+    struct cfg_schema_section *s_section, struct cfg_schema_entry *s_entries,
+    size_t count) {
+  size_t i;
+
+  d_handler->s_type = s_section->t_type;
+  d_handler->callback = callback;
+  d_handler->filter = d_filter;
+
+  for (i=0; i < count; i++) {
+    memset(&d_filter[i], 0, sizeof(struct cfg_delta_filter));
+    d_filter[i].k = s_entries[i].t_name;
+  }
+  memset(&d_filter[i], 0, sizeof(struct cfg_delta_filter));
+
+  cfg_delta_add_handler(delta, d_handler);
+}
+
+/**
+ * Calculates the difference between two configuration
+ * databases and call all corresponding handlers.
+ * @param delta pointer to cfg_delta object
+ * @param pre_change database containing the pre-change settings
+ * @param post_change database containing the post-change settings
+ */
+void
+cfg_delta_calculate(struct cfg_delta *delta,
+    struct cfg_db *pre_change, struct cfg_db *post_change) {
+  struct cfg_section_type *section_pre = NULL, *section_post = NULL;
+
+  struct cfg_named_section *named, *named_it;
+
+  section_pre = avl_first_element_safe(&pre_change->sectiontypes, section_pre, node);
+  section_post = avl_first_element_safe(&post_change->sectiontypes, section_post, node);
+
+  while (section_pre != NULL || section_post != NULL) {
+    int cmp_sections;
+
+    /* compare pre and post */
+    cmp_sections = cfg_cmp_keys(section_pre->type, section_post->type);
+
+    if (cmp_sections < 0) {
+      /* handle pre-section */
+      OLSR_FOR_ALL_CFG_SECTION_NAMES(section_pre, named, named_it) {
+        _handle_namedsection(delta, section_pre->type, named, NULL);
+      }
+    }
+    else if (cmp_sections > 0) {
+      /* handle post-section */
+      OLSR_FOR_ALL_CFG_SECTION_NAMES(section_post, named, named_it) {
+        _handle_namedsection(delta, section_post->type, NULL, named);
+      }
+    }
+    else {
+      /* type is available in both db's, this might be an change event */
+      _delta_section(delta, section_pre, section_post);
+    }
+
+    if (cmp_sections <= 0) {
+      section_pre = avl_next_element_safe(&pre_change->sectiontypes, section_pre, node);
+    }
+    if (cmp_sections >= 0) {
+      section_post = avl_next_element_safe(&post_change->sectiontypes, section_post, node);
+    }
+  }
+}
+
+/**
+ * Calculates the delta between two section types
+ * @param delta pointer to cfg_delta object
+ * @param pre_change
+ * @param post_change
+ */
+static void
+_delta_section(struct cfg_delta *delta,
+    struct cfg_section_type *pre_change, struct cfg_section_type *post_change) {
+  struct cfg_named_section *named_pre = NULL, *named_post = NULL;
+
+  named_pre = avl_first_element_safe(&pre_change->names, named_pre, node);
+  named_post = avl_first_element_safe(&post_change->names, named_post, node);
+
+  while (named_pre != NULL || named_post != NULL) {
+    int cmp_sections;
+
+    /* compare pre and post */
+    cmp_sections = cfg_cmp_keys(named_pre->name, named_post->name);
+
+    if (cmp_sections < 0) {
+      /* handle pre-named */
+      _handle_namedsection(delta, pre_change->type, named_pre, NULL);
+    }
+    else if (cmp_sections > 0) {
+      /* handle post-section */
+      _handle_namedsection(delta, post_change->type, NULL, named_post);
+    }
+    else {
+      /* named section is available in both db's, we have section change */
+      _handle_namedsection(delta, pre_change->type, named_pre, named_post);
+    }
+
+    if (cmp_sections <= 0) {
+      named_pre = avl_next_element_safe(&pre_change->names, named_pre, node);
+    }
+    if (cmp_sections >= 0) {
+      named_post = avl_next_element_safe(&post_change->names, named_post, node);
+    }
+  }
+}
+/**
+ * Handles the difference between two named sections
+ * @param delta pointer to cfg_delta object
+ * @param type pointer to type string of section
+ * @param pre_change pointer to a named section before the change,
+ *   NULL if section was added.
+ * @param post_change pointer to a named section after the change,
+ *   NULL if section was removed.
+ */
+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_delta_handler *handler;
+
+  list_for_each_element(&delta->handler, handler, node) {
+    if (cfg_cmp_keys(handler->s_type, type) != 0) {
+      continue;
+    }
+
+    if (_setup_filterresults(handler, pre_change, post_change)) {
+      handler->callback(handler, pre_change, post_change);
+    }
+  }
+  list_for_each_element(&delta->all_types_handler, handler, node) {
+    if (_setup_filterresults(handler, pre_change, post_change)) {
+      handler->callback(handler, pre_change, post_change);
+    }
+  }
+}
+
+/**
+ * Initializes the filter results for a change between two named
+ * sections for a handler
+ *
+ * @param handler pointer to delta handler
+ * @param pre_change pointer to a named section before the change,
+ *   NULL if section was added.
+ * @param post_change pointer to a named section after the change,
+ *   NULL if section was removed.
+ * @return true if callback has to be called, either because at least
+ *   one filter matches or because the handler has no filters.
+ *   false otherwise.
+ */
+static bool
+_setup_filterresults(struct cfg_delta_handler *handler,
+    struct cfg_named_section *pre_change, struct cfg_named_section *post_change) {
+  struct cfg_entry *pre, *post;
+  bool change;
+  size_t i;
+
+  if (handler->filter == NULL) {
+    return true;
+  }
+
+  pre = NULL;
+  post = NULL;
+  change = false;
+
+  for (i=0; handler->filter[i].k != NULL; i++) {
+    if (pre_change) {
+      pre = avl_find_element(&pre_change->entries, handler->filter[i].k, pre, node);
+    }
+    if (post_change) {
+      post = avl_find_element(&post_change->entries, handler->filter[i].k, post, node);
+    }
+
+    handler->filter[i].pre = pre;
+    handler->filter[i].post = post;
+
+    if (pre == NULL && post == NULL) {
+      handler->filter[i].delta = CFG_DELTA_NO_CHANGE;
+    }
+    else if (pre == NULL) {
+      handler->filter[i].delta = CFG_DELTA_ADDED;
+      change = true;
+    }
+    else if (post == NULL) {
+      handler->filter[i].delta = CFG_DELTA_REMOVED;
+      change = true;
+    }
+    else if (pre->length == post->length
+        && memcmp(pre->value, post->value, pre->length) == 0) {
+      handler->filter[i].delta = CFG_DELTA_NO_CHANGE;
+    }
+    else {
+      handler->filter[i].delta = CFG_DELTA_CHANGED;
+      change = true;
+    }
+  }
+  return change;
+}
diff --git a/src/config/cfg_delta.h b/src/config/cfg_delta.h
new file mode 100644 (file)
index 0000000..2e5fe09
--- /dev/null
@@ -0,0 +1,143 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_DELTA_H_
+#define CFG_DELTA_H_
+
+struct cfg_delta;
+struct cfg_delta_handler;
+struct cfg_delta_filter;
+
+#include "common/list.h"
+#include "config/cfg_db.h"
+#include "config/cfg_schema.h"
+
+/**
+ * Root of a series of delta handlers
+ */
+struct cfg_delta {
+  /* list of handlers that apply to a specific section type */
+  struct list_entity handler;
+
+  /* list of handlers that apply to all section types */
+  struct list_entity all_types_handler;
+};
+
+/* callback for delta management */
+typedef void cfg_delta_callback(struct cfg_delta_handler *,
+    struct cfg_named_section *, struct cfg_named_section *);
+
+/**
+ * A single handler definition for configuration delta
+ * calculation
+ */
+struct cfg_delta_handler {
+  /*
+   * Node that holds the handler list together,
+   * will be initialized by cfg_delta_add_handler
+   */
+  struct list_entity node;
+
+  /* section type for this handler, NULL for all types */
+  const char *s_type;
+
+  /*
+   * pointer to a list of filters for this handler,
+   * NULL for no filters (interested in anything)
+   */
+  struct cfg_delta_filter *filter;
+
+  /*
+   * callback handling detected changes between
+   * different named configuration sections
+   */
+  cfg_delta_callback *callback;
+
+  /* custom pointer for callback usage */
+  void *custom;
+
+};
+
+/* 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.
+ */
+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;
+
+  /*
+   * Pointer to entry before and after the change.
+   * pre will be NULL for new entries,
+   * post will be NULL for removed entries
+   */
+  struct cfg_entry *pre, *post;
+};
+
+EXPORT void cfg_delta_add(struct cfg_delta *);
+EXPORT void cfg_delta_remove(struct cfg_delta *);
+
+EXPORT void cfg_delta_add_handler(struct cfg_delta *, struct cfg_delta_handler *);
+EXPORT void cfg_delta_remove_handler(struct cfg_delta_handler *);
+
+EXPORT void cfg_delta_add_handler_by_schema(
+    struct cfg_delta *delta, cfg_delta_callback *callback,
+    struct cfg_delta_handler *d_handler, struct cfg_delta_filter *d_filter,
+    struct cfg_schema_section *s_section, struct cfg_schema_entry *s_entries,
+    size_t count);
+
+EXPORT void cfg_delta_calculate(struct cfg_delta *, struct cfg_db *, struct cfg_db *);
+
+#endif /* CFG_DELTA_H_ */
diff --git a/src/config/cfg_io.c b/src/config/cfg_io.c
new file mode 100644 (file)
index 0000000..5d0e990
--- /dev/null
@@ -0,0 +1,220 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef WIN32
+#include <alloca.h>
+#else
+#include <malloc.h>
+#endif
+#include <assert.h>
+#include <string.h>
+
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "common/common_types.h"
+#include "common/string.h"
+
+#include "config/cfg.h"
+#include "config/cfg_io.h"
+
+static struct cfg_io *_find_io(const char *url,
+    const char **io_param, struct autobuf *log);
+
+struct avl_tree cfg_io_tree;
+struct cfg_io *cfg_io_default = NULL;
+static bool _io_initialized = false;
+
+
+/**
+ * Add a new io-handler to the global registry
+ * @param io pointer to io handler object
+ * @param name name of IO handler
+ */
+void
+cfg_io_add(struct cfg_io *io) {
+  if (!_io_initialized) {
+    avl_init(&cfg_io_tree, cfg_avlcmp_keys, false, NULL);
+    _io_initialized = true;
+
+    /* first io-handler, make it the default (can be overwritten later) */
+    io->def = true;
+  }
+
+  io->node.key = &io->name;
+  avl_insert(&cfg_io_tree, &io->node);
+
+  if (io->def) {
+    cfg_io_default = io;
+  }
+}
+
+/**
+ * Unregister an io-handler
+ * @param io pointer to io handler
+ */
+void
+cfg_io_remove(struct cfg_io *io) {
+  if (io->name) {
+    avl_remove(&cfg_io_tree, &io->node);
+    io->node.key = NULL;
+    io->name = NULL;
+  }
+
+  if (cfg_io_default == io) {
+    if (avl_is_empty(&cfg_io_tree)) {
+      cfg_io_default = NULL;
+    }
+    else {
+      cfg_io_default = avl_first_element(&cfg_io_tree, cfg_io_default, node);
+    }
+  }
+}
+
+/**
+ * Load a configuration database from an external source
+ * @param url URL specifying the external source
+ *   might contain io-handler specification with <iohandler>://
+ *   syntax.
+ * @param parser name of parser to be used by io-handler (if necessary),
+ *   NULL if parser autodetection should be used
+ * @param log pointer to autobuffer to contain logging output
+ *   by loader.
+ * @return pointer to configuration database, NULL if an error happened
+ */
+struct cfg_db *
+cfg_io_load_parser(const char *url, const char *parser, struct autobuf *log) {
+  struct cfg_io *io;
+  const char *io_param = NULL;
+
+  io = _find_io(url, &io_param, log);
+  if (io == NULL) {
+    cfg_append_printable_line(log, "Error, unknown config io '%s'.", io->name);
+    return NULL;
+  }
+
+  if (io->load == NULL) {
+    cfg_append_printable_line(log, "Error, config io '%s' does not support loading.", io->name);
+    return NULL;
+  }
+  return io->load(io_param, parser, log);
+}
+
+/**
+ * Store a configuration database into an external destination.
+ * @param url URL specifying the external source
+ *   might contain io-handler specification with <iohandler>://
+ *   syntax.
+ * @param parser name of parser to be used by io-handler (if necessary),
+ *   NULL if parser autodetection should be used
+ * @param src configuration database to be stored
+ * @param log pointer to autobuffer to contain logging output
+ *   by storage.
+ * @return 0 if data was stored, -1 if an error happened
+ */
+int
+cfg_io_save_parser(const char *url, const char *parser, struct cfg_db *src, struct autobuf *log) {
+  struct cfg_io *io;
+  const char *io_param = NULL;
+
+  io = _find_io(url, &io_param, log);
+  if (io == NULL) {
+    cfg_append_printable_line(log, "Error, unknown config io '%s'.", io->name);
+    return -1;
+  }
+
+  if (io->save == NULL) {
+    cfg_append_printable_line(log, "Error, config io '%s' does not support saving.", io->name);
+    return -1;
+  }
+  return io->save(io_param, parser, src, log);
+}
+
+/**
+ * Decode the URL string for load/storage
+ * @param url url string
+ * @param io_param pointer to a charpointer, will be used as a second
+ *   return parameter for URL postfix
+ * @param log pointer to autobuffer to contain logging output
+ *   by storage.
+ * @return pointer to io handler, NULL if none found or an error
+ *   happened
+ */
+static struct cfg_io *
+_find_io(const char *url, const char **io_param, struct autobuf *log) {
+  struct cfg_io *io;
+  char *buffer;
+  const char *ptr1;
+
+  if (!_io_initialized) {
+    cfg_append_printable_line(log, "IO-handler empty!");
+    return NULL;
+  }
+
+  ptr1 = strstr(url, "://");
+  if (ptr1 == url) {
+    cfg_append_printable_line(log, "Illegal URL '%s' as parameter for io selection", url);
+    return NULL;
+  }
+  if (ptr1 == NULL) {
+    /* get default io handler */
+    io = cfg_io_default;
+    ptr1 = url;
+  }
+  else {
+    buffer = alloca(strlen(url) + 1);
+    strcpy(buffer, url);
+    if (ptr1 - url < (int)sizeof(buffer)) {
+      buffer[ptr1 - url] = 0;
+    }
+
+    io = avl_find_element(&cfg_io_tree, buffer, io, node);
+    ptr1 += 3;
+  }
+
+  if (io == NULL) {
+    cfg_append_printable_line(log, "Cannot find loader for parameter '%s'", url);
+    return NULL;
+  }
+
+  *io_param = ptr1;
+  return io;
+}
diff --git a/src/config/cfg_io.h b/src/config/cfg_io.h
new file mode 100644 (file)
index 0000000..3dae9da
--- /dev/null
@@ -0,0 +1,107 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_IO_H_
+#define CFG_IO_H_
+
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "common/common_types.h"
+
+/* Represents a single IO-Handler */
+struct cfg_io {
+  /* node for global tree in cfg_io.c */
+  struct avl_node node;
+
+  /* name of io handler */
+  const char *name;
+
+  /* true if this is the default handler */
+  bool def;
+
+  /* callback to load a configuration */
+  struct cfg_db *(*load)(const char *param, const char *parser, struct autobuf *log);
+
+  /* callback to save a configuration */
+  int (*save)(const char *param, const char *parser, struct cfg_db *src, struct autobuf *log);
+};
+
+EXPORT extern struct avl_tree cfg_io_tree;
+#define OLSR_FOR_ALL_CFG_IO(io, iterator) avl_for_each_element_safe(&cfg_io_tree, io, node, iterator)
+
+EXPORT void cfg_io_add(struct cfg_io *);
+EXPORT void cfg_io_remove(struct cfg_io *);
+
+EXPORT struct cfg_db *cfg_io_load_parser(const char *url, const char *parser, struct autobuf *log);
+EXPORT int cfg_io_save_parser(const char *url, const char *parser, struct cfg_db *src, struct autobuf *log);
+
+/**
+ * Load a configuration database from an external source.
+ * This call will always use autodetection for choosing the parser.
+ * @param url URL specifying the external source
+ *   might contain io-handler specification with <iohandler>://
+ *   syntax.
+ * @param log pointer to autobuffer to contain logging output
+ *   by loader.
+ * @return pointer to configuration database, NULL if an error happened
+ */
+static INLINE struct cfg_db *
+cfg_io_load(const char *url, struct autobuf *log) {
+  return cfg_io_load_parser(url, NULL, log);
+}
+
+/**
+ * Store a configuration database into an external destination.
+ * This call will always use autodetection for choosing the parser.
+ * @param url URL specifying the external source
+ *   might contain io-handler specification with <iohandler>://
+ *   syntax.
+ * @param src configuration database to be stored
+ * @param log pointer to autobuffer to contain logging output
+ *   by storage.
+ * @return 0 if data was stored, -1 if an error happened
+ */
+static INLINE int
+cfg_io_save(const char *url, struct cfg_db *src, struct autobuf *log) {
+  return cfg_io_save_parser(url, NULL, src, log);
+}
+
+#endif /* CFG_IO_H_ */
diff --git a/src/config/cfg_memory.c b/src/config/cfg_memory.c
new file mode 100644 (file)
index 0000000..fd1a025
--- /dev/null
@@ -0,0 +1,290 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "common/list.h"
+
+#include "config/cfg.h"
+#include "config/cfg_memory.h"
+
+#ifdef CFG_MEMORY_MANAGER
+/* list of possible block sizes */
+static const size_t _alloc_size[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
+
+/* largest index of the array above */
+static const int _largest_block_idx = (int)ARRAYSIZE(_alloc_size) - 1;
+
+/* amount of memory allocated for each chunk */
+static const size_t _block_size = 4096;
+
+static int _get_sizeidx(size_t size);
+static void _add_block(struct cfg_memory *mem);
+static void *_alloc(struct cfg_memory *mem, int size_idx);
+static void _free(struct cfg_memory *mem, void *ptr, int size_idx);
+
+/**
+ * Initialize a new memory allocator and add a first block of
+ * memory.
+ * @param mem pointer to uninitialized cfg_memory struct
+ */
+void
+cfg_memory_add(struct cfg_memory *mem) {
+  int i;
+
+  /* initialize list */
+  list_init_head(&mem->blocks);
+
+  for (i=0; i<=_largest_block_idx; i++) {
+    list_init_head(&mem->free_list[i]);
+  }
+}
+
+/**
+ * Remove a memory allocator including all attached
+ * memory blocks
+ * @param mem pointer to memory allocator
+ */
+void
+cfg_memory_remove(struct cfg_memory *mem) {
+  struct cfg_memory_block *block, *iterator;
+
+  list_for_each_element_reverse_safe(&mem->blocks, block, node, iterator) {
+    list_remove(&block->node);
+    free(block->ptr);
+  }
+}
+
+/**
+ * Allocates a slot of memory for a string and store
+ * the size of the slot in the first byte, give the rest
+ * to the user.
+ * The returned pointer will not be aligned for anothing
+ * except characters.
+ * @param mem pointer to memory allocator
+ * @param size number of bytes necessary for the string
+ *   including 0-byte.
+ * @return pointer to allocated string buffer
+ */
+char *
+cfg_memory_alloc_string(struct cfg_memory *mem, size_t size) {
+  char *ptr;
+
+  size++;
+  ptr = cfg_memory_alloc(mem, size);
+
+  ptr[0] = (char)_get_sizeidx(size);
+  return ptr + 1;
+}
+
+/**
+ * Free an allocated string and put it into the
+ * corresponding free slot list.
+ * @param mem pointer to memory allocator
+ * @param ptr pointer to string
+ */
+void
+cfg_memory_free_string(struct cfg_memory *mem, char *ptr) {
+  if (ptr) {
+    ptr--;
+
+    _free(mem, ptr, ptr[0]);
+  }
+}
+
+/**
+ * Allocate a slot of memory. User have to remember the
+ * size of the allocated slot.
+ * The returned pointer will be aligned similar to a
+ * normal malloc() block.
+ * @param mem pointer to memory allocator
+ * @param size number of bytes necessary for the user
+ * @param pointer to allocated memory
+ */
+void *
+cfg_memory_alloc(struct cfg_memory *mem, size_t size) {
+  int idx;
+
+  idx = _get_sizeidx(size);
+
+  if (idx == -1) {
+    return malloc(size);
+  }
+
+  return _alloc(mem, idx);
+}
+
+/**
+ * Fre a slot of allocated memory.
+ * @param mem pointer to memory allocator
+ * @param ptr pointer to allocated memory
+ * @param size size of allocated memory
+ */
+void
+cfg_memory_free(struct cfg_memory *mem, void *ptr, size_t size) {
+  int idx;
+
+  if (ptr) {
+    idx = _get_sizeidx(size);
+    if (idx == -1) {
+      free(ptr);
+      return;
+    }
+
+    _free(mem, ptr, idx);
+  }
+}
+
+/**
+ * Duplicate a string into an allocated string memory block
+ * @param mem pointer to memory allocator
+ * @param txt pointer to string
+ * @return pointer to copied string
+ */
+char *
+cfg_memory_strdup(struct cfg_memory *mem, const char *txt) {
+  char *ptr;
+  size_t len;
+
+  if (txt == NULL) {
+    return NULL;
+  }
+
+  len = strlen(txt) + 1;
+  ptr = cfg_memory_alloc_string(mem, len);
+  memcpy(ptr, txt, len);
+  return ptr;
+}
+
+/**
+ * Calculate the index of the slotsize necessary for
+ * a certain memory size.
+ * @param size necessary memory size
+ * @return slotsize index, -1 if too large for slots
+ */
+static int
+_get_sizeidx(size_t size) {
+  int i;
+
+  for (i=0; i <= _largest_block_idx; i++) {
+    if (size < _alloc_size[i]) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+/**
+ * Add a new block of memory to the allocator
+ * @param mem pointer to memory allocator
+ */
+static void
+_add_block(struct cfg_memory *mem) {
+  struct list_entity *ptr;
+  struct cfg_memory_block *block_data;
+
+  /* first get new memory block and put it into the free list */
+  ptr = calloc(1, _block_size);
+  list_add_tail(&mem->free_list[_largest_block_idx], ptr);
+
+  /* now get a cfg_memory_block */
+  block_data = cfg_memory_alloc(mem, sizeof(*block_data));
+  block_data->ptr = ptr;
+  list_add_tail(&mem->blocks, &block_data->node);
+}
+
+/**
+ * Allocate a slot of memory
+ * @param mem pointer to memory allocator
+ * @param size_idx index of slotsize
+ * @return pointer to allocated slot
+ */
+static void *
+_alloc(struct cfg_memory *mem, int size_idx) {
+  char *ptr;
+  struct list_entity *node;
+  struct list_entity *freelist;
+
+  assert (size_idx <= _largest_block_idx);
+
+  freelist = &mem->free_list[size_idx];
+
+  if (list_is_empty(freelist)) {
+    if (size_idx == _largest_block_idx) {
+      /* not enough memory left, get a new block */
+      _add_block(mem);
+      return _alloc(mem, size_idx);
+    }
+
+    /* split larger block, add first to freelist */
+    node = _alloc(mem, size_idx + 1);
+    list_add_tail(freelist, node);
+
+    ptr = (char *)node + _alloc_size[size_idx];
+  }
+  else {
+    /* get first element */
+    node = freelist->next;
+    list_remove(node);
+
+    ptr = (char *)node;
+  }
+
+  memset (ptr, 0, _alloc_size[size_idx]);
+  return ptr;
+}
+
+/**
+ * Free a slot of memory
+ * @param mem pointer to memory allocator
+ * @param ptr pointer to allocated slot
+ * @param size_idx size index of allocated slot
+ */
+static void
+_free(struct cfg_memory *mem, void *ptr, int size_idx) {
+  struct list_entity *node = ptr;
+
+  /* add to free list */
+  list_add_tail(&mem->free_list[size_idx], node);
+}
+
+#endif /* CFG_MEMORY_MANAGER */
diff --git a/src/config/cfg_memory.h b/src/config/cfg_memory.h
new file mode 100644 (file)
index 0000000..206b6bc
--- /dev/null
@@ -0,0 +1,127 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_MEMORY_H_
+#define CFG_MEMORY_H_
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "common/common_types.h"
+#include "config/cfg.h"
+
+/* one block of allocated memory */
+#ifdef CFG_MEMORY_MANAGER
+struct cfg_memory_block {
+  /* node for list in cfg_memory */
+  struct list_entity node;
+
+  /* pointer to allocated block */
+  void *ptr;
+};
+#endif /* CFG_MEMORY_MANAGER */
+
+/*
+ * Represents a memory allocator
+ * for a single configuration database
+ */
+struct cfg_memory {
+#ifdef CFG_MEMORY_MANAGER
+  /* list of memory blocks */
+  struct list_entity blocks;
+
+  /*
+   * memory blocks are split into slots of
+   * 16, 32, 64, 128, 256, 512, 1024, 2048 and 4096 bytes.
+   *
+   * the list contains the free slots of this allocator
+   */
+  struct list_entity free_list[9];
+#endif /* CFG_MEMORY_MANAGER */
+};
+
+#ifdef CFG_MEMORY_MANAGER
+EXPORT void cfg_memory_add(struct cfg_memory *);
+EXPORT void cfg_memory_remove(struct cfg_memory *);
+
+EXPORT char *cfg_memory_alloc_string(struct cfg_memory *, size_t size);
+EXPORT void cfg_memory_free_string(struct cfg_memory *, char *ptr);
+
+EXPORT void *cfg_memory_alloc(struct cfg_memory *, size_t size);
+EXPORT void cfg_memory_free(struct cfg_memory *, void *ptr, size_t);
+
+EXPORT char *cfg_memory_strdup(struct cfg_memory *mem, const char *txt);
+#else /* CFG_MEMORY_MANAGER */
+static INLINE void
+cfg_memory_add(struct cfg_memory *m __attribute__((unused))) {}
+static INLINE void
+cfg_memory_remove(struct cfg_memory *m __attribute__((unused))) {}
+
+static INLINE char *
+cfg_memory_alloc_string(struct cfg_memory *m __attribute__((unused)), size_t size) {
+  return calloc(1, size);
+}
+static INLINE void
+cfg_memory_free_string(struct cfg_memory *m __attribute__((unused)), char *ptr) {
+  free (ptr);
+}
+
+static INLINE void *
+cfg_memory_alloc(struct cfg_memory *m __attribute__((unused)), size_t size) {
+  return calloc(1, size);
+}
+static INLINE void
+cfg_memory_free(struct cfg_memory *m __attribute__((unused)), void *ptr,
+    size_t size __attribute__((unused))) {
+  free (ptr);
+}
+
+static INLINE char *
+cfg_memory_strdup(struct cfg_memory *m __attribute__((unused)), const char *txt) {
+  if (txt) {
+    return strdup(txt);
+  }
+  return NULL;
+}
+
+#endif /* CFG_MEMORY_MANAGER */
+
+#endif /* CFG_MEMORY_H_ */
diff --git a/src/config/cfg_parser.c b/src/config/cfg_parser.c
new file mode 100644 (file)
index 0000000..0c4cee0
--- /dev/null
@@ -0,0 +1,202 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <assert.h>
+
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+
+#include "config/cfg.h"
+#include "config/cfg_db.h"
+#include "config/cfg_io.h"
+#include "config/cfg_parser.h"
+
+struct avl_tree cfg_parser_tree;
+struct cfg_parser *cfg_parser_default = NULL;
+static bool _parser_initialized = false;
+
+static struct cfg_parser *_find_parser(const char *name, struct autobuf *log);
+
+/**
+ * Adds a parser to the global registry.
+ * @param parser pointer to parser description
+ * @param name name of parser
+ */
+void
+cfg_parser_add(struct cfg_parser *parser) {
+  if (!_parser_initialized) {
+    avl_init(&cfg_parser_tree, cfg_avlcmp_keys, false, NULL);
+    _parser_initialized = true;
+
+    /* first parser, make it the default (can be overwritten later) */
+    parser->def = true;
+  }
+
+  parser->node.key = parser->name;
+  avl_insert(&cfg_parser_tree, &parser->node);
+
+  if (parser->def) {
+    cfg_parser_default = parser;
+  }
+}
+
+/**
+ * Removes a parser from the global registry.
+ * @param parser pointer to initialized parser description
+ */
+void
+cfg_parser_remove(struct cfg_parser *parser) {
+  if (parser->node.key == NULL) {
+    return;
+  }
+
+  avl_remove(&cfg_parser_tree, &parser->node);
+  parser->node.key = NULL;
+  if (cfg_parser_default == parser) {
+    cfg_parser_default = NULL;
+  }
+
+}
+
+/**
+ * Looks for a parser that can understand a certain buffer content.
+ * A path name and a mimetype can be used to give the parser additional
+ * hints about the buffers content.
+ * @param abuf pointer to buffer to be parsed
+ * @param path path where the buffers content was read from (might be NULL)
+ * @param mimetype mimetype of buffer (might be NULL)
+ * @return name of parser that can read the buffer, NULL if none fitting
+ *   parser was found
+ */
+const char *
+cfg_parser_find(struct autobuf *abuf, const char *path, const char *mimetype) {
+  struct cfg_parser *parser;
+
+  if (!_parser_initialized) {
+    return NULL;
+  }
+
+  avl_for_each_element(&cfg_parser_tree, parser, node) {
+    if (parser->check_hints != NULL) {
+      if (parser->check_hints(abuf, path, mimetype)) {
+        return parser->name;
+      }
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Parse the content of a buffer into a configuration database
+ * @param parser parser name
+ * @param src pointer to input buffer
+ * @param len length of input buffer
+ * @param log autobuffer for logging output
+ * @return pointer to configuration database, NULL if an error happened
+ */
+struct cfg_db *
+cfg_parser_parse_buffer(const char *parser, void *src, size_t len, struct autobuf *log) {
+  struct cfg_parser *f;
+
+  f = _find_parser(parser, log);
+  if (f == NULL) {
+    cfg_append_printable_line(log, "Cannot find parser '%s'", parser);
+    return NULL;
+  }
+
+  if (f->parse == NULL) {
+    cfg_append_printable_line(log, "Configuration parser '%s'"
+        " does not support parsing", parser);
+    return NULL;
+  }
+
+  return f->parse(src, len, log);
+}
+
+/**
+ * Serialize a configuration database into a buffer
+ * @param parser parser name
+ * @param dst autobuffer to write into
+ * @param src configuration database to serialize
+ * @param log autobuffer for logging output
+ * @return 0 if database was serialized, -1 if an error happened
+ */
+int
+cfg_parser_serialize_to_buffer(const char *parser, struct autobuf *dst,
+    struct cfg_db *src, struct autobuf *log) {
+  struct cfg_parser *f;
+
+  f = _find_parser(parser, log);
+  if (f == NULL) {
+    cfg_append_printable_line(log, "Cannot find parser '%s'", parser);
+    return -1;
+  }
+
+  if (f->serialize == NULL) {
+    cfg_append_printable_line(log, "Configuration parser '%s' does not"
+        " support db storage into buffer", parser);
+    return -1;
+  }
+
+  return f->serialize(dst, src, log);
+}
+
+/**
+ * Lookup a parser in the registry
+ * @param name name of parser, NULL for default parser
+ * @return pointer to parser, NULL if not found
+ */
+static struct cfg_parser *
+_find_parser(const char *name, struct autobuf *log) {
+  struct cfg_parser *parser;
+
+  if (!_parser_initialized) {
+    cfg_append_printable_line(log, "Parser-database empty!");
+    return NULL;
+  }
+
+  if (name == NULL) {
+    return cfg_parser_default;
+  }
+
+  return avl_find_element(&cfg_parser_tree, name, parser, node);
+}
diff --git a/src/config/cfg_parser.h b/src/config/cfg_parser.h
new file mode 100644 (file)
index 0000000..b0998c3
--- /dev/null
@@ -0,0 +1,85 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_PARSER_H_
+#define CFG_PARSER_H_
+
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "common/common_types.h"
+#include "config/cfg.h"
+#include "config/cfg_db.h"
+
+/* Represents a config parser */
+struct cfg_parser {
+  /* node for global tree in cfg_parser.c */
+  struct avl_node node;
+
+  /* name of parser */
+  const char *name;
+
+  /* true if this is the default parser */
+  bool def;
+
+  /* callback for checking if the parser supports a certain input */
+  bool (*check_hints)(struct autobuf *abuf, const char *path, const char *mimetype);
+
+  /* callback for parsing a buffer into a configuration database */
+  struct cfg_db *(*parse)(char *src, size_t len, struct autobuf *log);
+
+  /* callback for serializing a database into a buffer */
+  int (*serialize)(struct autobuf *dst, struct cfg_db *src, struct autobuf *log);
+};
+
+EXPORT extern struct avl_tree cfg_parser_tree;
+#define OLSR_FOR_ALL_CFG_PARSER(parser, iterator) avl_for_each_element_safe(&cfg_parser_tree, parser, node, iterator)
+
+EXPORT void cfg_parser_add(struct cfg_parser *);
+EXPORT void cfg_parser_remove(struct cfg_parser *);
+
+EXPORT const char *cfg_parser_find(struct autobuf *abuf, const char *path, const char *mimetype);
+
+EXPORT struct cfg_db *cfg_parser_parse_buffer(
+    const char *parser, void *src, size_t len, struct autobuf *log);
+EXPORT int cfg_parser_serialize_to_buffer(const char *parser,
+    struct autobuf *dst, struct cfg_db *src, struct autobuf *log);
+
+#endif /* CFG_PARSER_H_ */
diff --git a/src/config/cfg_schema.c b/src/config/cfg_schema.c
new file mode 100644 (file)
index 0000000..aab133d
--- /dev/null
@@ -0,0 +1,836 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/netaddr.h"
+
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "common/string.h"
+
+#include "config/cfg.h"
+#include "config/cfg_db.h"
+#include "config/cfg_schema.h"
+
+static struct cfg_schema *_handle_default_schema(struct cfg_schema *);
+static bool _validate_cfg_entry(struct cfg_schema_section *schema_section,
+    struct cfg_db *db, struct cfg_section_type *section,
+    struct cfg_named_section *named, struct cfg_entry *entry,
+    const char *section_name, bool cleanup, bool failFast,
+    struct autobuf *out);
+static bool
+_check_missing_entries(struct cfg_schema_section *schema_section,
+    struct cfg_db *db, struct cfg_section_type *section,
+    struct cfg_named_section *named,
+    bool failFast, const char *section_name, struct autobuf *out);
+static bool
+_check_single_value(struct cfg_schema_entry *schema_entry,
+    struct cfg_db *db, struct cfg_section_type *section,
+    struct cfg_named_section *named, struct cfg_entry *entry,
+    bool cleanup, const char *section_name, struct autobuf *out);
+
+static struct cfg_schema *_default_schema_ptr = NULL;
+static struct cfg_schema _default_schema;
+
+/**
+ * Initialize a schema
+ * @param schema pointer to uninitialized schema
+ */
+void
+cfg_schema_add(struct cfg_schema *schema) {
+  avl_init(&schema->sections, cfg_avlcmp_keys, false, NULL);
+}
+
+/**
+ * Removes all connected objects of a schema
+ * @param schema pointer to schema
+ */
+void
+cfg_schema_remove(struct cfg_schema *schema) {
+  struct cfg_schema_section *t_section, *tsec_it;
+
+  /* kill sections of schema */
+  OLSR_FOR_ALL_CFG_SCHEMA_SECTIONS(schema, t_section, tsec_it) {
+    cfg_schema_remove_section(schema, t_section);
+  }
+}
+
+/**
+ * Add a section to a schema
+ * @param schema pointer to configuration schema, NULL for default schema
+ * @param section pointer to section
+ * @return -1 if an error happened, 0 otherwise
+ */
+int
+cfg_schema_add_section(struct cfg_schema *schema, struct cfg_schema_section *section) {
+  assert (cfg_is_allowed_key(section->t_type));
+  schema = _handle_default_schema(schema);
+
+  section->node.key = section->t_type;
+  if (avl_insert(&schema->sections, &section->node)) {
+    /* name collision */
+    return -1;
+  }
+
+  avl_init(&section->entries, cfg_avlcmp_keys, false, NULL);
+  return 0;
+}
+
+/**
+ * Removes a section from a schema
+ * @param schema pointer to configuration schema, NULL for default schema
+ * @param section pointer to section
+ */
+void
+cfg_schema_remove_section(struct cfg_schema *schema, struct cfg_schema_section *section) {
+  struct cfg_schema_entry *entry, *ent_it;
+  schema = _handle_default_schema(schema);
+
+  /* kill entries of section_schema */
+  OLSR_FOR_ALL_CFG_SCHEMA_ENTRIES(section, entry, ent_it) {
+    cfg_schema_remove_entry(section, entry);
+  }
+
+  avl_remove(&schema->sections, &section->node);
+}
+
+/**
+ * Adds a series of entries to a schema section
+ * @param section pointer to section
+ * @param entries pointer to array of entries
+ * @param e_cnt number of array entries
+ * @return -1 if an error happened, 0 otherwise
+ */
+int
+cfg_schema_add_entries(struct cfg_schema_section *section,
+    struct cfg_schema_entry *entries, size_t e_cnt) {
+  size_t i;
+
+  for (i=0; i<e_cnt; i++) {
+    if (cfg_schema_add_entry(section, &entries[i])) {
+      /* error, while adding entry, remove all of them again */
+      cfg_schema_remove_entries(section, entries, e_cnt);
+      return -1;
+    }
+  }
+  return 0;
+}
+
+/**
+ * Adds a single entry to a schema section
+ * @param section pointer to section
+ * @param entry pointer to entry
+ * @return -1 if an error happened, 0 otherwise
+ */
+int
+cfg_schema_add_entry(struct cfg_schema_section *section, struct cfg_schema_entry *entry) {
+  assert (cfg_is_allowed_key(entry->t_name));
+
+  entry->node.key = &entry->t_name[0];
+  if (avl_insert(&section->entries, &entry->node)) {
+    /* name collision */
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * Remove an array of entries from a schema section
+ * @param section pointer to section
+ * @param entries pointer to array of entries
+ * @param e_cnt number of array entries
+ */
+void
+cfg_schema_remove_entries(struct cfg_schema_section *section, struct cfg_schema_entry *entries, size_t e_cnt) {
+  size_t i;
+
+  for (i=0; i<e_cnt; i++) {
+    cfg_schema_remove_entry(section, &entries[i]);
+  }
+}
+
+/**
+ * Validates a database with a schema
+ * @param db pointer to configuration database
+ * @param failFast if true, validation stops at the first error
+ * @param cleanup if true, bad values will be removed from the database
+ * @param out autobuffer for validation output
+ * @return 0 if validation found no problems, -1 otherwise
+ */
+int
+cfg_schema_validate(struct cfg_db *db,
+    bool failFast, bool cleanup, struct autobuf *out) {
+  char section_name[256];
+  struct cfg_section_type *section, *section_it;
+  struct cfg_named_section *named, *named_it;
+  struct cfg_entry *entry, *entry_it;
+
+  struct cfg_schema_section *schema_section, *schema_section_it;
+
+  bool error = false;
+  bool warning = false;
+  bool hasName = false;
+
+  if (db->schema == NULL) {
+    return 1;
+  }
+
+  OLSR_FOR_ALL_CFG_SECTION_TYPES(db, section, section_it) {
+    /* check for missing schema sections */
+    schema_section = cfg_schema_find_section(db->schema, section->type);
+    if (schema_section == NULL) {
+      cfg_append_printable_line(out,
+          "Cannot find schema for section type '%s'", section->type);
+
+      if (cleanup) {
+        cfg_db_remove_sectiontype(db, section->type);
+      }
+      if (failFast) {
+        /* stop here */
+        return -1;
+      }
+
+      error |= true;
+      continue;
+    }
+
+    /* check data of named sections in db */
+    OLSR_FOR_ALL_CFG_SECTION_NAMES(section, named, named_it) {
+      warning = false;
+      hasName = cfg_db_is_named_section(named);
+
+      if (schema_section->t_named && !hasName) {
+        cfg_append_printable_line(out, "The section type '%s' demands a name", section->type);
+
+        warning = true;
+      }
+      else if (!schema_section->t_named && hasName) {
+        cfg_append_printable_line(out, "The section type '%s'"
+            " has to be used without a name"
+            " ('%s' was given as a name)", section->type, named->name);
+
+        warning = true;
+      }
+
+      if (hasName && !cfg_is_allowed_key(named->name)) {
+        cfg_append_printable_line(out, "The section name '%s' for"
+            " type '%s' contains illegal characters",
+            named->name, section->type);
+        warning = true;
+      }
+
+      /* test abort condition */
+      if (warning && cleanup) {
+        /* remove bad named section */
+        cfg_db_remove_namedsection(db, section->type, named->name);
+      }
+
+      if (warning && failFast) {
+        /* stop here */
+        break;
+      }
+      error |= warning;
+
+      if (warning) {
+        continue;
+      }
+
+      /* initialize section_name field for validate */
+      snprintf(section_name, sizeof(section_name), "'%s%s%s'",
+          section->type, hasName ? "=" : "", hasName ? named->name : "");
+
+      /* check for bad values */
+      OLSR_FOR_ALL_CFG_ENTRIES(named, entry, entry_it) {
+        warning = _validate_cfg_entry(schema_section,
+            db, section, named, entry, section_name,
+            cleanup, failFast, out);
+        if (warning && failFast) {
+          /* stop here */
+          return -1;
+        }
+        error |= warning;
+      }
+
+      if (schema_section->t_validate) {
+        if (schema_section->t_validate(schema_section, section_name, named, out)) {
+          if (failFast) {
+            /* stop here */
+            return -1;
+          }
+          error = true;
+        }
+      }
+      /* check for missing values */
+      warning = _check_missing_entries(schema_section, db, section, named, failFast, section_name, out);
+      if (warning && failFast) {
+        /* stop here */
+        return -1;
+      }
+      error |= warning;
+    }
+
+    if (cleanup && avl_is_empty(&section->names)) {
+      /* if section type is empty, remove it too */
+      cfg_db_remove_sectiontype(db, section->type);
+    }
+    if (warning && failFast) {
+      return -1;
+    }
+  }
+
+  /* search for missing mandatory sections */
+  OLSR_FOR_ALL_CFG_SCHEMA_SECTIONS(db->schema, schema_section, schema_section_it) {
+    if (!schema_section->t_mandatory) {
+      continue;
+    }
+
+    section = cfg_db_find_sectiontype(db, schema_section->t_type);
+    warning = section == NULL || avl_is_empty(&section->names);
+    if (warning) {
+      cfg_append_printable_line(out, "Missing mandatory section of type '%s'",
+          schema_section->t_type);
+    }
+    if (warning && failFast) {
+      /* stop here */
+      return -1;
+    }
+    error |= warning;
+  }
+  return error ? -1 : 0;
+}
+
+int
+cfg_schema_tobin(void *target, struct cfg_named_section *named,
+    struct cfg_schema_entry *entries, size_t count) {
+  struct cfg_entry *db_entry;
+  const char *value;
+  char *ptr;
+  size_t i;
+
+  ptr = (char *)target;
+
+  for (i=0; i<count; i++) {
+    if (entries[i].t_to_binary == NULL) {
+      continue;
+    }
+
+    value = entries[i].t_default;
+    db_entry = avl_find_element(&named->entries, entries[i].t_name, db_entry, node);
+    if (db_entry) {
+      value = db_entry->value;
+    }
+
+    if (value == NULL) {
+      /* missing mandatory entry */
+      return -1;
+    }
+
+    if (entries[i].t_to_binary(&entries[i], value, ptr + entries[i].t_offset)) {
+      /* error in conversion */
+      return -1;
+    }
+  }
+  return 0;
+}
+
+/**
+ * Schema entry validator for string maximum length.
+ * @param entry pointer to schema entry
+ * @param section_name name of section type and name
+ * @param value value of schema entry, NULL for help text generation
+ * @param out pointer to autobuffer for validator output
+ * @return 0 if validation found no problems, -1 otherwise
+ */
+int
+cfg_schema_validate_strlen(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out) {
+  if (value == NULL) {
+    if (entry->t_validate_params.p_i1 < INT32_MAX) {
+      cfg_append_printable_line(out, "    Parameter must have a maximum length of %d characters\n",
+          entry->t_validate_params.p_i1);
+    }
+    return 0;
+  }
+  if ((int)strlen(value) > entry->t_validate_params.p_i1) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s is longer than %d characters",
+        value, entry->t_name, section_name, entry->t_validate_params.p_i1);
+    return 1;
+  }
+  return 0;
+}
+
+/**
+ * Schema entry validator for strings printable characters
+ * and a maximum length.
+ * See CFG_VALIDATE_PRINTABLE() und CFG_VALIDATE_PRINTABLE_LEN()
+ * macro in cfg_schema.h
+ * @param entry pointer to schema entry
+ * @param section_name name of section type and name
+ * @param value value of schema entry
+ * @param out pointer to autobuffer for validator output
+ * @return 0 if validation found no problems, -1 otherwise
+ */
+int
+cfg_schema_validate_printable(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out) {
+  if (cfg_schema_validate_strlen(entry, section_name, value, out)) {
+    return 1;
+  }
+  if (value == NULL) {
+    cfg_append_printable_line(out, "    Parameter must only contain printable characters.\n");
+    return 0;
+  }
+  if (!cfg_is_printable(value)) {
+    /* not a printable ascii character */
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s has has non-printable characters",
+        value, entry->t_name, section_name);
+    return 1;
+
+  }
+  return 0;
+}
+
+/**
+ * Schema entry validator for choice (list of possible strings)
+ * See CFG_VALIDATE_CHOICE() macro in cfg_schema.h
+ * List selection will be case insensitive.
+ * @param entry pointer to schema entry
+ * @param section_name name of section type and name
+ * @param value value of schema entry
+ * @param out pointer to autobuffer for validator output
+ * @return 0 if validation found no problems, -1 otherwise
+ */
+int
+cfg_schema_validate_choice(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out) {
+  const char **list = entry->t_validate_params.p_ptr;
+  int i;
+
+  if (value == NULL) {
+    cfg_append_printable_line(out, "    Parameter must be on of the following list:");
+
+    abuf_puts(out, "    ");
+    for (i=0; i < entry->t_validate_params.p_i1; i++) {
+      abuf_appendf(out, "%s'%s'",
+          i==0 ? "" : ", ", list[i]);
+    }
+    abuf_puts(out, "\n");
+    return 0;
+  }
+  i = cfg_get_choice_index(value, list, (size_t)entry->t_validate_params.p_i1);
+  if (i >= 0) {
+    return 0;
+  }
+
+  cfg_append_printable_line(out, "Unknown value '%s'"
+      " for entry '%s' in section %s",
+      value, entry->t_name, section_name);
+  return -1;
+}
+
+/**
+ * Schema entry validator for integers
+ * See CFG_VALIDATE_INT() and CFG_VALIDATE_INT_MINMAX() macro in cfg_schema.h
+ * @param entry pointer to schema entry
+ * @param section_name name of section type and name
+ * @param value value of schema entry
+ * @param out pointer to autobuffer for validator output
+ * @return 0 if validation found no problems, -1 otherwise
+ */
+int
+cfg_schema_validate_int(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out) {
+  int32_t i;
+  char *endptr = NULL;
+
+  if (value == NULL) {
+    cfg_append_printable_line(out, "    Parameter must be an integer between %d and %d\n",
+        entry->t_validate_params.p_i1, entry->t_validate_params.p_i2);
+    return 0;
+  }
+
+  i = strtol(value, &endptr, 10);
+  if (endptr == NULL || *endptr != 0) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s is not an integer",
+        value, entry->t_name, section_name);
+    return 1;
+  }
+  if (i < entry->t_validate_params.p_i1 || i > entry->t_validate_params.p_i2) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s' in section %s is "
+        "not between %d and %d",
+        value, entry->t_name, section_name,
+        entry->t_validate_params.p_i1, entry->t_validate_params.p_i2);
+    return 1;
+  }
+  return 0;
+}
+
+/**
+ * Schema entry validator for network addresses and prefixes
+ * See CFG_VALIDATE_NETADDR_() macros in cfg_schema.h
+ * @param entry pointer to schema entry
+ * @param section_name name of section type and name
+ * @param value value of schema entry
+ * @param out pointer to autobuffer for validator output
+ * @return 0 if validation found no problems, -1 otherwise
+ */
+int
+cfg_schema_validate_netaddr(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out) {
+  struct netaddr addr;
+  bool prefix = false;
+  int p1,p2;
+  uint8_t max_prefix;
+
+  p1 = entry->t_validate_params.p_i1;
+  p2 = entry->t_validate_params.p_i2;
+
+  /* check if we may accept a prefix */
+  if (p1 < 0) {
+    prefix = true;
+    p1 = -p1;
+  }
+  if (p2 < 0) {
+    prefix = true;
+    p2 = -p2;
+
+    /* explicit 'all addresses, but no prefix' case */
+    if (p1 == 0) {
+      p2 = 0;
+    }
+  }
+
+  if (value == NULL) {
+    const char *p_string = prefix ? " with optional prefix string" : "";
+
+    switch (p1) {
+      case AF_INET:
+        cfg_append_printable_line(out, "    Parameter must be an IPv4%s address%s\n",
+            p2 == AF_INET6 ? " or IPv6" : "", p_string);
+        break;
+      case AF_INET6:
+        cfg_append_printable_line(out, "    Parameter must be an IPv6 address%s\n",
+            p_string);
+        break;
+      case AF_MAC48:
+        cfg_append_printable_line(out, "    Parameter must be an MAC-48%s address%s\n",
+            p2 == AF_EUI64 ? " or EUI64" : "", p_string);
+        break;
+      case AF_EUI64:
+        cfg_append_printable_line(out, "    Parameter must be an EUI-64 address%s\n",
+            p_string);
+        break;
+      default:
+        cfg_append_printable_line(out, "    Parameter must be an IPv4, "
+            "IPv6, MAC-48 or EUI-64 address%s\n", p_string);
+        break;
+    }
+    return 0;
+  }
+
+  if (netaddr_from_string(&addr, value)) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s is no valid network address",
+        value, entry->t_name, section_name);
+    return -1;
+  }
+
+  max_prefix = netaddr_get_maxprefix(&addr);
+
+  /* check prefix length */
+  if (addr.prefix_len > max_prefix) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s has an illegal prefix length",
+        value, entry->t_name, section_name);
+    return -1;
+  }
+  if (!prefix && addr.prefix_len != max_prefix) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s must be a single address, not a prefix",
+        value, entry->t_name, section_name);
+    return -1;
+  }
+
+  if (p1 == 0) {
+    /* no further type check */
+    return 0;
+  }
+
+  /* check address type */
+  if ((p2 != 0 && p2 == addr.type) || (p1 == addr.type)) {
+    return 0;
+  }
+
+  /* at least one condition was set, but no one matched */
+  cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+      " in section '%s' is wrong address type",
+      value, entry->t_name, section_name);
+  return -1;
+}
+
+int
+cfg_schema_tobin_strptr(struct cfg_schema_entry *s_entry __attribute__((unused)),
+    const char *value, void *reference) {
+  char **ptr;
+
+  ptr = (char **)reference;
+  if (*ptr) {
+    free(ptr);
+  }
+
+  *ptr = strdup(value);
+  return *ptr == NULL ? 1 : 0;
+}
+
+int
+cfg_schema_tobin_strarray(struct cfg_schema_entry *s_entry,
+    const char *value, void *reference) {
+  char *ptr;
+
+  ptr = (char *)reference;
+
+  strscpy(ptr, value, (size_t)s_entry->t_validate_params.p_i1);
+  return 0;
+}
+
+int
+cfg_schema_tobin_choice(struct cfg_schema_entry *s_entry,
+    const char *value, void *reference) {
+  int *ptr;
+
+  ptr = (int *)reference;
+
+  *ptr = cfg_get_choice_index(value, s_entry->t_validate_params.p_ptr,
+      (size_t)s_entry->t_validate_params.p_i1);
+  return 0;
+}
+
+int
+cfg_schema_tobin_int(struct cfg_schema_entry *s_entry __attribute__((unused)),
+    const char *value, void *reference) {
+  int *ptr;
+
+  ptr = (int *)reference;
+
+  *ptr = strtol(value, NULL, 10);
+  return 0;
+}
+
+int
+cfg_schema_tobin_netaddr(struct cfg_schema_entry *s_entry __attribute__((unused)),
+    const char *value, void *reference) {
+  struct netaddr *ptr;
+
+  ptr = (struct netaddr *)reference;
+
+  return netaddr_from_string(ptr, value);
+}
+
+int
+cfg_schema_tobin_bool(struct cfg_schema_entry *s_entry __attribute__((unused)),
+    const char *value, void *reference) {
+  bool *ptr;
+
+  ptr = (bool *)reference;
+
+  *ptr = cfg_get_bool(value);
+  return 0;
+}
+/**
+ * Converts a null pointer into the default schema pointer.
+ * Initializes the default schema if necessary.
+ * @param schema pointer to custom schema or NULL
+ * @return argument pointer or default schema pointer if argument was NULL
+ */
+static struct cfg_schema *
+_handle_default_schema(struct cfg_schema *schema) {
+  if (schema != NULL) {
+    return schema;
+  }
+
+  if (_default_schema_ptr == NULL) {
+    cfg_schema_add(&_default_schema);
+    _default_schema_ptr = &_default_schema;
+  }
+  return _default_schema_ptr;
+}
+
+static bool
+_validate_cfg_entry(struct cfg_schema_section *schema_section,
+    struct cfg_db *db, struct cfg_section_type *section,
+    struct cfg_named_section *named, struct cfg_entry *entry,
+    const char *section_name, bool cleanup, bool failFast,
+    struct autobuf *out) {
+  struct cfg_schema_entry *schema_entry;
+  bool warning = false;
+  char *ptr1 = NULL, *ptr2 = NULL;
+  size_t size;
+
+  schema_entry = cfg_schema_find_entry(schema_section, entry->name);
+
+  if (schema_entry == NULL) {
+    cfg_append_printable_line(out, "Unknown entry '%s'"
+        " for section type '%s'", entry->name, section->type);
+    return true;
+  }
+
+  if (!schema_entry->t_list) {
+    return _check_single_value(schema_entry,
+        db, section, named, entry,
+        cleanup, section_name, out);
+  }
+
+  if (cleanup) {
+    /* first remove duplicate entries */
+    OLSR_FOR_ALL_CFG_LIST_ENTRIES(entry, ptr1) {
+      /* get pointer to next element */
+      ptr2 = ptr1 + strlen(ptr1)+1;
+
+      /* compare list value to any later value */
+      while (ptr2 <= entry->last_value) {
+        size = strlen(ptr2) + 1;
+
+        if (strcmp(ptr2, ptr1) == 0) {
+          /* duplicate found, remove it */
+          size_t offset = (size_t)(ptr2 - entry->value);
+          memmove (ptr2, ptr2 + size, entry->length - size - offset);
+          entry->length -= size;
+        }
+        else {
+          ptr2 += size;
+        }
+      }
+    }
+    entry->last_value = ptr1;
+  }
+
+  /* now validate syntax */
+  ptr1 = entry->value;
+  while (ptr1 < entry->value + entry->length) {
+    if (schema_entry->t_validate(schema_entry, section_name, ptr1, out)) {
+      /* warning is generated by the validate callback itself */
+      warning = true;
+
+      if (failFast) {
+        return true;
+      }
+    }
+
+    size = strlen(ptr1) + 1;
+
+    if (warning && cleanup) {
+      /* illegal entry found, remove it */
+      size_t offset = (size_t)(ptr2 - entry->value);
+      memmove(ptr1, ptr1 + size, entry->length - size - offset);
+    }
+    else {
+      ptr1 += size;
+    }
+  }
+
+  if (entry->length == 0) {
+    /* remove empty entry */
+    cfg_db_remove_entry(db, section->type, named->name, entry->name);
+  }
+
+  return warning;
+}
+
+static bool
+_check_single_value(struct cfg_schema_entry *schema_entry,
+    struct cfg_db *db, struct cfg_section_type *section,
+    struct cfg_named_section *named, struct cfg_entry *entry,
+    bool cleanup, const char *section_name, struct autobuf *out) {
+  bool warning = false;
+
+  /* warning is generated by the validate callback itself */
+  if (schema_entry->t_validate) {
+    warning = schema_entry->t_validate(schema_entry, section_name, entry->last_value, out) != 0;
+  }
+
+  if (warning && cleanup) {
+    /* remove bad entry */
+    cfg_db_remove_entry(db, section->type, named->name, entry->name);
+  }
+  else if (cleanup && entry->last_value != entry->value) {
+    /* shorten value */
+    entry->length = strlen(entry->last_value) + 1;
+    memmove(entry->value, entry->last_value, entry->length);
+  }
+  return warning;
+}
+
+static bool
+_check_missing_entries(struct cfg_schema_section *schema_section,
+    struct cfg_db *db, struct cfg_section_type *section,
+    struct cfg_named_section *named,
+    bool failFast, const char *section_name, struct autobuf *out) {
+  struct cfg_schema_entry *schema_entry, *schema_entry_it;
+  bool warning = false;
+
+  /* check for missing values */
+  OLSR_FOR_ALL_CFG_SCHEMA_ENTRIES(schema_section, schema_entry, schema_entry_it) {
+    if (schema_entry->t_default != NULL) {
+      continue;
+    }
+
+    /* mandatory parameter */
+    warning = !cfg_db_find_entry(db, section->type, named->name, schema_entry->t_name);
+    if (warning) {
+      cfg_append_printable_line(out, "Missing mandatory value for entry '%s' in section %s",
+          schema_entry->t_name, section_name);
+
+      if (failFast) {
+        /* stop here */
+        break;
+      }
+    }
+  }
+  return warning;
+}
diff --git a/src/config/cfg_schema.h b/src/config/cfg_schema.h
new file mode 100644 (file)
index 0000000..98a83f3
--- /dev/null
@@ -0,0 +1,283 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_SCHEMA_H_
+#define CFG_SCHEMA_H_
+
+struct cfg_schema;
+struct cfg_schema_section;
+struct cfg_schema_entry;
+
+#ifndef WIN32
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+#include <netinet/ip.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "common/netaddr.h"
+
+#include "config/cfg.h"
+#include "config/cfg_db.h"
+
+#define CFG_VALIDATE_STRING(name, def, args...)                  { .t_name = (name), .t_default = (def), ##args }
+#define CFG_VALIDATE_STRING_LEN(name, def, maxlen, args...)      { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_strlen, .t_validate_params = {.p_i1 = (maxlen) }, ##args }
+#define CFG_VALIDATE_PRINTABLE(name, def, args...)               { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_printable, .t_validate_params = {.p_i1 = INT32_MAX }, ##args }
+#define CFG_VALIDATE_PRINTABLE_LEN(name, def, maxlen, args...)   { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_printable, .t_validate_params = {.p_i1 = (maxlen) }, ##args }
+#define CFG_VALIDATE_CHOICE(name, def, list, args...)            { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_choice, .t_validate_params = {.p_ptr = (list), .p_i1 = ARRAYSIZE(list)}, ##args }
+#define CFG_VALIDATE_INT(name, def, args...)                     { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_int, .t_validate_params = {.p_i1 = INT32_MIN, .p_i2 = INT32_MAX}, ##args }
+#define CFG_VALIDATE_INT_MINMAX(name, def, min, max, args...)    { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_int, .t_validate_params = {.p_i1 = (min), .p_i2 = (max)}, ##args }
+#define CFG_VALIDATE_NETADDR(name, def, prefix, args...)         { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_netaddr, .t_validate_params = {.p_i1 = 0, .p_i2 = !!(prefix) ? -1 : 0 }, ##args }
+#define CFG_VALIDATE_NETADDR_HWADDR(name, def, prefix, args...)  { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_netaddr, .t_validate_params = {.p_i1 = !!(prefix) ? -AF_MAC48 : AF_MAC48, .p_i2 = AF_EUI64 }, ##args }
+#define CFG_VALIDATE_NETADDR_MAC48(name, def, prefix, args...)   { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_netaddr, .t_validate_params = {.p_i1 = !!(prefix) ? -AF_MAC48 : AF_MAC48}, ##args }
+#define CFG_VALIDATE_NETADDR_EUI64(name, def, prefix, args...)   { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_netaddr, .t_validate_params = {.p_i1 = !!(prefix) ? -AF_EUI64 : AF_EUI64}, ##args }
+#define CFG_VALIDATE_NETADDR_V4(name, def, prefix, args...)      { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_netaddr, .t_validate_params = {.p_i1 = !!(prefix) ? -AF_INET : AF_INET }, ##args }
+#define CFG_VALIDATE_NETADDR_V6(name, def, prefix, args...)      { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_netaddr, .t_validate_params = {.p_i1 = !!(prefix) ? -AF_INET6 : AF_INET6 }, ##args }
+#define CFG_VALIDATE_NETADDR_V46(name, def, prefix, args...)     { .t_name = (name), .t_default = (def), .t_validate = cfg_schema_validate_netaddr, .t_validate_params = {.p_i1 = !!(prefix) ? -AF_INET : AF_INET, .p_i2 = AF_INET6}, ##args }
+
+#define CFG_VALIDATE_BOOL(name, def, args...)                   CFG_VALIDATE_CHOICE(name, def, CFGLIST_BOOL, ##args)
+
+#define CFG_MAP_STRING(reference, name, def, args...)                  { .t_name = #name, .t_default = def, .t_to_binary = cfg_schema_tobin_strptr, .t_offset = offsetof(struct reference, name), ##args }
+#define CFG_MAP_STRING_LEN(reference, name, def, maxlen, args...)      CFG_VALIDATE_STRING_LEN(#name, def, maxlen, .t_to_binary = cfg_schema_tobin_strptr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_STRING_ARRAY(reference, name, def, maxlen, args...)    { .t_name = #name, .t_default = def, .t_validate_params = {.p_i1 = (maxlen) }, .t_to_binary = cfg_schema_tobin_strarray, .t_offset = offsetof(struct reference, name), ##args }
+#define CFG_MAP_PRINTABLE(reference, name, def, args...)               CFG_VALIDATE_PRINTABLE(#name, def, .t_to_binary = cfg_schema_tobin_strptr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_PRINTABLE_LEN(reference, name, def, args...)           CFG_VALIDATE_PRINTABLE_LEN(#name, def, maxlen, .t_to_binary = cfg_schema_tobin_strptr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_PRINTABLE_ARRAY(reference, name, def, maxlen, args...) CFG_VALIDATE_PRINTABLE_LEN(#name, def, maxlen, .t_to_binary = cfg_schema_tobin_strarray, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_CHOICE(reference, name, def, list, args...)            CFG_VALIDATE_CHOICE(#name, def, list, .t_to_binary = cfg_schema_tobin_choice, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_INT(reference, name, def, args...)                     CFG_VALIDATE_INT(#name, def, .t_to_binary = cfg_schema_tobin_int, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_INT_MINMAX(reference, name, def, min, max, args...)    CFG_VALIDATE_INT_MINMAX(#name, def, min, max, .t_to_binary = cfg_schema_tobin_int, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_NETADDR(reference, name, def, prefix, args...)         CFG_VALIDATE_NETADDR(#name, def, prefix, .t_to_binary = cfg_schema_tobin_netaddr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_NETADDR_HWADDR(reference, name, def, prefix, args...)  CFG_VALIDATE_NETADDR_HWADDR(#name, def, prefix, .t_to_binary = cfg_schema_tobin_netaddr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_NETADDR_MAC48(reference, name, def, prefix, args...)   CFG_VALIDATE_NETADDR_MAC48(#name, def, prefix, .t_to_binary = cfg_schema_tobin_netaddr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_NETADDR_EUI64(reference, name, def, prefix, args...)   CFG_VALIDATE_NETADDR_EUI64(#name, def, prefix, .t_to_binary = cfg_schema_tobin_netaddr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_NETADDR_V4(reference, name, def, prefix, args...)      CFG_VALIDATE_NETADDR_V4(#name, def, prefix, .t_to_binary = cfg_schema_tobin_netaddr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_NETADDR_V6(reference, name, def, prefix, args...)      CFG_VALIDATE_NETADDR_V6(#name, def, prefix, .t_to_binary = cfg_schema_tobin_netaddr, .t_offset = offsetof(struct reference, name), ##args)
+#define CFG_MAP_NETADDR_V46(reference, name, def, prefix, args...)     CFG_VALIDATE_NETADDR_V46(#name, def, prefix, .t_to_binary = cfg_schema_tobin_netaddr, .t_offset = offsetof(struct reference, name), ##args)
+
+#define CFG_MAP_BOOL(reference, name, def, args...)                    CFG_VALIDATE_BOOL(#name, def, .t_to_binary = cfg_schema_tobin_bool, .t_offset = offsetof(struct reference, name), ##args)
+
+/*
+ * Example of a section schema definition
+ *
+ * struct cfg_schema_section test_section = {
+ *   .t_type = "plugin", .t_named = true
+ * };
+ *
+ * struct cfg_schema_entry test_entries[] = {
+ *   CFG_VALIDATE_BOOL("enable", "true"),
+ *   CFG_VALIDATE_PRINTABLE("logfile", "/tmp/test", .t_list = true),
+ *   CFG_VALIDATE_INT_MINMAX("value", "0", 0, 20),
+ * };
+ */
+
+/*
+ * Example of a section schema definition with binary mapping
+ *
+ * struct bin_data {
+ *   bool enable;
+ *   char *logfile;
+ *   int value;
+ * };
+ *
+ * struct cfg_schema_section test_section = {
+ *   .t_type = "plugin", .t_named = true
+ * };
+ *
+ * struct cfg_schema_entry test_entries[] = {
+ *   CFG_MAP_BOOL(bin_data, enable, "true"),
+ *   CFG_MAP_PRINTABLE(bin_data, logfile, "/tmp/test", .t_list = true),
+ *   CFG_MAP_INT_MINMAX(bin_data, value, "0", 0, 20),
+ * };
+ */
+
+struct cfg_schema {
+  /* tree of sections of this schema */
+  struct avl_tree sections;
+};
+
+/*
+ * Represents the schema of all named sections within
+ * a certain type
+ */
+struct cfg_schema_section {
+  /* node for tree in schema, initialized by schema_add() */
+  struct avl_node node;
+
+  /* name of section type */
+  const char *t_type;
+
+  /* true if sections of this  schema have a name */
+  bool t_named;
+
+  /* true if at least one section of this type must exist */
+  bool t_mandatory;
+
+  /* help text for section */
+  const char *t_help;
+
+  /* callback for checking configuration of section */
+  int (*t_validate)(struct cfg_schema_section *, const char *section_name,
+      struct cfg_named_section *, struct autobuf *);
+
+  /* list of entries in section */
+  struct avl_tree entries;
+};
+
+/* Represents the schema of a configuration entry */
+struct cfg_schema_entry {
+  /* node for tree in section schema */
+  struct avl_node node;
+
+  /* name of entry */
+  const char *t_name;
+
+  /* default value */
+  const char *t_default;
+
+  /* help text for entry */
+  const char *t_help;
+
+  /* value is a list of parameters instead of a single one */
+  bool t_list;
+
+  /* callback for checking value of entry */
+  int (*t_validate)(struct cfg_schema_entry *entry,
+      const char *section_name, char *value, struct autobuf *out);
+
+  /* parameters for check functions */
+  struct validate_params {
+      int p_i1, p_i2;
+      void *p_ptr;
+  } t_validate_params;
+
+  /* callback for converting string into binary */
+  int (*t_to_binary)(struct cfg_schema_entry *s_entry,
+      const char *value, void *ptr);
+
+  /* offset of current binary data compared to reference pointer */
+  size_t t_offset;
+};
+
+#define OLSR_FOR_ALL_CFG_SCHEMA_SECTIONS(tmpl, section, iterator) avl_for_each_element_safe(&(tmpl->sections), section, node, iterator)
+#define OLSR_FOR_ALL_CFG_SCHEMA_ENTRIES(section, entry, iterator) avl_for_each_element_safe(&section->entries, entry, node, iterator)
+
+EXPORT void cfg_schema_add(struct cfg_schema *schema);
+EXPORT void cfg_schema_remove(struct cfg_schema *schema);
+
+EXPORT int cfg_schema_add_section(struct cfg_schema *schema, struct cfg_schema_section *section);
+EXPORT void cfg_schema_remove_section(struct cfg_schema *schema, struct cfg_schema_section *section);
+
+EXPORT int cfg_schema_add_entries(struct cfg_schema_section *section, struct cfg_schema_entry *entries, size_t e_cnt);
+EXPORT int cfg_schema_add_entry(struct cfg_schema_section *, struct cfg_schema_entry *entry);
+EXPORT void cfg_schema_remove_entries(struct cfg_schema_section *, struct cfg_schema_entry *entries, size_t e_cnt);
+
+EXPORT int cfg_schema_validate(struct cfg_db *db,
+    bool failFast, bool cleanup, struct autobuf *out);
+
+EXPORT int cfg_schema_tobin(void *target, struct cfg_named_section *named,
+    struct cfg_schema_entry *entries, size_t count);
+
+EXPORT int cfg_schema_validate_printable(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out);
+EXPORT int cfg_schema_validate_strlen(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out);
+EXPORT int cfg_schema_validate_choice(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out);
+EXPORT int cfg_schema_validate_int(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out);
+EXPORT int cfg_schema_validate_netaddr(struct cfg_schema_entry *entry,
+    const char *section_name, char *value, struct autobuf *out);
+
+EXPORT int cfg_schema_tobin_strptr(struct cfg_schema_entry *s_entry,
+    const char *value, void *reference);
+EXPORT int cfg_schema_tobin_strarray(struct cfg_schema_entry *s_entry,
+    const char *value, void *reference);
+EXPORT int cfg_schema_tobin_choice(struct cfg_schema_entry *s_entry,
+    const char *value, void *reference);
+EXPORT int cfg_schema_tobin_int(struct cfg_schema_entry *s_entry,
+    const char *value, void *reference);
+EXPORT int cfg_schema_tobin_netaddr(struct cfg_schema_entry *s_entry,
+    const char *value, void *reference);
+EXPORT int cfg_schema_tobin_bool(struct cfg_schema_entry *s_entry,
+    const char *value, void *reference);
+
+/**
+ * Finds a section in a schema
+ * @param schema pointer to schema
+ * @param type type of section
+ * @return pointer to section, NULL if not found
+ */
+static INLINE struct cfg_schema_section *
+cfg_schema_find_section(struct cfg_schema *schema, const char *type) {
+  struct cfg_schema_section *section;
+
+  return avl_find_element(&schema->sections, type, section, node);
+}
+
+/**
+ * Remove a single entry from a schema section
+ * @param section pointer to section
+ * @param entry pointer to entry
+ */
+static INLINE void
+cfg_schema_remove_entry(struct cfg_schema_section *section, struct cfg_schema_entry *entry) {
+  avl_remove(&section->entries, &entry->node);
+  entry->node.key = NULL;
+}
+
+/**
+ * Finds an entry in a schema section
+ * @param section pointer to section
+ * @param name name of entry
+ * @return pointer of entry, NULL if not found
+ */
+static INLINE struct cfg_schema_entry *
+cfg_schema_find_entry(struct cfg_schema_section *section, const char *name) {
+  struct cfg_schema_entry *entry;
+
+  return avl_find_element(&section->entries, name, entry, node);
+}
+
+#endif /* CFG_SCHEMA_H_ */
diff --git a/src/config/io/cfg_io_file.c b/src/config/io/cfg_io_file.c
new file mode 100644 (file)
index 0000000..0d78c76
--- /dev/null
@@ -0,0 +1,195 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "common/autobuf.h"
+#include "config/cfg_io.h"
+#include "config/cfg_parser.h"
+#include "config/cfg.h"
+#include "config/io/cfg_io_file.h"
+
+static struct cfg_db *_file_load(
+    const char *param, const char *parser, struct autobuf *log);
+static int _file_save(
+    const char *param, const char *parser, struct cfg_db *src, struct autobuf *log);
+
+/*
+ * Definition of the file-io handler.
+ *
+ * This handler can read and write files and use a parser to
+ * translate them into a configuration database (and the other way around)
+ *
+ * The parameter of this parser has to be a filename
+ */
+const char *CFG_IO_FILE = "file";
+struct cfg_io cfg_io_file = {
+  .name = "file",
+  .load = _file_load,
+  .save = _file_save,
+  .def = true,
+};
+
+/**
+ * Reads a file from a filesystem, parse it with the help of a
+ * configuration parser and returns a configuration database.
+ * @param parser parser name, NULL if autodetection should be used
+ * @param param file to be read
+ * @param log autobuffer for logging purpose
+ * @return pointer to configuration database, NULL if an error happened
+ */
+static struct cfg_db *
+_file_load(const char *param, const char *parser, struct autobuf *log) {
+  struct autobuf dst;
+  struct cfg_db *db;
+  char buffer[1024];
+  int fd = 0;
+  ssize_t bytes;
+
+  fd = open(param, O_RDONLY, 0);
+  if (fd == -1) {
+    cfg_append_printable_line(log,
+        "Cannot open file '%s' to read configuration: %s (%d)",
+        param, strerror(errno), errno);
+    return NULL;
+  }
+
+  bytes = 1;
+  if (abuf_init(&dst, 4096)) {
+    cfg_append_printable_line(log,
+        "Out of memory error while allocating io buffer");
+    close (fd);
+    return NULL;
+  }
+
+  /* read file into binary buffer */
+  while (bytes > 0) {
+    bytes = read(fd, buffer, sizeof(buffer));
+    if (bytes < 0 && errno != EINTR) {
+      cfg_append_printable_line(log,
+          "Error while reading file '%s': %s (%d)",
+          param, strerror(errno), errno);
+      close(fd);
+      abuf_free(&dst);
+      return NULL;
+    }
+
+    if (bytes > 0) {
+      abuf_memcpy(&dst, buffer, (size_t)bytes);
+    }
+  }
+  close(fd);
+
+  if (parser == NULL) {
+    /* lookup a fitting parser, we know the path as a hint */
+    parser = cfg_parser_find(&dst, param, NULL);
+  }
+
+  db = cfg_parser_parse_buffer(parser, dst.buf, dst.len, log);
+  abuf_free(&dst);
+  return db;
+}
+
+/**
+ * Stores a configuration database into a file. It will use a
+ * parser (the serialization part) to translate the database into
+ * a storage format.
+ * @param parser parser name, NULL if autodetection should be used
+ * @param param pathname to write configuration file into
+ * @param src_db source configuration database
+ * @param log autobuffer for logging purpose
+ * @return 0 if database was stored sucessfully, -1 otherwise
+ */
+static int
+_file_save(const char *param, const char *parser,
+    struct cfg_db *src_db, struct autobuf *log) {
+  int fd = 0;
+  ssize_t bytes;
+  size_t total;
+  struct autobuf abuf;
+
+  if (abuf_init(&abuf, 4096)) {
+    cfg_append_printable_line(log,
+        "Out of memory error while allocating io buffer");
+    return -1;
+  }
+
+  if (parser == NULL) {
+    parser = cfg_parser_find(NULL, param, NULL);
+  }
+  if (cfg_parser_serialize_to_buffer(parser, &abuf, src_db, log)) {
+    abuf_free(&abuf);
+    return -1;
+  }
+
+  fd = open(param, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+  if (fd == -1) {
+    cfg_append_printable_line(log,
+        "Cannot open file '%s' for writing configuration: %s (%d)",
+        param, strerror(errno), errno);
+    return -1;
+  }
+
+  total = 0;
+  while (total < abuf.len) {
+    bytes = write(fd, &abuf.buf[total], abuf.len - total);
+    if (bytes <= 0 && errno != EINTR) {
+      cfg_append_printable_line(log,
+          "Error while writing to file '%s': %s (%d)",
+          param, strerror(errno), errno);
+      close(fd);
+      return -1;
+    }
+
+    if (bytes > 0) {
+      total += (size_t)bytes;
+    }
+  }
+  close(fd);
+  abuf_free(&abuf);
+
+  return 0;
+}
diff --git a/src/config/io/cfg_io_file.h b/src/config/io/cfg_io_file.h
new file mode 100644 (file)
index 0000000..b5b6dae
--- /dev/null
@@ -0,0 +1,51 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_IO_FILE_H_
+#define CFG_IO_FILE_H_
+
+#include "config/cfg_io.h"
+#include "config/cfg.h"
+
+EXPORT const char *CFG_IO_FILE;
+EXPORT struct cfg_io cfg_io_file;
+
+#endif /* CFG_IO_FILE_H_ */
diff --git a/src/config/parser/cfg_parser_compact.c b/src/config/parser/cfg_parser_compact.c
new file mode 100644 (file)
index 0000000..0aef7b5
--- /dev/null
@@ -0,0 +1,262 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "common/autobuf.h"
+#include "common/string.h"
+#include "config/cfg_db.h"
+#include "config/cfg_parser.h"
+#include "config/cfg.h"
+#include "config/parser/cfg_parser_compact.h"
+
+static struct cfg_db *_compact_parse(
+    char *src, size_t len, struct autobuf *log);
+static int _compact_serialize(
+    struct autobuf *dst, struct cfg_db *src, struct autobuf *log);
+static int _parse_line(struct cfg_db *db, char *line,
+    char *section, size_t section_size,
+    char *name, size_t name_size,
+    struct autobuf *log);
+
+/*
+ * Defintion of the 'compact' configuration parser.
+ *
+ * This parser/serializer use a line oriented text format.
+ * All lines beginning with '#' will be ignored as comments.
+ * All leading and trailing whitespaces will be ignored.
+ *
+ * Sections are defined as '[<section-typ>]'.
+ * Named sections are defined as '[<section-type>=<section-name>]'.
+ * Entrys are defined as 'key value'.
+ *
+ * No entry must be put before the first section.
+ */
+const char *CFG_PARSER_COMPACT = "compact";
+struct cfg_parser cfg_parser_compact = {
+  .name = "compact",
+  .parse = _compact_parse,
+  .serialize = _compact_serialize,
+  .def = true
+};
+
+/**
+ * Parse a buffer into a configuration database
+ * @param src pointer to text buffer
+ * @param len length of buffer
+ * @param log autobuffer for logging output
+ * @return pointer to configuration database, NULL if an error happened
+ */
+static struct cfg_db *
+_compact_parse(char *src, size_t len, struct autobuf *log) {
+  char section[128];
+  char name[128];
+  struct cfg_db *db;
+  char *eol, *line;
+
+  db = cfg_db_add();
+
+  memset(section, 0, sizeof(section));
+  memset(name, 0, sizeof(name));
+
+  line = src;
+  while (line < src + len) {
+    /* find end of line */
+    eol = line;
+    while (*eol != 0 && *eol != '\n') {
+      eol++;
+    }
+
+    /* termiate line with zero byte */
+    *eol = 0;
+    if (eol > line && eol[-1] == '\r') {
+      /* handle \r\n line ending */
+      eol[-1] = 0;
+    }
+
+    if (_parse_line(db, line, section, sizeof(section),
+        name, sizeof(name), log)) {
+      cfg_db_remove(db);
+      return NULL;
+    }
+
+    line = eol+1;
+  }
+
+  return db;
+}
+
+/**
+ * Serialize a configuration database into a buffer
+ * @param dst target buffer
+ * @param src source configuration database
+ * @param log autbuffer for logging
+ * @return 0 if database was serialized, -1 otherwise
+ */
+static int
+_compact_serialize(struct autobuf *dst, struct cfg_db *src,
+    struct autobuf *log __attribute__ ((unused))) {
+  struct cfg_section_type *section, *s_it;
+  struct cfg_named_section *name, *n_it;
+  struct cfg_entry *entry, *e_it;
+
+  OLSR_FOR_ALL_CFG_SECTION_TYPES(src, section, s_it) {
+    OLSR_FOR_ALL_CFG_SECTION_NAMES(section, name, n_it) {
+      if (cfg_db_is_named_section(name)) {
+        abuf_appendf(dst, "[%s=%s]\n", section->type, name->name);
+      }
+      else {
+        abuf_appendf(dst, "[%s]\n", section->type);
+      }
+
+      OLSR_FOR_ALL_CFG_ENTRIES(name, entry, e_it) {
+        abuf_appendf(dst, "\t%s %s\n", entry->name, entry->value);
+      }
+    }
+  }
+  return 0;
+}
+
+/**
+ * Parse a single line of the compact format
+ * @param db pointer to configuration database
+ * @param line pointer to line to be parsed (will be modified
+ *   during parsing)
+ * @param section pointer to array with current section type
+ *   (might be modified during parsing)
+ * @param section_size number of bytes for section type
+ * @param name pointer to array with current section name
+ *   (might be modified during parsing)
+ * @param name_size number of bytes for section name
+ * @param log autobuffer for logging output
+ * @return 0 if line was parsed successfully, -1 otherwise
+ */
+static int
+_parse_line(struct cfg_db *db, char *line,
+    char *section, size_t section_size,
+    char *name, size_t name_size,
+    struct autobuf *log) {
+  char *first, *ptr;
+
+  /* trim leading and trailing whitespaces */
+  first = line;
+  str_trim(&first);
+
+  if (*first == 0 || *first == '#') {
+    /* empty line or comment */
+    return 0;
+  }
+
+  if (*first == '[') {
+    first++;
+    ptr = strchr(first, ']');
+    if (ptr == NULL) {
+      cfg_append_printable_line(log,
+          "Section syntax error in line: '%s'", line);
+      return -1;
+    }
+    *ptr = 0;
+
+    ptr = strchr(first, '=');
+    if (ptr) {
+      /* trim section name */
+      *ptr++ = 0;
+      str_trim(&ptr);
+    }
+
+    /* trim section name */
+    str_trim(&first);
+    if (*first == 0) {
+      cfg_append_printable_line(log,
+          "Section syntax error, no section type found");
+      return -1;
+    }
+
+    /* copy section type */
+    strscpy(section, first, section_size);
+
+    /* copy section name */
+    if (ptr) {
+      strscpy(name, ptr, name_size);
+    }
+    else {
+      *name = 0;
+    }
+
+    /* add section to db */
+    _cfg_db_add_section(db, section, *name ? name : NULL);
+    return 0;
+  }
+
+  if (*section == 0) {
+    cfg_append_printable_line(log,
+        "Entry before first section is not allowed in this format");
+    return -1;
+  }
+
+  ptr = first;
+
+  /* look for separator */
+  while (!isspace(*ptr)) {
+    ptr++;
+  }
+
+  *ptr++ = 0;
+
+  /* trim second token */
+  str_trim(&ptr);
+
+  if (*ptr == 0) {
+    cfg_append_printable_line(log,
+        "No second token found in line '%s'",  line);
+    return -1;
+  }
+
+  /* found two tokens */
+  cfg_db_add_entry(db, section, *name ? name : NULL, first, ptr);
+  return 0;
+}
diff --git a/src/config/parser/cfg_parser_compact.h b/src/config/parser/cfg_parser_compact.h
new file mode 100644 (file)
index 0000000..1e6cc28
--- /dev/null
@@ -0,0 +1,51 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CFG_PARSER_COMPACT_H_
+#define CFG_PARSER_COMPACT_H_
+
+#include "config/cfg_parser.h"
+#include "config/cfg.h"
+
+EXPORT const char *CFG_PARSER_COMPACT;
+EXPORT struct cfg_parser cfg_parser_compact;
+
+#endif /* CFG_FRONTENT_COMPACT_H_ */
diff --git a/src/core/interface.h b/src/core/interface.h
new file mode 100644 (file)
index 0000000..77d2c85
--- /dev/null
@@ -0,0 +1,56 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef INTERFACE_H_
+#define INTERFACE_H_
+
+#include <net/if.h>
+
+#include "common/common_types.h"
+#include "common/netaddr.h"
+
+struct olsr_interface {
+  struct netaddr local_v4, local_v6;
+  char name[IF_NAMESIZE];
+  int index;
+};
+
+#endif /* INTERFACE_H_ */
diff --git a/src/core/olsr.c b/src/core/olsr.c
new file mode 100644 (file)
index 0000000..a6157e5
--- /dev/null
@@ -0,0 +1,419 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of olsr.org, olsrd 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 OWNER 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.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <net/if.h>
+#include <sys/types.h>
+
+#include "common/daemonize.h"
+#include "common/list.h"
+#include "config/cfg_cmd.h"
+#include "config/cfg_db.h"
+#include "config/cfg_schema.h"
+#include "builddata/plugin_static.h"
+#include "olsr_logging.h"
+#include "olsr_logging_cfg.h"
+#include "olsr_memcookie.h"
+#include "olsr_clock.h"
+#include "olsr_timer.h"
+#include "olsr_socket.h"
+#include "olsr_packet_socket.h"
+#include "olsr_stream_socket.h"
+#include "olsr_plugins.h"
+#include "olsr_cfg.h"
+#include "olsr.h"
+
+static bool running;
+
+enum olsr_option_short {
+  olsr_option_schema = 256
+};
+
+static struct option olsr_options[] = {
+  { "help",         no_argument,       0, 'h' },
+  { "load",         required_argument, 0, 'l' },
+  { "save",         required_argument, 0, 'S' },
+  { "set",          required_argument, 0, 's' },
+  { "remove",       required_argument, 0, 'r' },
+  { "get",          optional_argument, 0, 'g' },
+  { "format",       required_argument, 0, 'f' },
+  { "schema",       optional_argument, 0, olsr_option_schema },
+  { "plugin",       required_argument, 0, 'p' },
+  { NULL, 0,0,0 }
+};
+
+static const char *help_text =
+    "Starts the OLSR routing agent\n"
+    "Mandatory arguments to long options are mandatory for short options too.\n"
+    "  -h, --help                             Display this help file\n"
+    "  --schema                               Display all allowed section types of configuration\n"
+    "          =section_type                  Display all allowed entries of one configuration section\n"
+    "          =section_type.key              Display help text for configuration entry\n"
+    "  -l, --load=SOURCE                      Load configuration from a SOURCE\n"
+    "  -S, --save=TARGET                      Save configuration to a TARGET\n"
+    "  -s, --set=section_type.                Add an unnamed section to the configuration\n"
+    "           =section_type.key=value       Add a key/value pair to an unnamed section\n"
+    "           =section_type[name].          Add a named section to the configuration\n"
+    "           =section_type[name].key=value Add a key/value pair to a named section\n"
+    "  -r, --remove=section_type.             Remove all sections of a certain type\n"
+    "              =section_type.key          Remove a key in an unnamed section\n"
+    "              =section_type[name].       Remove a named section\n"
+    "              =section_type[name].key    Remove a key in a named section\n"
+    "  -g, --get                              Show all section types in database\n"
+    "           =section_type.                Show all named sections of a certain type\n"
+    "           =section_type.key             Show the value(s) of a key in an unnamed section\n"
+    "           =section_type[name].key       Show the value(s) of a key in a named section\n"
+    "  -f, --format=FORMAT                    Set the format for loading/saving data\n"
+    "                                         (use 'AUTO' for automatic detection of format)\n"
+    "  -p, --plugin=shared-library            Load a shared library as an OLSRd plugin\n";
+
+static enum log_source level_1_sources[] = {
+  LOG_MAIN
+};
+
+static const char *DEFAULT_CONFIGFILE = OLSRD_GLOBAL_CONF_FILE;
+
+/* prototype for local statics */
+static void signal_handler(int);
+static void setup_signalhandler(void);
+static int mainloop(void);
+static int parse_commandline(int argc, char **argv, const char *);
+
+/**
+ * Main program
+ */
+int
+main(int argc, char **argv) {
+  int return_code = 0;
+  int fork_pipe = -1;
+  const char *fork_str;
+
+  /* setup signal handler */
+  running = true;
+  setup_signalhandler();
+
+  /* initialize logger */
+  if (olsr_log_init(SEVERITY_DEBUG)) {
+    return -1;
+  }
+
+  /* add configuration definition */
+  if (olsr_cfg_init()) {
+    return 1;
+  }
+
+  /* initialize logging to config interface */
+  olsr_logcfg_init(level_1_sources, ARRAYSIZE(level_1_sources));
+  olsr_logcfg_addschema(olsr_cfg_get_schema());
+
+  /* load static plugins */
+  olsr_plugins_init();
+
+  /* parse command line and read configuration files */
+  return_code = parse_commandline(argc, argv, DEFAULT_CONFIGFILE);
+  if (return_code != -1) {
+    /* end OLSRd now */
+    goto olsrd_cleanup;
+  }
+
+  /* prepare for an error during initialization */
+  return_code = 1;
+
+  /* become root */
+  if (geteuid()) {
+    OLSR_WARN(LOG_MAIN, "You must be root(uid = 0) to run olsrd!\n");
+    goto olsrd_cleanup;
+  }
+
+  /* see if we need to fork */
+  fork_str = cfg_db_get_entry_value(olsr_cfg_get_db(), CFG_SECTION_GLOBAL, NULL, CFG_GLOBAL_FORK);
+  if (cfg_get_bool(fork_str)) {
+    /* fork into background */
+    fork_pipe = daemonize_prepare();
+    if (fork_pipe == -1) {
+      OLSR_WARN(LOG_MAIN, "Cannot fork into background");
+      goto olsrd_cleanup;
+    }
+  }
+
+  /* configure logger */
+  if (olsr_logcfg_apply(olsr_cfg_get_db())) {
+    goto olsrd_cleanup;
+  }
+
+  /* initialize basic framework */
+  olsr_memcookie_init();
+  if (olsr_clock_init()) {
+    goto olsrd_cleanup;
+  }
+  if (olsr_timer_init()) {
+    goto olsrd_cleanup;
+  }
+  if (olsr_socket_init()) {
+    goto olsrd_cleanup;
+  }
+  olsr_packet_init();
+  if (olsr_stream_init()) {
+    goto olsrd_cleanup;
+  }
+
+  /* apply olsr configuration */
+  if (olsr_cfg_apply()) {
+    goto olsrd_cleanup;
+  }
+
+  if (fork_pipe != -1) {
+    /* tell main process that we are finished with initialization */
+    daemonize_finish(fork_pipe, 0);
+    fork_pipe = -1;
+  }
+
+  /* activate mainloop */
+  return_code = mainloop();
+
+olsrd_cleanup:
+  /* free framework resources */
+  olsr_stream_cleanup();
+  olsr_packet_cleanup();
+  olsr_socket_cleanup();
+  olsr_timer_cleanup();
+  olsr_memcookie_cleanup();
+
+  /* free configuration resources */
+  olsr_cfg_cleanup();
+
+  /* free logger resources */
+  olsr_logcfg_cleanup();
+  olsr_log_cleanup();
+
+  if (fork_pipe != -1) {
+    /* tell main process that we had a problem */
+    daemonize_finish(fork_pipe, return_code);
+  }
+  return return_code;
+}
+
+/**
+ * Handle incoming SIGINT signal
+ * @param signo
+ */
+static void
+signal_handler(int signo __attribute__ ((unused))) {
+  running = false;
+}
+
+/**
+ * Mainloop of olsrd
+ * @return exit code for olsrd
+ */
+static int
+mainloop(void) {
+  uint32_t next_interval;
+  int exit_code = 0;
+
+  OLSR_INFO(LOG_MAIN, "Starting olsr routing daemon");
+
+  /* enter main loop */
+  while (running) {
+    /*
+     * Update the global timestamp. We are using a non-wallclock timer here
+     * to avoid any undesired side effects if the system clock changes.
+     */
+    if (olsr_clock_update()) {
+      exit_code = 1;
+      break;
+    }
+    next_interval = olsr_clock_getAbsolute(50);
+
+    /* Process timers */
+    olsr_timer_walk();
+
+    /* Read incoming data and handle it immediately */
+    if (olsr_socket_handle(next_interval)) {
+      exit_code = 1;
+      break;
+    }
+  }
+
+  OLSR_INFO(LOG_MAIN, "Ending olsr routing daemon");
+  return exit_code;
+}
+
+/**
+ * Setup signal handling for olsrd
+ */
+static void
+setup_signalhandler(void) {
+  static struct sigaction act;
+
+  memset(&act, 0, sizeof(act));
+
+  /* setup signal handler first */
+  sigemptyset(&act.sa_mask);
+  act.sa_flags = 0;
+
+  act.sa_handler = signal_handler;
+  sigaction(SIGINT, &act, NULL);
+  sigaction(SIGQUIT, &act, NULL);
+  sigaction(SIGILL, &act, NULL);
+  sigaction(SIGABRT, &act, NULL);
+  sigaction(SIGTERM, &act, NULL);
+
+  act.sa_handler = SIG_IGN;
+  sigaction(SIGHUP, &act, NULL);
+  sigaction(SIGPIPE, &act, NULL);
+  sigaction(SIGUSR1, &act, NULL);
+  sigaction(SIGUSR2, &act, NULL);
+}
+
+/**
+ * Parse command line of olsrd
+ * @param argc number of arguments
+ * @param argv argument vector
+ * @param def_config default configuration file, NULL if
+ *   no default config file should be loaded
+ * @return -1 if olsrd should start, otherwise olsrd should exit
+ *   with the returned number
+ */
+static int
+parse_commandline(int argc, char **argv, const char *def_config) {
+  int opt, opt_idx;
+  struct autobuf log;
+  struct cfg_cmd_state state;
+  int return_code = -1;
+  bool loaded_file = false;
+
+  abuf_init(&log, 1024);
+  cfg_cmd_add(&state);
+
+  while (return_code == -1
+      && 0 <= (opt = getopt_long(argc, argv, "hl:S:s:r:g::p:", olsr_options, &opt_idx))) {
+    log.len = 0;
+    log.buf[0] = 0;
+
+    switch (opt) {
+      case 'h':
+        abuf_appendf(&log, "Usage: %s [OPTION]...\n%s", argv[0], help_text);
+        return_code = 0;
+        break;
+
+      case olsr_option_schema:
+        if (cfg_cmd_handle_schema(olsr_cfg_get_db(), &state, optarg, &log)) {
+          return_code = 1;
+        }
+        else {
+          return_code = 0;
+        }
+        break;
+      case 'l':
+        if (cfg_cmd_handle_load(olsr_cfg_get_db(), &state, optarg, &log)) {
+          return_code = 1;
+        }
+        loaded_file = true;
+        break;
+      case 'S':
+        if (cfg_cmd_handle_save(olsr_cfg_get_db(), &state, optarg, &log)) {
+          return_code = 1;
+        }
+        break;
+      case 's':
+        if (cfg_cmd_handle_set(olsr_cfg_get_db(), &state, optarg, &log)) {
+          return_code = 1;
+        }
+        break;
+      case 'r':
+        if (cfg_cmd_handle_remove(olsr_cfg_get_db(), &state, optarg, &log)) {
+          return_code = 1;
+        }
+        break;
+      case 'g':
+        if (cfg_cmd_handle_get(olsr_cfg_get_db(), &state, optarg, &log)) {
+          return_code = 1;
+        }
+        else {
+          return_code = 0;
+        }
+        break;
+      case 'f':
+        if (cfg_cmd_handle_format(olsr_cfg_get_db(), &state, optarg, &log)) {
+          return_code = 1;
+        }
+        break;
+      case 'p':
+        if (olsr_plugins_load(optarg) == NULL) {
+          return_code = 1;
+        }
+        break;
+
+      default:
+        return_code = 1;
+        break;
+    }
+  }
+
+  if (return_code == -1 && !loaded_file) {
+    /* load default config file if no other loaded */
+    if (cfg_cmd_handle_load(olsr_cfg_get_db(), &state, def_config, &log)) {
+      return_code = 1;
+    }
+  }
+
+  if (return_code == -1) {
+    /* validate configuration */
+    if (cfg_schema_validate(olsr_cfg_get_db(), false, false, &log)) {
+      return_code = 1;
+    }
+  }
+
+  if (log.len > 0) {
+    fputs(log.buf, stderr);
+  }
+
+  abuf_free(&log);
+  cfg_cmd_remove(&state);
+
+  return return_code;
+}
diff --git a/src/core/olsr.h b/src/core/olsr.h
new file mode 100644 (file)
index 0000000..61abed0
--- /dev/null
@@ -0,0 +1,89 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions