changeset 0:13530e1f02e3

Initial files imported
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 28 Aug 2009 19:14:42 +0900
parents
children bafb831ba688
files .hgignore CMakeLists.txt INSTALL LICENSE README cmake/Modules/CMakeUserUseBison.cmake cmake/Modules/CMakeUserUseFlex.cmake cmake/Modules/FindGNUTLS.cmake cmake/Modules/FindSCTP.cmake cmake/Modules/LibFindMacros.cmake doc/update_copyright.sh freediameter/CMakeLists.txt freediameter/dict_base_proto.c freediameter/fd.h freediameter/main.c freediameter/tests/CMakeLists.txt freediameter/tests/testdict.c freediameter/tests/testmesg.c freediameter/tests/testmq.c freediameter/tests/tests.h include/freediameter/CMakeLists.txt include/freediameter/freediameter-host.h.in include/freediameter/freediameter.h include/freediameter/libfreediameter.h libfreediameter/CMakeLists.txt libfreediameter/dictionary.c libfreediameter/init.c libfreediameter/libfd.h libfreediameter/lists.c libfreediameter/log.c libfreediameter/messages.c libfreediameter/mqueues.c
diffstat 32 files changed, 12961 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,9 @@
+syntax: glob
+*.orig
+*.rej
+*~
+*.log
+*.sum
+.hg
+build*
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CMakeLists.txt	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,43 @@
+# This file is the source for generating the Makefile for the project, using cmake tool (cmake.org)
+
+# Name of the project, and language
+PROJECT("FreeDiameter" C)
+
+# Some subfolders may have tests
+ENABLE_TESTING()
+
+# CMake version
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+# Location of additional CMake modules
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+# All source code should be POSIX 200112L compatible, but some other extensions might be used, so:
+ADD_DEFINITIONS(-D_GNU_SOURCE)
+
+# Location for the include files
+INCLUDE_DIRECTORIES(include)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/include)
+SUBDIRS(include/freediameter)
+
+# some subfolders use yacc and lex parsers
+SET(BISON_GENERATE_DEFINES TRUE)
+SET(BISON_PREFIX_OUTPUTS TRUE)
+INCLUDE(CMakeUserUseBison)
+SET(FLEX_PREFIX_OUTPUTS TRUE)
+INCLUDE(CMakeUserUseFlex)
+IF( NOT BISON_EXECUTABLE OR NOT FLEX_EXECUTABLE )
+  MESSAGE( SEND_ERROR "Bison and Flex are required" )
+ENDIF( NOT BISON_EXECUTABLE OR NOT FLEX_EXECUTABLE )
+# Check that flex is at least 2.5.20 to support bison-bridge
+# how to do the check with cmake???
+
+# Location for the source code
+SUBDIRS(libfreediameter)
+SUBDIRS(freediameter)
+
+# Do we build the extensions?
+OPTION(IGNORE_ALL_EXTENSIONS "Ignore the extensions completly?")
+IF(NOT IGNORE_ALL_EXTENSIONS)
+	SUBDIRS(extensions)
+ENDIF(NOT IGNORE_ALL_EXTENSIONS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/INSTALL	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,39 @@
+This package uses CMake (cmake.org) as building system. You'll need the cmake tool in order 
+to generate the Makefiles for your platform. You can also select which extensions must be built.
+
+Building in a separate directory is recommended:
+mkdir build
+cd build
+cmake ../
+make
+
+You can enable the unary tests by doing:
+cmake -DNO_TESTS:BOOL=OFF ../
+make
+make tests
+
+Note: instead of passing options on the command line, you can edit the CCmakeCache.txt file
+or use a CMake front-end (for example cmake-gui)
+
+Note that there are dependencies on some external tools that may not be enforced by the configure script.
+On Ubuntu Intrepid, the following packages were required (aptitude install ...):
+ gcc make flex bison libsctp1 libsctp-dev cmake
+
+On FreeBSD the following packages were required:
+ cmake flex bison
+Then the cmake command had to look like:
+ cmake -DFLEX_EXECUTABLE:FILEPATH=/usr/local/bin/flex ...
+
+make install has not been tested yet and will probably not behave as expected!
+
+You can also configure which extensions to build with CMake:
+NoExtensions:BOOL=OFF    (or the following are ignored)
+BUILD_APP_TEST:BOOL=ON
+BUILD_RT_ANY:BOOL=ON
+BUILD_RT_DEBUG:BOOL=ON
+BUILD_RT_DEFAULT:BOOL=ON
+BUILD_SAMPLE:BOOL=ON
+
+You can change the default configuration file name:
+DEFAULT_CONF_FILE:STRING=/path/to/some/freediameter.conf
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,34 @@
+This software package is copyrighted under the terms of the BSD license, as follow:
+
+Software License Agreement (BSD License)
+
+Copyright (c) 2009, WIDE Project and NICT
+All rights reserved.
+
+Redistribution and use of this software 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 the WIDE Project or NICT nor the 
+  names of its contributors may be used to endorse or 
+  promote products derived from this software without 
+  specific prior written permission of WIDE Project and 
+  NICT.
+
+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.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,12 @@
+The FreeDiameter daemon implements the Diameter base protocol.
+Loadable extensions add the logic of Diameter applications or advanced use of the daemon.
+See http://aaa.koganei.wide.ad.jp/ for more information on the project.
+FreeDiameter was previously known as the "waaad" project (WIDE AAA Daemon)
+
+This version is not related to the "freediameter" project from Sun, which seems abandoned.
+
+Author: Sebastien Decugis.
+
+See LICENSE file for legal information on this software.
+
+See INSTALL for information on building and using this software.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/Modules/CMakeUserUseBison.cmake	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,71 @@
+# - Look for GNU Bison, the parser generator
+# Based off a news post from Andy Cedilnik at Kitware
+# Defines the following:
+#  BISON_EXECUTABLE - path to the bison executable
+#  BISON_FILE - parse a file with bison
+#  BISON_PREFIX_OUTPUTS - Set to true to make BISON_FILE produce prefixed
+#                         symbols in the generated output based on filename.
+#                         So for ${filename}.y, you'll get ${filename}parse(), etc.
+#                         instead of yyparse().
+#  BISON_GENERATE_DEFINES - Set to true to make BISON_FILE output the matching
+#                           .h file for a .c file. You want this if you're using
+#                           flex.
+
+IF(NOT DEFINED BISON_PREFIX_OUTPUTS)
+ SET(BISON_PREFIX_OUTPUTS FALSE)
+ENDIF(NOT DEFINED BISON_PREFIX_OUTPUTS)
+
+IF(NOT DEFINED BISON_GENERATE_DEFINES)
+ SET(BISON_GENERATE_DEFINES FALSE)
+ENDIF(NOT DEFINED BISON_GENERATE_DEFINES)
+
+IF(NOT BISON_EXECUTABLE)
+ MESSAGE(STATUS "Looking for bison")
+ FIND_PROGRAM(BISON_EXECUTABLE bison)
+ IF(BISON_EXECUTABLE)
+   MESSAGE(STATUS "Looking for bison -- ${BISON_EXECUTABLE}")
+ ENDIF(BISON_EXECUTABLE)
+ENDIF(NOT BISON_EXECUTABLE)
+
+IF(BISON_EXECUTABLE)
+ MACRO(BISON_FILE FILENAME)
+   GET_FILENAME_COMPONENT(PATH "${FILENAME}" PATH)
+   IF("${PATH}" STREQUAL "")
+     SET(PATH_OPT "")
+   ELSE("${PATH}" STREQUAL "")
+     SET(PATH_OPT "/${PATH}")
+   ENDIF("${PATH}" STREQUAL "")
+   GET_FILENAME_COMPONENT(HEAD "${FILENAME}" NAME_WE)
+   IF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
+     FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
+   ENDIF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
+   IF(BISON_PREFIX_OUTPUTS)
+     SET(PREFIX "${HEAD}")
+   ELSE(BISON_PREFIX_OUTPUTS)
+     SET(PREFIX "yy")
+   ENDIF(BISON_PREFIX_OUTPUTS)
+   SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/${HEAD}.tab.c")
+   IF(BISON_GENERATE_DEFINES)
+     SET(HEADER "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/${HEAD}.tab.h")
+     ADD_CUSTOM_COMMAND(
+       OUTPUT "${OUTFILE}" "${HEADER}"
+       COMMAND "${BISON_EXECUTABLE}"
+       ARGS "--name-prefix=${PREFIX}"
+       "--defines"
+       "--output-file=${OUTFILE}"
+       "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}"
+       DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
+     SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" "${HEADER}" PROPERTIES GENERATED TRUE)
+     SET_SOURCE_FILES_PROPERTIES("${HEADER}" PROPERTIES HEADER_FILE_ONLY TRUE)
+   ELSE(BISON_GENERATE_DEFINES)
+     ADD_CUSTOM_COMMAND(
+       OUTPUT "${OUTFILE}"
+       COMMAND "${BISON_EXECUTABLE}"
+       ARGS "--name-prefix=${PREFIX}"
+       "--output-file=${OUTFILE}"
+       "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}"
+       DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
+     SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" PROPERTIES GENERATED TRUE)
+   ENDIF(BISON_GENERATE_DEFINES)
+ ENDMACRO(BISON_FILE) 
+ENDIF(BISON_EXECUTABLE)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/Modules/CMakeUserUseFlex.cmake	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,46 @@
+# - Look for GNU flex, the lexer generator.
+# Defines the following:
+#  FLEX_EXECUTABLE - path to the flex executable
+#  FLEX_FILE - parse a file with flex
+#  FLEX_PREFIX_OUTPUTS - Set to true to make FLEX_FILE produce outputs of
+#                        lex.${filename}.c, not lex.yy.c . Passes -P to flex. 
+
+IF(NOT DEFINED FLEX_PREFIX_OUTPUTS)
+  SET(FLEX_PREFIX_OUTPUTS FALSE)
+ENDIF(NOT DEFINED FLEX_PREFIX_OUTPUTS) 
+
+IF(NOT FLEX_EXECUTABLE)
+  MESSAGE(STATUS "Looking for flex")
+  FIND_PROGRAM(FLEX_EXECUTABLE flex)
+  IF(FLEX_EXECUTABLE)
+    MESSAGE(STATUS "Looking for flex -- ${FLEX_EXECUTABLE}")
+  ENDIF(FLEX_EXECUTABLE)
+ENDIF(NOT FLEX_EXECUTABLE) 
+
+IF(FLEX_EXECUTABLE)
+  MACRO(FLEX_FILE FILENAME)
+    GET_FILENAME_COMPONENT(PATH "${FILENAME}" PATH)
+    IF("${PATH}" STREQUAL "")
+      SET(PATH_OPT "")
+    ELSE("${PATH}" STREQUAL "")
+      SET(PATH_OPT "/${PATH}")
+    ENDIF("${PATH}" STREQUAL "")
+    IF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
+      FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
+    ENDIF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}")
+    IF(FLEX_PREFIX_OUTPUTS)
+      GET_FILENAME_COMPONENT(PREFIX "${FILENAME}" NAME_WE)
+    ELSE(FLEX_PREFIX_OUTPUTS)
+      SET(PREFIX "yy")
+    ENDIF(FLEX_PREFIX_OUTPUTS)
+    SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/lex.${PREFIX}.c")
+    ADD_CUSTOM_COMMAND(
+      OUTPUT "${OUTFILE}"
+      COMMAND "${FLEX_EXECUTABLE}"
+      ARGS "-P${PREFIX}"
+      "-o${OUTFILE}"
+      "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}"
+      DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}")
+    SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" PROPERTIES GENERATED TRUE)
+  ENDMACRO(FLEX_FILE)
+ENDIF(FLEX_EXECUTABLE)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/Modules/FindGNUTLS.cmake	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,29 @@
+# - Try to find GNU TLS library and headers
+# Once done, this will define
+#
+#  GNUTLS_FOUND - system has GNU TLS
+#  GNUTLS_INCLUDE_DIRS - the GNU TLS include directories
+#  GNUTLS_LIBRARIES - link these to use GNU TLS
+
+include(LibFindMacros)
+
+# Use pkg-config to get hints about paths
+libfind_pkg_check_modules(GNUTLS_PKGCONF gnutls)
+
+# Include dir
+find_path(GNUTLS_INCLUDE_DIR
+  NAMES gnutls/gnutls.h
+  PATHS ${GNUTLS_PKGCONF_INCLUDE_DIRS}
+)
+
+# Finally the library itself
+find_library(GNUTLS_LIBRARY
+  NAMES gnutls
+  PATHS ${GNUTLS_PKGCONF_LIBRARY_DIRS}
+)
+
+# Set the include dir variables and the libraries and let libfind_process do the rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
+set(GNUTLS_PROCESS_INCLUDES GNUTLS_INCLUDE_DIR)
+set(GNUTLS_PROCESS_LIBS GNUTLS_LIBRARY)
+libfind_process(GNUTLS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/Modules/FindSCTP.cmake	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,29 @@
+# - Try to find SCTP library and headers
+# Once done, this will define
+#
+#  SCTP_FOUND - system has SCTP
+#  SCTP_INCLUDE_DIRS - the SCTP include directories
+#  SCTP_LIBRARIES - link these to use SCTP
+
+include(LibFindMacros)
+
+# Use pkg-config to get hints about paths (Note: not yet supported?)
+# libfind_pkg_check_modules(SCTP_PKGCONF sctp)
+
+# Include dir
+find_path(SCTP_INCLUDE_DIR
+  NAMES netinet/sctp.h
+  PATHS ${SCTP_PKGCONF_INCLUDE_DIRS}
+)
+
+# Finally the library itself
+find_library(SCTP_LIBRARY
+  NAMES sctp
+  PATHS ${SCTP_PKGCONF_LIBRARY_DIRS}
+)
+
+# Set the include dir variables and the libraries and let libfind_process do the rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
+set(SCTP_PROCESS_INCLUDES SCTP_INCLUDE_DIR)
+set(SCTP_PROCESS_LIBS SCTP_LIBRARY)
+libfind_process(SCTP)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/Modules/LibFindMacros.cmake	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,99 @@
+# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
+# used for the current package. For this to work, the first parameter must be the
+# prefix of the current package, then the prefix of the new package etc, which are
+# passed to find_package.
+macro (libfind_package PREFIX)
+  set (LIBFIND_PACKAGE_ARGS ${ARGN})
+  if (${PREFIX}_FIND_QUIETLY)
+    set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
+  endif (${PREFIX}_FIND_QUIETLY)
+  if (${PREFIX}_FIND_REQUIRED)
+    set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
+  endif (${PREFIX}_FIND_REQUIRED)
+  find_package(${LIBFIND_PACKAGE_ARGS})
+endmacro (libfind_package)
+
+# Damn CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
+# where they added pkg_check_modules. Consequently I need to support both in my scripts
+# to avoid those deprecated warnings. Here's a helper that does just that.
+# Works identically to pkg_check_modules, except that no checks are needed prior to use.
+macro (libfind_pkg_check_modules PREFIX PKGNAME)
+  if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+    include(UsePkgConfig)
+    pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
+  else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+    find_package(PkgConfig)
+    if (PKG_CONFIG_FOUND)
+      pkg_check_modules(${PREFIX} ${PKGNAME})
+    endif (PKG_CONFIG_FOUND)
+  endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+endmacro (libfind_pkg_check_modules)
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+macro (libfind_process PREFIX)
+  # Skip processing if already processed during this run
+  if (NOT ${PREFIX}_FOUND)
+    # Start with the assumption that the library was found
+    set (${PREFIX}_FOUND TRUE)
+
+    # Process all includes and set _FOUND to false if any are missing
+    foreach (i ${${PREFIX}_PROCESS_INCLUDES})
+      if (${i})
+        set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
+        mark_as_advanced(${i})
+      else (${i})
+        set (${PREFIX}_FOUND FALSE)
+      endif (${i})
+    endforeach (i)
+
+    # Process all libraries and set _FOUND to false if any are missing
+    foreach (i ${${PREFIX}_PROCESS_LIBS})
+      if (${i})
+        set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
+        mark_as_advanced(${i})
+      else (${i})
+        set (${PREFIX}_FOUND FALSE)
+      endif (${i})
+    endforeach (i)
+
+    # Print message and/or exit on fatal error
+    if (${PREFIX}_FOUND)
+      if (NOT ${PREFIX}_FIND_QUIETLY)
+        message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+      endif (NOT ${PREFIX}_FIND_QUIETLY)
+    else (${PREFIX}_FOUND)
+      if (${PREFIX}_FIND_REQUIRED)
+        foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
+          message("${i}=${${i}}")
+        endforeach (i)
+        message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
+      endif (${PREFIX}_FIND_REQUIRED)
+    endif (${PREFIX}_FOUND)
+  endif (NOT ${PREFIX}_FOUND)
+endmacro (libfind_process)
+
+macro(libfind_library PREFIX basename)
+  set(TMP "")
+  if(MSVC80)
+    set(TMP -vc80)
+  endif(MSVC80)
+  if(MSVC90)
+    set(TMP -vc90)
+  endif(MSVC90)
+  set(${PREFIX}_LIBNAMES ${basename}${TMP})
+  if(${ARGC} GREATER 2)
+    set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
+    string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
+    set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
+  endif(${ARGC} GREATER 2)
+  find_library(${PREFIX}_LIBRARY
+    NAMES ${${PREFIX}_LIBNAMES}
+    PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
+  )
+endmacro(libfind_library)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/update_copyright.sh	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,33 @@
+#!/bin/bash -x
+
+# This script will search all waaad copyrights from source files, and update these if 
+# the waaad source was modified later.
+
+if [ ! -f waaad/waaad-internal.h ];
+then echo "This script must be run from waaad top directory"
+exit 1;
+fi;
+
+# Create a clean working copy
+TMPDIR=`mktemp -d up_cop.XXXXXXX` || exit 1
+hg clone . $TMPDIR/waaad || exit 1
+pushd $TMPDIR/waaad
+
+# Now, for each file
+for SRC_FILE in `find . -name .hg -prune -or -type f -exec grep -q 'Copyright (c) 20.., WIDE Project and NICT' {} \; -print`;
+do 
+HG_YEAR=`hg log --template '{date|shortdate}' $SRC_FILE | tr - ' ' | awk '{print \$1}'`
+CPY_YEAR=`grep 'Copyright (c) 20.., WIDE Project and NICT' $SRC_FILE | awk '{print substr(\$4, 1, 4) }'`
+if [ $HG_YEAR -gt $CPY_YEAR ];
+then
+echo "Updating copyright $CPY_YEAR -> $HG_YEAR in $SRC_FILE";
+sed -i -e "s/Copyright (c) $CPY_YEAR, WIDE Project and NICT/Copyright (c) $HG_YEAR, WIDE Project and NICT/" $SRC_FILE
+fi;
+done
+
+hg commit -m"Updated copyright information"
+hg push
+popd
+rm -rf $TMPDIR
+hg update
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/CMakeLists.txt	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,24 @@
+# The subproject name
+Project("freediameterd" C)
+
+SET(PROJECT_VERSION 0.1)
+SET(PROJECT_COPYRIGHT "Copyright (c) 2008-2009, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)")
+
+# List of source files
+SET(FD_COMMON_SRC
+	fd.h
+	dict_base_proto.c
+	)
+
+# Building the executable
+ADD_EXECUTABLE(freediameterd ${FD_COMMON_SRC} main.c)
+
+# The link command
+LINK_DIRECTORIES(${CURRENT_BINARY_DIR}/../libfreediameter)
+TARGET_LINK_LIBRARIES(freediameterd libfreediameter ${FD_LIBS})
+
+# The unary tests directory
+OPTION(SKIP_TESTS "Skip compilation of the tests?" OFF)
+IF ( NOT SKIP_TESTS )
+	SUBDIRS(tests)
+ENDIF ( NOT SKIP_TESTS )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/dict_base_proto.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,3435 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+/* Diameter Base protocol definitions.
+ */
+
+#include "fd.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+/* The pointer for the global dictionary (initialized from main) */
+struct dictionary * fd_g_dict = NULL;
+
+/* The functions to encode and interpret the derived types defined in the base protocol */
+
+/* Address AVP <-> struct sockaddr_storage */
+static int Address_encode(void * data, union avp_value * avp_value)
+{
+	sSS * ss = (sSS *) data;
+	uint16_t AddressType = 0;
+	size_t	size = 0;
+	unsigned char * buf = NULL;
+	
+	TRACE_ENTRY("%p %p", data, avp_value);
+	CHECK_PARAMS( data && avp_value  );
+	
+	switch (ss->ss_family) {
+		case AF_INET:
+			{
+				/* We are encoding an IP address */
+				sSA4 * sin = (sSA4 *)ss;
+				
+				AddressType = 1;/* see http://www.iana.org/assignments/address-family-numbers/ */
+				size = 6;	/* 2 for AddressType + 4 for data */
+				
+				CHECK_MALLOC(  buf = malloc(size)  );
+				
+				/* may not work because of alignment: *(uint32_t *)(buf+2) = htonl(sin->sin_addr.s_addr); */
+				memcpy(buf + 2, &sin->sin_addr.s_addr, 4);
+			}
+			break;
+				
+		case AF_INET6:
+			{
+				/* We are encoding an IPv6 address */
+				sSA6 * sin6 = (sSA6 *)ss;
+				
+				AddressType = 2;/* see http://www.iana.org/assignments/address-family-numbers/ */
+				size = 18;	/* 2 for AddressType + 16 for data */
+				
+				CHECK_MALLOC(  buf = malloc(size)  );
+				
+				/* The order is already good here */
+				memcpy(buf + 2, &sin6->sin6_addr.s6_addr, 16);
+			}
+			break;
+				
+		default:
+			CHECK_PARAMS( AddressType = 0 );
+	}
+	
+	*(uint16_t *)buf = htons(AddressType);
+
+	avp_value->os.len = size;
+	avp_value->os.data = buf;
+	
+	return 0;
+}
+
+static int Address_interpret(union avp_value * avp_value, void * interpreted)
+{
+	uint16_t AddressType = 0;
+	unsigned char * buf;
+	
+	TRACE_ENTRY("%p %p", avp_value, interpreted);
+	
+	CHECK_PARAMS( avp_value && interpreted && (avp_value->os.len >= 2)  );
+	
+	AddressType = ntohs(*(uint16_t *)avp_value->os.data);
+	buf = &avp_value->os.data[2];
+	
+	switch (AddressType) {
+		case 1 /* IP */:
+			{
+				sSA4 * sin = (sSA4 *)interpreted;
+				
+				CHECK_PARAMS(  avp_value->os.len == 6  );
+				
+				sin->sin_family = AF_INET;
+				/* sin->sin_addr.s_addr = ntohl( * (uint32_t *) buf); -- may not work because of bad alignment */
+				memcpy(&sin->sin_addr.s_addr, buf, 4);
+			}
+			break;
+				
+		case 2 /* IP6 */:
+			{
+				sSA6 * sin6 = (sSA6 *)interpreted;
+				
+				CHECK_PARAMS(  avp_value->os.len == 18  );
+				
+				sin6->sin6_family = AF_INET6;
+				memcpy(&sin6->sin6_addr.s6_addr, buf, 16);
+			}
+			break;
+				
+		default:
+			CHECK_PARAMS( AddressType = 0 );
+	}
+	
+	return 0;
+}
+
+
+
+#define CHECK_dict_new( _type, _data, _parent, _ref )				\
+	CHECK_FCT(  fd_dict_new( dict, (_type), (_data), (_parent), (_ref))  );
+
+#define CHECK_dict_search( _type, _criteria, _what, _result )					\
+	CHECK_FCT(  fd_dict_search( dict, (_type), (_criteria), (_what), (_result), ENOENT)  );
+
+struct local_rules_definition {
+	char 			*avp_name;
+	enum rule_position	position;
+	int 			min;
+	int			max;
+};
+
+#define RULE_ORDER( _position ) ((((_position) == RULE_FIXED_HEAD) || ((_position) == RULE_FIXED_TAIL)) ? 1 : 0 )
+
+#define PARSE_loc_rules( _rulearray, _parent) {						\
+	int __ar;									\
+	for (__ar=0; __ar < sizeof(_rulearray) / sizeof((_rulearray)[0]); __ar++) {	\
+		struct dict_rule_data __data = { NULL, 					\
+			(_rulearray)[__ar].position,					\
+			0, 								\
+			(_rulearray)[__ar].min,						\
+			(_rulearray)[__ar].max};					\
+		__data.rule_order = RULE_ORDER(__data.rule_position);			\
+		CHECK_FCT(  fd_dict_search( 						\
+			dict,								\
+			DICT_AVP, 							\
+			AVP_BY_NAME, 							\
+			(_rulearray)[__ar].avp_name, 					\
+			&__data.rule_avp, 0 ) );					\
+		if ( !__data.rule_avp ) {						\
+			TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_name );	\
+			return ENOENT;							\
+		}									\
+		CHECK_FCT_DO( fd_dict_new( dict, DICT_RULE, &__data, _parent, NULL),	\
+			{								\
+				TRACE_DEBUG(INFO, "Error on rule with AVP '%s'",	\
+					 (_rulearray)[__ar].avp_name );			\
+				return EINVAL;						\
+			} );								\
+	}										\
+}
+
+int fd_dict_base_protocol(struct dictionary * dict)
+{
+	TRACE_ENTRY("%p", dict);
+	CHECK_PARAMS(dict);
+	
+	/* Vendors section */
+	{
+		/* The base RFC has no vendor information */
+		;
+	}
+	
+	/* Applications section */
+	{
+		/* base accounting application */
+		{
+			struct dict_application_data data = {          3, "Diameter Base Accounting" 	};
+			CHECK_dict_new( DICT_APPLICATION, &data, NULL, NULL);
+		}
+		
+		/* relay application */
+		{
+			struct dict_application_data data  = { 0xffffffff, "Relay" 				};
+			CHECK_dict_new( DICT_APPLICATION, &data , NULL, NULL);
+		}
+	}
+	
+	/* Derived AVP types section */
+	{
+		/* Address */
+		{
+			/*
+				The Address format is derived from the OctetString AVP Base
+				Format.  It is a discriminated union, representing, for example a
+				32-bit (IPv4) [RFC791] or 128-bit (IPv6) [RFC4291] address, most
+				significant octet first.  The first two octets of the Address AVP
+				represents the AddressType, which contains an Address Family
+				defined in [IANAADFAM].  The AddressType is used to discriminate
+				the content and format of the remaining octets.
+			*/
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"Address"		, Address_interpret	, Address_encode	};
+			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
+		}
+		
+		/* Time */
+		{
+			/*
+				The Time format is derived from the OctetString AVP Base Format.
+				The string MUST contain four octets, in the same format as the
+				first four bytes are in the NTP timestamp format.  The NTP
+				Timestamp format is defined in chapter 3 of [RFC4330].
+
+				This represents the number of seconds since 0h on 1 January 1900
+				with respect to the Coordinated Universal Time (UTC).
+
+				On 6h 28m 16s UTC, 7 February 2036 the time value will overflow.
+				SNTP [RFC4330] describes a procedure to extend the time to 2104.
+				This procedure MUST be supported by all DIAMETER nodes.
+			*/
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"Time"			, NULL			, NULL			};
+			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
+		}
+		
+		/* UTF8String */
+		{
+			/*
+				The UTF8String format is derived from the OctetString AVP Base
+				Format.  This is a human readable string represented using the
+				ISO/IEC IS 10646-1 character set, encoded as an OctetString using
+				the UTF-8 [RFC3629] transformation format described in RFC 3629.
+
+				Since additional code points are added by amendments to the 10646
+				standard from time to time, implementations MUST be prepared to
+				encounter any code point from 0x00000001 to 0x7fffffff.  Byte
+				sequences that do not correspond to the valid encoding of a code
+				point into UTF-8 charset or are outside this range are prohibited.
+
+				The use of control codes SHOULD be avoided.  When it is necessary
+				to represent a new line, the control code sequence CR LF SHOULD be
+				used.
+
+				The use of leading or trailing white space SHOULD be avoided.
+
+				For code points not directly supported by user interface hardware
+				or software, an alternative means of entry and display, such as
+				hexadecimal, MAY be provided.
+
+				For information encoded in 7-bit US-ASCII, the UTF-8 charset is
+				identical to the US-ASCII charset.
+
+				UTF-8 may require multiple bytes to represent a single character /
+				code point; thus the length of an UTF8String in octets may be
+				different from the number of characters encoded.
+
+				Note that the AVP Length field of an UTF8String is measured in
+				octets, not characters.
+			*/
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"UTF8String"		, NULL			, NULL			};
+			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
+		}
+		
+		/* DiameterIdentity */
+		{
+			/*
+				The DiameterIdentity format is derived from the OctetString AVP
+				Base Format.
+
+                				DiameterIdentity  = FQDN
+
+
+				DiameterIdentity value is used to uniquely identify a Diameter
+				node for purposes of duplicate connection and routing loop
+				detection.
+
+				The contents of the string MUST be the FQDN of the Diameter node.
+				If multiple Diameter nodes run on the same host, each Diameter
+				node MUST be assigned a unique DiameterIdentity.  If a Diameter
+
+				node can be identified by several FQDNs, a single FQDN should be
+				picked at startup, and used as the only DiameterIdentity for that
+				node, whatever the connection it is sent on.  Note that in this
+				document, DiameterIdentity is in ASCII form in order to be
+				compatible with existing DNS infrastructure.  See Appendix D for
+				interactions between the Diameter protocol and Internationalized
+				Domain Name (IDNs).
+			*/
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"DiameterIdentity"	, NULL			, NULL			};
+			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
+		}
+		
+		/* DiameterURI */
+		{
+			/*
+				The DiameterURI MUST follow the Uniform Resource Identifiers (URI)
+				syntax [RFC3986] rules specified below:
+
+				 "aaa://" FQDN [ port ] [ transport ] [ protocol ]
+
+                				 ; No transport security
+
+				 "aaas://" FQDN [ port ] [ transport ] [ protocol ]
+
+                				 ; Transport security used
+
+				 FQDN               = Fully Qualified Host Name
+
+				 port               = ":" 1*DIGIT
+
+                				 ; One of the ports used to listen for
+                				 ; incoming connections.
+                				 ; If absent,
+                				 ; the default Diameter port (3868) is
+                				 ; assumed.
+
+				 transport          = ";transport=" transport-protocol
+
+                				 ; One of the transports used to listen
+                				 ; for incoming connections.  If absent,
+                				 ; the default SCTP [RFC2960] protocol is
+                				 ; assumed. UDP MUST NOT be used when
+                				 ; the aaa-protocol field is set to
+                				 ; diameter.
+
+				transport-protocol = ( "tcp" / "sctp" / "udp" )
+
+				protocol           = ";protocol=" aaa-protocol
+
+                				 ; If absent, the default AAA protocol
+                				 ; is diameter.
+
+				aaa-protocol       = ( "diameter" / "radius" / "tacacs+" )
+
+				The following are examples of valid Diameter host identities:
+
+				aaa://host.example.com;transport=tcp
+				aaa://host.example.com:6666;transport=tcp
+				aaa://host.example.com;protocol=diameter
+				aaa://host.example.com:6666;protocol=diameter
+				aaa://host.example.com:6666;transport=tcp;protocol=diameter
+				aaa://host.example.com:1813;transport=udp;protocol=radius
+			*/
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"DiameterURI"		, NULL			, NULL			};
+			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
+		}
+		
+		/* Enumerated */
+		{
+			/*
+				Enumerated is derived from the Integer32 AVP Base Format.  The
+				definition contains a list of valid values and their
+				interpretation and is described in the Diameter application
+				introducing the AVP.
+			*/
+			
+			/* We don't use a generic "Enumerated" type in waaad. Instead, we define
+			 * types of the form "Enumerated(<avpname>)" where <avpname> is replaced 
+			 * by the name of the AVP to which the type applies.
+			 *  Example: Enumerated(Disconnect-Cause)
+			 */
+			;
+		}
+		
+		/* IPFilterRule */
+		{
+			/*
+				The IPFilterRule format is derived from the OctetString AVP Base
+				Format and uses the ASCII charset.  The rule syntax is a modified
+				subset of ipfw(8) from FreeBSD.  Packets may be filtered based on
+				the following information that is associated with it:
+
+				    Direction                          (in or out)
+				    Source and destination IP address  (possibly masked)
+				    Protocol
+				    Source and destination port        (lists or ranges)
+				    TCP flags
+				    IP fragment flag
+				    IP options
+				    ICMP types
+
+				Rules for the appropriate direction are evaluated in order, with
+				the first matched rule terminating the evaluation.  Each packet is
+				evaluated once.  If no rule matches, the packet is dropped if the
+				last rule evaluated was a permit, and passed if the last rule was
+				a deny.
+
+				IPFilterRule filters MUST follow the format:
+				
+				    action dir proto from src to dst [options]
+				
+			(...skipped loooong explanation...)
+				
+				There is one kind of packet that the access device MUST always
+				discard, that is an IP fragment with a fragment offset of one.
+				This is a valid packet, but it only has one use, to try to
+				circumvent firewalls.
+
+				An access device that is unable to interpret or apply a deny rule
+				MUST terminate the session.  An access device that is unable to
+				interpret or apply a permit rule MAY apply a more restrictive
+				rule.  An access device MAY apply deny rules of its own before the
+				supplied rules, for example to protect the access device owner's
+				infrastructure.
+			*/
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"IPFilterRule"		, NULL			, NULL			};
+			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
+		}
+	}
+	
+	/* AVP section */
+	{
+		struct dict_object * Address_type;
+		struct dict_object * UTF8String_type;
+		struct dict_object * DiameterIdentity_type;
+		struct dict_object * DiameterURI_type;
+		struct dict_object * Time_type;
+		
+		CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Address", &Address_type);
+		CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "UTF8String", &UTF8String_type);
+		CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "DiameterIdentity", &DiameterIdentity_type);
+		CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "DiameterURI", &DiameterURI_type);
+		CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Time", &Time_type);
+		
+		/* Vendor-Id */
+		{
+			/*
+				The Vendor-Id AVP (AVP Code 266) is of type Unsigned32 and contains
+				the IANA "SMI Network Management Private Enterprise Codes" [RFC3232]
+				value assigned to the vendor of the Diameter device.  It is
+				envisioned that the combination of the Vendor-Id, Product-Name
+				(Section 5.3.7) and the Firmware-Revision (Section 5.3.4) AVPs may
+				provide useful debugging information.
+
+				A Vendor-Id value of zero in the CER or CEA messages is reserved and
+				indicates that this field is ignored.
+			*/
+			struct dict_avp_data data = { 
+					266, 					/* Code */
+					#if AC_VENDOR_ID != 266
+					#error "AC_VENDOR_ID definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Vendor-Id", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY, 			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data, NULL, NULL);
+		}
+		
+		/* Firmware-Revision */
+		{
+			/*
+				The Firmware-Revision AVP (AVP Code 267) is of type Unsigned32 and is
+				used to inform a Diameter peer of the firmware revision of the
+				issuing device.
+
+				For devices that do not have a firmware revision (general purpose
+				computers running Diameter software modules, for instance), the
+				revision of the Diameter software module may be reported instead.
+			*/
+			struct dict_avp_data data = { 
+					267, 					/* Code */
+					#if AC_FIRMWARE_REVISION != 267
+					#error "AC_FIRMWARE_REVISION definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Firmware-Revision", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					0,		 			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Host-IP-Address */
+		{
+			/*
+				The Host-IP-Address AVP (AVP Code 257) is of type Address and is used
+				to inform a Diameter peer of the sender's IP address.  All source
+				addresses that a Diameter node expects to use with SCTP [RFC2960]
+				MUST be advertised in the CER and CEA messages by including a
+				Host-IP- Address AVP for each address.  This AVP MUST ONLY be used in
+				the CER and CEA messages.
+			*/
+			struct dict_avp_data data = { 
+					257, 					/* Code */
+					#if AC_HOST_IP_ADDRESS != 257
+					#error "AC_HOST_IP_ADDRESS definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Host-IP-Address", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , Address_type, NULL);
+		}
+		
+		/* Supported-Vendor-Id */
+		{
+			/*
+				The Supported-Vendor-Id AVP (AVP Code 265) is of type Unsigned32 and
+				contains the IANA "SMI Network Management Private Enterprise Codes"
+				[RFC3232] value assigned to a vendor other than the device vendor but
+				including the application vendor.  This is used in the CER and CEA
+				messages in order to inform the peer that the sender supports (a
+				subset of) the vendor-specific AVPs defined by the vendor identified
+				in this AVP.  The value of this AVP SHOULD NOT be set to zero.
+				Multiple instances of this AVP containing the same value SHOULD NOT
+				be sent.
+			*/
+			struct dict_avp_data data = { 
+					265, 					/* Code */
+					#if AC_SUPPORTED_VENDOR_ID != 265
+					#error "AC_SUPPORTED_VENDOR_ID definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Supported-Vendor-Id", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Product-Name */
+		{
+			/*
+				The Product-Name AVP (AVP Code 269) is of type UTF8String, and
+				contains the vendor assigned name for the product.  The Product-Name
+				AVP SHOULD remain constant across firmware revisions for the same
+				product.
+			*/
+			struct dict_avp_data data = { 
+					269, 					/* Code */
+					#if AC_PRODUCT_NAME != 269
+					#error "AC_PRODUCT_NAME definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Product-Name", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					0,					/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
+		}
+		
+		/* Disconnect-Cause */
+		{
+			/*
+				The Disconnect-Cause AVP (AVP Code 273) is of type Enumerated.  A
+				Diameter node MUST include this AVP in the Disconnect-Peer-Request
+				message to inform the peer of the reason for its intention to
+				shutdown the transport connection.  The following values are
+				supported:
+
+				REBOOTING                         0
+				A scheduled reboot is imminent. Receiver of DPR with above result
+				code MAY attempt reconnection.
+
+				BUSY                              1
+				The peer's internal resources are constrained, and it has
+				determined that the transport connection needs to be closed.
+				Receiver of DPR with above result code SHOULD NOT attempt
+				reconnection.
+
+				DO_NOT_WANT_TO_TALK_TO_YOU        2
+				The peer has determined that it does not see a need for the
+				transport connection to exist, since it does not expect any
+				messages to be exchanged in the near future. Receiver of DPR
+				with above result code SHOULD NOT attempt reconnection.
+			*/
+			struct dict_object 	* 	type;
+			struct dict_type_data 		tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Disconnect-Cause)"	, NULL, NULL};
+			struct dict_enumval_data 	t_0 = { "REBOOTING", 			{ .i32 = 0 }};
+			struct dict_enumval_data 	t_1 = { "BUSY", 			{ .i32 = 1 }};
+			struct dict_enumval_data 	t_2 = { "DO_NOT_WANT_TO_TALK_TO_YOU", 	{ .i32 = 2 }};
+			struct dict_avp_data 		data = { 
+					273, 					/* Code */
+					#if AC_DISCONNECT_CAUSE != 273
+					#error "AC_DISCONNECT_CAUSE definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Disconnect-Cause", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_0 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Origin-Host */
+		{
+			/*
+				The Origin-Host AVP (AVP Code 264) is of type DiameterIdentity, and
+				MUST be present in all Diameter messages.  This AVP identifies the
+				endpoint that originated the Diameter message.  Relay agents MUST NOT
+				modify this AVP.
+
+				The value of the Origin-Host AVP is guaranteed to be unique within a
+				single host.
+
+				Note that the Origin-Host AVP may resolve to more than one address as
+				the Diameter peer may support more than one address.
+
+				This AVP SHOULD be placed as close to the Diameter header as
+				possible.
+			*/
+			struct dict_avp_data data = { 
+					264, 					/* Code */
+					#if AC_ORIGIN_HOST != 264
+					#error "AC_ORIGIN_HOST definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Origin-Host", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , DiameterIdentity_type, NULL);
+		}
+		
+		/* Origin-Realm */
+		{
+			/*
+				The Origin-Realm AVP (AVP Code 296) is of type DiameterIdentity.
+				This AVP contains the Realm of the originator of any Diameter message
+				and MUST be present in all messages.
+
+				This AVP SHOULD be placed as close to the Diameter header as
+				possible.
+			*/
+			struct dict_avp_data data = { 
+					296, 					/* Code */
+					#if AC_ORIGIN_REALM != 296
+					#error "AC_ORIGIN_REALM definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Origin-Realm", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , DiameterIdentity_type, NULL);
+		}
+		
+		/* Destination-Host */
+		{
+			/*
+				The Destination-Host AVP (AVP Code 293) is of type DiameterIdentity.
+				This AVP MUST be present in all unsolicited agent initiated messages,
+				MAY be present in request messages, and MUST NOT be present in Answer
+				messages.
+
+				The absence of the Destination-Host AVP will cause a message to be
+				sent to any Diameter server supporting the application within the
+				realm specified in Destination-Realm AVP.
+
+				This AVP SHOULD be placed as close to the Diameter header as
+				possible.
+			*/
+			struct dict_avp_data data = { 
+					293, 					/* Code */
+					#if AC_DESTINATION_HOST != 293
+					#error "AC_DESTINATION_HOST definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Destination-Host", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , DiameterIdentity_type, NULL);
+		}
+		
+		/* Destination-Realm */
+		{
+			/*
+				The Destination-Realm AVP (AVP Code 283) is of type DiameterIdentity,
+				and contains the realm the message is to be routed to.  The
+				Destination-Realm AVP MUST NOT be present in Answer messages.
+				Diameter Clients insert the realm portion of the User-Name AVP.
+				Diameter servers initiating a request message use the value of the
+				Origin-Realm AVP from a previous message received from the intended
+				target host (unless it is known a priori).  When present, the
+				Destination-Realm AVP is used to perform message routing decisions.
+
+				Request messages whose ABNF does not list the Destination-Realm AVP
+				as a mandatory AVP are inherently non-routable messages.
+
+				This AVP SHOULD be placed as close to the Diameter header as
+				possible.
+			*/
+			struct dict_avp_data data = { 
+					283, 					/* Code */
+					#if AC_DESTINATION_REALM != 283
+					#error "AC_DESTINATION_REALM definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Destination-Realm", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , DiameterIdentity_type, NULL);
+		}
+		
+		/* Route-Record */
+		{
+			/*
+				The Route-Record AVP (AVP Code 282) is of type DiameterIdentity.  The
+				identity added in this AVP MUST be the same as the one received in
+				the Origin-Host of the Capabilities Exchange message.
+			*/
+			struct dict_avp_data data = { 
+					282, 					/* Code */
+					#if AC_ROUTE_RECORD != 282
+					#error "AC_ROUTE_RECORD definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Route-Record", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , DiameterIdentity_type, NULL);
+		}
+		
+		/* Proxy-Host */
+		{
+			/*
+				The Proxy-Host AVP (AVP Code 280) is of type DiameterIdentity.  This
+				AVP contains the identity of the host that added the Proxy-Info AVP.
+			*/
+			struct dict_avp_data adata = { 
+					280, 					/* Code */
+					#if AC_PROXY_HOST != 280
+					#error "AC_PROXY_HOST definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Proxy-Host", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &adata , DiameterIdentity_type, NULL);
+		}
+		
+		/* Proxy-State */
+		{
+			/*
+				The Proxy-State AVP (AVP Code 33) is of type OctetString, and
+				contains state local information, and MUST be treated as opaque data.
+			*/
+			struct dict_avp_data adata = { 
+					33, 					/* Code */
+					#if AC_PROXY_STATE != 33
+					#error "AC_PROXY_STATE definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Proxy-State", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &adata , NULL, NULL);
+		}
+			
+		/* Proxy-Info */
+		{
+			/*
+				The Proxy-Info AVP (AVP Code 284) is of type Grouped.  The Grouped
+				Data field has the following ABNF grammar:
+
+				 Proxy-Info ::= < AVP Header: 284 >
+                				{ Proxy-Host }
+                				{ Proxy-State }
+        				      * [ AVP ]
+			*/
+			struct dict_object * avp;
+			struct dict_avp_data data = { 
+					284, 					/* Code */
+					#if AC_PROXY_INFO != 284
+					#error "AC_PROXY_INFO definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Proxy-Info", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_GROUPED 			/* base type of data */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Proxy-Host", 			RULE_REQUIRED, -1, 1 }
+							,{  "Proxy-State",			RULE_REQUIRED, -1, 1 }
+						};
+			
+			CHECK_dict_new( DICT_AVP, &data , NULL, &avp);
+			PARSE_loc_rules( rules, avp );
+		}
+		
+		/* Auth-Application-Id */
+		{
+			/*
+				The Auth-Application-Id AVP (AVP Code 258) is of type Unsigned32 and
+				is used in order to advertise support of the Authentication and
+				Authorization portion of an application (see Section 2.4).  If
+				present in a message other than CER and CEA, the value of the Auth-
+				Application-Id AVP MUST match the Application Id present in the
+				Diameter message header.
+			*/
+			struct dict_avp_data data = { 
+					258, 					/* Code */
+					#if AC_AUTH_APPLICATION_ID != 258
+					#error "AC_AUTH_APPLICATION_ID definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Auth-Application-Id", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Acct-Application-Id */
+		{
+			/*
+				The Acct-Application-Id AVP (AVP Code 259) is of type Unsigned32 and
+				is used in order to advertise support of the Accounting portion of an
+				application (see Section 2.4).  If present in a message other than
+				CER and CEA, the value of the Acct-Application-Id AVP MUST match the
+				Application Id present in the Diameter message header.
+			*/
+			struct dict_avp_data data = { 
+					259, 					/* Code */
+					#if AC_ACCT_APPLICATION_ID != 259
+					#error "AC_ACCT_APPLICATION_ID definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Acct-Application-Id", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Inband-Security-Id */
+		{
+			/*
+				The Inband-Security-Id AVP (AVP Code 299) is of type Unsigned32 and
+				is used in order to advertise support of the Security portion of the
+				application.
+
+				Currently, the following values are supported, but there is ample
+				room to add new security Ids.
+
+
+				NO_INBAND_SECURITY 0
+
+				This peer does not support TLS.  This is the default value, if the
+				AVP is omitted.
+
+				TLS 1
+
+				This node supports TLS security, as defined by [RFC4346].
+			*/
+			
+			/* Although the RFC does not specify an "Enumerated" type here, we go forward and create one.
+			 * This is the reason for the "*" in the type name
+			 */
+			
+			struct dict_object 	* 	type;
+			struct dict_type_data	 	tdata = { AVP_TYPE_UNSIGNED32,	"Enumerated*(Inband-Security-Id)"	, NULL, NULL};
+			struct dict_enumval_data 	t_0 = { "NO_INBAND_SECURITY", 		{ .u32 = 0 }};
+			struct dict_enumval_data 	t_1 = { "TLS", 			{ .u32 = 1 }};
+			struct dict_avp_data 		data = { 
+					299, 					/* Code */
+					#if AC_INBAND_SECURITY_ID != 299
+					#error "AC_INBAND_SECURITY_ID definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Inband-Security-Id", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_0 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Vendor-Specific-Application-Id */
+		{
+			/*
+				The Vendor-Specific-Application-Id AVP (AVP Code 260) is of type
+				Grouped and is used to advertise support of a vendor-specific
+				Diameter Application.  Exactly one instance of either Auth-
+				Application-Id or Acct-Application-Id AVP MUST be present.  The
+				Application Id carried by either Auth-Application-Id or Acct-
+				Application-Id AVP MUST comply with vendor specific Application Id
+				assignment described in Sec 11.3.  It MUST also match the Application
+				Id present in the diameter header except when used in a CER or CEA
+				messages.
+
+				The Vendor-Id AVP is an informational AVP pertaining to the vendor
+				who may have authorship of the vendor-specific Diameter application.
+				It MUST NOT be used as a means of defining a completely separate
+				vendor-specific Application Id space.
+
+				This AVP MUST also be present as the first AVP in all experimental
+				commands defined in the vendor-specific application.
+
+				This AVP SHOULD be placed as close to the Diameter header as
+				possible.
+
+				AVP Format
+
+				<Vendor-Specific-Application-Id> ::= < AVP Header: 260 >
+                                				   { Vendor-Id }
+                                				   [ Auth-Application-Id ]
+                                				   [ Acct-Application-Id ]
+
+				A Vendor-Specific-Application-Id AVP MUST contain exactly one of
+				either Auth-Application-Id or Acct-Application-Id.  If a Vendor-
+				Specific-Application-Id is received without any of these two AVPs,
+				then the recipient SHOULD issue an answer with a Result-Code set to
+				DIAMETER_MISSING_AVP.  The answer SHOULD also include a Failed-AVP
+				which MUST contain an example of an Auth-Application-Id AVP and an
+				Acct-Application-Id AVP.
+
+				If a Vendor-Specific-Application-Id is received that contains both
+				Auth-Application-Id and Acct-Application-Id, then the recipient
+				SHOULD issue an answer with Result-Code set to
+				DIAMETER_AVP_OCCURS_TOO_MANY_TIMES.  The answer SHOULD also include a
+				Failed-AVP which MUST contain the received Auth-Application-Id AVP
+				and Acct-Application-Id AVP.
+			*/
+			struct dict_object 	* avp;
+			struct dict_avp_data	  data = { 
+					260, 					/* Code */
+					#if AC_VENDOR_SPECIFIC_APPLICATION_ID != 260
+					#error "AC_VENDOR_SPECIFIC_APPLICATION_ID definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Vendor-Specific-Application-Id", 	/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_GROUPED 			/* base type of data */
+					};
+					
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Vendor-Id", 			RULE_REQUIRED, -1, 1 }
+							,{  "Auth-Application-Id",		RULE_OPTIONAL, -1, 1 }
+							,{  "Acct-Application-Id",		RULE_OPTIONAL, -1, 1 }
+						};
+			
+			/* Create the grouped AVP */
+			CHECK_dict_new( DICT_AVP, &data , NULL, &avp);
+			PARSE_loc_rules( rules, avp );
+			
+		}
+		
+		/* Redirect-Host */
+		{
+			/*
+				One or more of instances of this AVP MUST be present if the answer
+				message's 'E' bit is set and the Result-Code AVP is set to
+				DIAMETER_REDIRECT_INDICATION.
+
+				Upon receiving the above, the receiving Diameter node SHOULD forward
+				the request directly to one of the hosts identified in these AVPs.
+				The server contained in the selected Redirect-Host AVP SHOULD be used
+				for all messages pertaining to this session.
+			*/
+			struct dict_avp_data data = { 
+					292, 					/* Code */
+					#if AC_REDIRECT_HOST != 292
+					#error "AC_REDIRECT_HOST definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Redirect-Host", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , DiameterURI_type, NULL);
+		}
+		
+		/* Redirect-Host-Usage */
+		{
+			/*
+				The Redirect-Host-Usage AVP (AVP Code 261) is of type Enumerated.
+				This AVP MAY be present in answer messages whose 'E' bit is set and
+				the Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION.
+
+				When present, this AVP dictates how the routing entry resulting from
+				the Redirect-Host is to be used.  The following values are supported:
+
+
+				DONT_CACHE 0
+
+				The host specified in the Redirect-Host AVP should not be cached.
+				This is the default value.
+
+
+				ALL_SESSION 1
+
+				All messages within the same session, as defined by the same value
+				of the Session-ID AVP MAY be sent to the host specified in the
+				Redirect-Host AVP.
+
+
+				ALL_REALM 2
+
+				All messages destined for the realm requested MAY be sent to the
+				host specified in the Redirect-Host AVP.
+
+
+				REALM_AND_APPLICATION 3
+
+				All messages for the application requested to the realm specified
+				MAY be sent to the host specified in the Redirect-Host AVP.
+
+				ALL_APPLICATION 4
+
+				All messages for the application requested MAY be sent to the host
+				specified in the Redirect-Host AVP.
+
+
+				ALL_HOST 5
+
+				All messages that would be sent to the host that generated the
+				Redirect-Host MAY be sent to the host specified in the Redirect-
+				Host AVP.
+
+
+				ALL_USER 6
+
+				All messages for the user requested MAY be sent to the host
+				specified in the Redirect-Host AVP.
+
+
+				When multiple cached routes are created by redirect indications and
+				they differ only in redirect usage and peers to forward requests to
+				(see Section 6.1.8), a precedence rule MUST be applied to the
+				redirect usage values of the cached routes during normal routing to
+				resolve contentions that may occur.  The precedence rule is the order
+				that dictate which redirect usage should be considered before any
+				other as they appear.  The order is as follows:
+
+
+				1.  ALL_SESSION
+
+				2.  ALL_USER
+
+				3.  REALM_AND_APPLICATION
+
+				4.  ALL_REALM
+
+				5.  ALL_APPLICATION
+
+				6.  ALL_HOST
+			*/
+			struct dict_object 	* 	type;
+			struct dict_type_data	 	tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Redirect-Host-Usage)"	, NULL, NULL};
+			struct dict_enumval_data 	t_0 = { "DONT_CACHE", 			{ .i32 = 0 }};
+			struct dict_enumval_data 	t_1 = { "ALL_SESSION", 			{ .i32 = 1 }};
+			struct dict_enumval_data 	t_2 = { "ALL_REALM", 			{ .i32 = 2 }};
+			struct dict_enumval_data 	t_3 = { "REALM_AND_APPLICATION", 	{ .i32 = 3 }};
+			struct dict_enumval_data 	t_4 = { "ALL_APPLICATION", 		{ .i32 = 4 }};
+			struct dict_enumval_data 	t_5 = { "ALL_HOST", 			{ .i32 = 5 }};
+			struct dict_enumval_data 	t_6 = { "ALL_USER", 			{ .i32 = 6 }};
+			struct dict_avp_data 		data = { 
+					261, 					/* Code */
+					#if AC_REDIRECT_HOST_USAGE != 261
+					#error "AC_REDIRECT_HOST_USAGE definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Redirect-Host-Usage", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_0 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_3 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_4 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_5 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_6 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Redirect-Max-Cache-Time */
+		{
+			/*
+				The Redirect-Max-Cache-Time AVP (AVP Code 262) is of type Unsigned32.
+				This AVP MUST be present in answer messages whose 'E' bit is set, the
+				Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION and the
+				Redirect-Host-Usage AVP set to a non-zero value.
+
+				This AVP contains the maximum number of seconds the peer and route
+				table entries, created as a result of the Redirect-Host, will be
+				cached.  Note that once a host created due to a redirect indication
+				is no longer reachable, any associated peer and routing table entries
+				MUST be deleted.
+			*/
+			struct dict_avp_data data = { 
+					262, 					/* Code */
+					#if AC_REDIRECT_MAX_CACHE_TIME != 262
+					#error "AC_REDIRECT_MAX_CACHE_TIME definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Redirect-Max-Cache-Time", 		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Result-Code */
+		{
+			/*
+				The Result-Code AVP (AVP Code 268) is of type Unsigned32 and
+				indicates whether a particular request was completed successfully or
+				whether an error occurred.  All Diameter answer messages defined in
+				IETF applications MUST include one Result-Code AVP.  A non-successful
+				Result-Code AVP (one containing a non 2xxx value other than
+				DIAMETER_REDIRECT_INDICATION) MUST include the Error-Reporting-Host
+				AVP if the host setting the Result-Code AVP is different from the
+				identity encoded in the Origin-Host AVP.
+
+				The Result-Code data field contains an IANA-managed 32-bit address
+				space representing errors (see Section 11.4).  Diameter provides the
+				following classes of errors, all identified by the thousands digit in
+				the decimal notation:
+
+				o  1xxx (Informational)
+
+				o  2xxx (Success)
+
+				o  3xxx (Protocol Errors)
+
+				o  4xxx (Transient Failures)
+
+				o  5xxx (Permanent Failure)
+
+				A non-recognized class (one whose first digit is not defined in this
+				section) MUST be handled as a permanent failure.
+			*/
+			
+			/* Although the RFC does not specify an "Enumerated" type here, we go forward and create one.
+			 * This is the reason for the "*" in the type name
+			 */
+			struct dict_object * 	type;
+			struct dict_type_data 	tdata = { AVP_TYPE_UNSIGNED32,	"Enumerated*(Result-Code)"	, NULL, NULL};
+			struct dict_avp_data 	data = { 
+					268, 					/* Code */
+					#if AC_RESULT_CODE != 268
+					#error "AC_RESULT_CODE definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Result-Code", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+			
+			/* Informational */
+			{
+				/* 1001 */
+				{
+					/*
+						This informational error is returned by a Diameter server to
+						inform the access device that the authentication mechanism being
+						used requires multiple round trips, and a subsequent request needs
+						to be issued in order for access to be granted.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_MULTI_ROUND_AUTH", 	{ .u32 = 1001 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+			}
+			/* Success */
+			{
+				/* 2001 */
+				{
+					/*
+						The Request was successfully completed.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_SUCCESS", 		{ .u32 = 2001 }};
+					#if ER_DIAMETER_SUCCESS != 2001
+					#error "ER_DIAMETER_SUCCESS definition mismatch"
+					#endif
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 2002 */
+				{
+					/*
+						When returned, the request was successfully completed, but
+						additional processing is required by the application in order to
+						provide service to the user.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_LIMITED_SUCCESS", 	{ .u32 = 2002 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+			}
+			/* Protocol Errors */
+			{
+				/* 3002 */
+				{
+					/*
+						This error is given when Diameter can not deliver the message to
+						the destination, either because no host within the realm
+						supporting the required application was available to process the
+						request, or because Destination-Host AVP was given without the
+						associated Destination-Realm AVP.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_UNABLE_TO_DELIVER", 	{ .u32 = 3002 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 3003 */
+				{
+					/*
+						The intended realm of the request is not recognized.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_REALM_NOT_SERVED", 	{ .u32 = 3003 }};
+					#if ER_DIAMETER_REALM_NOT_SERVED != 3003
+					#error "ER_DIAMETER_REALM_NOT_SERVED definition mismatch"
+					#endif
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 3004 */
+				{
+					/*
+						When returned, a Diameter node SHOULD attempt to send the message
+						to an alternate peer.  This error MUST only be used when a
+						specific server is requested, and it cannot provide the requested
+						service.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_TOO_BUSY", 		{ .u32 = 3004 }};
+					#if ER_DIAMETER_TOO_BUSY != 3004
+					#error "ER_DIAMETER_TOO_BUSY definition mismatch"
+					#endif
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 3005 */
+				{
+					/*
+						An agent detected a loop while trying to get the message to the
+						intended recipient.  The message MAY be sent to an alternate peer,
+						if one is available, but the peer reporting the error has
+						identified a configuration problem.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_LOOP_DETECTED", 	{ .u32 = 3005 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 3006 */
+				{
+					/*
+						A redirect agent has determined that the request could not be
+						satisfied locally and the initiator of the request should direct
+						the request directly to the server, whose contact information has
+						been added to the response.  When set, the Redirect-Host AVP MUST
+						be present.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_REDIRECT_INDICATION", 	{ .u32 = 3006 }};
+					#if ER_DIAMETER_REDIRECT_INDICATION != 3006
+					#error "ER_DIAMETER_REDIRECT_INDICATION definition mismatch"
+					#endif
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 3007 */
+				{
+					/*
+						A request was sent for an application that is not supported.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_APPLICATION_UNSUPPORTED",	{ .u32 = 3007 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 3011 */
+				{
+					/*
+						This error is returned when a reserved bit in the Diameter header
+						is set to one (1) or the bits in the Diameter header defined in
+						Sec 3 are set incorrectly.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_INVALID_BIT_IN_HEADER",	{ .u32 = 3011 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 3012 */
+				{
+					/*
+						This error is returned when a request is received with an invalid
+						message length.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_INVALID_MESSAGE_LENGTH",	{ .u32 = 3012 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+			}
+			/* Transient Failures */
+			{
+				/* 4001 */
+				{
+					/*
+						The authentication process for the user failed, most likely due to
+						an invalid password used by the user.  Further attempts MUST only
+						be tried after prompting the user for a new password.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_AUTHENTICATION_REJECTED", 	{ .u32 = 4001 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 4002 */
+				{
+					/*
+						A Diameter node received the accounting request but was unable to
+						commit it to stable storage due to a temporary lack of space.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_OUT_OF_SPACE", 		{ .u32 = 4002 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 4003 */
+				{
+					/*
+						The peer has determined that it has lost the election process and
+						has therefore disconnected the transport connection.
+					*/
+					struct dict_enumval_data 	error_code = { "ELECTION_LOST", 			{ .u32 = 4003 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+			}
+			/* Permanent Failures */
+			{
+				/* 5001 */
+				{
+					/*
+						The peer received a message that contained an AVP that is not
+						recognized or supported and was marked with the Mandatory bit.  A
+						Diameter message with this error MUST contain one or more Failed-
+						AVP AVP containing the AVPs that caused the failure.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_AVP_UNSUPPORTED", 	{ .u32 = 5001 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5002 */
+				{
+					/*
+						The request contained an unknown Session-Id.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_UNKNOWN_SESSION_ID", 	{ .u32 = 5002 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5003 */
+				{
+					/*
+						A request was received for which the user could not be authorized.
+						This error could occur if the service requested is not permitted
+						to the user.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_AUTHORIZATION_REJECTED",{ .u32 = 5003 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5004 */
+				{
+					/*
+						The request contained an AVP with an invalid value in its data
+						portion.  A Diameter message indicating this error MUST include
+						the offending AVPs within a Failed-AVP AVP.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_INVALID_AVP_VALUE",	{ .u32 = 5004 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5005 */
+				{
+					/*
+						The request did not contain an AVP that is required by the Command
+						Code definition.  If this value is sent in the Result-Code AVP, a
+						Failed-AVP AVP SHOULD be included in the message.  The Failed-AVP
+						AVP MUST contain an example of the missing AVP complete with the
+						Vendor-Id if applicable.  The value field of the missing AVP
+						should be of correct minimum length and contain zeroes.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_MISSING_AVP",		{ .u32 = 5005 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5006 */
+				{
+					/*
+						A request was received that cannot be authorized because the user
+						has already expended allowed resources.  An example of this error
+						condition is a user that is restricted to one dial-up PPP port,
+						attempts to establish a second PPP connection.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_RESOURCES_EXCEEDED",	{ .u32 = 5006 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5007 */
+				{
+					/*
+						The Home Diameter server has detected AVPs in the request that
+						contradicted each other, and is not willing to provide service to
+						the user.  The Failed-AVP AVPs MUST be present which contains the
+						AVPs that contradicted each other.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_CONTRADICTING_AVPS",	{ .u32 = 5007 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5008 */
+				{
+					/*
+						A message was received with an AVP that MUST NOT be present.  The
+						Failed-AVP AVP MUST be included and contain a copy of the
+						offending AVP.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_AVP_NOT_ALLOWED",	{ .u32 = 5008 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5009 */
+				{
+					/*
+						A message was received that included an AVP that appeared more
+						often than permitted in the message definition.  The Failed-AVP
+						AVP MUST be included and contain a copy of the first instance of
+						the offending AVP that exceeded the maximum number of occurrences
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES",{ .u32 = 5009 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5010 */
+				{
+					/*
+						This error is returned by a Diameter node that is not acting as a
+						relay when it receives a CER which advertises a set of
+						applications that it does not support.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_NO_COMMON_APPLICATION",{ .u32 = 5010 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5011 */
+				{
+					/*
+						This error is returned when a request was received, whose version
+						number is unsupported.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_UNSUPPORTED_VERSION",	{ .u32 = 5011 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5012 */
+				{
+					/*
+						This error is returned when a request is rejected for unspecified
+						reasons.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_UNABLE_TO_COMPLY",	{ .u32 = 5012 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5014 */
+				{
+					/*
+						The request contained an AVP with an invalid length.  A Diameter
+						message indicating this error MUST include the offending AVPs
+						within a Failed-AVP AVP.  In cases where the erroneous avp length
+						value exceeds the message length or is less than the minimum AVP
+						header length, it is sufficient to include the offending AVP
+						header and a zero filled payload of the minimum required length
+						for the payloads data type.  If the AVP is a grouped AVP, the
+						grouped AVP header with an empty payload would be sufficient to
+						indicate the offending AVP.  In the case where the offending AVP
+						header cannot be fully decoded when avp length is less than the
+						minimum AVP header length, it is sufficient to include an
+						offending AVP header that is formulated by padding the incomplete
+						AVP header with zero up to the minimum AVP header length.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_INVALID_AVP_LENGTH",	{ .u32 = 5014 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5017 */
+				{
+					/*
+						This error is returned when a CER message is received, and there
+						are no common security mechanisms supported between the peers.  A
+						Capabilities-Exchange-Answer (CEA) MUST be returned with the
+						Result-Code AVP set to DIAMETER_NO_COMMON_SECURITY.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_NO_COMMON_SECURITY",	{ .u32 = 5017 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5018 */
+				{
+					/*
+						A CER was received from an unknown peer.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_UNKNOWN_PEER",		{ .u32 = 5018 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5019 */
+				{
+					/*
+						The Request contained a Command-Code that the receiver did not
+						recognize or support.  This MUST be used when a Diameter node
+						receives an experimental command that it does not understand.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_COMMAND_UNSUPPORTED",	{ .u32 = 5019 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5020 */
+				{
+					/*
+						A request was received whose bits in the Diameter header were
+						either set to an invalid combination, or to a value that is
+						inconsistent with the command code's definition.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_INVALID_HDR_BITS",	{ .u32 = 5020 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+				/* 5021 */
+				{
+					/*
+						A request was received that included an AVP whose flag bits are
+						set to an unrecognized value, or that is inconsistent with the
+						AVP's definition.
+					*/
+					struct dict_enumval_data 	error_code = { "DIAMETER_INVALID_AVP_BITS",	{ .u32 = 5021 }};
+					CHECK_dict_new( DICT_ENUMVAL, &error_code , type, NULL);
+				}
+			}
+		}
+		
+		/* Error-Message */
+		{
+			/*
+				The Error-Message AVP (AVP Code 281) is of type UTF8String.  It MAY
+				accompany a Result-Code AVP as a human readable error message.  The
+				Error-Message AVP is not intended to be useful in real-time, and
+				SHOULD NOT be expected to be parsed by network entities.
+			*/
+			struct dict_avp_data data = { 
+					281, 					/* Code */
+					#if AC_ERROR_MESSAGE != 281
+					#error "AC_ERROR_MESSAGE definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Error-Message", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					0,					/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
+		}
+		
+		/* Error-Reporting-Host */
+		{
+			/*
+				The Error-Reporting-Host AVP (AVP Code 294) is of type
+				DiameterIdentity.  This AVP contains the identity of the Diameter
+				host that sent the Result-Code AVP to a value other than 2001
+				(Success), only if the host setting the Result-Code is different from
+				the one encoded in the Origin-Host AVP.  This AVP is intended to be
+				used for troubleshooting purposes, and MUST be set when the Result-
+				Code AVP indicates a failure.
+			*/
+			struct dict_avp_data data = { 
+					294, 					/* Code */
+					#if AC_ERROR_REPORTING_HOST != 294
+					#error "AC_ERROR_REPORTING_HOST definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Error-Reporting-Host", 		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					0,					/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , DiameterIdentity_type, NULL);
+		}
+		
+		/* Failed-AVP */
+		{
+			/*
+				The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides
+				debugging information in cases where a request is rejected or not
+				fully processed due to erroneous information in a specific AVP.  The
+				value of the Result-Code AVP will provide information on the reason
+				for the Failed-AVP AVP.  A Diameter message SHOULD contain only one
+				Failed-AVP that corresponds to the error indicated by the Result-Code
+				AVP.  For practical purposes, this Failed-AVP would typically refer
+				to the first AVP processing error that a Diameter node encounters.
+
+				The possible reasons for this AVP are the presence of an improperly
+				constructed AVP, an unsupported or unrecognized AVP, an invalid AVP
+				value, the omission of a required AVP, the presence of an explicitly
+				excluded AVP (see tables in Section 10), or the presence of two or
+				more occurrences of an AVP which is restricted to 0, 1, or 0-1
+				occurrences.
+
+				A Diameter message SHOULD contain one Failed-AVP AVP, containing the
+				entire AVP that could not be processed successfully.  If the failure
+				reason is omission of a required AVP, an AVP with the missing AVP
+				code, the missing vendor id, and a zero filled payload of the minimum
+				required length for the omitted AVP will be added.  If the failure
+				reason is an invalid AVP length where the reported length is less
+				than the minimum AVP header length or greater than the reported
+				message length, a copy of the offending AVP header and a zero filled
+				payload of the minimum required length SHOULD be added.
+
+				In the case where the offending AVP is embedded within a grouped AVP,
+				the Failed-AVP MAY contain the grouped AVP which in turn contains the
+				single offending AVP.  The same method MAY be employed if the grouped
+				AVP itself is embedded in yet another grouped AVP and so on.  In this
+				case, the Failed-AVP MAY contain the grouped AVP heirarchy up to the
+				single offending AVP.  This enables the recipient to detect the
+				location of the offending AVP when embedded in a group.
+
+				AVP Format
+
+				 <Failed-AVP> ::= < AVP Header: 279 >
+        				       1* {AVP}
+			*/
+			struct dict_avp_data data = { 
+					279, 					/* Code */
+					#if AC_FAILED_AVP != 279
+					#error "AC_FAILED_AVP definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Failed-AVP", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_GROUPED 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Experimental-Result */
+		{
+			/*
+				The Experimental-Result AVP (AVP Code 297) is of type Grouped, and
+				indicates whether a particular vendor-specific request was completed
+				successfully or whether an error occurred.  Its Data field has the
+				following ABNF grammar:
+
+				AVP Format
+
+				 Experimental-Result ::= < AVP Header: 297 >
+                        				 { Vendor-Id }
+                        				 { Experimental-Result-Code }
+
+				The Vendor-Id AVP (see Section 5.3.3) in this grouped AVP identifies
+				the vendor responsible for the assignment of the result code which
+				follows.  All Diameter answer messages defined in vendor-specific
+				applications MUST include either one Result-Code AVP or one
+				Experimental-Result AVP.
+			*/
+			struct dict_avp_data data = { 
+					297, 					/* Code */
+					0, 					/* Vendor */
+					"Experimental-Result", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_GROUPED 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Experimental-Result-Code */
+		{
+			/*
+				The Experimental-Result-Code AVP (AVP Code 298) is of type Unsigned32
+				and contains a vendor-assigned value representing the result of
+				processing the request.
+
+				It is recommended that vendor-specific result codes follow the same
+				conventions given for the Result-Code AVP regarding the different
+				types of result codes and the handling of errors (for non 2xxx
+				values).
+			*/
+			/* Although the RFC does not specify an "Enumerated" type here, we go forward and create one.
+			 * This is the reason for the "*" in the type name. Vendors will have to define their values.
+			 */
+			struct dict_object * 	type;
+			struct dict_type_data 	tdata = { AVP_TYPE_UNSIGNED32,	"Enumerated*(Experimental-Result-Code)"	, NULL, NULL};
+			struct dict_avp_data 	data = { 
+					298, 					/* Code */
+					0, 					/* Vendor */
+					"Experimental-Result-Code", 		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Auth-Request-Type */
+		{
+			/*
+				The Auth-Request-Type AVP (AVP Code 274) is of type Enumerated and is
+				included in application-specific auth requests to inform the peers
+				whether a user is to be authenticated only, authorized only or both.
+				Note any value other than both MAY cause RADIUS interoperability
+				issues.  The following values are defined:
+
+
+				AUTHENTICATE_ONLY 1
+
+				The request being sent is for authentication only, and MUST
+				contain the relevant application specific authentication AVPs that
+				are needed by the Diameter server to authenticate the user.
+
+
+				AUTHORIZE_ONLY 2
+
+				The request being sent is for authorization only, and MUST contain
+				the application specific authorization AVPs that are necessary to
+				identify the service being requested/offered.
+
+
+				AUTHORIZE_AUTHENTICATE 3
+
+				The request contains a request for both authentication and
+				authorization.  The request MUST include both the relevant
+				application specific authentication information, and authorization
+				information necessary to identify the service being requested/
+				offered.
+			*/
+			struct dict_object 	* 	type;
+			struct dict_type_data 		tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Auth-Request-Type)"	, NULL, NULL};
+			struct dict_enumval_data 	t_1 = { "AUTHENTICATE_ONLY", 		{ .i32 = 1 }};
+			struct dict_enumval_data 	t_2 = { "AUTHORIZE_ONLY", 		{ .i32 = 2 }};
+			struct dict_enumval_data 	t_3 = { "AUTHORIZE_AUTHENTICATE", 	{ .i32 = 3 }};
+			struct dict_avp_data 	data = { 
+					274, 					/* Code */
+					0, 					/* Vendor */
+					"Auth-Request-Type", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_3 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Session-Id */
+		{
+			/*
+				The Session-Id AVP (AVP Code 263) is of type UTF8String and is used
+				to identify a specific session (see Section 8).  All messages
+				pertaining to a specific session MUST include only one Session-Id AVP
+				and the same value MUST be used throughout the life of a session.
+				When present, the Session-Id SHOULD appear immediately following the
+				Diameter Header (see Section 3).
+
+				The Session-Id MUST be globally and eternally unique, as it is meant
+				to uniquely identify a user session without reference to any other
+				information, and may be needed to correlate historical authentication
+				information with accounting information.  The Session-Id includes a
+				mandatory portion and an implementation-defined portion; a
+				recommended format for the implementation-defined portion is outlined
+				below.
+				
+				(skipped, see RFC for detail)
+			*/
+			struct dict_avp_data data = { 
+					263, 					/* Code */
+					#if AC_SESSION_ID != 263
+					#error "AC_SESSION_ID definition mismatch"
+					#endif
+					0, 					/* Vendor */
+					"Session-Id", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
+		}
+		
+		/* Authorization-Lifetime */
+		{
+			/*
+				The Authorization-Lifetime AVP (AVP Code 291) is of type Unsigned32
+				and contains the maximum number of seconds of service to be provided
+				to the user before the user is to be re-authenticated and/or re-
+				authorized.  Great care should be taken when the Authorization-
+				Lifetime value is determined, since a low, non-zero, value could
+				create significant Diameter traffic, which could congest both the
+				network and the agents.
+
+				A value of zero (0) means that immediate re-auth is necessary by the
+				access device.  This is typically used in cases where multiple
+				authentication methods are used, and a successful auth response with
+				this AVP set to zero is used to signal that the next authentication
+				method is to be immediately initiated.  The absence of this AVP, or a
+				value of all ones (meaning all bits in the 32 bit field are set to
+				one) means no re-auth is expected.
+
+				If both this AVP and the Session-Timeout AVP are present in a
+				message, the value of the latter MUST NOT be smaller than the
+				Authorization-Lifetime AVP.
+
+				An Authorization-Lifetime AVP MAY be present in re-authorization
+				messages, and contains the number of seconds the user is authorized
+				to receive service from the time the re-auth answer message is
+				received by the access device.
+
+				This AVP MAY be provided by the client as a hint of the maximum
+				lifetime that it is willing to accept.  However, the server MAY
+				return a value that is equal to, or smaller, than the one provided by
+				the client.
+			*/
+			struct dict_avp_data data = { 
+					291, 					/* Code */
+					0, 					/* Vendor */
+					"Authorization-Lifetime", 		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Auth-Grace-Period */
+		{
+			/*
+				The Auth-Grace-Period AVP (AVP Code 276) is of type Unsigned32 and
+				contains the number of seconds the Diameter server will wait
+				following the expiration of the Authorization-Lifetime AVP before
+				cleaning up resources for the session.
+			*/
+			struct dict_avp_data data = { 
+					276, 					/* Code */
+					0, 					/* Vendor */
+					"Auth-Grace-Period", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Auth-Session-State */
+		{
+			/*
+				The Auth-Session-State AVP (AVP Code 277) is of type Enumerated and
+				specifies whether state is maintained for a particular session.  The
+				client MAY include this AVP in requests as a hint to the server, but
+				the value in the server's answer message is binding.  The following
+				values are supported:
+
+
+				STATE_MAINTAINED 0
+
+				This value is used to specify that session state is being
+				maintained, and the access device MUST issue a session termination
+				message when service to the user is terminated.  This is the
+				default value.
+
+
+				NO_STATE_MAINTAINED 1
+
+				This value is used to specify that no session termination messages
+				will be sent by the access device upon expiration of the
+				Authorization-Lifetime.
+			*/
+			struct dict_object 	* 	type;
+			struct dict_type_data	 	tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Auth-Session-State)"	, NULL, NULL};
+			struct dict_enumval_data 	t_0 = { "STATE_MAINTAINED", 		{ .i32 = 0 }};
+			struct dict_enumval_data 	t_1 = { "NO_STATE_MAINTAINED", 		{ .i32 = 1 }};
+			struct dict_avp_data	 	data = { 
+					277, 					/* Code */
+					0, 					/* Vendor */
+					"Auth-Session-State", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_0 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Re-Auth-Request-Type */
+		{
+			/*
+				The Re-Auth-Request-Type AVP (AVP Code 285) is of type Enumerated and
+				is included in application-specific auth answers to inform the client
+				of the action expected upon expiration of the Authorization-Lifetime.
+				If the answer message contains an Authorization-Lifetime AVP with a
+				positive value, the Re-Auth-Request-Type AVP MUST be present in an
+				answer message.  The following values are defined:
+
+
+				AUTHORIZE_ONLY 0
+
+				An authorization only re-auth is expected upon expiration of the
+				Authorization-Lifetime.  This is the default value if the AVP is
+				not present in answer messages that include the Authorization-
+				Lifetime.
+
+
+				AUTHORIZE_AUTHENTICATE 1
+
+				An authentication and authorization re-auth is expected upon
+				expiration of the Authorization-Lifetime.
+			*/
+			struct dict_object 	* 	type;
+			struct dict_type_data	 	tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Re-Auth-Request-Type)"	, NULL, NULL};
+			struct dict_enumval_data 	t_0 = { "AUTHORIZE_ONLY", 		{ .i32 = 0 }};
+			struct dict_enumval_data 	t_1 = { "AUTHORIZE_AUTHENTICATE",	{ .i32 = 1 }};
+			struct dict_avp_data	 	data = { 
+					285, 					/* Code */
+					0, 					/* Vendor */
+					"Re-Auth-Request-Type",			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_0 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Session-Timeout */
+		{
+			/*
+				The Session-Timeout AVP (AVP Code 27) [RFC2865] is of type Unsigned32
+				and contains the maximum number of seconds of service to be provided
+				to the user before termination of the session.  When both the
+				Session-Timeout and the Authorization-Lifetime AVPs are present in an
+				answer message, the former MUST be equal to or greater than the value
+				of the latter.
+
+				A session that terminates on an access device due to the expiration
+				of the Session-Timeout MUST cause an STR to be issued, unless both
+				the access device and the home server had previously agreed that no
+				session termination messages would be sent (see Section 8.11).
+
+				A Session-Timeout AVP MAY be present in a re-authorization answer
+				message, and contains the remaining number of seconds from the
+				beginning of the re-auth.
+
+				A value of zero, or the absence of this AVP, means that this session
+				has an unlimited number of seconds before termination.
+
+				This AVP MAY be provided by the client as a hint of the maximum
+				timeout that it is willing to accept.  However, the server MAY return
+				a value that is equal to, or smaller, than the one provided by the
+				client.
+			*/
+			struct dict_avp_data data = { 
+					27, 					/* Code */
+					0, 					/* Vendor */
+					"Session-Timeout", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* User-Name */
+		{
+			/*
+				The User-Name AVP (AVP Code 1) [RFC2865] is of type UTF8String, which
+				contains the User-Name, in a format consistent with the NAI
+				specification [RFC4282].
+			*/
+			struct dict_avp_data data = { 
+					1, 					/* Code */
+					0, 					/* Vendor */
+					"User-Name", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
+		}
+		
+		/* Termination-Cause */
+		{
+			/*
+				The Termination-Cause AVP (AVP Code 295) is of type Enumerated, and
+				is used to indicate the reason why a session was terminated on the
+				access device.  The following values are defined:
+
+
+				DIAMETER_LOGOUT 1
+
+				The user initiated a disconnect
+
+
+				DIAMETER_SERVICE_NOT_PROVIDED 2
+
+				This value is used when the user disconnected prior to the receipt
+				of the authorization answer message.
+
+
+				DIAMETER_BAD_ANSWER 3
+
+				This value indicates that the authorization answer received by the
+				access device was not processed successfully.
+
+
+				DIAMETER_ADMINISTRATIVE 4
+
+				The user was not granted access, or was disconnected, due to
+				administrative reasons, such as the receipt of a Abort-Session-
+				Request message.
+
+
+				DIAMETER_LINK_BROKEN 5
+
+				The communication to the user was abruptly disconnected.
+
+
+				DIAMETER_AUTH_EXPIRED 6
+
+				The user's access was terminated since its authorized session time
+				has expired.
+
+
+				DIAMETER_USER_MOVED 7
+
+				The user is receiving services from another access device.
+
+
+				DIAMETER_SESSION_TIMEOUT 8
+
+				The user's session has timed out, and service has been terminated.
+			*/
+			struct dict_object 	* 	type;
+			struct dict_type_data	 	tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Termination-Cause)"	, NULL, NULL};
+			struct dict_enumval_data 	t_1 = { "DIAMETER_LOGOUT",			{ .i32 = 1 }};
+			struct dict_enumval_data 	t_2 = { "DIAMETER_SERVICE_NOT_PROVIDED", 	{ .i32 = 2 }};
+			struct dict_enumval_data 	t_3 = { "DIAMETER_BAD_ANSWER",			{ .i32 = 3 }};
+			struct dict_enumval_data 	t_4 = { "DIAMETER_ADMINISTRATIVE", 		{ .i32 = 4 }};
+			struct dict_enumval_data 	t_5 = { "DIAMETER_LINK_BROKEN",			{ .i32 = 5 }};
+			struct dict_enumval_data 	t_6 = { "DIAMETER_AUTH_EXPIRED", 		{ .i32 = 6 }};
+			struct dict_enumval_data 	t_7 = { "DIAMETER_USER_MOVED",			{ .i32 = 7 }};
+			struct dict_enumval_data 	t_8 = { "DIAMETER_SESSION_TIMEOUT", 		{ .i32 = 8 }};
+			struct dict_avp_data 	data = { 
+					295, 					/* Code */
+					0, 					/* Vendor */
+					"Termination-Cause",			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_3 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_4 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_5 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_6 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_7 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_8 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Origin-State-Id */
+		{
+			/*
+				The Origin-State-Id AVP (AVP Code 278), of type Unsigned32, is a
+				monotonically increasing value that is advanced whenever a Diameter
+				entity restarts with loss of previous state, for example upon reboot.
+				Origin-State-Id MAY be included in any Diameter message, including
+				CER.
+
+				A Diameter entity issuing this AVP MUST create a higher value for
+				this AVP each time its state is reset.  A Diameter entity MAY set
+				Origin-State-Id to the time of startup, or it MAY use an incrementing
+				counter retained in non-volatile memory across restarts.
+
+				The Origin-State-Id, if present, MUST reflect the state of the entity
+				indicated by Origin-Host.  If a proxy modifies Origin-Host, it MUST
+				either remove Origin-State-Id or modify it appropriately as well.
+				Typically, Origin-State-Id is used by an access device that always
+				starts up with no active sessions; that is, any session active prior
+				to restart will have been lost.  By including Origin-State-Id in a
+				message, it allows other Diameter entities to infer that sessions
+				associated with a lower Origin-State-Id are no longer active.  If an
+				access device does not intend for such inferences to be made, it MUST
+				either not include Origin-State-Id in any message, or set its value
+				to 0.
+			*/
+			struct dict_avp_data data = { 
+					278, 					/* Code */
+					0, 					/* Vendor */
+					"Origin-State-Id", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Session-Binding */
+		{
+			/*
+				The Session-Binding AVP (AVP Code 270) is of type Unsigned32, and MAY
+				be present in application-specific authorization answer messages.  If
+				present, this AVP MAY inform the Diameter client that all future
+				application-specific re-auth messages for this session MUST be sent
+				to the same authorization server.  This AVP MAY also specify that a
+				Session-Termination-Request message for this session MUST be sent to
+				the same authorizing server.
+
+				This field is a bit mask, and the following bits have been defined:
+
+
+				RE_AUTH 1
+
+				When set, future re-auth messages for this session MUST NOT
+				include the Destination-Host AVP.  When cleared, the default
+				value, the Destination-Host AVP MUST be present in all re-auth
+				messages for this session.
+
+
+				STR 2
+
+				When set, the STR message for this session MUST NOT include the
+				Destination-Host AVP.  When cleared, the default value, the
+				Destination-Host AVP MUST be present in the STR message for this
+				session.
+
+
+				ACCOUNTING 4
+
+				When set, all accounting messages for this session MUST NOT
+				include the Destination-Host AVP.  When cleared, the default
+				value, the Destination-Host AVP, if known, MUST be present in all
+				accounting messages for this session.
+			*/
+			
+			/* Although the RFC does not specify an "Enumerated" type here, we go forward and create one.
+			 * This is the reason for the "*" in the type name
+			 * The actual values of the AVP will not always be defined here, but at least it can be used in some cases.
+			 *  ... maybe the code will be changed later to support bitfields AVP ...
+			 */
+			
+			struct dict_object 	* 	type;
+			struct dict_type_data	 	tdata = { AVP_TYPE_UNSIGNED32,	"Enumerated*(Session-Binding)"	, NULL, NULL};
+			struct dict_enumval_data 	t_1 = { "RE_AUTH", 		{ .u32 = 1 }};
+			struct dict_enumval_data 	t_2 = { "STR", 			{ .u32 = 2 }};
+			struct dict_enumval_data 	t_4 = { "ACCOUNTING", 		{ .u32 = 4 }};
+			struct dict_avp_data 	data = { 
+					270, 					/* Code */
+					0, 					/* Vendor */
+					"Session-Binding", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_4 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Session-Server-Failover */
+		{
+			/*
+				The Session-Server-Failover AVP (AVP Code 271) is of type Enumerated,
+				and MAY be present in application-specific authorization answer
+				messages that either do not include the Session-Binding AVP or
+				include the Session-Binding AVP with any of the bits set to a zero
+				value.  If present, this AVP MAY inform the Diameter client that if a
+				re-auth or STR message fails due to a delivery problem, the Diameter
+				client SHOULD issue a subsequent message without the Destination-Host
+				AVP.  When absent, the default value is REFUSE_SERVICE.
+
+				The following values are supported:
+
+
+				REFUSE_SERVICE 0
+
+				If either the re-auth or the STR message delivery fails, terminate
+				service with the user, and do not attempt any subsequent attempts.
+
+
+				TRY_AGAIN 1
+
+				If either the re-auth or the STR message delivery fails, resend
+				the failed message without the Destination-Host AVP present.
+
+
+				ALLOW_SERVICE 2
+
+				If re-auth message delivery fails, assume that re-authorization
+				succeeded.  If STR message delivery fails, terminate the session.
+
+
+				TRY_AGAIN_ALLOW_SERVICE 3
+
+				If either the re-auth or the STR message delivery fails, resend
+				the failed message without the Destination-Host AVP present.  If
+				the second delivery fails for re-auth, assume re-authorization
+				succeeded.  If the second delivery fails for STR, terminate the
+				session.
+			*/
+			struct dict_object  	* 	type;
+			struct dict_type_data	 	tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Session-Server-Failover)"	, NULL, NULL};
+			struct dict_enumval_data 	t_0 = { "REFUSE_SERVICE", 		{ .i32 = 0 }};
+			struct dict_enumval_data 	t_1 = { "TRY_AGAIN",			{ .i32 = 1 }};
+			struct dict_enumval_data 	t_2 = { "ALLOW_SERVICE", 		{ .i32 = 2 }};
+			struct dict_enumval_data 	t_3 = { "TRY_AGAIN_ALLOW_SERVICE",	{ .i32 = 3 }};
+			struct dict_avp_data	 	data = { 
+					271, 					/* Code */
+					0, 					/* Vendor */
+					"Session-Server-Failover",		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_0 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_3 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Multi-Round-Time-Out */
+		{
+			/*
+				The Multi-Round-Time-Out AVP (AVP Code 272) is of type Unsigned32,
+				and SHOULD be present in application-specific authorization answer
+				messages whose Result-Code AVP is set to DIAMETER_MULTI_ROUND_AUTH.
+				This AVP contains the maximum number of seconds that the access
+				device MUST provide the user in responding to an authentication
+				request.
+			*/
+			struct dict_avp_data data = { 
+					272, 					/* Code */
+					0, 					/* Vendor */
+					"Multi-Round-Time-Out", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Class */
+		{
+			/*
+				The Class AVP (AVP Code 25) is of type OctetString and is used to by
+				Diameter servers to return state information to the access device.
+				When one or more Class AVPs are present in application-specific
+				authorization answer messages, they MUST be present in subsequent re-
+				authorization, session termination and accounting messages.  Class
+				AVPs found in a re-authorization answer message override the ones
+				found in any previous authorization answer message.  Diameter server
+				implementations SHOULD NOT return Class AVPs that require more than
+				4096 bytes of storage on the Diameter client.  A Diameter client that
+				receives Class AVPs whose size exceeds local available storage MUST
+				terminate the session.
+			*/
+			struct dict_avp_data data = { 
+					25, 					/* Code */
+					0, 					/* Vendor */
+					"Class", 				/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Event-Timestamp */
+		{
+			/*
+				The Event-Timestamp (AVP Code 55) is of type Time, and MAY be
+				included in an Accounting-Request and Accounting-Answer messages to
+				record the time that the reported event occurred, in seconds since
+				January 1, 1900 00:00 UTC.
+			*/
+			struct dict_avp_data data = { 
+					55, 					/* Code */
+					0, 					/* Vendor */
+					"Event-Timestamp", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , Time_type, NULL);
+		}
+
+				
+		/* Accounting-Record-Type */
+		{
+			/*
+				The Accounting-Record-Type AVP (AVP Code 480) is of type Enumerated
+				and contains the type of accounting record being sent.  The following
+				values are currently defined for the Accounting-Record-Type AVP:
+
+
+				EVENT_RECORD 1
+
+				An Accounting Event Record is used to indicate that a one-time
+				event has occurred (meaning that the start and end of the event
+				are simultaneous).  This record contains all information relevant
+				to the service, and is the only record of the service.
+
+
+				START_RECORD 2
+
+				An Accounting Start, Interim, and Stop Records are used to
+				indicate that a service of a measurable length has been given.  An
+				Accounting Start Record is used to initiate an accounting session,
+				and contains accounting information that is relevant to the
+				initiation of the session.
+
+
+				INTERIM_RECORD 3
+
+				An Interim Accounting Record contains cumulative accounting
+				information for an existing accounting session.  Interim
+				Accounting Records SHOULD be sent every time a re-authentication
+				or re-authorization occurs.  Further, additional interim record
+				triggers MAY be defined by application-specific Diameter
+				applications.  The selection of whether to use INTERIM_RECORD
+				records is done by the Acct-Interim-Interval AVP.
+
+
+				STOP_RECORD 4
+
+				An Accounting Stop Record is sent to terminate an accounting
+				session and contains cumulative accounting information relevant to
+				the existing session.
+			*/
+			struct dict_object 	* 	type;
+			struct dict_type_data	  	tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Accounting-Record-Type)"	, NULL, NULL};
+			struct dict_enumval_data 	t_1 = { "EVENT_RECORD",			{ .i32 = 1 }};
+			struct dict_enumval_data 	t_2 = { "START_RECORD", 		{ .i32 = 2 }};
+			struct dict_enumval_data 	t_3 = { "INTERIM_RECORD",		{ .i32 = 3 }};
+			struct dict_enumval_data 	t_4 = { "STOP_RECORD", 			{ .i32 = 4 }};
+			struct dict_avp_data 	data = { 
+					480, 					/* Code */
+					0, 					/* Vendor */
+					"Accounting-Record-Type",		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_3 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_4 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+		/* Acct-Interim-Interval */
+		{
+			/*
+				The Acct-Interim-Interval AVP (AVP Code 85) is of type Unsigned32 and
+				is sent from the Diameter home authorization server to the Diameter
+				client.  The client uses information in this AVP to decide how and
+				when to produce accounting records.  With different values in this
+				AVP, service sessions can result in one, two, or two+N accounting
+				records, based on the needs of the home-organization.  The following
+				accounting record production behavior is directed by the inclusion of
+				this AVP:
+
+
+				1.  The omission of the Acct-Interim-Interval AVP or its inclusion
+				with Value field set to 0 means that EVENT_RECORD, START_RECORD,
+				and STOP_RECORD are produced, as appropriate for the service.
+
+
+				2.  The inclusion of the AVP with Value field set to a non-zero value
+				means that INTERIM_RECORD records MUST be produced between the
+				START_RECORD and STOP_RECORD records.  The Value field of this
+				AVP is the nominal interval between these records in seconds.
+
+				The Diameter node that originates the accounting information,
+				known as the client, MUST produce the first INTERIM_RECORD record
+				roughly at the time when this nominal interval has elapsed from
+				the START_RECORD, the next one again as the interval has elapsed
+				once more, and so on until the session ends and a STOP_RECORD
+				record is produced.
+
+				The client MUST ensure that the interim record production times
+				are randomized so that large accounting message storms are not
+				created either among records or around a common service start
+				time.
+			*/
+			struct dict_avp_data data = { 
+					85, 					/* Code */
+					0, 					/* Vendor */
+					"Acct-Interim-Interval", 		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Accounting-Record-Number */
+		{
+			/*
+				The Accounting-Record-Number AVP (AVP Code 485) is of type Unsigned32
+				and identifies this record within one session.  As Session-Id AVPs
+				are globally unique, the combination of Session-Id and Accounting-
+				Record-Number AVPs is also globally unique, and can be used in
+				matching accounting records with confirmations.  An easy way to
+				produce unique numbers is to set the value to 0 for records of type
+				EVENT_RECORD and START_RECORD, and set the value to 1 for the first
+				INTERIM_RECORD, 2 for the second, and so on until the value for
+				STOP_RECORD is one more than for the last INTERIM_RECORD.
+			*/
+			struct dict_avp_data data = { 
+					485, 					/* Code */
+					0, 					/* Vendor */
+					"Accounting-Record-Number", 		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED32 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Acct-Session-Id */
+		{
+			/*
+				The Acct-Session-Id AVP (AVP Code 44) is of type OctetString is only
+				used when RADIUS/Diameter translation occurs.  This AVP contains the
+				contents of the RADIUS Acct-Session-Id attribute.
+			*/
+			struct dict_avp_data data = { 
+					44, 					/* Code */
+					0, 					/* Vendor */
+					"Acct-Session-Id", 			/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Acct-Multi-Session-Id */
+		{
+			/*
+				The Acct-Multi-Session-Id AVP (AVP Code 50) is of type UTF8String,
+				following the format specified in Section 8.8.  The Acct-Multi-
+				Session-Id AVP is used to link together multiple related accounting
+				sessions, where each session would have a unique Session-Id, but the
+				same Acct-Multi-Session-Id AVP.  This AVP MAY be returned by the
+				Diameter server in an authorization answer, and MUST be used in all
+				accounting messages for the given session.
+			*/
+			struct dict_avp_data data = { 
+					50, 					/* Code */
+					0, 					/* Vendor */
+					"Acct-Multi-Session-Id", 		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_OCTETSTRING 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
+		}
+		
+		/* Accounting-Sub-Session-Id */
+		{
+			/*
+				The Accounting-Sub-Session-Id AVP (AVP Code 287) is of type
+				Unsigned64 and contains the accounting sub-session identifier.  The
+				combination of the Session-Id and this AVP MUST be unique per sub-
+				session, and the value of this AVP MUST be monotonically increased by
+				one for all new sub-sessions.  The absence of this AVP implies no
+				sub-sessions are in use, with the exception of an Accounting-Request
+				whose Accounting-Record-Type is set to STOP_RECORD.  A STOP_RECORD
+				message with no Accounting-Sub-Session-Id AVP present will signal the
+				termination of all sub-sessions for a given Session-Id.
+			*/
+			struct dict_avp_data data = { 
+					287, 					/* Code */
+					0, 					/* Vendor */
+					"Accounting-Sub-Session-Id", 		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_UNSIGNED64 			/* base type of data */
+					};
+			CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
+		}
+		
+		/* Accounting-Realtime-Required */
+		{
+			/*
+				The Accounting-Realtime-Required AVP (AVP Code 483) is of type
+				Enumerated and is sent from the Diameter home authorization server to
+				the Diameter client or in the Accounting-Answer from the accounting
+				server.  The client uses information in this AVP to decide what to do
+				if the sending of accounting records to the accounting server has
+				been temporarily prevented due to, for instance, a network problem.
+
+
+				DELIVER_AND_GRANT 1
+
+				The AVP with Value field set to DELIVER_AND_GRANT means that the
+				service MUST only be granted as long as there is a connection to
+				an accounting server.  Note that the set of alternative accounting
+				servers are treated as one server in this sense.  Having to move
+				the accounting record stream to a backup server is not a reason to
+				discontinue the service to the user.
+
+
+				GRANT_AND_STORE 2
+
+				The AVP with Value field set to GRANT_AND_STORE means that service
+				SHOULD be granted if there is a connection, or as long as records
+				can still be stored as described in Section 9.4.
+
+				This is the default behavior if the AVP isn't included in the
+				reply from the authorization server.
+
+
+				GRANT_AND_LOSE 3
+
+				The AVP with Value field set to GRANT_AND_LOSE means that service
+				SHOULD be granted even if the records can not be delivered or
+				stored.
+			*/
+			struct dict_object  	* 	type;
+			struct dict_type_data	 	tdata = { AVP_TYPE_INTEGER32,	"Enumerated(Accounting-Realtime-Required)"	, NULL, NULL};
+			struct dict_enumval_data 	t_1 = { "DELIVER_AND_GRANT",		{ .i32 = 1 }};
+			struct dict_enumval_data 	t_2 = { "GRANT_AND_STORE", 		{ .i32 = 2 }};
+			struct dict_enumval_data 	t_3 = { "GRANT_AND_LOSE",		{ .i32 = 3 }};
+			struct dict_avp_data 		data = { 
+					483, 					/* Code */
+					0, 					/* Vendor */
+					"Accounting-Realtime-Required",		/* Name */
+					AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, 	/* Fixed flags */
+					AVP_FLAG_MANDATORY,			/* Fixed flag values */
+					AVP_TYPE_INTEGER32 			/* base type of data */
+					};
+			/* Create the Enumerated type, and then the AVP */
+			CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
+			CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
+			CHECK_dict_new( DICT_ENUMVAL, &t_3 , type, NULL);
+			CHECK_dict_new( DICT_AVP, &data , type, NULL);
+		}
+		
+	}
+	
+	/* Commands section */
+	{
+		/* To avoid defining global variables for all the AVP that we use here, we do search the dictionary in each sub-block.
+		 * This is far from optimal, but the code is clearer like this, and the time it requires at execution is not noticeable.
+		 */
+		
+		/* Generic message syntax when the 'E' bit is set */
+		{
+			/*
+				The 'E' (Error Bit) in the Diameter header is set when the request
+				caused a protocol-related error (see Section 7.1.3).  A message with
+				the 'E' bit MUST NOT be sent as a response to an answer message.
+				Note that a message with the 'E' bit set is still subjected to the
+				processing rules defined in Section 6.2.  When set, the answer
+				message will not conform to the ABNF specification for the command,
+				and will instead conform to the following ABNF:
+
+				Message Format
+
+				<answer-message> ::= < Diameter Header: code, ERR [PXY] >
+                				0*1< Session-Id >
+                				   { Origin-Host }
+                				   { Origin-Realm }
+                				   { Result-Code }
+                				   [ Origin-State-Id ]
+                				   [ Error-Message ]
+                				   [ Error-Reporting-Host ]
+                				   [ Failed-AVP ]
+                				 * [ Proxy-Info ]
+                				 * [ AVP ]
+
+				Note that the code used in the header is the same than the one found
+				in the request message, but with the 'R' bit cleared and the 'E' bit
+				set.  The 'P' bit in the header is set to the same value as the one
+				found in the request message.
+			*/
+			struct dict_object * cmd_error;
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD,0, 1 }
+							,{  "Origin-Host",			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED, -1, 1 }
+							,{  "Result-Code",			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL, -1, 1 }
+							,{  "Error-Message",			RULE_OPTIONAL, -1, 1 }
+							,{  "Error-Reporting-Host",		RULE_OPTIONAL, -1, 1 }
+							,{  "Failed-AVP",			RULE_OPTIONAL, -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL, -1,-1 }
+						};
+			CHECK_FCT( fd_dict_get_error_cmd(dict, &cmd_error) );
+			PARSE_loc_rules( rules, cmd_error );
+		}		
+		
+		/* Capabilities-Exchange-Request */
+		{
+			/*
+				The Capabilities-Exchange-Request (CER), indicated by the Command-
+				Code set to 257 and the Command Flags' 'R' bit set, is sent to
+				exchange local capabilities.  Upon detection of a transport failure,
+				this message MUST NOT be sent to an alternate peer.
+
+				When Diameter is run over SCTP [RFC2960], which allows for
+				connections to span multiple interfaces and multiple IP addresses,
+				the Capabilities-Exchange-Request message MUST contain one Host-IP-
+				Address AVP for each potential IP address that MAY be locally used
+				when transmitting Diameter messages.
+
+				Message Format
+
+				 <CER> ::= < Diameter Header: 257, REQ >
+        				   { Origin-Host }
+        				   { Origin-Realm }
+        				1* { Host-IP-Address }
+        				   { Vendor-Id }
+        				   { Product-Name }
+        				   [ Origin-State-Id ]
+        				 * [ Supported-Vendor-Id ]
+        				 * [ Auth-Application-Id ]
+        				 * [ Inband-Security-Id ]
+        				 * [ Acct-Application-Id ]
+        				 * [ Vendor-Specific-Application-Id ]
+        				   [ Firmware-Revision ]
+        				 * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					257, 					/* Code */
+					#if CC_CAPABILITIES_EXCHANGE != 257
+					#error "CC_CAPABILITIES_EXCHANGE definition mismatch"
+					#endif
+					"Capabilities-Exchange-Request", 	/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_RETRANSMIT | CMD_FLAG_ERROR, 	/* Fixed flags */
+					CMD_FLAG_REQUEST 			/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Origin-Host", 			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED, -1, 1 }
+							,{  "Host-IP-Address",			RULE_REQUIRED, -1,-1 }
+							,{  "Vendor-Id",			RULE_REQUIRED, -1, 1 }
+							,{  "Product-Name",			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL, -1, 1 }
+							,{  "Supported-Vendor-Id",		RULE_OPTIONAL, -1,-1 }
+							,{  "Auth-Application-Id",		RULE_OPTIONAL, -1,-1 }
+							,{  "Inband-Security-Id",		RULE_OPTIONAL, -1,-1 }
+							,{  "Acct-Application-Id",		RULE_OPTIONAL, -1,-1 }
+							,{  "Vendor-Specific-Application-Id",	RULE_OPTIONAL, -1,-1 }
+							,{  "Firmware-Revision",		RULE_OPTIONAL, -1, 1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Capabilities-Exchange-Answer */
+		{
+			/*
+				The Capabilities-Exchange-Answer (CEA), indicated by the Command-Code
+				set to 257 and the Command Flags' 'R' bit cleared, is sent in
+				response to a CER message.
+
+				When Diameter is run over SCTP [RFC2960], which allows connections to
+				span multiple interfaces, hence, multiple IP addresses, the
+				Capabilities-Exchange-Answer message MUST contain one Host-IP-Address
+				AVP for each potential IP address that MAY be locally used when
+				transmitting Diameter messages.
+
+				Message Format
+
+				 <CEA> ::= < Diameter Header: 257 >
+        				   { Result-Code }
+        				   { Origin-Host }
+        				   { Origin-Realm }
+        				1* { Host-IP-Address }
+        				   { Vendor-Id }
+        				   { Product-Name }
+        				   [ Origin-State-Id ]
+        				   [ Error-Message ]
+        				   [ Failed-AVP ]
+        				 * [ Supported-Vendor-Id ]
+        				 * [ Auth-Application-Id ]
+        				 * [ Inband-Security-Id ]
+        				 * [ Acct-Application-Id ]
+        				 * [ Vendor-Specific-Application-Id ]
+        				   [ Firmware-Revision ]
+        				 * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					257, 					/* Code */
+					#if CC_CAPABILITIES_EXCHANGE != 257
+					#error "CC_CAPABILITIES_EXCHANGE definition mismatch"
+					#endif
+					"Capabilities-Exchange-Answer", 	/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_RETRANSMIT, 	/* Fixed flags */
+					0 					/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Result-Code", 			RULE_REQUIRED, -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED, -1, 1 }
+							,{  "Host-IP-Address",			RULE_REQUIRED, -1,-1 }
+							,{  "Vendor-Id",			RULE_REQUIRED, -1, 1 }
+							,{  "Product-Name",			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL, -1, 1 }
+							,{  "Error-Message",			RULE_OPTIONAL, -1, 1 }
+							,{  "Failed-AVP",			RULE_OPTIONAL, -1, 1 }
+							,{  "Supported-Vendor-Id",		RULE_OPTIONAL, -1,-1 }
+							,{  "Auth-Application-Id",		RULE_OPTIONAL, -1,-1 }
+							,{  "Inband-Security-Id",		RULE_OPTIONAL, -1,-1 }
+							,{  "Acct-Application-Id",		RULE_OPTIONAL, -1,-1 }
+							,{  "Vendor-Specific-Application-Id",	RULE_OPTIONAL, -1,-1 }
+							,{  "Firmware-Revision",		RULE_OPTIONAL, -1, 1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Disconnect-Peer-Request */
+		{
+			/*
+				The Disconnect-Peer-Request (DPR), indicated by the Command-Code set
+				to 282 and the Command Flags' 'R' bit set, is sent to a peer to
+				inform its intentions to shutdown the transport connection.  Upon
+				detection of a transport failure, this message MUST NOT be sent to an
+				alternate peer.
+
+				Message Format
+
+				 <DPR>  ::= < Diameter Header: 282, REQ >
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    { Disconnect-Cause }
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					282, 					/* Code */
+					#if CC_DISCONNECT_PEER != 282
+					#error "CC_DISCONNECT_PEER definition mismatch"
+					#endif
+					"Disconnect-Peer-Request", 		/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_RETRANSMIT | CMD_FLAG_ERROR, 	/* Fixed flags */
+					CMD_FLAG_REQUEST 			/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Origin-Host", 			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED, -1, 1 }
+							,{  "Disconnect-Cause",			RULE_REQUIRED, -1, 1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Disconnect-Peer-Answer */
+		{
+			/*
+				The Disconnect-Peer-Answer (DPA), indicated by the Command-Code set
+				to 282 and the Command Flags' 'R' bit cleared, is sent as a response
+				to the Disconnect-Peer-Request message.  Upon receipt of this
+				message, the transport connection is shutdown.
+
+				Message Format
+
+				 <DPA>  ::= < Diameter Header: 282 >
+        				    { Result-Code }
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    [ Error-Message ]
+        				    [ Failed-AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					282, 					/* Code */
+					#if CC_DISCONNECT_PEER != 282
+					#error "CC_DISCONNECT_PEER definition mismatch"
+					#endif
+					"Disconnect-Peer-Answer", 		/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_RETRANSMIT, 	/* Fixed flags */
+					0 					/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Result-Code", 			RULE_REQUIRED, -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED, -1, 1 }
+							,{  "Error-Message",			RULE_OPTIONAL, -1, 1 }
+							,{  "Failed-AVP",			RULE_OPTIONAL, -1, 1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+
+		/* Device-Watchdog-Request */
+		{
+			/*
+				The Device-Watchdog-Request (DWR), indicated by the Command-Code set
+				to 280 and the Command Flags' 'R' bit set, is sent to a peer when no
+				traffic has been exchanged between two peers (see Section 5.5.3).
+				Upon detection of a transport failure, this message MUST NOT be sent
+				to an alternate peer.
+
+				Message Format
+
+				 <DWR>  ::= < Diameter Header: 280, REQ >
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    [ Origin-State-Id ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					280, 					/* Code */
+					#if CC_DEVICE_WATCHDOG != 280
+					#error "CC_DEVICE_WATCHDOG definition mismatch"
+					#endif
+					"Device-Watchdog-Request", 		/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_RETRANSMIT | CMD_FLAG_ERROR, 	/* Fixed flags */
+					CMD_FLAG_REQUEST 			/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Origin-Host", 			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL, -1, 1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Device-Watchdog-Answer */
+		{
+			/*
+				The Device-Watchdog-Answer (DWA), indicated by the Command-Code set
+				to 280 and the Command Flags' 'R' bit cleared, is sent as a response
+				to the Device-Watchdog-Request message.
+
+				Message Format
+
+				 <DWA>  ::= < Diameter Header: 280 >
+        				    { Result-Code }
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    [ Error-Message ]
+        				    [ Failed-AVP ]
+        				    [ Origin-State-Id ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					280, 					/* Code */
+					#if CC_DEVICE_WATCHDOG != 280
+					#error "CC_DEVICE_WATCHDOG definition mismatch"
+					#endif
+					"Device-Watchdog-Answer", 		/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_RETRANSMIT, 	/* Fixed flags */
+					0 					/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Result-Code", 			RULE_REQUIRED, -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED, -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED, -1, 1 }
+							,{  "Error-Message",			RULE_OPTIONAL, -1, 1 }
+							,{  "Failed-AVP",			RULE_OPTIONAL, -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL, -1, 1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Re-Auth-Request */
+		{
+			/*
+				The Re-Auth-Request (RAR), indicated by the Command-Code set to 258
+				and the message flags' 'R' bit set, may be sent by any server to the
+				access device that is providing session service, to request that the
+				user be re-authenticated and/or re-authorized.
+
+
+				Message Format
+
+				 <RAR>  ::= < Diameter Header: 258, REQ, PXY >
+        				    < Session-Id >
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    { Destination-Realm }
+        				    { Destination-Host }
+        				    { Auth-Application-Id }
+        				    { Re-Auth-Request-Type }
+        				    [ User-Name ]
+        				    [ Origin-State-Id ]
+        				  * [ Proxy-Info ]
+        				  * [ Route-Record ]
+        				  * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					258, 					/* Code */
+					#if CC_RE_AUTH != 258
+					#error "CC_RE_AUTH definition mismatch"
+					#endif
+					"Re-Auth-Request", 			/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR,	/* Fixed flags */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE	/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD, -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED,   -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED,   -1, 1 }
+							,{  "Destination-Realm",		RULE_REQUIRED,   -1, 1 }
+						 	,{  "Destination-Host", 		RULE_REQUIRED,   -1, 1 }
+						 	,{  "Auth-Application-Id", 		RULE_REQUIRED,   -1, 1 }
+						 	,{  "Re-Auth-Request-Type", 		RULE_REQUIRED,   -1, 1 }
+							,{  "User-Name",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL,   -1,-1 }
+							,{  "Route-Record",			RULE_OPTIONAL,   -1,-1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Re-Auth-Answer */
+		{
+			/*
+				The Re-Auth-Answer (RAA), indicated by the Command-Code set to 258
+				and the message flags' 'R' bit clear, is sent in response to the RAR.
+				The Result-Code AVP MUST be present, and indicates the disposition of
+				the request.
+
+				A successful RAA message MUST be followed by an application-specific
+				authentication and/or authorization message.
+
+
+				Message Format
+
+				 <RAA>  ::= < Diameter Header: 258, PXY >
+        				    < Session-Id >
+        				    { Result-Code }
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    [ User-Name ]
+        				    [ Origin-State-Id ]
+        				    [ Error-Message ]
+        				    [ Error-Reporting-Host ]
+        				    [ Failed-AVP ]
+        				  * [ Redirect-Host ]
+        				    [ Redirect-Host-Usage ]
+        				    [ Redirect-Max-Cache-Time ]
+        				  * [ Proxy-Info ]
+        				  * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					258, 					/* Code */
+					#if CC_RE_AUTH != 258
+					#error "CC_RE_AUTH definition mismatch"
+					#endif
+					"Re-Auth-Answer", 			/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE,	/* Fixed flags */
+							   CMD_FLAG_PROXIABLE	/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD, -1, 1 }
+ 							,{  "Result-Code", 			RULE_REQUIRED,   -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED,   -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED,   -1, 1 }
+							,{  "User-Name",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Error-Message",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Error-Reporting-Host",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Failed-AVP",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Redirect-Host",			RULE_OPTIONAL,   -1,-1 }
+							,{  "Redirect-Host-Usage",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Redirect-Max-Cache-Time",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL,   -1,-1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Session-Termination-Request */
+		{
+			/*
+				The Session-Termination-Request (STR), indicated by the Command-Code
+				set to 275 and the Command Flags' 'R' bit set, is sent by the access
+				device to inform the Diameter Server that an authenticated and/or
+				authorized session is being terminated.
+
+
+        				   Message Format
+
+				 <STR> ::= < Diameter Header: 275, REQ, PXY >
+        				   < Session-Id >
+        				   { Origin-Host }
+        				   { Origin-Realm }
+        				   { Destination-Realm }
+        				   { Auth-Application-Id }
+        				   { Termination-Cause }
+        				   [ User-Name ]
+        				   [ Destination-Host ]
+        				 * [ Class ]
+        				   [ Origin-State-Id ]
+        				 * [ Proxy-Info ]
+        				 * [ Route-Record ]
+        				 * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					275, 					/* Code */
+					#if CC_SESSION_TERMINATION != 275
+					#error "CC_SESSION_TERMINATION definition mismatch"
+					#endif
+					"Session-Termination-Request", 		/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR,	/* Fixed flags */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE	/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD, -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED,   -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED,   -1, 1 }
+							,{  "Destination-Realm",		RULE_REQUIRED,   -1, 1 }
+						 	,{  "Auth-Application-Id", 		RULE_REQUIRED,   -1, 1 }
+						 	,{  "Termination-Cause", 		RULE_REQUIRED,   -1, 1 }
+							,{  "User-Name",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Destination-Host",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Class",				RULE_OPTIONAL,   -1,-1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL,   -1,-1 }
+							,{  "Route-Record",			RULE_OPTIONAL,   -1,-1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Session-Termination-Answer */
+		{
+			/*
+				The Session-Termination-Answer (STA), indicated by the Command-Code
+				set to 275 and the message flags' 'R' bit clear, is sent by the
+				Diameter Server to acknowledge the notification that the session has
+				been terminated.  The Result-Code AVP MUST be present, and MAY
+				contain an indication that an error occurred while servicing the STR.
+
+				Upon sending or receipt of the STA, the Diameter Server MUST release
+				all resources for the session indicated by the Session-Id AVP.  Any
+				intermediate server in the Proxy-Chain MAY also release any
+				resources, if necessary.
+
+        				    Message Format
+
+				 <STA>  ::= < Diameter Header: 275, PXY >
+        				    < Session-Id >
+        				    { Result-Code }
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    [ User-Name ]
+        				  * [ Class ]
+        				    [ Error-Message ]
+        				    [ Error-Reporting-Host ]
+        				    [ Failed-AVP ]
+        				    [ Origin-State-Id ]
+        				  * [ Redirect-Host ]
+        				    [ Redirect-Host-Usage ]
+        				    [ Redirect-Max-Cache-Time ]
+        				  * [ Proxy-Info ]
+        				  * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					275, 					/* Code */
+					#if CC_SESSION_TERMINATION != 275
+					#error "CC_SESSION_TERMINATION definition mismatch"
+					#endif
+					"Session-Termination-Answer", 		/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE,	/* Fixed flags */
+							   CMD_FLAG_PROXIABLE	/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD, -1, 1 }
+ 							,{  "Result-Code", 			RULE_REQUIRED,   -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED,   -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED,   -1, 1 }
+							,{  "User-Name",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Class",				RULE_OPTIONAL,   -1,-1 }
+							,{  "Error-Message",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Error-Reporting-Host",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Failed-AVP",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Redirect-Host",			RULE_OPTIONAL,   -1,-1 }
+							,{  "Redirect-Host-Usage",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Redirect-Max-Cache-Time",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL,   -1,-1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Abort-Session-Request */
+		{
+			/*
+				The Abort-Session-Request (ASR), indicated by the Command-Code set to
+				274 and the message flags' 'R' bit set, may be sent by any server to
+				the access device that is providing session service, to request that
+				the session identified by the Session-Id be stopped.
+
+
+        				    Message Format
+
+				 <ASR>  ::= < Diameter Header: 274, REQ, PXY >
+        				    < Session-Id >
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    { Destination-Realm }
+        				    { Destination-Host }
+        				    { Auth-Application-Id }
+        				    [ User-Name ]
+        				    [ Origin-State-Id ]
+        				  * [ Proxy-Info ]
+        				  * [ Route-Record ]
+        				  * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					274, 					/* Code */
+					#if CC_ABORT_SESSION != 274
+					#error "CC_ABORT_SESSION definition mismatch"
+					#endif
+					"Abort-Session-Request", 		/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR,	/* Fixed flags */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE	/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD, -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED,   -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED,   -1, 1 }
+							,{  "Destination-Realm",		RULE_REQUIRED,   -1, 1 }
+							,{  "Destination-Host",			RULE_REQUIRED,   -1, 1 }
+						 	,{  "Auth-Application-Id", 		RULE_REQUIRED,   -1, 1 }
+							,{  "User-Name",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL,   -1,-1 }
+							,{  "Route-Record",			RULE_OPTIONAL,   -1,-1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Abort-Session-Answer */
+		{
+			/*
+				The Abort-Session-Answer (ASA), indicated by the Command-Code set to
+				274 and the message flags' 'R' bit clear, is sent in response to the
+				ASR.  The Result-Code AVP MUST be present, and indicates the
+				disposition of the request.
+
+				If the session identified by Session-Id in the ASR was successfully
+				terminated, Result-Code is set to DIAMETER_SUCCESS.  If the session
+				is not currently active, Result-Code is set to
+				DIAMETER_UNKNOWN_SESSION_ID.  If the access device does not stop the
+				session for any other reason, Result-Code is set to
+				DIAMETER_UNABLE_TO_COMPLY.
+
+        				    Message Format
+
+				 <ASA>  ::= < Diameter Header: 274, PXY >
+        				    < Session-Id >
+        				    { Result-Code }
+        				    { Origin-Host }
+        				    { Origin-Realm }
+        				    [ User-Name ]
+        				    [ Origin-State-Id ]
+        				    [ Error-Message ]
+        				    [ Error-Reporting-Host ]
+        				    [ Failed-AVP ]
+        				  * [ Redirect-Host ]
+        				    [ Redirect-Host-Usage ]
+        				    [ Redirect-Max-Cache-Time ]
+        				  * [ Proxy-Info ]
+        				  * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					274, 					/* Code */
+					#if CC_ABORT_SESSION != 274
+					#error "CC_ABORT_SESSION definition mismatch"
+					#endif
+					"Abort-Session-Answer", 		/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE,	/* Fixed flags */
+							   CMD_FLAG_PROXIABLE	/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD, -1, 1 }
+ 							,{  "Result-Code", 			RULE_REQUIRED,   -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED,   -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED,   -1, 1 }
+							,{  "User-Name",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Error-Message",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Error-Reporting-Host",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Failed-AVP",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Redirect-Host",			RULE_OPTIONAL,   -1,-1 }
+							,{  "Redirect-Host-Usage",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Redirect-Max-Cache-Time",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL,   -1,-1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Accounting-Request */
+		{
+			/*
+				The Accounting-Request (ACR) command, indicated by the Command-Code
+				field set to 271 and the Command Flags' 'R' bit set, is sent by a
+				Diameter node, acting as a client, in order to exchange accounting
+				information with a peer.
+
+				One of Acct-Application-Id and Vendor-Specific-Application-Id AVPs
+				MUST be present.  If the Vendor-Specific-Application-Id grouped AVP
+				is present, it MUST include an Acct-Application-Id AVP.
+
+				The AVP listed below SHOULD include service specific accounting AVPs,
+				as described in Section 9.3.
+
+
+				Message Format
+
+				 <ACR> ::= < Diameter Header: 271, REQ, PXY >
+        				   < Session-Id >
+        				   { Origin-Host }
+        				   { Origin-Realm }
+        				   { Destination-Realm }
+        				   { Accounting-Record-Type }
+        				   { Accounting-Record-Number }
+        				   [ Acct-Application-Id ]
+        				   [ Vendor-Specific-Application-Id ]
+        				   [ User-Name ]
+        				   [ Destination-Host ]
+        				   [ Accounting-Sub-Session-Id ]
+        				   [ Acct-Session-Id ]
+        				   [ Acct-Multi-Session-Id ]
+        				   [ Acct-Interim-Interval ]
+        				   [ Accounting-Realtime-Required ]
+        				   [ Origin-State-Id ]
+        				   [ Event-Timestamp ]
+        				 * [ Proxy-Info ]
+        				 * [ Route-Record ]
+        				 * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					271, 					/* Code */
+					#if CC_ACCOUNTING != 271
+					#error "CC_ACCOUNTING definition mismatch"
+					#endif
+					"Accounting-Request", 			/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR,	/* Fixed flags */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE	/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD, -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED,   -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED,   -1, 1 }
+							,{  "Destination-Realm",		RULE_REQUIRED,   -1, 1 }
+							,{  "Accounting-Record-Type",		RULE_REQUIRED,   -1, 1 }
+							,{  "Accounting-Record-Number",		RULE_REQUIRED,   -1, 1 }
+							,{  "Acct-Application-Id",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Vendor-Specific-Application-Id",	RULE_OPTIONAL,   -1, 1 }
+							,{  "User-Name",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Destination-Host",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Accounting-Sub-Session-Id",	RULE_OPTIONAL,   -1, 1 }
+							,{  "Acct-Session-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Acct-Multi-Session-Id",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Acct-Interim-Interval",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Accounting-Realtime-Required",	RULE_OPTIONAL,   -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Event-Timestamp",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL,   -1,-1 }
+							,{  "Route-Record",			RULE_OPTIONAL,   -1,-1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+		
+		/* Accounting-Answer */
+		{
+			/*
+				The Accounting-Answer (ACA) command, indicated by the Command-Code
+				field set to 271 and the Command Flags' 'R' bit cleared, is used to
+				acknowledge an Accounting-Request command.  The Accounting-Answer
+				command contains the same Session-Id as the corresponding request.
+
+				Only the target Diameter Server, known as the home Diameter Server,
+				SHOULD respond with the Accounting-Answer command.
+
+				One of Acct-Application-Id and Vendor-Specific-Application-Id AVPs
+				MUST be present.  If the Vendor-Specific-Application-Id grouped AVP
+				is present, it MUST contain an Acct-Application-Id AVP.
+
+				The AVP listed below SHOULD include service specific accounting AVPs,
+				as described in Section 9.3.
+
+
+				Message Format
+
+				 <ACA> ::= < Diameter Header: 271, PXY >
+        				   < Session-Id >
+        				   { Result-Code }
+        				   { Origin-Host }
+        				   { Origin-Realm }
+        				   { Accounting-Record-Type }
+        				   { Accounting-Record-Number }
+        				   [ Acct-Application-Id ]
+        				   [ Vendor-Specific-Application-Id ]
+        				   [ User-Name ]
+        				   [ Accounting-Sub-Session-Id ]
+        				   [ Acct-Session-Id ]
+        				   [ Acct-Multi-Session-Id ]
+        				   [ Error-Message ]
+        				   [ Error-Reporting-Host ]
+        				   [ Failed-AVP ]
+        				   [ Acct-Interim-Interval ]
+        				   [ Accounting-Realtime-Required ]
+        				   [ Origin-State-Id ]
+        				   [ Event-Timestamp ]
+        				 * [ Proxy-Info ]
+        				 * [ AVP ]
+			*/
+			struct dict_object * cmd;
+			struct dict_cmd_data data = { 
+					271, 					/* Code */
+					#if CC_ACCOUNTING != 271
+					#error "CC_ACCOUNTING definition mismatch"
+					#endif
+					"Accounting-Answer", 			/* Name */
+					CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE,	/* Fixed flags */
+							   CMD_FLAG_PROXIABLE	/* Fixed flag values */
+					};
+			struct local_rules_definition rules[] = 
+						{ 	 {  "Session-Id", 			RULE_FIXED_HEAD, -1, 1 }
+ 							,{  "Result-Code", 			RULE_REQUIRED,   -1, 1 }
+						 	,{  "Origin-Host", 			RULE_REQUIRED,   -1, 1 }
+							,{  "Origin-Realm",			RULE_REQUIRED,   -1, 1 }
+							,{  "Accounting-Record-Type",		RULE_REQUIRED,   -1, 1 }
+							,{  "Accounting-Record-Number",		RULE_REQUIRED,   -1, 1 }
+							,{  "Acct-Application-Id",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Vendor-Specific-Application-Id",	RULE_OPTIONAL,   -1, 1 }
+							,{  "User-Name",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Accounting-Sub-Session-Id",	RULE_OPTIONAL,   -1, 1 }
+							,{  "Acct-Session-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Acct-Multi-Session-Id",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Error-Message",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Error-Reporting-Host",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Failed-AVP",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Acct-Interim-Interval",		RULE_OPTIONAL,   -1, 1 }
+							,{  "Accounting-Realtime-Required",	RULE_OPTIONAL,   -1, 1 }
+							,{  "Origin-State-Id",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Event-Timestamp",			RULE_OPTIONAL,   -1, 1 }
+							,{  "Proxy-Info",			RULE_OPTIONAL,   -1,-1 }
+						};
+			
+			CHECK_dict_new( DICT_COMMAND, &data , NULL, &cmd);
+			PARSE_loc_rules( rules, cmd );
+		}
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/fd.h	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,48 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+/* This file contains the definitions for internal use in the freediameter daemon */
+
+#ifndef _FD_H
+#define _FD_H
+
+#include <freediameter/freediameter-host.h>
+#include <freediameter/freediameter.h>
+
+/* Create all the dictionary objects defined in the Diameter base RFC. */
+int fd_dict_base_protocol(struct dictionary * dict);
+
+
+#endif /* _FD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/main.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,59 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#include "fd.h"
+
+/* Entry point */
+int main(int argc, char * argv[])
+{
+	/* Initialize the library */
+	CHECK_FCT( fd_lib_init() );
+	
+	/* Name this thread */
+	fd_log_threadname("Main");
+
+	/* Initialize the dictionary */
+	CHECK_FCT( fd_dict_init(&fd_g_dict) );
+	
+	/* Add definitions of the base protocol */
+	CHECK_FCT( fd_dict_base_protocol(fd_g_dict) );
+	
+	/* For debug */
+	fd_dict_dump(fd_g_dict);
+	
+	TRACE_DEBUG(INFO, "FreeDiameter daemon initialized.");
+	
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/tests/CMakeLists.txt	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,47 @@
+# Test directory
+PROJECT("libfreediameter tests" C)
+
+# give the possibility to configure the timeout duration for the tests
+OPTION(TEST_TIMEOUT "Timeout for the tests, in seconds (default: 5)?")
+IF(TEST_TIMEOUT)
+	ADD_DEFINITIONS(-DTEST_TIMEOUT=${TEST_TIMEOUT})
+ENDIF(TEST_TIMEOUT)
+
+
+#############################
+# List the test cases
+SET(TEST_LIST
+	testdict
+	testmesg
+	testmq
+)
+
+#############################
+# Some parameters for the tests
+
+# Add this flag to add some debug information in the tests themselves
+ADD_DEFINITIONS(-DTEST_DEBUG)
+
+INCLUDE_DIRECTORIES( ".." )
+
+SET(TEST_COMMON_SRC "")
+
+FOREACH( SRC_FILE ${FD_COMMON_SRC})
+   SET(TEST_COMMON_SRC ${TEST_COMMON_SRC} "../${SRC_FILE}")
+ENDFOREACH(SRC_FILE)
+
+# FOREACH( SRC_FILE ${FD_COMMON_GEN_SRC})
+#    SET(TEST_COMMON_SRC ${TEST_COMMON_SRC} "${CMAKE_CURRENT_BINARY_DIR}/../${SRC_FILE}")
+# ENDFOREACH(SRC_FILE)
+
+# Create an archive with the daemon common files
+ADD_LIBRARY(fdcore STATIC ${TEST_COMMON_SRC})
+
+
+#############################
+# Compile each test
+FOREACH( TEST ${TEST_LIST} )
+   ADD_EXECUTABLE(${TEST} ${TEST}.c tests.h)
+   TARGET_LINK_LIBRARIES(${TEST} libfreediameter fdcore ${FD_LIBS})
+   ADD_TEST(${TEST} ${EXECUTABLE_OUTPUT_PATH}/${TEST})
+ENDFOREACH( TEST )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/tests/testdict.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,136 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#include "tests.h"
+
+/* Test for the dict_iterate_rules function */
+int iter_test(void * data, struct dict_rule_data * rule)
+{
+	struct dict_avp_data avpdata;
+	(*(int *)data)++;
+	
+	CHECK( 0, fd_dict_getval ( rule->rule_avp, &avpdata ) );
+	TRACE_DEBUG(FULL, "rule #%d: avp '%s'", *(int *)data, avpdata.avp_name);
+	return 0;
+}
+
+/* Main test routine */
+int main(int argc, char *argv[])
+{
+	/* First, initialize the daemon modules */
+	INIT_FD();
+	
+	/* Test creating and searching all types of objects */
+	{
+		enum dict_object_type type;
+		struct dict_object * obj1 = NULL;
+		struct dict_object * obj2 = NULL;
+		struct dict_object * obj3 = NULL;
+
+		vendor_id_t vendor_id = 735671;
+		struct dict_vendor_data vendor1_data = { 735671, "Vendor test 1" };
+		struct dict_vendor_data vendor2_data = { 735672, "Vendor test 2" };
+		struct dict_application_data app1_data = { 735674, "Application test 1" };
+		
+		
+		/* Create two vendors */
+		CHECK( 0, fd_dict_new ( fd_g_dict, DICT_VENDOR, &vendor1_data , NULL, &obj1 ) );
+		CHECK( 0, fd_dict_new ( fd_g_dict, DICT_VENDOR, &vendor2_data , NULL, NULL ) );
+		
+		/* Check we always retrieve the correct vendor object */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) );
+		CHECK( obj1, obj2);
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 1", &obj2, ENOENT ) );
+		CHECK( obj1, obj2);
+		
+		/* Check the error conditions */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) );
+		
+		vendor_id = 735673; /* Not defined */
+		CHECK( ENOENT, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) );
+		CHECK( ENOENT, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", NULL, ENOENT ) );
+		CHECK( ENOENT, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) );
+		CHECK( ENOENT, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOENT ) );
+		CHECK( ENOTSUP, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOTSUP ) );
+		
+		/* Check the get_* functions */
+		CHECK( 0, fd_dict_getval ( obj1, &vendor1_data ) );
+		CHECK( 735671, vendor1_data.vendor_id );
+		CHECK( 0, strcmp(vendor1_data.vendor_name, "Vendor test 1") );
+		/* error conditions */
+		CHECK( EINVAL, fd_dict_getval ( (struct dict_object *)"not an object", &vendor1_data ) );
+		
+		/* Create the application with vendor1 as parent */
+		CHECK( EINVAL, fd_dict_new ( fd_g_dict, DICT_APPLICATION, &app1_data , (struct dict_object *)"bad object", &obj2 ) );
+		CHECK( 0, fd_dict_new ( fd_g_dict, DICT_APPLICATION, &app1_data , obj1, &obj2 ) );
+		
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_OF_APPLICATION, obj2, &obj3, ENOENT ) );
+		CHECK( obj1, obj3);
+		
+		/* Creating and searching the other objects is already done in dictionary initialization */
+	}
+
+	/* Test creation of the "Example-AVP" grouped AVP from the RFC */
+	{
+		int nbr = 0;
+		struct dict_object * origin_host_avp = NULL;
+		struct dict_object * session_id_avp = NULL;
+		struct dict_object * example_avp_avp = NULL;
+		struct dict_rule_data rule_data = { NULL, RULE_REQUIRED, -1, -1 };
+		struct dict_avp_data example_avp_data = { 999999, 0, "Example-AVP", AVP_FLAG_VENDOR , 0, AVP_TYPE_GROUPED };
+
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT ) );
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT ) );
+		
+		CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp ) );
+		
+		rule_data.rule_avp = origin_host_avp;
+		rule_data.rule_min = 1;
+		rule_data.rule_max = 1;
+		CHECK( 0, fd_dict_new ( fd_g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) );
+		
+		rule_data.rule_avp = session_id_avp;
+		rule_data.rule_min = 1;
+		rule_data.rule_max = -1;
+		CHECK( 0, fd_dict_new ( fd_g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) );
+		
+		CHECK( 0, fd_dict_iterate_rules ( example_avp_avp, &nbr, iter_test) );
+		CHECK( 2, nbr );
+	}
+
+	/* That's all for the tests yet */
+	PASSTEST();
+} 
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/tests/testmesg.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,1230 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#include "tests.h"
+
+/* Main test routine */
+int main(int argc, char *argv[])
+{
+	struct msg * acr = NULL;
+	struct avp * pi = NULL, *avp1, *avp2;
+	unsigned char * buf = NULL;
+	
+	/* First, initialize the daemon modules */
+	INIT_FD();
+	
+	/* Create the message object from model */
+	{
+		struct dict_object * acr_model = NULL;
+
+		/* Now find the ACR dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) );
+
+		/* Create the instance, using the templates */
+		CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) );
+
+		/* Check there is no child */
+		CHECK( ENOENT, fd_msg_browse ( acr, MSG_BRW_FIRST_CHILD, NULL, NULL) );
+		
+		#if 0
+		/* For debug: dump the object */
+		fd_log_debug("Dumping Accounting-Request empty message\n");
+		fd_msg_dump_walk( 0, acr );
+		#endif
+	}
+	
+	/* Create the Proxy-Info AVP from model */
+	{
+		struct dict_object * pi_model = NULL;
+
+		/* Now find the ACR dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &pi_model, ENOENT ) );
+
+		/* Create the instance, using the templates */
+		CHECK( 0, fd_msg_avp_new ( pi_model, 0, &pi ) );
+
+		#if 0
+		/* For debug: dump the object */
+		fd_log_debug("Dumping Proxy-Info AVP\n");
+		fd_msg_dump_walk(0, pi);
+		fd_log_debug("Dumping dictionary model\n");
+		fd_dict_dump_object(pi_model);
+		#endif
+		
+	}
+	
+	/* Get a reference to the current last AVP in the message */
+	{
+		int diff = 0;
+		
+		CHECK( 0, fd_msg_avp_new ( NULL, 0, &avp1 ) );
+		CHECK( 0, fd_msg_avp_add ( acr, MSG_BRW_LAST_CHILD, avp1) );
+		
+		CHECK( 0, fd_msg_browse ( acr, MSG_BRW_LAST_CHILD, &avp2, &diff) );
+		CHECK( 1, diff );
+		CHECK( avp1, avp2 );
+		
+		/* Check that we cannot add this AVP to another object since it is already linked */
+		CHECK( EINVAL, fd_msg_avp_add( pi, MSG_BRW_LAST_CHILD, avp1) );
+	}
+
+	/* Now add the Proxy-Info AVP at the end of the message */
+	{
+		CHECK( 0, fd_msg_avp_add( acr, MSG_BRW_LAST_CHILD, pi) );
+		#if 0
+		/* For debug: dump the object */
+		fd_log_debug("Dumping Accounting-Request with Proxy-Info AVP at the end\n");
+		fd_msg_dump_walk(0, acr);
+		#endif
+	}
+	
+	/* Check the last child is now the proxy-Info */
+	{
+		CHECK( 0, fd_msg_browse ( acr, MSG_BRW_LAST_CHILD, &avp2, NULL) );
+		CHECK( pi, avp2 );
+	}
+	
+	/* Check that the avp before the proxy-info is the previous last one */
+	{
+		int diff = 0;
+		CHECK( 0, fd_msg_browse ( pi, MSG_BRW_PREV, &avp2, &diff) );
+		CHECK( avp1, avp2 );
+		CHECK( 0, diff);
+	}
+	
+	/* Check that there are no AVP after the proxy-info */
+	CHECK( ENOENT, fd_msg_browse ( pi, MSG_BRW_NEXT, NULL, NULL) );
+	
+	/* Test the fd_msg_free function unlinks the object properly */
+	{
+		struct dict_object * rr_model = NULL;
+
+		/* Now find the dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &rr_model, ENOENT ) );
+
+		/* Create the instance, using the templates */
+		CHECK( 0, fd_msg_avp_new ( rr_model, 0, &avp1 ) );
+		
+		/* Add the AVP at the end of the message */
+		CHECK( 0, fd_msg_avp_add( pi, MSG_BRW_NEXT, avp1) );
+		
+		/* Check the last AVP of the message is now this one */
+		CHECK( 0, fd_msg_browse ( acr, MSG_BRW_LAST_CHILD, &avp2, NULL) );
+		CHECK( avp1, avp2 );
+		
+		/* Now delete it */
+		CHECK( 0, fd_msg_free( avp1 ) );
+		
+		/* Check the last AVP of the message is back to pi */
+		CHECK( 0, fd_msg_browse ( acr, MSG_BRW_LAST_CHILD, &avp2, NULL) );
+		CHECK( pi, avp2 );
+		
+		/* Delete the whole message */
+		CHECK( 0, fd_msg_free( acr ) );
+	}
+	
+	/* Recreate the message object */
+	{
+		struct dict_object * acr_model = NULL;
+
+		/* Now find the ACR dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) );
+
+		/* Create the instance, using the templates */
+		CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) );
+	}
+	
+	/* Now let's create some additional Dictionary objects for the test */
+	{
+		/* The constant values used here are totally arbitrary chosen */
+		struct dict_object * vendor;
+		{
+			struct dict_vendor_data vendor_data = { 73565, "Vendor test" };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_VENDOR, &vendor_data , NULL, &vendor ) );
+		}
+		
+		{
+			struct dict_application_data app_data = { 73566, "Application test" };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_APPLICATION, &app_data , vendor, NULL ) );
+		}
+		
+		{
+			struct dict_avp_data avp_data = { 73567, 0, "AVP Test - no vendor - f32", 0, 0, AVP_TYPE_FLOAT32 };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		
+		{ 
+			struct dict_object  * type = NULL;
+			struct dict_type_data type_data = { AVP_TYPE_INTEGER64, "Int64 test" };
+			struct dict_avp_data  avp_data = { 73568, 73565, "AVP Test - i64", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER64 };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data , NULL, &type ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , type, NULL ) );
+		}
+		
+		{
+			struct dict_object     * type = NULL;
+			struct dict_type_data    type_data = { AVP_TYPE_INTEGER32, "Enum32 test" };
+			struct dict_enumval_data val1 = { "i32 const test (val 1)", { .i32 = 1 } };
+			struct dict_enumval_data val2 = { "i32 const test (val 2)", { .i32 = 2 } };
+			struct dict_enumval_data val3 = { "i32 const test (val -5)",{ .i32 = -5 } };
+			struct dict_avp_data     avp_data = { 73569, 73565, "AVP Test - enumi32", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER32 };
+			
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data , NULL, &type ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val3 , type, NULL ) );
+		}
+			
+		{ 
+			struct dict_object  * type = NULL;
+			struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS test" };
+			struct dict_avp_data  avp_data = { 73570, 73565, "AVP Test - os", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data , NULL, &type ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , type, NULL ) );
+		}
+		
+		{
+			struct dict_object     * type = NULL;
+			struct dict_type_data    type_data = { AVP_TYPE_OCTETSTRING, "OS enum test" };
+			struct dict_enumval_data val1 = { "os const test (Test)", { .os = { (unsigned char *)"Test", 4 } } };
+			struct dict_enumval_data val2 = { "os const test (waaad)", { .os = { (unsigned char *)"waaad", 5 } } };
+			struct dict_enumval_data val3 = { "os const test (waa)", { .os = { (unsigned char *)"waaad", 3 } } };
+			struct dict_avp_data     avp_data = { 73571, 73565, "AVP Test - enumos", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
+			
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data , NULL, &type ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val3 , type, NULL ) );
+		}
+		
+		{
+			struct dict_object * gavp = NULL;
+			struct dict_avp_data avp_data = { 73572, 73565, "AVP Test - grouped", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED };
+			
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, &gavp ) );
+			
+			/* Macro to search AVP and create a rule */		
+			#define ADD_RULE( _parent, _vendor, _avpname, _pos, _min, _max, _ord ) {		\
+				struct dict_object * _avp = NULL;						\
+				struct dict_avp_request _req = { (_vendor), 0, (_avpname) };			\
+				struct dict_rule_data _data;							\
+				CHECK( 0, fd_dict_search( fd_g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\
+				_data.rule_avp = _avp;								\
+				_data.rule_position = (_pos);							\
+				_data.rule_order = (_ord);							\
+				_data.rule_min = (_min);							\
+				_data.rule_max = (_max);							\
+				CHECK( 0, fd_dict_new ( fd_g_dict, DICT_RULE, &_data , (_parent), NULL ) );	\
+			}
+			
+			ADD_RULE(gavp, 73565, "AVP Test - os", RULE_OPTIONAL,   -1, -1,  0);
+			
+		}
+			
+		{
+			struct dict_object  * application = NULL;
+			struct dict_object  * command = NULL;
+			struct dict_cmd_data  cmd_data = { 73573, "Test-Command-Request", CMD_FLAG_REQUEST, CMD_FLAG_REQUEST };
+			
+			CHECK( 0, fd_dict_search ( fd_g_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) );
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_COMMAND, &cmd_data , application, &command ) );
+			ADD_RULE(command, 0,     "AVP Test - no vendor - f32", 	RULE_FIXED_HEAD, -1,  1,  1);
+			ADD_RULE(command, 73565, "AVP Test - i64",		RULE_REQUIRED,   -1, -1,  0);
+			ADD_RULE(command, 73565, "AVP Test - enumi32", 		RULE_OPTIONAL,   -1, -1,  0);
+			ADD_RULE(command, 73565, "AVP Test - os", 		RULE_OPTIONAL,   -1, -1,  0);
+			ADD_RULE(command, 73565, "AVP Test - enumos", 		RULE_OPTIONAL,   -1, -1,  0);
+			ADD_RULE(command, 73565, "AVP Test - grouped", 		RULE_OPTIONAL,   -1, -1,  0);
+		}
+		
+		{
+			struct dict_object  * gavp = NULL;
+			struct dict_avp_data  avp_data = { 73574, 73565, "AVP Test - rules", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED };
+			
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, &gavp ) );
+			
+			ADD_RULE(gavp,     0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD,   0, 1, 1);
+			ADD_RULE(gavp, 73565, "AVP Test - i64", 	    RULE_FIXED_HEAD,  -1, 1, 2);
+			ADD_RULE(gavp, 73565, "AVP Test - enumi32", 	    RULE_FIXED_HEAD,  -1, 1, 3);
+			ADD_RULE(gavp, 73565, "AVP Test - os", 	    	    RULE_REQUIRED,     2, 3, 0);
+			ADD_RULE(gavp, 73565, "AVP Test - enumos",     	    RULE_OPTIONAL,     0, 1, 0);
+			ADD_RULE(gavp, 73565, "AVP Test - grouped",         RULE_FIXED_TAIL,  -1, 1, 1);
+			
+			#if 0
+			fd_dict_dump_object ( gavp );
+			#endif
+		}
+		#if 0
+		{
+			fd_dict_dump_object ( vendor );
+		}
+		#endif
+	}
+	
+	/* Now create some values and check the length is correctly handled */
+	{
+		struct dict_object * cmd_model = NULL;
+		struct msg         * msg = NULL;
+		struct dict_object * avp_model = NULL;
+		struct avp         * avp = NULL;
+		union avp_value      value;
+		
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) );
+		
+		/* Check an error is trigged if the AVP has no value set */
+		{
+			CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP,     AVP_BY_NAME,     "AVP Test - no vendor - f32", &avp_model, ENOENT ) );
+			
+			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
+			CHECK( 0, fd_msg_avp_new ( avp_model, 0, &avp ) );
+			
+			CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_FIRST_CHILD, avp ) );
+			
+			CHECK( EINVAL, fd_msg_update_length ( avp ) );
+			CHECK( EINVAL, fd_msg_update_length ( msg ) );
+			
+			CHECK( 0, fd_msg_free( msg ) );
+		}
+		
+		/* Check the sizes are handled properly */
+		{
+			struct avp * avpi = NULL;
+			struct avp * avpch = NULL;
+			struct avp_hdr * avpdata = NULL;
+			struct msg_hdr * msgdata = NULL;
+			#define ADD_AVP( _parent, _position, _avpi, _avpvendor, _avpname) {			\
+				struct dict_object * _avp = NULL;						\
+				struct dict_avp_request _req = { (_avpvendor), 0, (_avpname) };			\
+				CHECK( 0, fd_dict_search( fd_g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\
+				CHECK( 0, fd_msg_avp_new ( _avp, 0, &_avpi ) );					\
+				CHECK( 0, fd_msg_avp_add ( (_parent), (_position), _avpi ) );			\
+			}
+			/* Create a message with many AVP inside */
+			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
+			CHECK( 0, fd_msg_hdr ( msg, &msgdata ) );
+			
+			/* Avp no vendor, float32 => size = 12 */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,     "AVP Test - no vendor - f32" );
+			value.f32 = 3.1415;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+			CHECK( 0, fd_msg_update_length ( avpi ) );
+			#if 0
+			fd_log_debug("AVP no vendor, value 3.1415:\n");
+			fd_msg_dump_one(0, avpi);
+			#endif
+			CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
+			CHECK( 12, avpdata->avp_len );
+			
+			/* Check what happens when we delete the value */
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, NULL ) );
+			CHECK( EINVAL, fd_msg_update_length ( avpi ) );
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+			
+			/* Add a vendor AVP, integer64 => size = 20 */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - i64" );
+			value.i64 = 0x123456789abcdeLL;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+			CHECK( 0, fd_msg_update_length ( avpi ) );
+			#if 0
+			fd_log_debug("AVP vendor, value 0x123456789abcdeL:\n");
+			fd_msg_dump_one(0, avpi);
+			#endif
+			CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
+			CHECK( 20, avpdata->avp_len );
+			
+			/* Check the size of the message is 20 (header) + 12 + 20 = 52 */
+			CHECK( 0, fd_msg_update_length ( msg ) );
+			CHECK( 52, msgdata->msg_length );
+			
+			/* Add an AVP with an enum value */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
+			{
+				struct dict_object * type_model = NULL;
+				struct dict_object * value_model = NULL;
+				struct dict_enumval_request request;
+				
+				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
+				CHECK( 0, fd_dict_search ( fd_g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
+				memset(&request, 0, sizeof(request));
+				request.type_obj = type_model;
+				request.search.enum_name = "i32 const test (val 2)";
+				CHECK( 0, fd_dict_search ( fd_g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
+				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
+				#if 0
+				fd_log_debug("AVP enum i32, value 2 (from const):\n");
+				fd_msg_dump_one(0, avpi);
+				#endif
+			}
+			
+			/* Add an AVP with an enum value, negative */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
+			{
+				struct dict_object  * type_model = NULL;
+				struct dict_object  * value_model = NULL;
+				struct dict_enumval_request request;
+				
+				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
+				CHECK( 0, fd_dict_search ( fd_g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
+				memset(&request, 0, sizeof(request));
+				request.type_obj = type_model;
+				request.search.enum_name = "i32 const test (val -5)";
+				CHECK( 0, fd_dict_search ( fd_g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
+				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
+				#if 0
+				fd_log_debug("AVP enum i32, value -5 (from const):\n");
+				fd_msg_dump_one(0, avpi);
+				#endif
+				/* Check the size is correct ( 12 for header + 4 for value ) */
+				CHECK( 0, fd_msg_update_length ( avpi ) );
+				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
+				CHECK( 16, avpdata->avp_len );
+			}
+			
+			/* Now add a value which is not a constant into an enumerated AVP */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
+			value.i32 = -10;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+			CHECK( 0, fd_msg_update_length ( avpi ) );
+			#if 0
+			fd_log_debug("AVP vendor enum i32, value -10 (not const):\n");
+			fd_msg_dump_one(0, avpi);
+			#endif
+			
+			/* Add an octetstring AVP */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - os" );
+			{
+				unsigned char buf[90];
+				memcpy(&buf, "This\0 is a buffer of dat\a. It is not a string so we can have any c\0ntr\0l character here...\0\0", 89);
+				value.os.data = buf;
+				value.os.len = 89;
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+				memset(&buf, 0, sizeof(buf)); /* Test that the OS value is really copied */
+				CHECK( 0, fd_msg_update_length ( avpi ) );
+				#if 1
+				fd_log_debug("AVP octet string, 'This\\0 is a b...'\n");
+				fd_msg_dump_one(0, avpi);
+				#endif
+				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
+				CHECK( 101, avpdata->avp_len );
+				CHECK( 'T', avpdata->avp_value->os.data[0] );
+				CHECK( 'i', avpdata->avp_value->os.data[6] );
+			}
+
+			/* Check the size of the message is 20 (header) + 12 + 20 + 16 * 3 + 101 + 3 (padding) = 204 */
+			CHECK( 0, fd_msg_update_length ( msg ) );
+			CHECK( 204, msgdata->msg_length );
+			
+			/* Add an octetstring from an enumerated constant */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumos" );
+			{
+				struct dict_object  * type_model = NULL;
+				struct dict_object  * value_model = NULL;
+				struct dict_enumval_request request;
+				
+				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
+				CHECK( 0, fd_dict_search ( fd_g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
+				memset(&request, 0, sizeof(request));
+				request.type_obj = type_model;
+				request.search.enum_name = "os const test (waaad)";
+				CHECK( 0, fd_dict_search ( fd_g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
+				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
+				#if 0
+				fd_log_debug("AVP Enumuerated OctetString (from const):\n");
+				fd_msg_dump_one(0, avpi);
+				#endif
+				/* Check the size is correct ( 12 for header + 5 for value ) */
+				CHECK( 0, fd_msg_update_length ( avpi ) );
+				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
+				CHECK( 17, avpdata->avp_len );
+			}
+				
+			/* Add an octetstring from an enumerated constant */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumos" );
+			{
+				struct dict_object  * type_model = NULL;
+				struct dict_object  * value_model = NULL;
+				struct dict_enumval_request request;
+				
+				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
+				CHECK( 0, fd_dict_search ( fd_g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
+				memset(&request, 0, sizeof(request));
+				request.type_obj = type_model;
+				request.search.enum_name = "os const test (waa)";
+				CHECK( 0, fd_dict_search ( fd_g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
+				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
+				#if 0
+				fd_log_debug("AVP Enumuerated OctetString (from const):\n");
+				fd_msg_dump_one(0, avpi);
+				#endif
+				/* Check the size is correct ( 12 for header + 3 for value ) */
+				CHECK( 0, fd_msg_update_length ( avpi ) );
+				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
+				CHECK( 15, avpdata->avp_len );
+			}
+				
+
+			/* Check the size of the message is 20 (header) + 12 + 20 + 16 * 3 + (101 + 3) + (17 + 3) + (15 + 1) = 240 */
+			CHECK( 0, fd_msg_update_length ( msg ) );
+			CHECK( 240, msgdata->msg_length );
+			
+			/* Now test the grouped AVPs */	
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - grouped" );
+			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
+			  {
+				value.os.data = (unsigned char *)"12345678";
+				value.os.len = 8;
+				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
+				#if 0
+				fd_log_debug("AVP octet string, '1234678'\n");
+				fd_msg_dump_one(0, avpch);
+				#endif
+				CHECK( 0, fd_msg_update_length ( avpch ) );
+				CHECK( 0, fd_msg_avp_hdr ( avpch, &avpdata ) );
+				CHECK( 20, avpdata->avp_len );
+			  }
+			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
+			  {
+				value.os.data = (unsigned char *)"123456789";
+				value.os.len = 9;
+				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
+				#if 0
+				fd_log_debug("AVP octet string, '12346789'\n");
+				fd_msg_dump_one(0, avpch);
+				#endif
+			  }
+			
+			/* Check the size is updated recursively: (gavp hdr: 12) + (avp1: 20) + (avp2: 21 + 3) = 56 */
+			CHECK( 0, fd_msg_update_length ( avpi ) );
+			CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
+			CHECK( 56, avpdata->avp_len );
+			
+			/* Add another similar grouped AVP, to have lot of padding */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - grouped" );
+			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
+			  {
+				value.os.data = (unsigned char *)"1";
+				value.os.len = 1;
+				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
+			  }
+			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
+			  {
+				value.os.data = (unsigned char *)"1234567";
+				value.os.len = 7;
+				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
+			  }
+			
+			/* Now check the global size of the message, if padding is correctly handled */
+			/* size = 20 (header) + 12 + 20 + 16 * 3 + (101 + 3) + (17 + 3) + (15 + 1) 
+			 *        + ( 12 + ( 20 + 21) + 3 )         # padding for the grouped AVP = 3
+			 *        + ( 12 + ( (13 + 3) + 19 ) + 1 )  # and 1 for this one
+			 * size = 240 + 56 + 48 = 344
+			 */
+			CHECK( 0, fd_msg_update_length ( msg ) );
+			#if 0
+			fd_msg_dump_walk(0, msg);
+			#endif
+			CHECK( 344, msgdata->msg_length );
+			
+			/* Set the application to the test application: 73566 */
+			msgdata->msg_appl = 73566;
+			
+			/* Set the hop-by-hop ID to a random value: 0x4b44b41d */
+			msgdata->msg_hbhid = 0x4b44b41d;
+			/* Set the end-to-end ID to a random value: 0xe2ee2e1d */
+			msgdata->msg_eteid = 0xe2ee2e1d;
+		}
+		
+		/* Test the msg_bufferize function */
+		{
+			
+			CHECK( 0, fd_msg_bufferize( msg, &buf, NULL ) );
+			
+			/* Test the first bytes */
+			CHECK( 0x01, buf[0] ); /* Version */
+			CHECK( 0x00, buf[1] ); /* Length: 344 = 0x000158 */
+			CHECK( 0x01, buf[2] );
+			CHECK( 0x58, buf[3] );
+			CHECK( 0x80, buf[4] ); /* flags: only "R" is set. */
+			CHECK( 0x01, buf[5] ); /* Command code: 73573 = 0x011F65 */
+			CHECK( 0x1F, buf[6] );
+			CHECK( 0x65, buf[7] );
+			CHECK( 0x00, buf[8] ); /* App ID: 73566 = 0x00011F5E */
+			CHECK( 0x01, buf[9] ); 
+			CHECK( 0x1F, buf[10] );
+			CHECK( 0x5E, buf[11] );
+			CHECK( 0x4b, buf[12] ); /* hop-by-hop id: 0x4b44b41d */
+			CHECK( 0x44, buf[13] );
+			CHECK( 0xb4, buf[14] );
+			CHECK( 0x1d, buf[15] );
+			CHECK( 0xe2, buf[16] ); /* end-to-end id: 0xe2ee2e1d */
+			CHECK( 0xee, buf[17] );
+			CHECK( 0x2e, buf[18] );
+			CHECK( 0x1d, buf[19] );
+			
+			CHECK( 0x00, buf[20] ); /* First AVP (AVP Test - no vendor - f32) begin: code 73567 = 0x00011F5F */
+			CHECK( 0x01, buf[21] );
+			CHECK( 0x1F, buf[22] );
+			CHECK( 0x5F, buf[23] );
+			CHECK( 0x00, buf[24] ); /* flags: 0 */
+			CHECK( 0x00, buf[25] ); /* length: 12 = 0x00000c */
+			CHECK( 0x00, buf[26] );
+			CHECK( 0x0C, buf[27] );
+			CHECK( 0x40, buf[28] ); /* Value: 3.1415:  sign = '+' => most significant bit = 0 */
+			CHECK( 0x49, buf[29] ); /* 2 <= 3.1415 < 4 => exponent = 1 => biaised (on 8 bits) = (decimal) 128 = (binary) 100 0000 0 */
+			CHECK( 0x0e, buf[30] ); /* significand = (decimal) 1.57075 = (binary) 1.100 1001 0000 1110 0101 0110 */
+			CHECK( 0x56, buf[31] ); /* total => 0100 0000 0100 1001 0000 1110 0101 0110 = (hexa) 40 49 0e 56*/
+			
+			/* The other AVPs will be tested by successful parsing... */
+		}
+		
+		/* Now free the message, we keep only the buffer. */
+		CHECK( 0, fd_msg_free( msg ) );
+		
+	}
+	
+	/* Test the parsing of buffers and messages */
+	{
+		unsigned char * buf_cpy = NULL;
+		struct msg * msg;
+		
+		#define CPYBUF() {			\
+			buf_cpy = malloc(344);		\
+			CHECK( buf_cpy ? 1 : 0, 1);	\
+			memcpy(buf_cpy, buf, 344);	\
+		}
+		
+		/* Test the msg_parse_buffer function */
+		{
+			CPYBUF();
+			CHECK( EBADMSG, fd_msg_parse_buffer( &buf_cpy, 340, &msg) );
+			
+			CPYBUF();
+			CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
+			#if 0
+			fd_msg_dump_walk(0, msg);
+			#endif
+			
+			/* reinit the msg */
+			CHECK( 0, fd_msg_free ( msg ) );
+				
+		}
+		
+		/* Test the fd_msg_search_avp function */
+		{
+			struct dict_object * avp_model;
+			struct avp 	   * found;
+			struct avp_hdr     * avpdata = NULL;
+			
+			/* Now find the ACR dictionary object */
+			CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) );
+			
+			CPYBUF();
+			CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
+			
+			/* Search this AVP instance in the msg */
+			CHECK( 0, fd_msg_search_avp( msg, avp_model, &found ) );
+			
+			/* Check the AVP value is 3.1415 */
+			CHECK( 0, fd_msg_avp_hdr ( found, &avpdata ) );
+			CHECK( 3.1415F, avpdata->avp_value->f32 );
+			
+			/* reinit the msg */
+			CHECK( 0, fd_msg_free ( msg ) );
+				
+		}
+		
+		/* Test the msg_parse_dict function */
+		{
+			/* Test with an unknown command code */
+			{
+				CPYBUF();
+				
+				/* Change the command-code */
+				buf_cpy[5] = 0x11;
+				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
+				CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_dict ) );
+				
+				/* reset */
+				CHECK( 0, fd_msg_free ( msg ) );
+			}
+			
+			/* Test with an unknown Mandatory AVP */
+			{
+				CPYBUF();
+				
+				buf_cpy[20] = 0x11;	/* New AVP code = 0x11011F5F, undefined */
+				buf_cpy[24] = 0x40; 	/* Add the 'M' flag */
+				
+				/* Check that we cannot support this message now */
+				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
+				CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_dict ) );
+				
+				/* reset */
+				CHECK( 0, fd_msg_free ( msg ) );
+			}
+			
+			/* Test with an unknown optional AVP */
+			{
+				CPYBUF();
+				
+				buf_cpy[20] = 0x11;	/* New AVP code = 0x11011F5F, undefined */
+				
+				/* Check that we can support this message now */
+				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
+				CHECK( 0, fd_msg_parse_dict( msg, fd_g_dict ) );
+				
+				#if 0
+				fd_msg_dump_walk(0, msg);
+				#endif
+				
+				/* reset */
+				CHECK( 0, fd_msg_free ( msg ) );
+			}
+			
+			CHECK( 0, fd_msg_parse_buffer( &buf, 344, &msg) );
+			CHECK( 0, fd_msg_parse_dict( msg, fd_g_dict ) );
+			#if 0
+			fd_msg_dump_walk(0, msg);
+			#endif
+		}
+		
+		/* Now test the msg_parse_rule function */
+		{
+			struct dict_object * rule;
+			
+			CHECK( 0, fd_msg_parse_rules( msg, fd_g_dict, &rule ) );
+			
+			/* Use the "AVP Test - rules" AVP to test the rules */
+			{
+				struct avp * tavp = NULL;
+				struct avp * tempavp = NULL;
+				struct avp * childavp = NULL;
+				
+				ADD_AVP( msg, MSG_BRW_LAST_CHILD, tavp, 73565, "AVP Test - rules" );
+				
+				/* Create a conforming message first */
+				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp,     0, "AVP Test - no vendor - f32" );
+				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - i64" );
+				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - enumi32" );
+				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - os" );
+				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - os" );
+				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - grouped" );
+				
+				/* Check the message is still conform */
+				CHECK( 0, fd_msg_parse_rules( msg, fd_g_dict, &rule ) );
+				
+				/* The first avp is optional in fixed position, so remove it and check the message is still OK */
+				CHECK( 0, fd_msg_browse ( tavp, MSG_BRW_FIRST_CHILD, &childavp, NULL) );
+				CHECK( 0, fd_msg_free ( childavp ) );
+				CHECK( 0, fd_msg_parse_rules( msg, fd_g_dict, &rule ) );
+				ADD_AVP( tavp, MSG_BRW_FIRST_CHILD, childavp,     0, "AVP Test - no vendor - f32" );
+				
+				
+				/* Now break some rules and check it is detected */
+				#define CHECK_CONFLICT( _msg, _ruleavp, _avpvendor )		{				\
+					struct dict_object * _rule;								\
+					CHECK( EBADMSG,  fd_msg_parse_rules( _msg, fd_g_dict, &_rule ) );			\
+					if ((_ruleavp) == NULL) {								\
+						CHECK( NULL, _rule);								\
+					} else {										\
+						struct dict_rule_data   _ruledata;						\
+						struct dict_object *    _avp;							\
+						struct dict_avp_request _req = { (_avpvendor), 0, (_ruleavp) };			\
+						CHECK( 0, fd_dict_search( fd_g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));	\
+						CHECK( 0, fd_dict_getval( _rule, &_ruledata ) );				\
+						CHECK( _avp, _ruledata.rule_avp );						\
+					}											\
+				}
+
+				{
+					/* Test the FIXED_HEAD rules positions: add another AVP before the third */
+					CHECK( 0, fd_msg_browse ( tavp, MSG_BRW_FIRST_CHILD, &tempavp, NULL) ); /* tempavp is the novendor avp */
+					CHECK( 0, fd_msg_browse ( tempavp, MSG_BRW_NEXT, &tempavp, NULL) );     /* tempavp is the i64 avp */
+					ADD_AVP( tempavp, MSG_BRW_NEXT, childavp, 73565, "AVP Test - os" );
+					
+					CHECK_CONFLICT( msg, "AVP Test - enumi32", 73565 );
+					
+					/* Now remove this AVP */
+					CHECK( 0, fd_msg_free ( childavp ) );
+				}
+				{
+					/* Remove the third AVP, same rule must conflict */
+					CHECK( 0, fd_msg_browse ( tempavp, MSG_BRW_NEXT, &childavp, NULL) );     /* childavp is the enumi32 avp */
+					CHECK( 0, fd_msg_free ( childavp ) );
+					
+					CHECK_CONFLICT( msg, "AVP Test - enumi32", 73565 );
+					
+					/* Add the AVP back */
+					ADD_AVP( tempavp, MSG_BRW_NEXT, childavp, 73565, "AVP Test - enumi32" );
+				}
+				
+				{
+					/* Test the minimum value in the REQUIRED rule: delete one of the os AVPs */
+					CHECK( 0, fd_msg_browse ( childavp, MSG_BRW_NEXT, &tempavp, NULL) );     /* tempavp is the os avp */
+					CHECK( 0, fd_msg_free ( tempavp ) );
+					
+					CHECK_CONFLICT( msg, "AVP Test - os", 73565 );	/* The rule requires at least 2 AVP, we have only 1 */
+					
+					/* Now add this AVP */
+					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" );
+				}
+				{
+					/* Test the maximum value in the REQUIRED rule: add more of the os AVPs */
+					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" );
+					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" );
+					
+					CHECK_CONFLICT( msg, "AVP Test - os", 73565 );	/* The rule requires at most 3 AVP, we have 4 */
+					
+					/* Now delete these AVP */
+					CHECK( 0, fd_msg_free ( tempavp ) );
+					CHECK( 0, fd_msg_browse ( childavp, MSG_BRW_NEXT, &tempavp, NULL) );
+					CHECK( 0, fd_msg_free ( tempavp ) );
+				}
+				
+				{
+					/* Test the maximum value in the OPTIONAL rule: add 2 enumos AVPs */
+					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" );
+					
+					/* The message is still conform */
+					CHECK( 0, fd_msg_parse_rules( msg, fd_g_dict, &rule ) );
+					
+					/* Now break the rule */
+					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" );
+					
+					CHECK_CONFLICT( msg, "AVP Test - enumos", 73565 );	/* The rule requires at most 3 AVP, we have 4 */
+					
+					/* Now delete this AVP */
+					CHECK( 0, fd_msg_free ( tempavp ) );
+				}
+				
+				{
+					/* Test the RULE_FIXED_TAIL rules positions: add another AVP at the end */
+					ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - os" );
+					
+					CHECK_CONFLICT( msg, "AVP Test - grouped", 73565 );
+					
+					/* Now remove this AVP */
+					CHECK( 0, fd_msg_free ( childavp ) );
+				}
+			}
+		}
+	}
+	
+	/* Test the msg_avp_value_interpret and msg_avp_value_encode functions. use the Address type and Host-IP-Address AVPs */
+	{
+		struct dict_object * cer_model = NULL;
+		struct msg * cer = NULL;
+		
+		struct dict_object * hia_model = NULL;
+		struct avp *avp4, *avp6;
+		#define TEST_IP4 "192.168.100.101"
+		char buf4[INET_ADDRSTRLEN];
+		#define	TEST_IP6 "1111:2222:3333:4444:1234:5678:9abc:def0"
+		char buf6[INET6_ADDRSTRLEN];
+		
+		struct sockaddr_storage ss;
+		struct sockaddr_in  sin,  *psin;
+		struct sockaddr_in6 sin6, *psin6;
+		
+		/* Find the CER dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) );
+
+		/* Now find the Host-IP-Address dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &hia_model, ENOENT ) );
+
+		/* Create the msg instance */
+		CHECK( 0, fd_msg_new ( cer_model, 0, &cer ) );
+
+		/* Create the avp instances */
+		CHECK( 0, fd_msg_avp_new ( hia_model, 0, &avp4 ) );
+		CHECK( 0, fd_msg_avp_new ( hia_model, 0, &avp6 ) );
+		
+		/* Set the value of the IP avp */
+		sin.sin_family = AF_INET;
+		CHECK( 1, inet_pton( AF_INET, TEST_IP4, &sin.sin_addr.s_addr ) );
+		CHECK( 0, fd_msg_avp_value_encode ( &sin, avp4 ) );
+		
+		/* Set the value of the IP6 avp */
+		sin6.sin6_family = AF_INET6;
+		CHECK( 1, inet_pton( AF_INET6, TEST_IP6, &sin6.sin6_addr.s6_addr ) );
+		CHECK( 0, fd_msg_avp_value_encode ( &sin6, avp6 ) );
+		
+		/* Add these AVPs in the message */
+		CHECK( 0, fd_msg_avp_add( cer, MSG_BRW_LAST_CHILD, avp4) );
+		CHECK( 0, fd_msg_avp_add( cer, MSG_BRW_LAST_CHILD, avp6) );
+		
+		/* Create the buffer for this message */
+		CHECK( 0, fd_msg_bufferize( cer, &buf, NULL ) );
+		
+		/* Now free the message, we keep only the buffer. */
+		CHECK( 0, fd_msg_free( cer ) );
+		
+		/* Check the content of the buffer is correct (skip command header) */
+		CHECK( 0x00, buf[20] ); /* First AVP (IP4) begins: code 257 = 0x00000101 */
+		CHECK( 0x00, buf[21] );
+		CHECK( 0x01, buf[22] );
+		CHECK( 0x01, buf[23] );
+		CHECK( 0x40, buf[24] ); /* flags: M */
+		CHECK( 0x00, buf[25] ); /* length: 8+6 = 0x00000e */
+		CHECK( 0x00, buf[26] );
+		CHECK( 0x0E, buf[27] );
+		CHECK( 0x00, buf[28] ); /* Value: AddressType 1 */
+		CHECK( 0x01, buf[29] ); 
+		CHECK(  192, buf[30] ); /* 192.168.100.101 */
+		CHECK(  168, buf[31] ); 
+		CHECK(  100, buf[32] ); 
+		CHECK(  101, buf[33] );
+		
+		CHECK( 0x00, buf[34] ); /* Padding */
+		CHECK( 0x00, buf[35] );
+		
+		CHECK( 0x00, buf[36] ); /* Second AVP (IP6) begins: code 257 = 0x00000101 */
+		CHECK( 0x00, buf[37] );
+		CHECK( 0x01, buf[38] );
+		CHECK( 0x01, buf[39] );
+		CHECK( 0x40, buf[40] ); /* flags: M */
+		CHECK( 0x00, buf[41] ); /* length: 8+18 = 0x00001a */
+		CHECK( 0x00, buf[42] );
+		CHECK( 0x1A, buf[43] );
+		CHECK( 0x00, buf[44] ); /* Value: AddressType 2 */
+		CHECK( 0x02, buf[45] ); 
+		CHECK( 0x11, buf[46] ); /* 1111:2222:3333:4444:1234:5678:9abc:def0 */
+		CHECK( 0x11, buf[47] ); 
+		CHECK( 0x22, buf[48] ); 
+		CHECK( 0x22, buf[49] );
+		CHECK( 0x33, buf[50] );
+		CHECK( 0x33, buf[51] );
+		CHECK( 0x44, buf[52] );
+		CHECK( 0x44, buf[53] );
+		CHECK( 0x12, buf[54] );
+		CHECK( 0x34, buf[55] );
+		CHECK( 0x56, buf[56] );
+		CHECK( 0x78, buf[57] );
+		CHECK( 0x9a, buf[58] );
+		CHECK( 0xbc, buf[59] );
+		CHECK( 0xde, buf[60] );
+		CHECK( 0xf0, buf[61] );
+		
+		/* Ok, now let's recreate the message */
+		CHECK( 0, fd_msg_parse_buffer( &buf, 64, &cer) );
+		CHECK( 0, fd_msg_parse_dict( cer, fd_g_dict ) );
+		
+		/* Get the pointers to the first and last AVP */
+		CHECK( 0, fd_msg_browse( cer, MSG_BRW_FIRST_CHILD, &avp4, NULL) );
+		CHECK( 0, fd_msg_browse( cer, MSG_BRW_LAST_CHILD,  &avp6, NULL) );
+		
+		/* Try and interpret the data in the AVPs */
+		CHECK( 0, fd_msg_avp_value_interpret ( avp4, &ss ) );
+		psin = (struct sockaddr_in *)&ss;
+		CHECK( AF_INET, psin->sin_family );
+		CHECK( 0, (inet_ntop( AF_INET, &psin->sin_addr.s_addr, buf4, sizeof(buf4) ) == NULL) ? errno : 0 );
+		CHECK( 0, strcmp( buf4, TEST_IP4 ) );
+		
+		CHECK( 0, fd_msg_avp_value_interpret ( avp6, &ss ) );
+		psin6 = (struct sockaddr_in6 *)&ss;
+		CHECK( AF_INET6, psin6->sin6_family );
+		CHECK( 0, (inet_ntop( AF_INET6, &psin6->sin6_addr.s6_addr, buf6, sizeof(buf6) ) == NULL) ? errno : 0 );
+		CHECK( 0, strcasecmp( buf6, TEST_IP6 ) );
+		
+		/* Ok, it's done */
+		CHECK( 0, fd_msg_free( cer ) );
+	}
+	
+	/* Check proper encoding / decoding for all basic types of AVP */
+	{
+		{
+			struct dict_avp_data avp_data = { 91001, 0, "AVP Test 2 - os", 0, 0, AVP_TYPE_OCTETSTRING };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		{
+			struct dict_avp_data avp_data = { 91002, 0, "AVP Test 2 - i32", 0, 0, AVP_TYPE_INTEGER32 };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		{
+			struct dict_avp_data avp_data = { 91003, 0, "AVP Test 2 - i64", 0, 0, AVP_TYPE_INTEGER64 };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		{
+			struct dict_avp_data avp_data = { 91004, 0, "AVP Test 2 - u32", 0, 0, AVP_TYPE_UNSIGNED32 };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		{
+			struct dict_avp_data avp_data = { 91005, 0, "AVP Test 2 - u64", 0, 0, AVP_TYPE_UNSIGNED64 };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		{
+			struct dict_avp_data avp_data = { 91006, 0, "AVP Test 2 - f32", 0, 0, AVP_TYPE_FLOAT32 };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		{
+			struct dict_avp_data avp_data = { 91007, 0, "AVP Test 2 - f64", 0, 0, AVP_TYPE_FLOAT64 };
+			CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		
+		{
+			struct dict_object * cmd_model = NULL;
+			struct msg         * msg = NULL;
+			struct dict_object * avp_model = NULL;
+			struct avp         * avp = NULL;
+			union avp_value      value;
+			struct avp         * avpi = NULL;
+			struct avp         * avpch = NULL;
+			struct avp_hdr     * avpdata = NULL;
+			struct msg_hdr     * msgdata = NULL;
+
+			CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) );
+
+			/* Create a message */
+			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
+			CHECK( 0, fd_msg_hdr ( msg, &msgdata ) );
+			
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0, 	"AVP Test 2 - os" );
+			value.os.data = (unsigned char *) "waaad";
+			value.os.len = 6;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - i32" );
+			value.i32 = 0x123456;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - i32" );
+			value.i32 = -0x123456;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - i64" );
+			value.i64 = 0x11223344556677LL;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - i64" );
+			value.i64 = -0x11223344556677LL;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - u32" );
+			value.u32 = 0xFEDCBA98;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - u64" );
+			value.u64 = 0x123456789abcdef0LL;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - f32" );
+			value.f32 = 2097153.0F;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - f64" );
+			value.f64 = -1099511627777LL;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+			
+			/* Ok now bufferize */
+			CHECK( 0, fd_msg_bufferize( msg, &buf, NULL ) );
+			
+			/* Test the first bytes */
+			CHECK( 0x01, buf[0] ); /* Version */
+			CHECK( 0x00, buf[1] ); /* Length: 148 = 0x000094 */
+			CHECK( 0x00, buf[2] );
+			CHECK( 0x94, buf[3] );
+			CHECK( 0x80, buf[4] ); /* flags: only "R" is set. */
+			CHECK( 0x01, buf[5] ); /* Command code: 73573 = 0x011F65 */
+			CHECK( 0x1F, buf[6] );
+			CHECK( 0x65, buf[7] );
+			CHECK( 0x00, buf[8] ); /* App ID */
+			CHECK( 0x01, buf[9] ); 
+			CHECK( 0x1F, buf[10] );
+			CHECK( 0x5E, buf[11] );
+			CHECK( 0x00, buf[12] ); /* hop-by-hop id */
+			CHECK( 0x00, buf[13] );
+			CHECK( 0x00, buf[14] );
+			CHECK( 0x00, buf[15] );
+			CHECK( 0x00, buf[16] ); /* end-to-end id */
+			CHECK( 0x00, buf[17] );
+			CHECK( 0x00, buf[18] );
+			CHECK( 0x00, buf[19] );
+			
+			CHECK( 0x00, buf[20] ); /* First AVP (AVP Test 2 - os) begin: code 91001 = 0x00016379 */
+			CHECK( 0x01, buf[21] );
+			CHECK( 0x63, buf[22] );
+			CHECK( 0x79, buf[23] );
+			CHECK( 0x00, buf[24] ); /* flags: 0 */
+			CHECK( 0x00, buf[25] ); /* length: 14 = 0x00000e */
+			CHECK( 0x00, buf[26] );
+			CHECK( 0x0e, buf[27] );
+			
+			CHECK( 0x77, buf[28] ); /* "waaad\0" + padding */
+			CHECK( 0x61, buf[29] );
+			CHECK( 0x61, buf[30] );
+			CHECK( 0x61, buf[31] );
+			CHECK( 0x64, buf[32] );
+			CHECK( 0x00, buf[33] );
+			CHECK( 0x00, buf[34] );
+			CHECK( 0x00, buf[35] );
+			
+			/* 36 ~ 43 : 2nd AVP header (size at last octet) */
+			CHECK( 0x0c, buf[43] );
+			CHECK( 0x00, buf[44] ); /* 0x123456 stored in integer32 in network byte order */
+			CHECK( 0x12, buf[45] );
+			CHECK( 0x34, buf[46] );
+			CHECK( 0x56, buf[47] );
+			
+			/* 48 ~ 55 : next AVP header */
+			CHECK( 0xff, buf[56] ); /* -0x123456 stored in integer32 in network byte order. */ 
+			CHECK( 0xed, buf[57] ); /* We assume that two's complement is the correct representation, although it's not clearly specified. */
+			CHECK( 0xcb, buf[58] ); /* 00 12 34 56 inversed => FF ED CB A9 */
+			CHECK( 0xaa, buf[59] ); /* then "+1" => FF ED CB AA */
+			
+			/* 60 ~ 67 : next header */
+			CHECK( 0x10, buf[67] ); /* (the size) */
+			CHECK( 0x00, buf[68] ); /* 0x11223344556677 in network byte order */
+			CHECK( 0x11, buf[69] );
+			CHECK( 0x22, buf[70] );
+			CHECK( 0x33, buf[71] );
+			CHECK( 0x44, buf[72] );
+			CHECK( 0x55, buf[73] );
+			CHECK( 0x66, buf[74] );
+			CHECK( 0x77, buf[75] );
+			
+			/* 76 ~ 83 : next header */
+			CHECK( 0xFF, buf[84] ); /*  - 0x11223344556677 (in two's complement) */
+			CHECK( 0xEE, buf[85] ); /* gives FF EE DD CC BB AA 99 89 */
+			CHECK( 0xDD, buf[86] );
+			CHECK( 0xCC, buf[87] );
+			CHECK( 0xBB, buf[88] );
+			CHECK( 0xAA, buf[89] );
+			CHECK( 0x99, buf[90] );
+			CHECK( 0x89, buf[91] );
+			
+			/* 92 ~ 99 : next header */
+			CHECK( 0x0c, buf[99] ); /* (the size) */
+			CHECK( 0xFE, buf[100]); /* 0xFEDCBA98 in network byte order */
+			CHECK( 0xDC, buf[101]);
+			CHECK( 0xBA, buf[102]);
+			CHECK( 0x98, buf[103]);
+			
+			/* 104 ~ 111 : next header */
+			CHECK( 0x10, buf[111] ); /* (the size) */
+			CHECK( 0x12, buf[112]); /* 0x123456789abcdef0LL in network byte order */
+			CHECK( 0x34, buf[113]);
+			CHECK( 0x56, buf[114]);
+			CHECK( 0x78, buf[115]);
+			CHECK( 0x9a, buf[116]);
+			CHECK( 0xbc, buf[117]);
+			CHECK( 0xde, buf[118]);
+			CHECK( 0xf0, buf[119]);
+			
+			/* 120 ~ 127 : next header */
+			CHECK( 0x0c, buf[127] ); /* (the size) */
+			CHECK( 0x4a, buf[128]); /* http://en.wikipedia.org/wiki/IEEE_754-1985 to get descvription of the format */
+			CHECK( 0x00, buf[129]); /* v = 2097153 = 2^21 + 2 ^ 0; sign : "+", 2^21 <= v < 2^22 => exponent = 21; biaised on 8 bits => 21 + 127 => 100 1010 0 */
+			CHECK( 0x00, buf[130]); /* v = (+1) * (1 ^ 21) * ( 1 + 2^-21 ) => significand 000 0000 0000 0000 0000 0100 */
+			CHECK( 0x04, buf[131]); /* result: 4a 00 00 04 */
+			
+			/* 132 ~ 139 : next header */
+			CHECK( 0x10, buf[139] ); /* (the size) */
+			CHECK( 0xc2, buf[140]); /* -1099511627777L ( 2^40 + 1 ) in network byte order */
+			CHECK( 0x70, buf[141]); /* sign: - => most significant bit = 1 */
+			CHECK( 0x00, buf[142]); /* 2^40 <= v < 2^41 => biaised exponent on 11 bits: 1023 + 40: 100 0010  0111 */
+			CHECK( 0x00, buf[143]); /* significand: 1 + 2^-40 => 0000  0000 0000  0000 0000  0000 0000  0000 0000  0001 0000  0000 0000 */
+			CHECK( 0x00, buf[144]); /* result: c2 70 00 00 00 00 10 00 */
+			CHECK( 0x00, buf[145]);
+			CHECK( 0x10, buf[146]);
+			CHECK( 0x00, buf[147]);
+			
+			
+			
+			/* Okay, now delete the message and parse the buffer, then check we obtain the same values back */
+			#if 0
+			fd_msg_dump_walk(0, msg);
+			#endif
+			CHECK( 0, fd_msg_free( msg ) );
+			
+			CHECK( 0, fd_msg_parse_buffer( &buf, 148, &msg) );
+			CHECK( 0, fd_msg_parse_dict( msg, fd_g_dict ) );
+			#if 0
+			fd_msg_dump_walk(0, msg);
+			#endif
+			
+			CHECK( 0, fd_msg_browse ( msg, MSG_BRW_FIRST_CHILD, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( 6, avpdata->avp_value->os.len );
+			CHECK( 'w', (char)(avpdata->avp_value->os.data[0]) );
+			CHECK( 'a', (char)(avpdata->avp_value->os.data[1]) );
+			CHECK( 'd', (char)(avpdata->avp_value->os.data[4]) );
+			CHECK( '\0', (char)(avpdata->avp_value->os.data[5]) );
+			
+			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( 0x123456, avpdata->avp_value->i32 );
+			
+			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( -0x123456, avpdata->avp_value->i32 );
+			
+			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( 0x11223344556677LL, avpdata->avp_value->i64 );
+			
+			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( -0x11223344556677LL, avpdata->avp_value->i64 );
+			
+			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( 0xFEDCBA98, avpdata->avp_value->u32 );
+			
+			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( 0x123456789abcdef0LL, avpdata->avp_value->u64 );
+			
+			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( 2097153.0F, avpdata->avp_value->f32 );
+			
+			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
+			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
+			CHECK( -1099511627777LL, avpdata->avp_value->f64 );
+			
+			CHECK( 0, fd_msg_free( msg ) );
+		}
+	}
+	
+
+	/* That's all for the tests yet */
+	PASSTEST();
+} 
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/tests/testmq.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,423 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#include "tests.h"
+
+/* Structure for testing threashold function */
+static struct thrh_test {
+	struct mqueue * queue; /* pointer to the queue */
+	int		h_calls; /* number of calls of h_cb */
+	int		l_calls; /* number of calls of l_cb */
+} thrh_td;
+
+/* Callbacks for threasholds test */
+void thrh_cb_h(struct mqueue *queue, void **data)
+{
+	if (thrh_td.h_calls == thrh_td.l_calls) {
+		CHECK( NULL, *data );
+		*data = &thrh_td;
+	} else {
+		CHECK( *data, &thrh_td );
+	}
+	CHECK( queue, thrh_td.queue );
+	
+	/* Update the count */
+	thrh_td.h_calls ++;
+}
+void thrh_cb_l(struct mqueue *queue, void **data)
+{
+	CHECK( 1, data ? 1 : 0 );
+	CHECK( *data, &thrh_td );
+
+	/* Check the queue parameter is correct */
+	CHECK( queue, thrh_td.queue );
+	
+	/* Update the count */
+	thrh_td.l_calls ++;
+	/* Cleanup the data ptr if needed */
+	if (thrh_td.l_calls == thrh_td.h_calls)
+		*data = NULL;
+	/* done */
+}
+
+
+/* Structure that is passed to the test function */
+struct test_data {
+	struct mqueue     * queue; /* pointer to the queue */
+	pthread_barrier_t * bar;   /* if not NULL, barrier to synchronize before getting messages */
+	struct timespec   * ts;	   /* if not NULL, use a timedget instead of a get */
+	int		    nbr;   /* number of messages to retrieve from the queue */
+};
+
+/* The test function, to be threaded */
+static void * test_fct(void * data)
+{
+	int ret = 0, i;
+	struct msg * msg = NULL;
+	struct test_data * td = (struct test_data *) data;
+	
+	if (td->bar != NULL) {
+		ret = pthread_barrier_wait(td->bar);
+		if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
+			CHECK( 0, ret);
+		} else {
+			CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* just for the traces */
+		}
+	}
+	
+	for (i=0; i< td->nbr; i++) {
+		if (td->ts != NULL) {
+			CHECK( 0, fd_mq_timedget(td->queue, &msg, td->ts) );
+		} else {
+			CHECK( 0, fd_mq_get(td->queue, &msg) );
+		}
+	}
+	
+	return NULL;
+}
+
+
+/* Main test routine */
+int main(int argc, char *argv[])
+{
+	struct timespec ts;
+	
+	struct msg * msg1 = NULL;
+	struct msg * msg2 = NULL;
+	struct msg * msg3 = NULL;
+	
+	/* First, initialize the daemon modules */
+	INIT_FD();
+	
+	/* Prolog: create the messages */
+	{
+		struct dict_object * acr_model = NULL;
+		struct dict_object * cer_model = NULL;
+		struct dict_object * dwr_model = NULL;
+
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", 			&acr_model, ENOENT ) );
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", 	&cer_model, ENOENT ) );
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request",		&dwr_model, ENOENT ) );
+		CHECK( 0, fd_msg_new ( acr_model, 0, &msg1 ) );
+		CHECK( 0, fd_msg_new ( cer_model, 0, &msg2 ) );
+		CHECK( 0, fd_msg_new ( dwr_model, 0, &msg3 ) );
+	}
+	
+	/* Basic operation */
+	{
+		struct mqueue * queue = NULL;
+		int count;
+		struct msg * msg  = NULL;
+		
+		/* Create the queue */
+		CHECK( 0, fd_mq_new(&queue) );
+		
+		/* Check the count is 0 */
+		CHECK( 0, fd_mq_length(queue, &count) );
+		CHECK( 0, count);
+		
+		/* Now enqueue */
+		msg = msg1;
+		CHECK( 0, fd_mq_post(queue, &msg) );
+		msg = msg2;
+		CHECK( 0, fd_mq_post(queue, &msg) );
+		msg = msg3;
+		CHECK( 0, fd_mq_post(queue, &msg) );
+		
+		/* Check the count is 3 */
+		CHECK( 0, fd_mq_length(queue, &count) );
+		CHECK( 3, count);
+		
+		/* Retrieve the first message using fd_mq_get */
+		CHECK( 0, fd_mq_get(queue, &msg) );
+		CHECK( msg1, msg);
+		CHECK( 0, fd_mq_length(queue, &count) );
+		CHECK( 2, count);
+		
+		/* Retrieve the second message using fd_mq_timedget */
+		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
+		ts.tv_sec += 1; /* Set the timeout to 1 second */
+		CHECK( 0, fd_mq_timedget(queue, &msg, &ts) );
+		CHECK( msg2, msg);
+		CHECK( 0, fd_mq_length(queue, &count) );
+		CHECK( 1, count);
+		
+		/* Retrieve the third message using meq_tryget */
+		CHECK( 0, fd_mq_tryget(queue, &msg) );
+		CHECK( msg3, msg);
+		CHECK( 0, fd_mq_length(queue, &count) );
+		CHECK( 0, count);
+		
+		/* Check that another meq_tryget does not block */
+		CHECK( EWOULDBLOCK, fd_mq_tryget(queue, &msg) );
+		CHECK( 0, fd_mq_length(queue, &count) );
+		CHECK( 0, count);
+		
+		/* We're done for basic tests */
+		CHECK( 0, fd_mq_del(&queue) );
+	}
+	
+	/* Test robustness, ensure no messages are lost */
+	{
+#define NBR_MSG		200
+#define NBR_THREADS	60
+		struct mqueue  		*queue = NULL;
+		pthread_barrier_t	 bar;
+		struct test_data	 td_1;
+		struct test_data	 td_2;
+		struct msg   		*msgs[NBR_MSG * NBR_THREADS * 2], *msg;
+		pthread_t  		 thr [NBR_THREADS * 2];
+		struct dict_object	*dwr_model = NULL;
+		int 			 count;
+		int			 i;
+		
+		/* Create the queue */
+		CHECK( 0, fd_mq_new(&queue) );
+		
+		/* Create the barrier */
+		CHECK( 0, pthread_barrier_init(&bar, NULL, NBR_THREADS * 2 + 1) );
+		
+		/* Initialize the ts */
+		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
+		ts.tv_sec += 2; /* Set the timeout to 2 second */
+		
+		/* Create the messages */
+		CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request",		&dwr_model, ENOENT ) );
+		for (i = 0; i < NBR_MSG * NBR_THREADS * 2; i++) {
+			CHECK( 0, fd_msg_new ( dwr_model, 0, &msgs[i] ) );
+		}
+		
+		/* Initialize the test data structures */
+		td_1.queue = queue;
+		td_1.bar = &bar;
+		td_1.ts  = &ts;
+		td_1.nbr = NBR_MSG;
+		td_2.queue = queue;
+		td_2.bar = &bar;
+		td_2.ts  = NULL;
+		td_2.nbr = NBR_MSG;
+		
+		/* Create the threads */
+		for (i=0; i < NBR_THREADS * 2; i++) {
+			CHECK( 0, pthread_create( &thr[i], NULL, test_fct, (i & 1) ? &td_1 : &td_2 ) );
+		}
+		
+		/* Synchronize everyone */
+		{
+			int ret = pthread_barrier_wait(&bar);
+			if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
+				CHECK( 0, ret);
+			} else {
+				CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* for trace only */
+			}
+		}
+		
+		/* Now post all the messages */
+		for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) {
+			msg = msgs[i];
+			CHECK( 0, fd_mq_post(queue, &msg) );
+		}
+		
+		/* Join all threads. This blocks if messages are lost... */
+		for (i=0; i < NBR_THREADS * 2; i++) {
+			CHECK( 0, pthread_join( thr[i], NULL ) );
+		}
+		
+		/* Check the count of the queue is back to 0 */
+		CHECK( 0, fd_mq_length(queue, &count) );
+		CHECK( 0, count);
+		
+		/* Destroy this queue and the messages */
+		CHECK( 0, fd_mq_del(&queue) );
+		for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) {
+			CHECK( 0, fd_msg_free(  msgs[i] ) );
+		}
+	}
+	
+	/* Test thread cancelation */
+	{
+		struct mqueue      	*queue = NULL;
+		pthread_barrier_t	 bar;
+		struct test_data	 td;
+		pthread_t		 th;
+		
+		/* Create the queue */
+		CHECK( 0, fd_mq_new(&queue) );
+		
+		/* Create the barrier */
+		CHECK( 0, pthread_barrier_init(&bar, NULL, 2) );
+		
+		/* Initialize the ts */
+		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
+		ts.tv_sec += 2; /* Set the timeout to 2 second */
+		
+		/* Initialize the test data structures */
+		td.queue = queue;
+		td.bar = &bar;
+		td.ts  = &ts;
+		td.nbr = 1;
+		
+		/* Create the thread */
+		CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) );
+		
+		/* Wait for the thread to be running */
+		{
+			int ret = pthread_barrier_wait(&bar);
+			if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
+				CHECK( 0, ret);
+			} else {
+				CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret );
+			}
+		}
+		
+		/* Now cancel the thread */
+		CHECK( 0, pthread_cancel( th ) );
+		
+		/* Join it */
+		CHECK( 0, pthread_join( th, NULL ) );
+		
+		/* Do the same with the other function */
+		td.ts  = NULL;
+		
+		/* Create the thread */
+		CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) );
+		
+		/* Wait for the thread to be running */
+		{
+			int ret = pthread_barrier_wait(&bar);
+			if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
+				CHECK( 0, ret);
+			} else {
+				CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret );
+			}
+		}
+		
+		/* Now cancel the thread */
+		CHECK( 0, pthread_cancel( th ) );
+		
+		/* Join it */
+		CHECK( 0, pthread_join( th, NULL ) );
+		
+		/* Destroy the queue */
+		CHECK( 0, fd_mq_del(&queue) );
+	}
+	
+	/* Test the threashold function */
+	{
+		struct mqueue * queue = NULL;
+		int i;
+		struct msg * msg  = NULL;
+		
+		/* Create the queue */
+		CHECK( 0, fd_mq_new(&queue) );
+		
+		/* Prepare the test data */
+		memset(&thrh_td, 0, sizeof(thrh_td));
+		thrh_td.queue = queue;
+		
+		/* Set the thresholds for the queue */
+		CHECK( 0, fd_mq_setthrhd ( queue, NULL, 6, thrh_cb_h, 4, thrh_cb_l ) );
+		
+		/* Post 5 messages, no cb must be called. */
+		for (i=0; i<5; i++) {
+			msg = msg1;
+			CHECK( 0, fd_mq_post(queue, &msg) );
+		} /* 5 msg in queue */
+		CHECK( 0, thrh_td.h_calls );
+		CHECK( 0, thrh_td.l_calls );
+		
+		/* Get all these messages, and check again */
+		for (i=0; i<5; i++) {
+			CHECK( 0, fd_mq_get(queue, &msg) );
+		} /* 0 msg in queue */
+		CHECK( 0, thrh_td.h_calls );
+		CHECK( 0, thrh_td.l_calls );
+		
+		/* Now, post 6 messages, the high threashold */
+		for (i=0; i<6; i++) {
+			msg = msg1;
+			CHECK( 0, fd_mq_post(queue, &msg) );
+		} /* 6 msg in queue */
+		CHECK( 1, thrh_td.h_calls );
+		CHECK( 0, thrh_td.l_calls );
+		
+		/* Remove 2 messages, to reach the low threshold */
+		for (i=0; i<2; i++) {
+			CHECK( 0, fd_mq_get(queue, &msg) );
+		} /* 4 msg in queue */
+		CHECK( 1, thrh_td.h_calls );
+		CHECK( 1, thrh_td.l_calls );
+		
+		/* Come again at the high threshold */
+		for (i=0; i<2; i++) {
+			msg = msg1;
+			CHECK( 0, fd_mq_post(queue, &msg) );
+		} /* 6 msg in queue */
+		CHECK( 2, thrh_td.h_calls );
+		CHECK( 1, thrh_td.l_calls );
+		
+		/* Suppose the queue continues to grow */
+		for (i=0; i<6; i++) {
+			msg = msg1;
+			CHECK( 0, fd_mq_post(queue, &msg) );
+		} /* 12 msg in queue */
+		CHECK( 3, thrh_td.h_calls );
+		CHECK( 1, thrh_td.l_calls );
+		for (i=0; i<5; i++) {
+			msg = msg1;
+			CHECK( 0, fd_mq_post(queue, &msg) );
+		} /* 17 msg in queue */
+		CHECK( 3, thrh_td.h_calls );
+		CHECK( 1, thrh_td.l_calls );
+		
+		/* Now the queue goes back to 0 messages */
+		for (i=0; i<17; i++) {
+			CHECK( 0, fd_mq_get(queue, &msg) );
+		} /* 0 msg in queue */
+		CHECK( 3, thrh_td.h_calls );
+		CHECK( 3, thrh_td.l_calls );
+		
+		/* We're done for this test */
+		CHECK( 0, fd_mq_del(&queue) );
+	}
+	
+	/* Delete the messages */
+	CHECK( 0, fd_msg_free( msg1 ) );
+	CHECK( 0, fd_msg_free( msg2 ) );
+	CHECK( 0, fd_msg_free( msg3 ) );
+
+	/* That's all for the tests yet */
+	PASSTEST();
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freediameter/tests/tests.h	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,132 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+/* This file contains the definition of our test harness.
+ * The harness is very simple yet.
+ * It may be interessant to go to dejagnu later...
+ *
+ */
+#ifndef _TESTS_H
+#define _TESTS_H
+
+#include "fd.h"
+
+#include <pthread.h>
+#include <errno.h>
+
+/* Test timeout duration, unless -n is passed on the command line */
+#ifndef TEST_TIMEOUT
+#define TEST_TIMEOUT	5	/* 5 seconds */
+#endif /* TEST_TIMEOUT */
+
+static int test_verbosity = 0;
+
+/* Standard includes */
+#include <getopt.h>
+#include <time.h>
+#include <libgen.h>
+
+/* Define the return code values */
+#define PASS	0
+#define FAIL	1
+
+/* Define the macro to fail a test with a message */
+#define FAILTEST( message... ){				\
+	fprintf(stderr, ## message);			\
+	exit(FAIL);					\
+}
+
+/* Define the macro to pass a test */
+#define PASSTEST( ){					\
+	fprintf(stderr, "Test %s passed\n", __FILE__);	\
+	TRACE_DEBUG(INFO, "Test passed");		\
+	exit(PASS);					\
+}
+
+/* Define the standard check routines */
+#define CHECK( _val, _assert ){				\
+	if (test_verbosity > 0) {			\
+		fprintf(stderr,				\
+			"%s:%-4d: CHECK( " #_assert " == "\
+				#_val " )\n",		\
+			__FILE__, 			\
+			__LINE__);			\
+	}{						\
+	__typeof__ (_val) __ret = (_assert);		\
+	if (__ret != (_val)) {				\
+		FAILTEST( "%s:%d: %s == %lx != %lx\n",	\
+			__FILE__,			\
+			__LINE__,			\
+			#_assert,			\
+			(unsigned long)__ret,		\
+			(unsigned long)(_val));		\
+	}}						\
+}
+
+/* Minimum inits */
+#define INIT_FD() {					\
+	pthread_key_create(&fd_log_thname, free);	\
+	fd_log_threadname(basename(__FILE__));		\
+	CHECK( 0, fd_dict_init(&fd_g_dict) );		\
+	CHECK( 0, fd_dict_base_protocol(fd_g_dict) );	\
+	parse_cmdline(argc, argv);			\
+}
+
+static inline void parse_cmdline(int argc, char * argv[]) {
+	int c;
+	int no_timeout = 0;
+	while ((c = getopt (argc, argv, "dqn")) != -1) {
+		switch (c) {
+			case 'd':	/* Increase verbosity of debug messages.  */
+				test_verbosity++;
+				break;
+				
+			case 'q':	/* Decrease verbosity then remove debug messages.  */
+				test_verbosity--;
+				break;
+			
+			case 'n':	/* Disable the timeout of the test.  */
+				no_timeout = 1;
+				break;
+			
+			default:	/* bug: option not considered.  */
+				return;
+		}
+	}
+	if (!no_timeout)
+		alarm(TEST_TIMEOUT);
+}
+ 
+#endif /* _TESTS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/freediameter/CMakeLists.txt	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,84 @@
+#CMake configuration for freediameter include directory
+
+Project("FreeDiameter include directory" C)
+
+########################
+# Configurable parameters
+
+# Name of the default configuration file
+OPTION(DEFAULT_CONF_FILE "Default path to configuration file?" OFF)
+
+# Disable SCTP support completly ?
+OPTION(DISABLE_SCTP "Disable SCTP support?")
+
+
+########################
+# System checks 
+
+INCLUDE (CheckLibraryExists)
+INCLUDE (CheckFunctionExists)
+INCLUDE (CheckIncludeFiles)
+INCLUDE (CheckSymbolExists) 
+INCLUDE (TestBigEndian)
+
+# We use dlopen and dlclose
+SET(FD_LIBS ${FD_LIBS} ${CMAKE_DL_LIBS})
+
+# We need the threads library (pthread)
+INCLUDE(FindThreads)
+SET(FD_LIBS ${FD_LIBS} ${CMAKE_THREAD_LIBS_INIT})
+
+# We need the clock_gettime function ( -lrt, -lposix4 )
+CHECK_FUNCTION_EXISTS (clock_gettime HAVE_CLOCK_GETTIME)
+IF (HAVE_CLOCK_GETTIME)
+   SET(CLOCK_GETTIME_LIBS "")
+ELSE (HAVE_CLOCK_GETTIME)
+   CHECK_LIBRARY_EXISTS (rt clock_gettime "" HAVE_LIBRT)
+   IF (HAVE_LIBRT)
+     SET(CLOCK_GETTIME_LIBS "-lrt")
+   ELSE (HAVE_LIBRT)
+     CHECK_LIBRARY_EXISTS (posix4 clock_gettime "" HAVE_LIBPOSIX4)
+     IF (HAVE_LIBPOSIX4)
+       SET(CLOCK_GETTIME_LIBS "-lposix4")
+     ENDIF (HAVE_LIBPOSIX4)
+   ENDIF (HAVE_LIBRT)
+ENDIF (HAVE_CLOCK_GETTIME)
+SET(FD_LIBS ${FD_LIBS} ${CLOCK_GETTIME_LIBS})
+
+# We need the sctp_getladdrs function ( -lsctp )
+# We need the IPPROTO_SCTP symbol from sys/socket.h, netinet/in.h or netinet/sctp.h
+IF(NOT DISABLE_SCTP)
+	CHECK_FUNCTION_EXISTS(sctp_getladdrs HAVE_NATIVE_SCTP)
+	IF(NOT HAVE_NATIVE_SCTP)
+		FIND_PACKAGE(SCTP REQUIRED)
+		INCLUDE_DIRECTORIES(${SCTP_INCLUDE_DIRS})
+		SET(FD_LIBS ${FD_LIBS} ${SCTP_LIBRARIES})
+	ENDIF(NOT HAVE_NATIVE_SCTP)
+ENDIF(NOT DISABLE_SCTP)
+
+# Check byte ordering
+TEST_BIG_ENDIAN(HOST_BIG_ENDIAN)
+
+# We need the getopt_long function
+CHECK_FUNCTION_EXISTS (getopt_long HAVE_LONG_OPTIONS)
+IF (NOT HAVE_LONG_OPTIONS)
+   MESSAGE(SEND_ERROR "The getopt_long function is not found, please add needed library in build system")
+ENDIF (NOT HAVE_LONG_OPTIONS)
+
+# Check if ntohll is provided on the system
+CHECK_SYMBOL_EXISTS(ntohll "" HAVE_NTOHLL)
+
+# malloc.h ?
+CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
+
+# The default configuration file name
+IF (NOT DEFAULT_CONF_FILE)
+   SET(DEFAULT_CONF_FILE "freediameter.conf")
+ENDIF (NOT DEFAULT_CONF_FILE)
+##########################
+
+# Generate the host.h file
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/freediameter-host.h.in ${CMAKE_CURRENT_BINARY_DIR}/freediameter-host.h)
+
+# Save the FD_LIBS for parent scope
+SET(FD_LIBS ${FD_LIBS} PARENT_SCOPE)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/freediameter/freediameter-host.h.in	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,54 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+/* Configuration from compile-time */
+#ifndef FD_IS_CONFIG
+#define FD_IS_CONFIG
+
+#cmakedefine HAVE_NTOHLL
+#cmakedefine HAVE_MALLOC_H
+
+#cmakedefine HOST_BIG_ENDIAN @HOST_BIG_ENDIAN@
+
+#cmakedefine DISABLE_SCTP
+
+#cmakedefine PROJECT_NAME "@PROJECT_NAME@"
+#cmakedefine CMAKE_PROJECT_NAME "@CMAKE_PROJECT_NAME@"
+#cmakedefine PROJECT_VERSION "@PROJECT_VERSION@"
+#cmakedefine PROJECT_COPYRIGHT "@PROJECT_COPYRIGHT@"
+
+#cmakedefine DEFAULT_CONF_FILE "@DEFAULT_CONF_FILE@"
+
+#endif /* FD_IS_CONFIG */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/freediameter/freediameter.h	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,113 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#ifndef _FREEDIAMETER_H
+#define _FREEDIAMETER_H
+
+
+#include <freediameter/libfreediameter.h>
+
+
+/* The global dictionary */
+extern struct dictionary * fd_g_dict;
+
+
+/***************************************/
+/*   Sending a message on the network  */
+/***************************************/
+
+/*
+ * FUNCTION:	fd_msg_send
+ *
+ * PARAMETERS:
+ *  pmsg 	: Location of the message to be sent on the network (set to NULL on function return to avoid double deletion).
+ *  anscb	: A callback to be called when answer is received, if msg is a request (optional)
+ *  anscb_data	: opaque data to be passed back to the anscb when it is called.
+ *
+ * DESCRIPTION: 
+ *   Sends a message on the network. (actually simply queues it in a global queue, to be picked by a daemon's thread)
+ * For requests, the end-to-end id must be set (see fd_msg_get_eteid / MSGFL_ALLOC_ETEID).
+ * For answers, the message must be created with function fd_msg_new_answ.
+ *
+ * The routing module will handle sending to the correct peer, usually based on the Destination-Realm / Destination-Host AVP.
+ *
+ * If the msg is a request, there are two ways of receiving the answer:
+ *  - either having registered a callback in the dispatch module (see disp_register)
+ *  - or provide a callback as parameter here. If such callback is provided, it is called before the dispatch callbacks.
+ *    The prototype for this callback function is:
+ *     void anscb(void * data, struct msg ** answer)
+ *	where:
+ *		data   : opaque data that was registered along with the callback.
+ *		answer : location of the pointer to the answer.
+ *      note1: on function return, if *answer is not NULL, the message is passed to the dispatch module for regular callbacks.
+ *	       otherwise, the callback must take care of freeing the message (msg_free).
+ *	note2: the opaque data is not freed by the daemon in any case, extensions should ensure clean handling in waaad_ext_fini.
+ * 
+ * If no callback is registered to handle an answer, the message is discarded and an error is logged.
+ *
+ * RETURN VALUE:
+ *  0      	: The message has been queued for sending (sending may fail asynchronously).
+ *  EINVAL 	: A parameter is invalid (ex: anscb provided but message is not a request).
+ *  ...
+ */
+int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data );
+
+/*
+ * FUNCTION:	fd_msg_rescode_set
+ *
+ * PARAMETERS:
+ *  msg		: A msg object -- it must be an answer.
+ *  dict	: dictionary to use for AVP definitions
+ *  rescode	: The name of the returned error code (ex: "DIAMETER_INVALID_AVP")
+ *  errormsg    : (optional) human-readable error message to put in Error-Message AVP
+ *  optavp	: (optional) If provided, the content will be put inside a Failed-AVP
+ *  type_id	: 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host.
+ *
+ * DESCRIPTION: 
+ *   This function adds a Result-Code AVP to a message, and optionally
+ *  - sets the 'E' error flag in the header,
+ *  - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0      	: an error occurred.
+ */
+int fd_msg_rescode_set( struct msg * msg, struct dictionary * dict, char * rescode, char * errormsg, struct avp * optavp, int type_id );
+
+/* The following functions are used to achieve frequent operations on the messages */
+int fd_msg_add_origin ( struct msg * msg, struct dictionary * dict, int osi ); /* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */
+
+
+#endif /* _FREEDIAMETER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/freediameter/libfreediameter.h	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,2020 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+/* This file contains the definitions of functions and types used by the libfreediameter library.
+ *
+ * This library is meant to be used by both the freediameter daemon and its extensions.
+ *
+ * It provides the tools to manipulate Diameter messages and related data.
+ *
+ * This file should always be included as #include <freediameter/libfreediameter.h>
+ * Note that this library does not store any state. The daemon must pass the pointer to 
+ * the dictionary and other global objects to all extensions that use the libfreediameter 
+ * library.
+ */
+
+#ifndef _LIBFREEDIAMETER_H
+#define _LIBFREEDIAMETER_H
+
+#ifndef FD_IS_CONFIG
+#error "You must include 'freediameter-host.h' before this file."
+#endif /* FD_IS_CONFIG */
+
+#include <pthread.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*============================================================*/
+/*                          DEBUG                             */
+/*============================================================*/
+#ifndef ASSERT
+#define ASSERT(x) assert(x)
+#endif /* ASSERT */
+
+/*
+ * FUNCTION:	fd_log_debug
+ *
+ * PARAMETERS:
+ *  format 	: Same format string as in the printf function
+ *  ...		: Same list as printf
+ *
+ * DESCRIPTION: 
+ *  Log internal information for use of developpers only.
+ * The format and arguments may contain UTF-8 encoded data. The
+ * output medium (file or console) is expected to support this encoding.
+ *
+ * This function assumes that a global mutex called "fd_log_lock" exists
+ * in the address space of the current process.
+ *
+ * RETURN VALUE:
+ *  None.
+ */
+void fd_log_debug ( char * format, ... );
+extern pthread_mutex_t	fd_log_lock;
+
+/*
+ * FUNCTION:	fd_log_threadname
+ *
+ * PARAMETERS:
+ *  name 	: \0-terminated string containing a name to identify the current thread.
+ *
+ * DESCRIPTION: 
+ *  Name the current thread, useful for debugging multi-threaded problems.
+ *
+ * This function assumes that a global thread-specific key called "fd_log_thname" exists
+ * in the address space of the current process.
+ *
+ * RETURN VALUE:
+ *  None.
+ */
+void fd_log_threadname ( char * name );
+extern pthread_key_t	fd_log_thname;
+
+/*
+ * FUNCTION:	fd_log_time
+ *
+ * PARAMETERS:
+ *  buf 	: An array where the time must be stored
+ *  len		: size of the buffer
+ *
+ * DESCRIPTION: 
+ *  Writes the current timestamp (in human readable format) in a buffer. 
+ *
+ * RETURN VALUE:
+ *  pointer to buf.
+ */
+char * fd_log_time ( char * buf, size_t len );
+
+/************************** DEBUG MACROS ************************************/
+
+/* levels definitions */
+#define NONE 0	/* Display no debug message */
+#define INFO 1	/* Display errors only */
+#define FULL 2  /* Display additional information to follow code execution */
+#define ANNOYING 4 /* Very verbose, for example in loops */
+#define FCTS 6  /* Display entry parameters of most functions */
+#define CALL 9  /* Display calls to most functions (with CHECK macros) */
+
+/* Default level is INFO */
+#ifndef TRACE_LEVEL 
+#define TRACE_LEVEL INFO
+#endif /* TRACE_LEVEL */
+
+/* The level of the file being compiled */
+static int local_debug_level = TRACE_LEVEL;
+
+/* helper macros (pre-processor hacks) */
+#define __str( arg )  #arg
+#define _stringize( arg ) __str( arg )
+#define __agr( arg1, arg2 ) arg1 ## arg2
+#define _aggregate( arg1, arg2 ) __agr( arg1, arg2 )
+
+/* Some portability tricks to get nice function name in __PRETTY_FUNCTION__ */
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+#  define __func__ __FUNCTION__
+# else /* __GNUC__ >= 2 */
+#  define __func__ "<unknown>"
+# endif /* __GNUC__ >= 2 */
+#endif /* __STDC_VERSION__ < 199901L */
+#ifndef __PRETTY_FUNCTION__
+#define __PRETTY_FUNCTION__ __func__
+#endif /* __PRETTY_FUNCTION__ */
+
+/* Boolean for tracing at a certain level */
+#define TRACE_BOOL(_level_) ( (_level_) <= local_debug_level )
+
+/* The general debug macro, each call results in two lines of debug messages */
+#define TRACE_DEBUG(level,format,args... ) {											\
+	if ( TRACE_BOOL(level) ) {												\
+		char __buf[25];													\
+		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
+		fd_log_debug("\t | th:%-30s\t%s\tin %s@%s:%d\n"									\
+			  "\t%s|%*s" format "\n",  										\
+					__thn, fd_log_time(__buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,	\
+					(level < FULL)?"@":" ",level, "", ## args); 						\
+	}															\
+}
+
+/* Helper for function entry */
+#define TRACE_ENTRY(_format,_args... ) \
+	TRACE_DEBUG(FCTS, "->%s (" #_args ") = (" _format ") >", __PRETTY_FUNCTION__, ##_args );
+
+/* Helper for debugging by adding traces */
+#define TRACE_HERE()	\
+	TRACE_DEBUG(INFO, " -- debug checkpoint -- ");
+
+/* Helper for tracing the CHECK_* macros bellow */
+#define TRACE_DEBUG_ALL( str ) 	\
+	TRACE_DEBUG(CALL, str );
+
+
+/* Macros to check a return value and branch out in case of error.
+ * These macro must be used only when errors are highly improbable, not for expected errors.
+ */
+
+/* Check the return value of a system function and execute fallback in case of error */
+#define CHECK_SYS_DO( __call__, __fallback__  ) { 					\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ < 0) {								\
+		int __err__ = errno;	/* We may handle EINTR here */			\
+		TRACE_DEBUG(NONE, "ERROR: in '" #__call__ "' :\t%s", strerror(__err__));\
+		__fallback__;								\
+	}										\
+}
+/* Check the return value of a system function, return error code on error */
+#define CHECK_SYS( __call__  ) { 							\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ < 0) {								\
+		int __err__ = errno;	/* We may handle EINTR here */			\
+		TRACE_DEBUG(NONE, "ERROR: in '" #__call__ "' :\t%s", strerror(__err__));\
+		return __err__;								\
+	}										\
+}
+
+/* Check the return value of a POSIX function and execute fallback in case of error or special value */
+#define CHECK_POSIX_DO2( __call__, __speval__, __fallback1__, __fallback2__ ) {			\
+	int __ret__;										\
+	TRACE_DEBUG_ALL( "Check POSIX: " #__call__ );						\
+	__ret__ = (__call__);									\
+	if (__ret__ != 0) {									\
+		if (__ret__ == (__speval__)) {							\
+			__fallback1__;								\
+		} else {									\
+			TRACE_DEBUG(NONE, "ERROR: in '" #__call__ "':\t%s", strerror(__ret__));	\
+			__fallback2__;								\
+		}										\
+	}											\
+}
+
+/* Check the return value of a POSIX function and execute fallback in case of error */
+#define CHECK_POSIX_DO( __call__, __fallback__ ) 					\
+	CHECK_POSIX_DO2( (__call__), 0, , __fallback__ );
+
+/* Check the return value of a POSIX function and return it if error */
+#define CHECK_POSIX( __call__ ) { 							\
+	int __v__;									\
+	CHECK_POSIX_DO( __v__ = (__call__), return __v__ );				\
+}
+
+/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
+#define CHECK_MALLOC_DO( __call__, __fallback__ ) { 					\
+	void *  __ret__;								\
+	TRACE_DEBUG_ALL( "Check MALLOC: " #__call__ );					\
+	__ret__ = (void *)( __call__ );							\
+	if (__ret__ == NULL) {								\
+		int __err__ = errno;							\
+		TRACE_DEBUG(NONE, "ERROR: in '" #__call__ "':\t%s", strerror(__err__));	\
+		__fallback__;								\
+	}										\
+}
+
+/* Check that a memory allocator did not return NULL, otherwise return ENOMEM */
+#define CHECK_MALLOC( __call__ )							\
+	CHECK_MALLOC_DO( __call__, return ENOMEM );
+
+
+/* The next macros can be used also for expected errors */
+
+/* Check parameters at function entry, execute fallback on error */
+#define CHECK_PARAMS_DO( __bool__, __fallback__ )					\
+	TRACE_DEBUG_ALL( "Check PARAMS: " #__bool__ );					\
+	if ( ! (__bool__) ) {								\
+		TRACE_DEBUG(INFO, "Invalid parameter received in '" #__bool__ "'");	\
+		__fallback__;								\
+	}
+/* Check parameters at function entry, return EINVAL if the boolean is false (similar to assert) */
+#define CHECK_PARAMS( __bool__ )							\
+	CHECK_PARAMS_DO( __bool__, return EINVAL );
+
+/* Check the return value of an internal function, log and propagate */
+#define CHECK_FCT_DO( __call__, __fallback__ ) {					\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check FCT: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ != 0) {								\
+		TRACE_DEBUG(INFO, "Error in '" #__call__ "':\t%s", strerror(__ret__));	\
+		__fallback__;								\
+	}										\
+}
+/* Check the return value of a function call, return any error code */
+#define CHECK_FCT( __call__ ) {								\
+	int __v__;									\
+	CHECK_FCT_DO( __v__ = (__call__), return __v__ );				\
+}
+
+/****************************** Socket helpers ************************************/
+
+/* Some aliases to socket addresses structures */
+#define sSS	struct sockaddr_storage
+#define sSA	struct sockaddr
+#define sSA4	struct sockaddr_in
+#define sSA6	struct sockaddr_in6
+
+/* Dump one sockaddr */
+#define sSA_DUMP( level, text, sa ) {				\
+	sSA * __sa = (sSA *)(sa);				\
+	char *__str, __addrbuf[INET6_ADDRSTRLEN];		\
+	if (__sa) {						\
+	  int __rc = getnameinfo(__sa, 				\
+	  		sizeof(sSS),				\
+			__addrbuf,				\
+			sizeof(__addrbuf),			\
+			NULL,					\
+			0,					\
+			0);					\
+	  if (__rc)						\
+	  	__str = (char *)gai_strerror(__rc);		\
+	  else							\
+	  	__str = &__addrbuf[0];				\
+	} else {						\
+		__str = "(NULL / ANY)";				\
+	}							\
+	TRACE_DEBUG(level, text "%s", __str);			\
+}
+
+/* The sockaddr length of a sSS structure */
+#define sSSlen( _ss_ )	\
+	( (socklen_t) ( ((_ss_)->ss_family == AF_INET) ? (sizeof(sSA4)) :		\
+				(((_ss_)->ss_family == AF_INET6) ? (sizeof(sSA6)) :	\
+					0 ) ) )
+
+/* Define the value of IP loopback address */
+#ifndef INADDR_LOOPBACK 
+#define INADDR_LOOPBACK	inet_addr("127.0.0.1")
+#endif /* INADDR_LOOPBACK */
+
+/* create a V4MAPPED address */
+#define IN6_ADDR_V4MAP( a6, a4 ) {			\
+	((uint32_t *)(a6))[0] = 0;			\
+	((uint32_t *)(a6))[1] = 0;			\
+	((uint32_t *)(a6))[2] = htonl(0xffff);		\
+	((uint32_t *)(a6))[3] = (uint32_t)(a4);		\
+}
+
+/* Retrieve a v4 value from V4MAPPED address ( takes a s6_addr as param) */
+#define IN6_ADDR_V4UNMAP( a6 ) 				\
+	(((in_addr_t *)(a6))[3])
+
+/*
+ * Other macros 
+ */
+
+/* We provide macros to convert 64 bit values to and from network byte-order, on systems where it is not already provided. */
+#ifndef HAVE_NTOHLL	/* Defined in config.h, if the ntohll symbol is defined on the system */
+# if HOST_BIG_ENDIAN
+    /* In big-endian systems, we don't have to change the values, since the order is the same as network */
+#   define ntohll(x) (x)
+#   define htonll(x) (x)
+# else /* HOST_BIG_ENDIAN */
+    /* For these systems, we must reverse the bytes. Use ntohl and htonl on sub-32 blocs, and inverse these blocs. */
+#   define ntohll(x) (typeof (x))( (((uint64_t)ntohl( (uint32_t)(x))) << 32 ) | ((uint64_t) ntohl( ((uint64_t)(x)) >> 32 ))) 
+#   define htonll(x) (typeof (x))( (((uint64_t)htonl( (uint32_t)(x))) << 32 ) | ((uint64_t) htonl( ((uint64_t)(x)) >> 32 ))) 
+# endif /* HOST_BIG_ENDIAN */
+#endif /* HAVE_NTOHLL */
+
+/* This macro will pad a size to the next multiple of 4. */
+#define PAD4(_x) ((_x) + ( (4 - (_x)) & 3 ) )
+
+/* Useful to display as ASCII some bytes values */
+#define ASCII(_c) ( ((_c < 32) || (_c > 127)) ? ( _c ? '?' : ' ' ) : _c )
+
+/* Compare timespec structures */
+#define TS_IS_INFERIOR( ts1, ts2 ) 		\
+	(    ((ts1)->tv_sec  < (ts2)->tv_sec ) 	\
+	  || ((ts1)->tv_nsec < (ts2)->tv_nsec) )
+
+/* Some constants for dumping flags and values */
+#define DUMP_AVPFL_str	"%c%c"
+#define DUMP_AVPFL_val(_val) (_val & AVP_FLAG_VENDOR)?'V':'-' , (_val & AVP_FLAG_MANDATORY)?'M':'-'
+#define DUMP_CMDFL_str	"%c%c%c%c"
+#define DUMP_CMDFL_val(_val) (_val & CMD_FLAG_REQUEST)?'R':'-' , (_val & CMD_FLAG_PROXIABLE)?'P':'-' , (_val & CMD_FLAG_ERROR)?'E':'-' , (_val & CMD_FLAG_RETRANSMIT)?'T':'-'
+
+/*============================================================*/
+/*                          THREADS                           */
+/*============================================================*/
+
+/* Terminate a thread */
+static __inline__ int fd_thr_term(pthread_t * th)
+{
+	int ret = 0;
+	void * th_ret = NULL;
+	
+	CHECK_PARAMS(th);
+	
+	/* Test if it was already terminated */
+	if (*th == (pthread_t)NULL)
+		return 0;
+	
+	/* Cancel the thread if it is still running - ignore error if it was already terminated */
+	(void) pthread_cancel(*th);
+	
+	/* Then join the thread */
+	CHECK_POSIX_DO( ret = pthread_join(*th, &th_ret), /* continue */ );
+	
+	if (th_ret != NULL) {
+		TRACE_DEBUG(FULL, "The thread returned the following value: %p (ignored)", th_ret);
+	}
+	
+	/* Clean the location */
+	*th = (pthread_t)NULL;
+	
+	return ret;
+}
+
+/* Cleanups for cancellation (all threads should be safely cancelable!) */
+static __inline__ void fd_cleanup_mutex( void * mutex )
+{
+	CHECK_POSIX_DO( pthread_mutex_unlock((pthread_mutex_t *)mutex), /* */);
+}
+		
+static __inline__ void fd_cleanup_rwlock( void * rwlock )
+{
+	CHECK_POSIX_DO( pthread_rwlock_unlock((pthread_rwlock_t *)rwlock), /* */);
+}
+
+static __inline__ void fd_cleanup_buffer( void * buffer )
+{
+	free(buffer);
+}
+
+/*============================================================*/
+/*                          LISTS                             */
+/*============================================================*/
+
+/* The following structure represents a chained list element  */
+struct fd_list {
+	struct fd_list 	*next; /* next element in the list */
+	struct fd_list 	*prev; /* previous element in the list */
+	struct fd_list 	*head; /* head of the list */
+	void		*o;    /* additional avialbe pointer used for start of the parento object or other purpose */
+};
+
+#define FD_LIST( _li ) ((struct fd_list *)( _li ))
+
+/* Initialize a list element */
+void fd_list_init ( struct fd_list * list, void *obj );
+
+/* Return boolean, true if the list is empty */
+#define FD_IS_LIST_EMPTY( _list ) (((FD_LIST(_list))->head == (_list)) && ((FD_LIST(_list))->next == (_list)))
+
+/* Insert an item in a list at known position */
+void fd_list_insert_after  ( struct fd_list * ref, struct fd_list * item );
+void fd_list_insert_before ( struct fd_list * ref, struct fd_list * item );
+
+/* Insert an item in an ordered list -- ordering function provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */
+int fd_list_insert_ordered( struct fd_list * head, struct fd_list * item, int (*cmp_fct)(void *, void *), void ** ref_duplicate);
+
+/* Unlink an item from a list */
+void fd_list_unlink ( struct fd_list * item );
+
+/* Compute a hash value of a string (session id, diameter id, ...) */
+uint32_t fd_hash ( char * string, size_t len );
+
+
+
+/*============================================================*/
+/*                        DICTIONARY                          */
+/*============================================================*/
+/* Structure that contains the complete dictionary definitions */
+struct dictionary;
+
+/* Structure that contains a dictionary object */
+struct dict_object;
+
+/* Types of object in the dictionary. */
+enum dict_object_type {
+	DICT_VENDOR	= 1,	/* Vendor */
+	DICT_APPLICATION,	/* Diameter Application */
+	DICT_TYPE,		/* AVP data type */
+	DICT_ENUMVAL,		/* Named constant (value of an enumerated AVP type) */
+	DICT_AVP,		/* AVP */
+	DICT_COMMAND,		/* Diameter Command */
+	DICT_RULE		/* a Rule for AVP in command or grouped AVP */
+#define DICT_TYPE_MAX	DICT_RULE
+};
+	
+/* Initialize a dictionary */
+int fd_dict_init(struct dictionary ** dict);
+/* Destroy a dictionary */
+int fd_dict_fini(struct dictionary ** dict);
+
+/*
+ * FUNCTION:	fd_dict_new
+ *
+ * PARAMETERS:
+ *  dict	: Pointer to the dictionnary where the object is created
+ *  type 	: What kind of object must be created
+ *  data 	: pointer to the data for the object. 
+ *          	 type parameter is used to determine the type of data (see bellow for detail).
+ *  parent 	: a reference to a parent object, if needed.
+ *  ref 	: upon successful creation, reference to new object is stored here if !null.
+ *
+ * DESCRIPTION: 
+ *  Create a new object in the dictionary. 
+ *  See following object sections in this header file for more information on data and parent parameters format.
+ *
+ * RETURN VALUE:
+ *  0      	: The object is created in the dictionary.
+ *  EINVAL 	: A parameter is invalid.
+ *  EEXIST 	: This object is already defined in the dictionary (with conflicting data). 
+ *                If "ref" is not NULL, it points to the existing element on return.
+ *  (other standard errors may be returned, too, with their standard meaning. Example:
+ *    ENOMEM 	: Memory allocation for the new object element failed.)
+ */
+int fd_dict_new ( struct dictionary * dict, enum dict_object_type type, void * data, struct dict_object * parent, struct dict_object **ref );
+
+/*
+ * FUNCTION: 	fd_dict_search
+ *
+ * PARAMETERS:
+ *  dict	: Pointer to the dictionnary where the object is searched
+ *  type 	: type of object that is being searched
+ *  criteria 	: how the object must be searched. See object-related sections bellow for more information.
+ *  what 	: depending on criteria, the data that must be searched.
+ *  result 	: On successful return, pointer to the object is stored here.
+ *  retval	: this value is returned if the object is not found and result is not NULL.
+ *
+ * DESCRIPTION: 
+ *   Perform a search in the dictionary. 
+ *   See the object-specific sections bellow to find how to look for each objects.
+ *   If the "result" parameter is NULL, the function is used to check if an object is in the dictionary.
+ *   Otherwise, a reference to the object is stored in result if found.
+ *   If result is not NULL and the object is not found, retval is returned (should be 0 or ENOENT usually)
+ *
+ * RETURN VALUE:
+ *  0      	: The object has been found in the dictionary, or *result is NULL.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOENT	: No matching object has been found, and result was NULL.
+ */
+int fd_dict_search ( struct dictionary * dict, enum dict_object_type type, int criteria, void * what, struct dict_object **result, int retval );
+
+/* Special case: get the generic error command object */
+int fd_dict_get_error_cmd(struct dictionary * dict, struct dict_object **obj);
+
+/*
+ * FUNCTION:	fd_dict_getval
+ *
+ * PARAMETERS:
+ *  object 	: Pointer to a dictionary object.
+ *  data 	: pointer to a structure to hold the data for the object.
+ *          	  The type is the same as "data" parameter in fd_dict_new function.
+ *
+ * DESCRIPTION: 
+ *  Retrieve content of a dictionary object.
+ *  See following object sections in this header file for more information on data and parent parameters format.
+ *
+ * RETURN VALUE:
+ *  0      	: The content of the object has been retrieved.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_dict_getval ( struct dict_object * object, void * val);
+int fd_dict_gettype ( struct dict_object * object, enum dict_object_type * type);
+int fd_dict_getdict ( struct dict_object * object, struct dictionary ** dict);
+
+/* Debug functions */
+void fd_dict_dump_object(struct dict_object * obj);
+void fd_dict_dump(struct dictionary * dict);
+
+
+/*
+ ***************************************************************************
+ *
+ * Vendor object 
+ *
+ * These types are used to manage vendors in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold a Vendor ID: "SMI Network Management Private Enterprise Codes" (RFC3232) */
+typedef uint32_t	vendor_id_t;
+
+/* Type to hold data associated to a vendor */
+struct dict_vendor_data {
+	vendor_id_t	 vendor_id;	/* ID of a vendor */
+	char 		*vendor_name;	/* The name of this vendor */
+};
+
+/* The criteria for searching a vendor object in the dictionary */
+enum {
+	VENDOR_BY_ID = 10,	/* "what" points to a vendor_id_t */
+	VENDOR_BY_NAME,		/* "what" points to a string */
+	VENDOR_OF_APPLICATION	/* "what" points to a struct dict_object containing an application (see bellow) */
+};
+
+/***
+ *  API usage :
+
+Note: the value of "vendor_name" is copied when the object is created, and the string may be disposed afterwards.
+On the other side, when value is retrieved with dict_getval, the string is not copied and MUST NOT be freed. It will
+be freed automatically along with the object itself with call to dict_fini later.
+ 
+- dict_new:
+ The "parent" parameter is not used for vendors. 
+ Sample code to create a vendor:
+ {
+	 int ret;
+	 struct dict_object * myvendor;
+	 struct dict_vendor_data myvendordata = { 23455, "my vendor name" };  -- just an example...
+	 ret = dict_new ( DICT_VENDOR, &myvendordata, NULL, &myvendor );
+ }
+
+- dict_search:
+ Sample codes to look for a vendor object, by its id or name:
+ {
+	 int ret;
+	 struct dict_object * vendor_found;
+	 vendor_id_t vendorid = 23455;
+	 ret = dict_search ( DICT_VENDOR, VENDOR_BY_ID, &vendorid, &vendor_found, ENOENT);
+	 - or -
+	 ret = dict_search ( DICT_VENDOR, VENDOR_BY_NAME, "my vendor name", &vendor_found, ENOENT);
+ }
+ 
+ - dict_getval:
+ Sample code to retrieve the data from a vendor object:
+ {
+	 int ret;
+	 struct dict_object * myvendor;
+	 struct dict_vendor_data myvendordata;
+	 ret = dict_search ( DICT_VENDOR, VENDOR_BY_NAME, "my vendor name", &myvendor, ENOENT);
+	 ret = dict_getval ( myvendor, &myvendordata );
+	 printf("my vendor id: %d\n", myvendordata.vendor_id );
+ }
+		 
+ 
+*/
+	 
+/*
+ ***************************************************************************
+ *
+ * Application object 
+ *
+ * These types are used to manage Diameter applications in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold a Diameter application ID: IANA assigned value for this application. */
+typedef uint32_t	application_id_t;
+
+/* Type to hold data associated to an application */
+struct dict_application_data {
+	application_id_t	 application_id;	/* ID of the application */
+	char 			*application_name;	/* The name of this application */
+};
+
+/* The criteria for searching an application object in the dictionary */
+enum {
+	APPLICATION_BY_ID = 20,		/* "what" points to a application_id_t */
+	APPLICATION_BY_NAME,		/* "what" points to a string */
+	APPLICATION_OF_TYPE,		/* "what" points to a struct dict_object containing a type object (see bellow) */
+	APPLICATION_OF_COMMAND		/* "what" points to a struct dict_object containing a command (see bellow) */
+};
+
+/***
+ *  API usage :
+
+The "parent" parameter of dict_new may point to a vendor object to inform of what vendor defines the application.
+for standard-track applications, the "parent" parameter should be NULL.
+The vendor associated to an application is retrieved with VENDOR_OF_APPLICATION search criteria on vendors.
+
+- dict_new:
+ Sample code for application creation:
+ {
+	 int ret;
+	 struct dict_object * vendor;
+	 struct dict_object * appl;
+	 struct dict_vendor_data vendor_data = {
+		 23455,
+		 "my vendor name"
+	 };
+	 struct dict_application_data app_data = {
+		 9789,
+		 "my vendor's application"
+	 };
+	
+	 ret = dict_new ( DICT_VENDOR, &vendor_data, NULL, &vendor );
+	 ret = dict_new ( DICT_APPLICATION, &app_data, vendor, &appl );
+ }
+
+- dict_search:
+ Sample code to retrieve the vendor of an application
+ {
+	 int ret;
+	 struct dict_object * vendor, * appli;
+	 
+	 ret = dict_search ( DICT_APPLICATION, APPLICATION_BY_NAME, "my vendor's application", &appli, ENOENT);
+	 ret = dict_search ( DICT_VENDOR, VENDOR_OF_APPLICATION, appli, &vendor, ENOENT);
+ }
+ 
+ - dict_getval:
+ Sample code to retrieve the data from an application object:
+ {
+	 int ret;
+	 struct dict_object * appli;
+	 struct dict_application_data appl_data;
+	 ret = dict_search ( DICT_APPLICATION, APPLICATION_BY_NAME, "my vendor's application", &appli, ENOENT);
+	 ret = dict_getval ( appli, &appl_data );
+	 printf("my application id: %s\n", appl_data.application_id );
+ }
+
+*/
+
+/*
+ ***************************************************************************
+ *
+ * Type object 
+ *
+ * These types are used to manage AVP data types in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to store any AVP value */ 
+union avp_value {
+	struct {
+		uint8_t *data;	/* bytes buffer */
+		size_t   len;	/* length of the data buffer */
+	}           os;		/* Storage for an octet string, data is alloc'd and must be freed */
+	int32_t     i32;	/* integer 32 */
+	int64_t     i64;	/* integer 64 */
+	uint32_t    u32;	/* unsigned 32 */
+	uint64_t    u64;	/* unsigned 64 */
+	float       f32;	/* float 32 */
+	double 	    f64;	/* float 64 */
+};
+
+/* These are the basic AVP types defined in RFC3588bis */
+enum dict_avp_basetype {
+	AVP_TYPE_GROUPED,
+	AVP_TYPE_OCTETSTRING,
+	AVP_TYPE_INTEGER32,
+	AVP_TYPE_INTEGER64,
+	AVP_TYPE_UNSIGNED32,
+	AVP_TYPE_UNSIGNED64,
+	AVP_TYPE_FLOAT32,
+	AVP_TYPE_FLOAT64
+#define AVP_TYPE_MAX AVP_TYPE_FLOAT64
+};
+
+/* Callbacks that can be associated with a derived type to easily interpret the AVP value. */
+/*
+ * CALLBACK:	dict_avpdata_interpret
+ *
+ * PARAMETERS:
+ *   val         : Pointer to the AVP value that must be interpreted.
+ *   interpreted : The result of interpretation is stored here. The format and meaning depends on each type.
+ *
+ * DESCRIPTION: 
+ *   This callback can be provided with a derived type in order to facilitate the interpretation of formated data.
+ *  For example, when an AVP of type "Address" is received, it can be used to convert the octetstring into a struct sockaddr.
+ *  This callback is not called directly, but through the message's API msg_avp_value_interpret function.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0 		: An error occurred, the error code is returned.
+ */
+typedef int (*dict_avpdata_interpret) (union avp_value * value, void * interpreted);
+/*
+ * CALLBACK:	dict_avpdata_encode
+ *
+ * PARAMETERS:
+ *   data	: The formated data that must be stored in the AVP value.
+ *   val	: Pointer to the AVP value storage area where the data must be stored.
+ *
+ * DESCRIPTION: 
+ *   This callback can be provided with a derived type in order to facilitate the encoding of formated data.
+ *  For example, it can be used to convert a struct sockaddr in an AVP value of type Address.
+ *  This callback is not called directly, but through the message's API msg_avp_value_encode function.
+ *  If the callback is defined for an OctetString based type, the created string must be malloc'd. free will be called 
+ *  automatically later.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0 		: An error occurred, the error code is returned.
+ */
+typedef int (*dict_avpdata_encode) (void * data, union avp_value * val);
+
+
+/* Type to hold data associated to a derived AVP data type */
+struct dict_type_data {
+	enum dict_avp_basetype	 type_base;	/* How the data of such AVP must be interpreted */
+	char 			*type_name;	/* The name of this type */
+	dict_avpdata_interpret	 type_interpret;/* cb to convert the AVP value in more comprehensive format (or NULL) */
+	dict_avpdata_encode	 type_encode;	/* cb to convert formatted data into an AVP value (or NULL) */
+};
+
+/* The criteria for searching a type object in the dictionary */
+enum {
+	TYPE_BY_NAME = 30,		/* "what" points to a string */
+	TYPE_OF_ENUMVAL,		/* "what" points to a struct dict_object containing an enumerated constant (DICT_ENUMVAL, see bellow). */
+	TYPE_OF_AVP			/* "what" points to a struct dict_object containing an AVP object. */
+};
+
+
+/***
+ *  API usage :
+
+- dict_new:
+ The "parent" parameter may point to an application object, when a type is defined by a Diameter application. 
+ 
+ Sample code:
+ {
+	 int ret;
+	 struct dict_object * mytype;
+	 struct dict_type_data mytypedata = 
+		{ 
+		 AVP_TYPE_OCTETSTRING,
+		 "Address",
+		 NULL,
+		 NULL
+		};
+	 ret = dict_new ( DICT_TYPE, &mytypedata, NULL, &mytype );
+ }
+
+- dict_search:
+ Sample code:
+ {
+	 int ret;
+	 struct dict_object * address_type;
+	 ret = dict_search ( DICT_TYPE, TYPE_BY_NAME, "Address", &address_type, ENOENT);
+ }
+ 
+*/
+	 
+/*
+ ***************************************************************************
+ *
+ * Enumerated values object 
+ *
+ * These types are used to manage named constants of some AVP,
+ * for enumerated types. Waaad allows contants for types others than Unsigned32
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold data of named constants for AVP */
+struct dict_enumval_data {
+	char 		*enum_name;	/* The name of this constant */
+	union avp_value  enum_value;	/* Value of the constant. Union term depends on parent type's base type. */
+};
+
+/* The criteria for searching a constant in the dictionary */
+enum {
+	ENUMVAL_BY_STRUCT = 40,	/* "what" points to a struct dict_enumval_request as defined bellow */
+};
+
+struct dict_enumval_request {
+	/* Identifier of the parent type, one of the following must not be NULL */
+	struct dict_object	*type_obj;
+	char			*type_name;
+	
+	/* Search criteria for the constant */
+	struct dict_enumval_data search; /* search.enum_value is used only if search.enum_name == NULL */
+};
+
+/***
+ *  API usage :
+
+- dict_new:
+ The "parent" parameter must point to a derived type object. 
+ Sample code to create a type "Boolean" with two constants "True" and "False":
+ {
+	 int ret;
+	 struct dict_object * type_boolean;
+	 struct dict_type_data type_boolean_data = 
+		{ 
+		 AVP_TYPE_INTEGER32,
+		 "Boolean",
+		 NULL,
+		 NULL
+		};
+	 struct dict_enumval_data boolean_false =
+	 	{
+		 .enum_name="False",
+		 .enum_value.i32 = 0
+	 	};
+	 struct dict_enumval_data boolean_true =
+	 	{
+		 .enum_name="True",
+		 .enum_value.i32 = -1
+	 	};
+	 ret = dict_new ( DICT_TYPE, &type_boolean_data, NULL, &type_boolean );
+	 ret = dict_new ( DICT_ENUMVAL, &boolean_false, type_boolean, NULL );
+	 ret = dict_new ( DICT_ENUMVAL, &boolean_true , type_boolean, NULL );
+	 
+ }
+
+- dict_search:
+ Sample code to look for a constant name, by its value:
+ {
+	 int ret;
+	 struct dict_object * value_found;
+	 struct dict_enumval_request boolean_by_value =
+	 	{
+		 .type_name = "Boolean",
+		 .search.enum_name=NULL,
+		 .search.enum_value.i32 = -1
+	 	};
+	 
+	 ret = dict_search ( DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &boolean_by_value, &value_found, ENOENT);
+ }
+ 
+ - dict_getval:
+ Sample code to retrieve the data from a constant object:
+ {
+	 int ret;
+	 struct dict_object * value_found;
+	 struct dict_enumval_data boolean_data = NULL;
+	 struct dict_enumval_request boolean_by_value =
+	 	{
+		 .type_name = "Boolean",
+		 .search.enum_name=NULL,
+		 .search.enum_value.i32 = 0
+	 	};
+	 
+	 ret = dict_search ( DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &boolean_by_value, &value_found, ENOENT);
+	 ret = dict_getval ( value_found, &boolean_data );
+	 printf(" Boolean with value 0: %s", boolean_data.enum_name );
+ }
+*/
+	 
+/*
+ ***************************************************************************
+ *
+ * AVP object 
+ *
+ * These objects are used to manage AVP definitions in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold an AVP code. For vendor 0, these codes are assigned by IANA. Otherwise, it is managed by the vendor */
+typedef uint32_t	avp_code_t;
+
+/* Values of AVP flags */
+#define	AVP_FLAG_VENDOR	  	0x80
+#define	AVP_FLAG_MANDATORY	0x40
+#define	AVP_FLAG_RESERVED3	0x20
+#define	AVP_FLAG_RESERVED4	0x10
+#define	AVP_FLAG_RESERVED5	0x08
+#define	AVP_FLAG_RESERVED6	0x04
+#define	AVP_FLAG_RESERVED7	0x02
+#define	AVP_FLAG_RESERVED8	0x01
+
+
+/* Type to hold data associated to an avp */
+struct dict_avp_data {
+	avp_code_t	 	 avp_code;	/* Code of the avp */
+	vendor_id_t	 	 avp_vendor;	/* Vendor of the AVP, or 0 */
+	char			*avp_name;	/* Name of this AVP */
+	uint8_t		 	 avp_flag_mask;	/* Mask of fixed AVP flags */
+	uint8_t		 	 avp_flag_val;	/* Values of the fixed flags */
+	enum dict_avp_basetype 	 avp_basetype;	/* Basic type of data found in the AVP */
+};
+
+/* The criteria for searching an avp object in the dictionary */
+enum {
+	AVP_BY_CODE = 50,	/* "what" points to an avp_code_t, vendor is always 0 */
+	AVP_BY_NAME,		/* "what" points to a string, vendor is always 0 */
+	AVP_BY_CODE_AND_VENDOR,	/* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_code are set */
+	AVP_BY_NAME_AND_VENDOR	/* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_name are set */
+};
+
+/* Struct used for some researchs */
+struct dict_avp_request {
+	vendor_id_t	 avp_vendor;
+	avp_code_t	 avp_code;
+	char		*avp_name;
+};
+
+
+/***
+ *  API usage :
+
+If "parent" parameter is not NULL during AVP creation, it must point to a DICT_TYPE object. 
+The extended type is then attached to the AVP. In case where it is an enumerated type, the value of 
+AVP is automatically interpreted in debug messages, and in message checks.
+The derived type of an AVP can be retrieved with: dict_search ( DICT_TYPE, TYPE_OF_AVP, avp, ... )
+
+To create the rules (ABNF) for children of Grouped AVP, see the DICT_RULE related part.
+
+- dict_new:
+ Sample code for AVP creation:
+ {
+	 int ret;
+	 struct dict_object * user_name_avp;
+	 struct dict_object * boolean_type;
+	 struct dict_object * sample_boolean_avp;
+	 struct dict_avp_data user_name_data = {
+		 1,					// code
+		 0,					// vendor
+		 "User-Name",				// name
+		 AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY,	// fixed mask: V and M values must always be defined as follow. other flags can be set or cleared
+		 AVP_FLAG_MANDATORY,			// the V flag must be cleared, the M flag must be set.
+		 AVP_TYPE_OCTETSTRING			// User-Name AVP contains OctetString data (further precision such as UTF8String can be given with a parent derived type)
+	 };
+	 struct dict_avp_data sample_boolean_data = {
+		 31337,
+		 23455,
+		 "Sample-Boolean",
+		 AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY,
+		 AVP_FLAG_VENDOR,
+		 AVP_TYPE_INTEGER32			// This MUST be the same as parent type's
+	 };
+	
+ 	 -- Create an AVP with a base type --
+	 ret = dict_new ( DICT_AVP, &user_name_data, NULL, &user_name_avp );
+	 
+	 -- Create an AVP with a derived type --
+	 ret = dict_search ( DICT_TYPE, TYPE_BY_NAME, "Boolean", &boolean_type, ENOENT);
+	 ret = dict_new ( DICT_AVP, &sample_boolean_data , boolean_type, &sample_boolean_avp );
+	 
+ }
+
+- dict_search:
+ Sample code to look for an AVP
+ {
+	 int ret;
+	 struct dict_object * avp_username;
+	 struct dict_object * avp_sampleboolean;
+	 struct dict_avp_request avpvendorboolean =
+	 	{
+		 .avp_vendor = 23455,
+		 .avp_name   = "Sample-Boolean"
+	 	};
+	 
+	 ret = dict_search ( DICT_AVP, AVP_BY_NAME, "User-Name", &avp_username, ENOENT);
+	 
+	 ret = dict_search ( DICT_AVP, AVP_BY_NAME_AND_VENDOR, &avpvendorboolean, &avp_sampleboolean, ENOENT);
+	 
+ }
+ 
+ - dict_getval:
+ Sample code to retrieve the data from an AVP object:
+ {
+	 int ret;
+	 struct dict_object * avp_username;
+	 struct dict_avp_data user_name_data;
+	 ret = dict_search ( DICT_AVP, AVP_BY_NAME, "User-Name", &avp_username, ENOENT);
+	 ret = dict_getval ( avp_username, &user_name_data );
+	 printf("User-Name code: %d\n", user_name_data.avp_code );
+ }
+
+*/
+
+/*
+ ***************************************************************************
+ *
+ * Command object 
+ *
+ * These types are used to manage commands objects in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold a Diameter command code: IANA assigned values. 0x0-0x7fffff=standard, 0x800000-0xfffffd=vendors, 0xfffffe-0xffffff=experimental */
+typedef uint32_t	command_code_t;
+
+/* Values of command flags */
+#define CMD_FLAG_REQUEST	0x80
+#define CMD_FLAG_PROXIABLE	0x40
+#define CMD_FLAG_ERROR		0x20
+#define CMD_FLAG_RETRANSMIT	0x10
+#define CMD_FLAG_RESERVED5	0x08
+#define CMD_FLAG_RESERVED6	0x04
+#define CMD_FLAG_RESERVED7	0x02
+#define CMD_FLAG_RESERVED8	0x01
+
+/* Type to hold data associated to a command */
+struct dict_cmd_data {
+	command_code_t	 cmd_code;	/* code of the command */
+	char		*cmd_name;	/* Name of the command */
+	uint8_t		 cmd_flag_mask;	/* Mask of fixed-value flags */
+	uint8_t		 cmd_flag_val;	/* values of the fixed flags */
+};
+
+/* The criteria for searching an avp object in the dictionary */
+enum {
+	CMD_BY_NAME = 60,	/* "what" points to a string */
+	CMD_BY_CODE_R,		/* "what" points to a command_code_t. The "Request" command is returned. */
+	CMD_BY_CODE_A,		/* "what" points to a command_code_t. The "Answer" command is returned. */
+	CMD_ANSWER		/* "what" points to a struct dict_object of a request command. The corresponding "Answer" command is returned. */
+};
+
+
+/***
+ *  API usage :
+
+The "parent" parameter of dict_new may point to an application object to inform of what application defines the command.
+The application associated to a command is retrieved with APPLICATION_OF_COMMAND search criteria on applications.
+
+To create the rules for children of commands, see the DICT_RULE related part.
+
+Note that the "Request" and "Answer" commands are two independant objects. This allows to have different rules for each.
+
+- dict_new:
+ Sample code for command creation:
+ {
+	 int ret;
+	 struct dict_object * cer;
+	 struct dict_object * cea;
+	 struct dict_cmd_data ce_data = {
+		 257,					// code
+		 "Capabilities-Exchange-Request",	// name
+		 CMD_FLAG_REQUEST,			// mask
+		 CMD_FLAG_REQUEST			// value. Only the "R" flag is constrained here, set.
+	 };
+	
+	 ret = dict_new ( DICT_COMMAND, &ce_data, NULL, &cer );
+	 
+	 ce_data.cmd_name = "Capabilities-Exchange-Answer";
+	 ce_data.cmd_flag_val = 0;			// Same constraint on "R" flag, but this time it must be cleared.
+
+	 ret = dict_new ( DICT_COMMAND, &ce_data, NULL, &cea );
+ }
+
+- dict_search:
+ Sample code to look for a command
+ {
+	 int ret;
+	 struct dict_object * cer, * cea;
+	 command_code_t	code = 257;
+	 ret = dict_search ( DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer, ENOENT);
+	 ret = dict_search ( DICT_COMMAND, CMD_BY_CODE_R, &code, &cer, ENOENT);
+ }
+ 
+ - dict_getval:
+ Sample code to retrieve the data from a command object:
+ {
+	 int ret;
+	 struct dict_object * cer;
+	 struct dict_object * cea;
+	 struct dict_cmd_data cea_data;
+	 ret = dict_search ( DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer, ENOENT);
+	 ret = dict_search ( DICT_COMMAND, CMD_ANSWER, cer, &cea, ENOENT);
+	 ret = dict_getval ( cea, &cea_data );
+	 printf("Answer to CER: %s\n", cea_data.cmd_name );
+ }
+
+*/
+
+/*
+ ***************************************************************************
+ *
+ * Rule object
+ *
+ * These objects are used to manage rules in the dictionary (ABNF implementation)
+ * This is used for checking messages validity (more powerful than a DTD)
+ *
+ ***************************************************************************
+ */
+
+/* This defines the kind of rule that is defined */
+enum rule_position {
+	RULE_FIXED_HEAD = 1,	/* The AVP must be at the head of the group. The rule_order field is used to specify the position. */
+	RULE_REQUIRED,		/* The AVP must be present in the parent, but its position is not defined. */
+	RULE_OPTIONAL,		/* The AVP may be present in the message. Used to specify a max number of occurences for example */
+	RULE_FIXED_TAIL		/* The AVP must be at the end of the group. The rule_order field is used to specify the position. */
+};
+
+/* Content of a RULE object data */
+struct dict_rule_data {
+	struct dict_object	*rule_avp;	/* Pointer to the AVP object that is concerned by this rule */
+	enum rule_position	 rule_position;	/* The position in which the rule_avp must appear in the parent */
+	unsigned		 rule_order;	/* for RULE_FIXED_* rules, the place. 1,2,3.. for HEAD rules; ...,3,2,1 for TAIL rules. */
+	int	 		 rule_min;	/* Minimum number of occurences. -1 means "default": 0 for optional rules, 1 for other rules */
+	int			 rule_max;	/* Maximum number of occurences. -1 means no maximum. 0 means the AVP is forbidden. */
+};
+
+/* The criteria for searching a rule in the dictionary */
+enum {
+	RULE_BY_AVP_AND_PARENT = 70	/* "what" points to a struct dict_rule_request -- see bellow. This is used to query "what is the rule for this AVP in this group?" */
+};
+
+/* Structure for querying the dictionary about a rule */
+struct dict_rule_request {
+	struct dict_object	*rule_parent;	/* The grouped avp or command to which the rule apply */
+	struct dict_object	*rule_avp;	/* The AVP concerned by this rule */
+};
+
+
+/***
+ *  API usage :
+
+The "parent" parameter can not be NULL. It points to the object (grouped avp or command) to which this rule apply (i.e. for which the ABNF is defined).
+
+- dict_new:
+ Sample code for rule creation. Let's create the Proxy-Info grouped AVP for example.
+ {
+	int ret;
+	struct dict_object * proxy_info_avp;
+	struct dict_object * proxy_host_avp;
+	struct dict_object * proxy_state_avp;
+	struct dict_object * diameteridentity_type;
+	struct dict_rule_data rule_data;
+	struct dict_type_data di_type_data = { AVP_TYPE_OCTETSTRING, "DiameterIdentity", NULL, NULL };
+	struct dict_avp_data proxy_info_data = { 284, 0, "Proxy-Info", AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_GROUPED };
+	struct dict_avp_data proxy_host_data = { 280, 0, "Proxy-Host", AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_OCTETSTRING };
+	struct dict_avp_data proxy_state_data = { 33, 0, "Proxy-State",AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_OCTETSTRING };
+	
+	-- Create the parent AVP
+	ret = dict_new ( DICT_AVP, &proxy_info_data, NULL, &proxy_info_avp );
+	
+	-- Create the first child AVP.
+	ret = dict_new ( DICT_TYPE, &di_type_data, NULL, &diameteridentity_type );
+	ret = dict_new ( DICT_AVP, &proxy_host_data, diameteridentity_type, &proxy_host_avp );
+	
+	-- Create the other child AVP
+	ret = dict_new ( DICT_AVP, &proxy_state_data, NULL, &proxy_state_avp );
+	
+	-- Now we can create the rules. Both children AVP are mandatory.
+	rule_data.rule_position = RULE_REQUIRED;
+	rule_data.rule_min = -1;
+	rule_data.rule_max = -1;
+	
+	rule_data.rule_avp = proxy_host_avp;
+	ret = dict_new ( DICT_RULE, &rule_data, proxy_info_avp, NULL );
+	
+	rule_data.rule_avp = proxy_state_avp;
+	ret = dict_new ( DICT_RULE, &rule_data, proxy_info_avp, NULL );
+}
+
+- dict_search and dict_getval are similar to previous examples.
+
+*/
+		
+/* Define some hard-coded values */
+/* Commands Codes */
+#define CC_CAPABILITIES_EXCHANGE	257
+#define CC_RE_AUTH			258
+#define CC_ACCOUNTING			271
+#define CC_ABORT_SESSION		274
+#define CC_SESSION_TERMINATION		275
+#define CC_DEVICE_WATCHDOG		280
+#define CC_DISCONNECT_PEER		282
+
+/* AVPs (Vendor 0) */
+#define AC_PROXY_STATE			33
+#define AC_HOST_IP_ADDRESS		257
+#define AC_AUTH_APPLICATION_ID		258
+#define AC_ACCT_APPLICATION_ID		259
+#define AC_VENDOR_SPECIFIC_APPLICATION_ID 260
+#define AC_REDIRECT_HOST_USAGE		261
+#define AC_REDIRECT_MAX_CACHE_TIME	262
+#define AC_SESSION_ID 			263
+#define AC_ORIGIN_HOST			264
+#define AC_SUPPORTED_VENDOR_ID		265
+#define AC_VENDOR_ID			266
+#define AC_FIRMWARE_REVISION		267
+#define AC_RESULT_CODE			268
+#define AC_PRODUCT_NAME			269
+#define AC_DISCONNECT_CAUSE		273
+#define ACV_DC_REBOOTING			0
+#define ACV_DC_BUSY				1
+#define ACV_DC_NOT_FRIEND			2
+#define AC_ORIGIN_STATE_ID		278
+#define AC_FAILED_AVP			279
+#define AC_PROXY_HOST			280
+#define AC_ERROR_MESSAGE		281
+#define AC_ROUTE_RECORD			282
+#define AC_DESTINATION_REALM		283
+#define AC_PROXY_INFO			284
+#define AC_REDIRECT_HOST		292
+#define AC_DESTINATION_HOST		293
+#define AC_ERROR_REPORTING_HOST		294
+#define AC_ORIGIN_REALM			296
+#define AC_INBAND_SECURITY_ID		299
+
+/* Error codes */
+#define ER_DIAMETER_SUCCESS			2001
+#define ER_DIAMETER_REALM_NOT_SERVED		3003
+#define ER_DIAMETER_TOO_BUSY			3004
+#define ER_DIAMETER_REDIRECT_INDICATION		3006
+
+/* Iterator on the rules of a parent object */
+int fd_dict_iterate_rules ( struct dict_object *parent, void * data, int (*cb)(void *, struct dict_rule_data *) );
+
+
+/*============================================================*/
+/*                         MESSAGES                           */
+/*============================================================*/
+
+/* The following types are opaque */
+struct	msg;	/* A message: command with children AVPs (possibly grand children) */
+struct	avp;	/* AVP object */
+
+/* Some details about chaining:
+ *
+ *  A message is made of a header ( msg ) and 0 or more AVPs ( avp ).
+ * The structure is a kind of tree, where some AVPs (grouped AVPs) can contain other AVPs.
+ * Exemple:
+ * msg
+ *  |-avp
+ *  |-gavp
+ *  |   |-avp
+ *  |   |-avp
+ *  |   \-avp
+ *  |-avp
+ *  \-avp
+ *
+ */
+
+/* The following type is used to point to either a msg or an AVP */
+typedef void msg_or_avp;
+
+/* The Diameter protocol version */
+#define DIAMETER_VERSION	1
+
+/* In the two following types, some fields are marked (READONLY). 
+ * This means that the content of these fields will be overwritten by the daemon so modifying it is useless.
+ */
+
+/* The following structure represents the header of a message. All data is in host byte order. */
+struct msg_hdr {
+	uint8_t		 msg_version;		/* (READONLY) Version of Diameter: must be DIAMETER_VERSION. */
+	uint32_t	 msg_length;		/* (READONLY)(3 bytes) indicates the length of the message */
+	uint8_t		 msg_flags;		/* Message flags: CMD_FLAG_* */
+	command_code_t	 msg_code;		/* (3 bytes) the command-code. See dictionary-api.h for more detail */
+	application_id_t msg_appl;		/* The application issuing this message */
+	uint32_t	 msg_hbhid;		/* The Hop-by-Hop identifier of the message */
+	uint32_t	 msg_eteid;		/* The End-to-End identifier of the message */
+};
+
+/* The following structure represents the visible content of an AVP. All data is in host byte order. */
+struct avp_hdr {
+	avp_code_t	 avp_code;		/* the AVP Code */
+	uint8_t		 avp_flags;		/* AVP_FLAG_* flags */
+	uint32_t	 avp_len;		/* (READONLY)(Only 3 bytes are used) the length of the AVP as described in the RFC */
+	vendor_id_t	 avp_vendor;		/* Only used if AVP_FLAG_VENDOR is present */
+	union avp_value *avp_value;		/* pointer to the value of the AVP. NULL means that the value is not set / not understood.
+						   One should not directly change this value. Use the msg_avp_setvalue function instead.
+						   The content of the pointed structure can be changed directly, with this restriction:
+						     if the AVP is an OctetString, and you change the value of the pointer avp_value->os.data, then
+						     you must call free() on the previous value, and the new one must be free()-able.
+						 */
+};
+
+/* The following enum is used to browse inside message hierarchy (msg, gavp, avp) */
+enum msg_brw_dir {
+	MSG_BRW_NEXT = 1,	/* Get the next element at the same level, or NULL if this is the last element. */
+	MSG_BRW_PREV,		/* Get the previous element at the same level, or NULL if this is the first element. */
+	MSG_BRW_FIRST_CHILD,	/* Get the first child AVP of this element, if any. */
+	MSG_BRW_LAST_CHILD,	/* Get the last child AVP of this element, if any. */
+	MSG_BRW_PARENT,		/* Get the parent element of this element, if any. Only the msg_t object has no parent. */
+	MSG_BRW_WALK		/* This is equivalent to FIRST_CHILD or NEXT or PARENT->next, first that is not NULL. Use this to walk inside all AVPs. */
+};
+
+/* Some flags used in the functions bellow */
+#define MSGFL_ALLOC_ETEID	0x01	/* When creating a message, a new end-to-end ID is allocated and set in the message */
+#define MSGFL_ANSW_ERROR	0x02	/* When creating an answer message, set the 'E' bit and use the generic error ABNF instead of command-specific ABNF */
+#define MSGFL_MAX		MSGFL_ANSW_ERROR	/* The biggest valid flag value */
+
+/**************************************************/
+/*   Message creation, manipulation, disposal     */
+/**************************************************/
+/*
+ * FUNCTION:	fd_msg_avp_new
+ *
+ * PARAMETERS:
+ *  model 	: Pointer to a DICT_AVP dictionary object describing the avp to create, or NULL.
+ *  flags	: Flags to use in creation (not used yet, should be 0).
+ *  avp 	: Upon success, pointer to the new avp is stored here.
+ *
+ * DESCRIPTION: 
+ *   Create a new AVP instance.
+ *
+ * RETURN VALUE:
+ *  0      	: The AVP is created.
+ *  EINVAL 	: A parameter is invalid.
+ *  (other standard errors may be returned, too, with their standard meaning. Example:
+ *    ENOMEM 	: Memory allocation for the new avp failed.)
+ */
+int fd_msg_avp_new ( struct dict_object * model, int flags, struct avp ** avp );
+
+/*
+ * FUNCTION:	fd_msg_new
+ *
+ * PARAMETERS:
+ *  model 	: Pointer to a DICT_COMMAND dictionary object describing the message to create, or NULL.
+ *  flags	: combination of MSGFL_* flags.
+ *  msg 	: Upon success, pointer to the new message is stored here.
+ *
+ * DESCRIPTION: 
+ *   Create a new empty Diameter message. 
+ *
+ * RETURN VALUE:
+ *  0      	: The message is created.
+ *  EINVAL 	: A parameter is invalid.
+ *  (other standard errors may be returned, too, with their standard meaning. Example:
+ *    ENOMEM 	: Memory allocation for the new message failed.)
+ */
+int fd_msg_new ( struct dict_object * model, int flags, struct msg ** msg );
+
+/*
+ * FUNCTION:	msg_new_answer_from_req
+ *
+ * PARAMETERS:
+ *  dict	: Pointer to the dictionary containing the model of the query.
+ *  msg		: The location of the query on function call. Updated by the location of answer message on return.
+ *  flag        : Pass MSGFL_ANSW_ERROR to indicate if the answer is an error message (will set the 'E' bit)
+ *
+ * DESCRIPTION: 
+ *   This function creates the empty answer message corresponding to a request.
+ *  The header is set properly (R flag, ccode, appid, hbhid, eteid)
+ *  The Session-Id AVP is copied if present.
+ *  The calling code should usually call fd_msg_rescode_set function on the answer.
+ *  Upon return, the original query may be retrieved by calling fd_msg_answ_getq on the message.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0      	: an error occurred.
+ */
+int fd_msg_new_answer_from_req ( struct dictionary * dict, struct msg ** msg, int flag );
+
+/*
+ * FUNCTION:	fd_msg_browse
+ *
+ * PARAMETERS:
+ *  reference 	: Pointer to a struct msg or struct avp.
+ *  dir         : Direction for browsing
+ *  found       : If not NULL, updated with the element that has been found, if any, or NULL if no element was found / an error occurred.
+ *  depth	: If not NULL, points to an integer representing the "depth" of this object in the tree. This is a relative value, updated on return.
+ *
+ * DESCRIPTION: 
+ *   Explore the content of a message object (hierarchy). If "found" is null, only error checking is performed.
+ *  If "depth" is provided, it is updated as follow on successful function return:
+ *   - not modified for MSG_BRW_NEXT and MSG_BRW_PREV.
+ *   - *depth = *depth + 1 for MSG_BRW_FIRST_CHILD and MSG_BRW_LAST_CHILD.
+ *   - *depth = *depth - 1 for MSG_BRW_PARENT.
+ *   - *depth = *depth + X for MSG_BRW_WALK, with X between 1 (returned the 1st child) and -N (returned the Nth parent's next).
+ *
+ * RETURN VALUE:
+ *  0      	: found has been updated (if non NULL).
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOENT	: No element has been found where requested, and "found" was NULL (otherwise, *found is set to NULL and 0 is returned). 
+ */
+int fd_msg_browse_internal ( msg_or_avp * reference, enum msg_brw_dir dir, msg_or_avp ** found, int * depth );
+/* Macro to avoid having to cast the third parameter everywhere */
+#define fd_msg_browse( ref, dir, found, depth )	\
+	fd_msg_browse_internal( (ref), (dir), (void *)(found), (depth) )
+
+
+/*
+ * FUNCTION:	fd_msg_avp_add
+ *
+ * PARAMETERS:
+ *  reference 	: Pointer to a valid msg or avp.
+ *  dir         : location where the new AVP should be inserted, relative to the reference. MSG_BRW_PARENT and MSG_BRW_WALK are not valid.
+ *  avp         : pointer to the AVP object that must be inserted.
+ *
+ * DESCRIPTION: 
+ *   Adds an AVP into an object that can contain it: grouped AVP or message.
+ *
+ * RETURN VALUE:
+ *  0      	: The AVP has been added.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_avp_add ( msg_or_avp * reference, enum msg_brw_dir dir, struct avp *avp);
+
+/*
+ * FUNCTION:	fd_msg_search_avp
+ *
+ * PARAMETERS:
+ *  msg 	: The message structure in which to search the AVP.
+ *  what 	: The dictionary model of the AVP to search.
+ *  avp		: location where the AVP reference is stored if found.
+ *
+ * DESCRIPTION: 
+ *   Search the first top-level AVP of a given model inside a message.
+ * Note: only the first instance of the AVP is returned by this function.
+ * Note: only top-level AVPs are searched, not inside grouped AVPs.
+ * Use msg_browse if you need more advanced research features.
+ *
+ * RETURN VALUE:
+ *  0      	: The AVP has been found.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOENT	: No AVP has been found, and "avp" was NULL (otherwise, *avp is set to NULL and 0 returned).
+ */
+int fd_msg_search_avp ( struct msg * msg, struct dict_object * what, struct avp ** avp );
+
+/*
+ * FUNCTION:	fd_msg_free
+ *
+ * PARAMETERS:
+ *  object      : pointer to the message or AVP object that must be unlinked and freed.
+ *
+ * DESCRIPTION: 
+ *   Unlink and free a message or AVP object and its children.
+ *  If the object is an AVP linked into a message, the AVP is removed before being freed.
+ *
+ * RETURN VALUE:
+ *  0      	: The message has been freed.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_free ( msg_or_avp * object );
+
+/***************************************/
+/*   Dump functions                    */
+/***************************************/
+/*
+ * FUNCTION:	fd_msg_dump_*
+ *
+ * PARAMETERS:
+ *  level	: the log level (INFO, FULL, ...) at which the object is dumped
+ *  obj		: A msg or avp object.
+ *
+ * DESCRIPTION: 
+ *   These functions dump the content of a message to the debug log
+ * either recursively or only the object itself.
+ *
+ * RETURN VALUE:
+ *   -
+ */
+void fd_msg_dump_walk ( int level, msg_or_avp *obj );
+void fd_msg_dump_one  ( int level, msg_or_avp *obj );
+
+
+/*********************************************/
+/*   Message metadata management functions   */
+/*********************************************/
+/*
+ * FUNCTION:	fd_msg_model
+ *
+ * PARAMETERS:
+ *  reference 	: Pointer to a valid msg or avp.
+ *  model       : on success, pointer to the dictionary model of this command or AVP. NULL if the model is unknown.
+ *
+ * DESCRIPTION: 
+ *   Retrieve the dictionary object describing this message or avp. If the object is unknown or the fd_msg_parse_dict has not been called,
+ *  *model is set to NULL.
+ *
+ * RETURN VALUE:
+ *  0      	: The model has been set.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_model ( msg_or_avp * reference, struct dict_object ** model );
+
+/*
+ * FUNCTION:	fd_msg_hdr
+ *
+ * PARAMETERS:
+ *  msg 	: Pointer to a valid message object.
+ *  pdata 	: Upon success, pointer to the msg_hdr structure of this message. The fields may be modified.
+ *
+ * DESCRIPTION: 
+ *   Retrieve location of modifiable section of a message. 
+ *
+ * RETURN VALUE:
+ *  0      	: The location has been written.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_hdr ( struct msg *msg, struct msg_hdr **pdata );
+
+/*
+ * FUNCTION:	fd_msg_avp_hdr
+ *
+ * PARAMETERS:
+ *  avp 	: Pointer to a valid avp object.
+ *  pdata 	: Upon success, pointer to the avp_hdr structure of this avp. The fields may be modified.
+ *
+ * DESCRIPTION: 
+ *   Retrieve location of modifiable data of an avp. 
+ *
+ * RETURN VALUE:
+ *  0      	: The location has been written.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_avp_hdr ( struct avp *avp, struct avp_hdr **pdata );
+
+/*
+ * FUNCTION:	fd_msg_answ_associate, fd_msg_answ_getq, fd_msg_answ_detach
+ *
+ * PARAMETERS:
+ *  answer	: the received answer message
+ *  query	: the corresponding query that had been sent
+ *
+ * DESCRIPTION:
+ *  fd_msg_answ_associate associates a query msg with the received answer. 
+ * Query is retrieved with fd_msg_answ_getq.
+ * If answer message is freed, the query is also freed.
+ * If the msg_answ_detach function is called, the association is removed.
+ * This is meant to be called from the daemon only.
+ *
+ * RETURN VALUE:
+ *  0 	  : ok
+ *  EINVAL: a parameter is invalid
+ */
+int fd_msg_answ_associate( struct msg * answer, struct msg * query );
+int fd_msg_answ_getq     ( struct msg * answer, struct msg ** query );
+int fd_msg_answ_detach   ( struct msg * answer );
+
+/*
+ * FUNCTION:	fd_msg_anscb_associate, fd_msg_anscb_get
+ *
+ * PARAMETERS:
+ *  msg		: the answer message
+ *  anscb	: the callback to associate with the message
+ *  data	: the data to pass to the callback
+ *
+ * DESCRIPTION:
+ *  Associate or retrieve a callback with an answer message.
+ * This is meant to be called from the daemon only.
+ *
+ * RETURN VALUE:
+ *  0 	  : ok
+ *  EINVAL: a parameter is invalid
+ */
+int fd_msg_anscb_associate( struct msg * msg, void ( *anscb)(void *, struct msg **), void  * data );
+int fd_msg_anscb_get      ( struct msg * msg, void (**anscb)(void *, struct msg **), void ** data );
+
+/*
+ * FUNCTION:	fd_msg_rt_associate, fd_msg_rt_get
+ *
+ * PARAMETERS:
+ *  msg		: the query message to be sent
+ *  list	: the ordered list of possible next-peers
+ *
+ * DESCRIPTION:
+ *  Associate a routing list with a query, and retrieve it.
+ * If the message is freed, the list is also freed.
+ *
+ * RETURN VALUE:
+ *  0 	  : ok
+ *  EINVAL: a parameter is invalid
+ */
+int fd_msg_rt_associate( struct msg * msg, struct fd_list ** list );
+int fd_msg_rt_get      ( struct msg * msg, struct fd_list ** list );
+
+/*
+ * FUNCTION:	fd_msg_is_routable
+ *
+ * PARAMETERS:
+ *  msg		: A msg object.
+ *
+ * DESCRIPTION: 
+ *   This function returns a boolean telling if a given message is routable in the Diameter network, 
+ *  or if it is a local link message only (ex: CER/CEA, DWR/DWA, ...).
+ *
+ * RETURN VALUE:
+ *  0      	: The message is not routable / an error occurred.
+ *  1      	: The message is routable.
+ */
+int fd_msg_is_routable ( struct msg * msg );
+
+/*
+ * FUNCTION:	fd_msg_source_(g/s)et
+ *
+ * PARAMETERS:
+ *  msg		: A msg object.
+ *  diamid	: The diameter id of the peer from which this message was received.
+ *  hash	: The hash for the diamid value.
+ *  add_rr	: if true, a Route-Record AVP is added to the message with content diamid. In that case, dict must be supplied.
+ *  dict	: a dictionary with definition of Route-Record AVP (if add_rr is true)
+ *
+ * DESCRIPTION: 
+ *   Store or retrieve the diameted id of the peer from which this message was received.
+ * Will be used for example by the routing module to add the Route-Record AVP in forwarded requests,
+ * or to direct answers to the appropriate peer.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0      	: an error occurred.
+ */
+int fd_msg_source_set( struct msg * msg, char * diamid, uint32_t hash, int add_rr, struct dictionary * dict );
+int fd_msg_source_get( struct msg * msg, char ** diamid, uint32_t *hash );
+
+/*
+ * FUNCTION:	fd_msg_eteid_get
+ *
+ * PARAMETERS:
+ *  -
+ *
+ * DESCRIPTION: 
+ *   Get a new unique end-to-end id value for the local peer.
+ *
+ * RETURN VALUE:
+ *  The new assigned value. No error code is defined.
+ */
+uint32_t fd_msg_eteid_get ( void );
+
+
+/***************************************/
+/*   Manage AVP values                 */
+/***************************************/
+
+/*
+ * FUNCTION:	fd_msg_avp_setvalue
+ *
+ * PARAMETERS:
+ *  avp 	: Pointer to a valid avp object with a NULL avp_value pointer. The model must be known.
+ *  value 	: pointer to an avp_value. The content will be COPIED into the internal storage area. 
+ *		 If data type is an octetstring, the data is also copied.
+ * 		 If value is a NULL pointer, the previous data is erased and value is unset in the AVP.
+ *
+ * DESCRIPTION: 
+ *   Initialize the avp_value field of an AVP header.
+ *
+ * RETURN VALUE:
+ *  0      	: The avp_value pointer has been set.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_avp_setvalue ( struct avp *avp, union avp_value *value );
+
+/*
+ * FUNCTION:	fd_msg_avp_value_encode
+ *
+ * PARAMETERS:
+ *  avp 	: Pointer to a valid avp object with a NULL avp_value. The model must be known.
+ *  data 	: Pointer to the data that must be encoded as AVP value and stored in the AVP.
+ *		 This is only valid for AVPs of derived type for which type_data_encode callback is set. (ex: Address type)
+ *
+ * DESCRIPTION: 
+ *   Initialize the avp_value field of an AVP object from formatted data, using the AVP's type "type_data_encode" callback.
+ *
+ * RETURN VALUE:
+ *  0      	: The avp_value has been set.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOTSUP 	: There is no appropriate callback registered with this AVP's type.
+ */
+int fd_msg_avp_value_encode ( void *data, struct avp *avp );
+
+/*
+ * FUNCTION:	fd_msg_avp_value_interpret
+ *
+ * PARAMETERS:
+ *  avp 	: Pointer to a valid avp object with a non-NULL avp_value value.
+ *  data 	: Upon success, formatted interpretation of the AVP value is stored here.
+ *
+ * DESCRIPTION: 
+ *   Interpret the content of an AVP of Derived type and store the result in data pointer. The structure
+ * of the data pointer is dependent on the AVP type. This function calls the "type_data_interpret" callback 
+ * of the type.
+ *
+ * RETURN VALUE:
+ *  0      	: The avp_value has been set.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOTSUP 	: There is no appropriate callback registered with this AVP's type.
+ */
+int fd_msg_avp_value_interpret ( struct avp *avp, void *data );
+
+
+/***************************************/
+/*   Message parsing functions         */
+/***************************************/
+
+/*
+ * FUNCTION:	fd_msg_bufferize
+ *
+ * PARAMETERS:
+ *  msg		: A valid msg object. All AVPs must have a value set. 
+ *  buffer 	: Upon success, this points to a buffer (malloc'd) containing the message ready for network transmission (or security transformations). 
+ *		 The buffer may be freed after use.
+ *  len		: if not NULL, the size of the buffer is written here. In any case, this size is updated in the msg header.
+ *
+ * DESCRIPTION: 
+ *   Renders a message in memory as a buffer that can be sent over the network to the next peer.
+ *
+ * RETURN VALUE:
+ *  0      	: The location has been written.
+ *  EINVAL 	: The buffer does not contain a valid Diameter message.
+ *  ENOMEM	: Unable to allocate enough memory to create the buffer object.
+ */
+int fd_msg_bufferize ( struct msg * msg, unsigned char ** buffer, size_t * len );
+
+/*
+ * FUNCTION:	fd_msg_parse_buffer
+ *
+ * PARAMETERS:
+ *  buffer 	: Pointer to a buffer containing a message received from the network. 
+ *  buflen	: the size in bytes of the buffer.
+ *  msg		: Upon success, this points to a valid msg object. No AVP value is resolved in this object, nor grouped AVP.
+ *
+ * DESCRIPTION: 
+ *   This function parses a buffer an creates a msg object to represent the structure of the message.
+ *  Since no dictionary lookup is performed, the values of the AVPs are not interpreted. To interpret the values,
+ *  the returned message object must be passed to fd_msg_parse_dict function.
+ *  The buffer pointer is saved inside the message and will be freed when not needed anymore.
+ *
+ * RETURN VALUE:
+ *  0      	: The location has been written.
+ *  ENOMEM	: Unable to allocate enough memory to create the msg object.
+ *  EBADMSG	: The buffer does not contain a valid Diameter message (or is truncated).
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_parse_buffer ( unsigned char ** buffer, size_t buflen, struct msg ** msg );
+
+/*
+ * FUNCTION:	fd_msg_parse_dict
+ *
+ * PARAMETERS:
+ *  object	: A msg or AVP object as returned by fd_msg_parse_buffer.
+ *  dict	: the dictionary containing the objects definitions to use for resolving all AVPs.
+ *
+ * DESCRIPTION: 
+ *   This function looks up for the command and each children AVP definitions in the dictionary.
+ *  If the dictionary definition is found, avp_model is set and the value of the AVP is interpreted accordingly and:
+ *   - for grouped AVPs, the children AVP are created and interpreted also.
+ *   - for numerical AVPs, the value is converted to host byte order and saved in the avp_value field.
+ *   - for octetstring AVPs, the string is copied into a new buffer and its address is saved in avp_value. 
+ *  If the dictionary definition is not found, avp_model is set to NULL and
+ *  the content of the AVP is saved as an octetstring in an internal structure. avp_value is NULL.
+ *  As a result, after this function has been called, there is no more dependency of the msg object to the message buffer, that is be freed.
+ *
+ * RETURN VALUE:
+ *  0      	: The message has been fully parsed as described.
+ *  EINVAL 	: The msg parameter is invalid for this operation.
+ *  ENOMEM	: Unable to allocate enough memory to complete the operation.
+ *  ENOTSUP	: No dictionary definition for the command or one of the mandatory AVP was found.
+ */
+int fd_msg_parse_dict ( msg_or_avp * object, struct dictionary * dict );
+
+/*
+ * FUNCTION:	fd_msg_parse_rules
+ *
+ * PARAMETERS:
+ *  object	: A msg or grouped avp object that must be verified.
+ *  dict	: The dictionary containing the rules definitions.
+ *  rule	: If not NULL, the first conflicting rule will be saved here if a conflict is found.
+ *
+ * DESCRIPTION: 
+ *   Check that the children of the object do not conflict with the dictionary rules (ABNF compliance).
+ *
+ * RETURN VALUE:
+ *  0      	: The message has been fully parsed and complies to the defined rules.
+ *  EBADMSG	: A conflict was detected, or a mandatory AVP is unknown in the dictionary.
+ *  EINVAL 	: The msg or avp object is invalid for this operation.
+ *  ENOMEM	: Unable to allocate enough memory to complete the operation.
+ */
+int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct dict_object ** rule);
+
+
+/*
+ * FUNCTION:	fd_msg_update_length
+ *
+ * PARAMETERS:
+ *  object 	: Pointer to a valid msg or avp. 
+ *
+ * DESCRIPTION: 
+ *   Update the length field of the object passed as parameter.
+ * As a side effect, all children objects are also updated. Therefore, all avp_value fields of
+ * the children AVPs must be set, or an error will occur.
+ *
+ * RETURN VALUE:
+ *  0      	: The size has been recomputed.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_update_length ( msg_or_avp * object );
+
+
+
+/*============================================================*/
+/*                    MESSAGE QUEUES                          */
+/*============================================================*/
+
+/* Management of queues of messages */
+
+/* A message queue is an opaque object */
+struct mqueue;
+
+/*
+ * FUNCTION:	fd_mq_new
+ *
+ * PARAMETERS:
+ *  queue	: Upon success, a pointer to the new message queue is saved here.
+ *
+ * DESCRIPTION: 
+ *  Create a new empty message queue.
+ *
+ * RETURN VALUE :
+ *  0		: The message queue has been initialized successfully.
+ *  EINVAL 	: The parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the creation.  
+ */
+int fd_mq_new ( struct mqueue ** queue );
+
+/*
+ * FUNCTION:	fd_mq_del
+ *
+ * PARAMETERS:
+ *  queue	: Pointer to an empty message queue to delete.
+ *
+ * DESCRIPTION: 
+ *  Destroys a message queue. This is only possible if no thread is waiting for a message,
+ * and the queue is empty.
+ *
+ * RETURN VALUE:
+ *  0		: The message queue has been destroyed successfully.
+ *  EINVAL 	: The parameter is invalid.
+ */
+int fd_mq_del ( struct mqueue  ** queue );
+
+/*
+ * FUNCTION:	fd_mq_length
+ *
+ * PARAMETERS:
+ *  queue	: The queue from which to retrieve the length.
+ *  length	: Upon success, the current number of messages in the queue is stored here.
+ *
+ * DESCRIPTION: 
+ *  Retrieve the number of messages pending in a queue.
+ *
+ * RETURN VALUE:
+ *  0		: The length of the queue has been written.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_mq_length ( struct mqueue * queue, int * length );
+int fd_mq_length_noerr ( struct mqueue * queue ); /* alternate with no error checking */
+
+/*
+ * FUNCTION:	fd_mq_setthrhd
+ *
+ * PARAMETERS:
+ *  queue	: The queue for which the thresholds are being set.
+ *  data	: An opaque pointer that is passed to h_cb and l_cb callbacks.
+ *  high        : The high-level threshold. If the number of elements in the queue increase to this value, h_cb is called.
+ *  h_cb        : if not NULL, a callback to call when the queue lengh is bigger than "high".
+ *  low         : The low-level threshold. Must be < high.
+ *  l_cb        : If the number of elements decrease to low, this callback is called.
+ *
+ * DESCRIPTION: 
+ *  This function allows to adjust the number of producer / consumer threads of a queue.
+ * If the consumer are slower than the producers, the number of messages in the queue increase.
+ * By setting a "high" value, we allow a callback to be called when this number is too high.
+ * The typical use would be to create an additional consumer thread in this callback.
+ * If the queue continues to grow, the callback will be called again when the length is 2 * high, then 3*high, ... N * high
+ * (the callback itself may implement a limit on the number of consumers that can be created)
+ * When the queue starts to decrease, and the number of elements go under ((N - 1) * high + low, the l_cb callback is called
+ * and would typially stop one of the consumer threads. If the queue continue to reduce, l_cb is again called at (N-2)*high + low,
+ * and so on.
+ *
+ * Since there is no destructor for the data pointer, if cleanup operations are required, they should be performed in
+ * l_cb when the length of the queue is becoming < low.
+ *
+ * Note that the callbacks are called synchronously, during fd_mq_post or fd_mq_get. Their operation should be quick.
+ *
+ * RETURN VALUE:
+ *  0		: The thresholds have been set
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_mq_setthrhd ( struct mqueue * queue, void * data, uint16_t high, void (*h_cb)(struct mqueue *, void **), uint16_t low, void (*l_cb)(struct mqueue *, void **) );
+
+/*
+ * FUNCTION:	fd_mq_post
+ *
+ * PARAMETERS:
+ *  queue	: The queue in which the message must be posted.
+ *  msg		: The message that is put in the queue.
+ *
+ * DESCRIPTION: 
+ *  A message is added in a queue. Messages are retrieved from the queue (in FIFO order)
+ *  with the fd_mq_get, fd_mq_tryget, or fd_mq_timedget functions.
+ *
+ * RETURN VALUE:
+ *  0		: The message is queued.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM 	: Not enough memory to complete the operation.
+ */
+int fd_mq_post ( struct mqueue * queue, struct msg ** msg );
+
+/*
+ * FUNCTION:	fd_mq_get
+ *
+ * PARAMETERS:
+ *  queue	: The queue from which the message must be retrieved.
+ *  msg		: On return, the first message of the queue is stored here.
+ *
+ * DESCRIPTION: 
+ *  This function retrieves a message from a queue. If the queue is empty, the function will block the 
+ * thread until a new message is posted to the queue, or until the thread is canceled (in which case the 
+ * function does not return).
+ *
+ * RETURN VALUE:
+ *  0		: A new message has been retrieved.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_mq_get ( struct mqueue * queue, struct msg ** msg );
+
+/*
+ * FUNCTION:	fd_mq_tryget
+ *
+ * PARAMETERS:
+ *  queue	: The queue from which the message must be retrieved.
+ *  msg		: On return, the message is stored here.
+ *
+ * DESCRIPTION: 
+ *  This function is similar to fd_mq_get, except that it will not block if 
+ * the queue is empty, but return EWOULDBLOCK instead.
+ *
+ * RETURN VALUE:
+ *  0		: A new message has been retrieved.
+ *  EINVAL 	: A parameter is invalid.
+ *  EWOULDBLOCK : The queue was empty.
+ */
+int fd_mq_tryget ( struct mqueue * queue, struct msg ** msg );
+
+/*
+ * FUNCTION:	fd_mq_timedget
+ *
+ * PARAMETERS:
+ *  queue	: The queue from which the message must be retrieved.
+ *  msg		: On return, the message is stored here.
+ *  abstime	: the absolute time until which we allow waiting for a message.
+ *
+ * DESCRIPTION: 
+ *  This function is similar to fd_mq_get, except that it will block if the queue is empty 
+ * only until the absolute time abstime (see pthread_cond_timedwait for + info).
+ * If the queue is still empty when the time expires, the function returns ETIMEDOUT
+ *
+ * RETURN VALUE:
+ *  0		: A new message has been retrieved.
+ *  EINVAL 	: A parameter is invalid.
+ *  ETIMEDOUT   : The time out has passed and no message has been received.
+ */
+int fd_mq_timedget ( struct mqueue * queue, struct msg ** msg, const struct timespec *abstime );
+
+#endif /* _LIBFREEDIAMETER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfreediameter/CMakeLists.txt	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,25 @@
+# Name of the subproject
+Project("libfreediameter" C)
+
+SET(PROJECT_COPYRIGHT "Copyright (c) 2008-2009, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)")
+
+# List of source files for the library
+SET(LFD_SRC
+	libfd.h
+	init.c
+	log.c
+	lists.c
+	dictionary.c
+	messages.c
+	mqueues.c
+	)
+
+# Build as a shared library
+ADD_LIBRARY(libfreediameter SHARED ${LFD_SRC})
+
+# Avoid the liblib name
+SET_TARGET_PROPERTIES(libfreediameter PROPERTIES OUTPUT_NAME "freediameter")
+
+# The library itself needs other libraries 
+TARGET_LINK_LIBRARIES(libfreediameter ${FD_LIBS})
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfreediameter/dictionary.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,1671 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#include "libfd.h"
+
+/* Names of the base types */
+const char * type_base_name[] = { /* must keep in sync with dict_avp_basetype */
+	"GROUPED", 	/* AVP_TYPE_GROUPED */
+	"OCTETSTRING", 	/* AVP_TYPE_OCTETSTRING */
+	"INTEGER32", 	/* AVP_TYPE_INTEGER32 */
+	"INTEGER64", 	/* AVP_TYPE_INTEGER64 */
+	"UNSIGNED32", 	/* AVP_TYPE_UNSIGNED32 */
+	"UNSIGNED64", 	/* AVP_TYPE_UNSIGNED64 */
+	"FLOAT32", 	/* AVP_TYPE_FLOAT32 */
+	"FLOAT64"	/* AVP_TYPE_FLOAT64 */
+	};
+
+/* The number of lists in an object */
+#define NB_LISTS_PER_OBJ	3
+
+/* Some eye catchers definitions */
+#define OBJECT_EYECATCHER	(0x0b13c7)
+#define DICT_EYECATCHER		(0x00d1c7)
+
+/* Definition of the dictionary objects */
+struct dict_object {
+	enum dict_object_type	type;	/* What type of object is this? */
+	int			objeyec;/* eyecatcher for this object */
+	int			typeyec;/* eyecatcher for this type of object */
+	struct dictionary	*dico;  /* The dictionary this object belongs to */
+	
+	union {
+		struct dict_vendor_data		vendor;
+		struct dict_application_data	application;
+		struct dict_type_data		type;
+		struct dict_enumval_data	enumval;
+		struct dict_avp_data		avp;
+		struct dict_cmd_data		cmd;
+		struct dict_rule_data		rule;
+	} data;				/* The data of this object */
+	
+	struct dict_object *	parent; /* The parent of this object, if any */
+	
+	struct fd_list		list[NB_LISTS_PER_OBJ];/* used to chain objects.*/
+	/* More information about the lists :
+	
+	 - the use for each list depends on the type of object. See detail bellow.
+	 
+	 - a sentinel for a list has its 'o' field cleared. (this is the criteria to detect end of a loop)
+	 
+	 - The lists are always ordered. The criteria are described bellow. the functions to order them are referenced in dict_obj_info
+	 
+	 - The dict_lock must be held for any list operation.
+	 
+	 => VENDORS:
+	 list[0]: list of the vendors, ordered by their id. The sentinel is g_dict_vendors (vendor with id 0)
+	 list[1]: sentinel for the list of AVPs from this vendor, ordered by AVP code.
+	 list[2]: sentinel for the list of AVPs from this vendor, ordered by AVP name.
+	 
+	 => APPLICATIONS:
+	 list[0]: list of the applications, ordered by their id. The sentinel is g_dict_applications (application with id 0)
+	 list[1]: not used
+	 list[2]: not used.
+	 
+	 => TYPES:
+	 list[0]: list of the types, ordered by their names. The sentinel is g_list_types.
+	 list[1]: sentinel for the type_enum list of this type, ordered by their constant name.
+	 list[2]: sentinel for the type_enum list of this type, ordered by their constant value.
+	 
+	 => TYPE_ENUMS:
+	 list[0]: list of the contants for a given type, ordered by the constant name. Sentinel is a (list[1]) element of a TYPE object.
+	 list[1]: list of the contants for a given type, ordered by the constant value. Sentinel is a (list[2]) element of a TYPE object.
+	 list[2]: not used
+	 
+	 => AVPS:
+	 list[0]: list of the AVP from a given vendor, ordered by avp code. Sentinel is a list[1] element of a VENDOR object.
+	 list[1]: list of the AVP from a given vendor, ordered by avp name. Sentinel is a list[2] element of a VENDOR object.
+	 list[2]: sentinel for the rule list that apply to this AVP.
+	 
+	 => COMMANDS:
+	 list[0]: list of the commands, ordered by their names. The sentinel is g_list_cmd_name.
+	 list[1]: list of the commands, ordered by their command code and 'R' flag. The sentinel is g_list_cmd_code.
+	 list[2]: sentinel for the rule list that apply to this command.
+	 
+	 => RULES:
+	 list[0]: list of the rules for a given (grouped) AVP or Command, ordered by the AVP name to which they refer. sentinel is list[2] of a command or (grouped) avp.
+	 list[1]: not used
+	 list[2]: not used.
+	 
+	 */
+	 
+	 /* Sentinel for the dispatch callbacks */
+	 struct fd_list		disp_cbs;
+	
+};
+
+/* Definition of the dictionary structure */
+struct dictionary {
+	int		 	dict_eyec;		/* Eye-catcher for the dictionary (DICT_EYECATCHER) */
+	
+	pthread_rwlock_t 	dict_lock;		/* The global rwlock for the dictionary */
+	
+	struct dict_object	dict_vendors;		/* Sentinel for the list of vendors, corresponding to vendor 0 */
+	struct dict_object	dict_applications;	/* Sentinel for the list of applications, corresponding to app 0 */
+	struct fd_list		dict_types;		/* Sentinel for the list of types */
+	struct fd_list		dict_cmd_name;		/* Sentinel for the list of commands, ordered by names */
+	struct fd_list		dict_cmd_code;		/* Sentinel for the list of commands, ordered by codes */
+	
+	struct dict_object	dict_cmd_error;		/* Special command object for answers with the 'E' bit set */
+	
+	int			dict_count[DICT_TYPE_MAX]; /* Number of objects of each type */
+};
+
+/* Forward declarations of dump functions */
+static void dump_vendor_data 	  ( void * data );
+static void dump_application_data ( void * data );
+static void dump_type_data 	  ( void * data );
+  /* the dump function for enum has a different prototype since it need the datatype */
+static void dump_avp_data 	  ( void * data );
+static void dump_command_data 	  ( void * data );
+static void dump_rule_data 	  ( void * data );
+
+/* Forward declarations of search functions */
+static int search_vendor 	( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
+static int search_application   ( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
+static int search_type 		( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
+static int search_enumval 	( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
+static int search_avp		( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
+static int search_cmd		( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
+static int search_rule		( struct dictionary * dict, int criteria, void * what, struct dict_object **result );
+
+/* The following array contains lot of data about the different types of objects, for automated handling */
+static struct {
+	enum dict_object_type 	type; 		/* information for this type */
+	char *			name;		/* string describing this object, for debug */
+	size_t			datasize;	/* The size of the data structure */
+	int			parent;		/* 0: never; 1: may; 2: must */
+	enum dict_object_type	parenttype;	/* The type of the parent, when relevant */
+	int			eyecatcher;	/* A kind of signature for this object */
+	void 		      (*dump_data)(void * data );	/* The function to dump the data section */
+	int 		      (*search_fct)(struct dictionary * dict, int criteria, void * what, struct dict_object **result );;	/* The function to search an object of this type */
+	int			haslist[NB_LISTS_PER_OBJ];	/* Tell if this list is used */
+} dict_obj_info[] = { { 0, "(error)", 0, 0, 0, 0, NULL, NULL, {0, 0, 0} }
+
+	/* type			 name		datasize		   	  parent  	parenttype 
+			eyecatcher		dump_data	  	search_fct,		haslist[] 	*/
+
+	,{ DICT_VENDOR,		"VENDOR",	sizeof(struct dict_vendor_data),	0, 	0,
+			OBJECT_EYECATCHER + 1, 	dump_vendor_data, 	search_vendor, 		{ 1, 0, 0 } }
+	
+	,{ DICT_APPLICATION,	"APPLICATION",	sizeof(struct dict_application_data),	1, 	DICT_VENDOR,
+			OBJECT_EYECATCHER + 2,	dump_application_data,	search_application,	{ 1, 0, 0 } }
+	
+	,{ DICT_TYPE,		"TYPE",		sizeof(struct dict_type_data),		1, 	DICT_APPLICATION,
+			OBJECT_EYECATCHER + 3,	dump_type_data,		search_type,		{ 1, 0, 0 } }
+	
+	,{ DICT_ENUMVAL,	"ENUMVAL",	sizeof(struct dict_enumval_data),	2, 	DICT_TYPE,
+			OBJECT_EYECATCHER + 4,	NULL,			search_enumval,	{ 1, 1, 0 } }
+	
+	,{ DICT_AVP,		"AVP",		sizeof(struct dict_avp_data),		1, 	DICT_TYPE,
+			OBJECT_EYECATCHER + 5,	dump_avp_data,		search_avp,		{ 1, 1,	0 } }
+	
+	,{ DICT_COMMAND,	"COMMAND",	sizeof(struct dict_cmd_data),		1, 	DICT_APPLICATION,
+			OBJECT_EYECATCHER + 6,	dump_command_data,	search_cmd,		{ 1, 1, 0 } }
+	
+	,{ DICT_RULE,		"RULE",		sizeof(struct dict_rule_data),		2, 	-1 /* special case: grouped avp or command */,
+			OBJECT_EYECATCHER + 7,	dump_rule_data,		search_rule,		{ 1, 0, 0 } }
+	
+};
+	
+/* Macro to verify a "type" value */
+#define CHECK_TYPE( type ) ( ((type) > 0) && ((type) <= DICT_TYPE_MAX) )
+
+/* Cast macro */
+#define _O( object ) ((struct dict_object *) (object))
+
+/* Get information line for a given object */
+#define _OBINFO(object) (dict_obj_info[CHECK_TYPE(_O(object)->type) ? _O(object)->type : 0])
+
+
+
+
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+/*                                                                                                     */
+/*                                  Objects management                                                 */
+/*                                                                                                     */
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+
+/* Functions to manage the objects creation and destruction. */
+
+/* Duplicate a string inplace */
+#define DUP_string( str ) {				\
+	char * __str = (str);				\
+	CHECK_MALLOC( (str) = strdup(__str) );		\
+}
+	
+/* Initialize an object */
+static void init_object( struct dict_object * obj, enum dict_object_type type )
+{
+	int i;
+	
+	TRACE_ENTRY("%p %d", obj, type);
+	
+	/* Clean the object first */
+	memset ( obj, 0, sizeof(struct dict_object));
+	
+	CHECK_PARAMS_DO(  CHECK_TYPE(type),  return  );
+
+	obj->type = type;
+	obj->objeyec = OBJECT_EYECATCHER;
+	obj->typeyec = _OBINFO(obj).eyecatcher;
+
+	/* We don't initialize the data nor the parent here */
+	
+	/* Now init the lists */
+	for (i=0; i<NB_LISTS_PER_OBJ; i++) {
+		if (_OBINFO(obj).haslist[i] != 0) 
+			fd_list_init(&obj->list[i], obj);
+		else
+			fd_list_init(&obj->list[i], NULL);
+	}
+	
+	fd_list_init(&obj->disp_cbs, NULL);
+}
+
+/* Initialize the "data" part of an object */
+static int init_object_data(void * dest, void * source, enum dict_object_type type)
+{
+	TRACE_ENTRY("%p %p %d", dest, source, type);
+	CHECK_PARAMS( dest && source && CHECK_TYPE(type) );
+	
+	/* Generic: copy the full data structure */	
+	memcpy( dest, source, dict_obj_info[type].datasize );
+	
+	/* Then strings must be duplicated, not copied */
+	/* This function might be simplified by always defining the "name" field as the first field of the structures, but... it's error-prone */
+	switch (type) {
+		case DICT_VENDOR:
+			DUP_string( ((struct dict_vendor_data *)dest)->vendor_name );
+			break;
+		
+		case DICT_APPLICATION:
+			DUP_string( ((struct dict_application_data *)dest)->application_name );
+			break;
+			
+		case DICT_TYPE:
+			DUP_string( ((struct dict_type_data *)dest)->type_name );
+			break;
+			
+		case DICT_ENUMVAL:
+			DUP_string( ((struct dict_enumval_data *)dest)->enum_name );
+			break;
+
+		case DICT_AVP:
+			DUP_string( ((struct dict_avp_data *)dest)->avp_name );
+			break;
+			
+		case DICT_COMMAND:
+			DUP_string( ((struct dict_cmd_data *)dest)->cmd_name );
+			break;
+		
+		default:
+			/* Nothing to do for RULES */
+			;
+	}
+	
+	return 0;
+}
+
+/* Check that an object is valid (1: OK, 0: error) */
+static int verify_object( struct dict_object * obj )
+{
+	TRACE_ENTRY("%p", obj);
+	
+	CHECK_PARAMS_DO(  obj
+			&& (obj->objeyec == OBJECT_EYECATCHER)
+			&& CHECK_TYPE(obj->type)
+			&& (obj->typeyec == dict_obj_info[obj->type].eyecatcher),
+		{
+			if (obj) {
+				TRACE_DEBUG(FULL, "Invalid object : %p\n"
+						  "     obj->objeyec : %x / %x\n"
+						  "     obj->type    : %d\n"
+						  "     obj->objeyec : %x / %x\n"
+						  "     obj->typeyec : %x / %x", 
+						obj,
+						obj->objeyec, OBJECT_EYECATCHER,
+						obj->type,
+						obj->objeyec, OBJECT_EYECATCHER,
+						obj->typeyec, _OBINFO(obj).eyecatcher);
+			}
+			return 0;
+		}  );
+	
+	/* The object is probably valid. */
+	return 1;
+}
+
+/* Free the data associated to an object */
+static void destroy_object_data(struct dict_object * obj)
+{
+	/* TRACE_ENTRY("%p", obj); */
+	
+	switch (obj->type) {
+		case DICT_VENDOR:
+			free( obj->data.vendor.vendor_name );
+			break;
+		
+		case DICT_APPLICATION:
+			free( obj->data.application.application_name );
+			break;
+			
+		case DICT_TYPE:
+			free( obj->data.type.type_name );
+			break;
+			
+		case DICT_ENUMVAL:
+			free( obj->data.enumval.enum_name );
+			break;
+
+		case DICT_AVP:
+			free( obj->data.avp.avp_name );
+			break;
+			
+		case DICT_COMMAND:
+			free( obj->data.cmd.cmd_name );
+			break;
+		
+		default:
+			/* nothing to do */
+			;
+	}
+}
+
+/* Forward declaration */
+static void destroy_object(struct dict_object * obj);
+
+/* Destroy all objects in a list - the lock must be held */
+static void destroy_list(struct fd_list * head) 
+{
+	/* TRACE_ENTRY("%p", head); */
+	
+	/* loop in the list */
+	while (!FD_IS_LIST_EMPTY(head))
+	{
+		/* When destroying the object, it is unlinked from the list */
+		destroy_object(_O(head->next->o));
+	}
+}
+	
+/* Free an object and its sublists */
+static void destroy_object(struct dict_object * obj)
+{
+	int i;
+	
+	/* TRACE_ENTRY("%p", obj); */
+	
+	/* Update global count */
+	if (obj->dico) 
+		obj->dico->dict_count[obj->type]--;
+	
+	/* Mark the object as invalid */
+	obj->objeyec = 0xdead;
+	
+	/* First, destroy the data associated to the object */
+	destroy_object_data(obj);
+	
+	for (i=0; i<NB_LISTS_PER_OBJ; i++) {
+		if (_OBINFO(obj).haslist[i])
+			/* unlink the element from the list */
+			fd_list_unlink( &obj->list[i] );
+		else
+			/* This is either a sentinel or unused (=emtpy) list, let's destroy it */
+			destroy_list( &obj->list[i] );
+	}
+	
+	/* Unlink all elements from the dispatch list; they will be freed when callback is unregistered */
+	while (!FD_IS_LIST_EMPTY(&obj->disp_cbs)) {
+		fd_list_unlink( obj->disp_cbs.next );
+	}
+	
+	/* Last, destroy the object */
+	free(obj);
+}
+
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+/*                                                                                                     */
+/*                                  Compare functions                                                  */
+/*                                                                                                     */
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+
+/* Compare two values */
+#define ORDER_scalar( i1, i2 ) \
+	((i1 < i2 ) ? -1 : ( i1 > i2 ? 1 : 0 )) 
+
+
+/* Compare two vendor objects by their id (checks already performed) */
+static int order_vendor_by_id ( struct dict_object *o1, struct dict_object *o2 )
+{
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	return ORDER_scalar( o1->data.vendor.vendor_id, o2->data.vendor.vendor_id );
+}
+
+/* Compare two application objects by their id (checks already performed) */
+static int order_appli_by_id  ( struct dict_object *o1, struct dict_object *o2 )
+{
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	return ORDER_scalar( o1->data.application.application_id, o2->data.application.application_id );
+}
+
+/* Compare two type objects by their name (checks already performed) */
+static int order_type_by_name ( struct dict_object *o1, struct dict_object *o2 )
+{
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	return strcmp( o1->data.type.type_name, o2->data.type.type_name );
+}
+
+/* Compare two type_enum objects by their names (checks already performed) */
+static int order_enum_by_name ( struct dict_object *o1, struct dict_object *o2 )
+{
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	return strcmp( o1->data.enumval.enum_name, o2->data.enumval.enum_name );
+}
+
+/* Compare two type_enum objects by their values (checks already performed) */
+static int order_enum_by_val  ( struct dict_object *o1, struct dict_object *o2 )
+{
+	size_t oslen;
+	int cmp = 0;
+	
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	/* The comparison function depends on the type of data */
+	switch ( o1->parent->data.type.type_base ) {
+		case AVP_TYPE_OCTETSTRING:
+			oslen = o1->data.enumval.enum_value.os.len;
+			if (o2->data.enumval.enum_value.os.len < oslen)
+				oslen = o2->data.enumval.enum_value.os.len;
+			cmp = memcmp(o1->data.enumval.enum_value.os.data, o2->data.enumval.enum_value.os.data, oslen );
+			return (cmp ? cmp : ORDER_scalar(o1->data.enumval.enum_value.os.len,o2->data.enumval.enum_value.os.len));
+		
+		case AVP_TYPE_INTEGER32:
+			return ORDER_scalar( o1->data.enumval.enum_value.i32, o2->data.enumval.enum_value.i32 );
+
+		case AVP_TYPE_INTEGER64:
+			return ORDER_scalar( o1->data.enumval.enum_value.i64, o2->data.enumval.enum_value.i64 );
+
+		case AVP_TYPE_UNSIGNED32:
+			return ORDER_scalar( o1->data.enumval.enum_value.u32, o2->data.enumval.enum_value.u32 );
+
+		case AVP_TYPE_UNSIGNED64:
+			return ORDER_scalar( o1->data.enumval.enum_value.u64, o2->data.enumval.enum_value.u64 );
+
+		case AVP_TYPE_FLOAT32:
+			return ORDER_scalar( o1->data.enumval.enum_value.f32, o2->data.enumval.enum_value.f32 );
+
+		case AVP_TYPE_FLOAT64:
+			return ORDER_scalar( o1->data.enumval.enum_value.f64, o2->data.enumval.enum_value.f64 );
+
+		case AVP_TYPE_GROUPED:
+		default:
+			ASSERT(0);
+	}
+	return 0;
+}
+
+/* Compare two avp objects by their codes (checks already performed) */
+static int order_avp_by_code  ( struct dict_object *o1, struct dict_object *o2 )
+{
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	return ORDER_scalar( o1->data.avp.avp_code, o2->data.avp.avp_code );
+}
+
+/* Compare two avp objects by their names (checks already performed) */
+static int order_avp_by_name  ( struct dict_object *o1, struct dict_object *o2 )
+{
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	return strcmp( o1->data.avp.avp_name, o2->data.avp.avp_name );
+}
+
+/* Compare two command objects by their names (checks already performed) */
+static int order_cmd_by_name  ( struct dict_object *o1, struct dict_object *o2 )
+{
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	return strcmp( o1->data.cmd.cmd_name, o2->data.cmd.cmd_name );
+}
+
+/* Compare two command objects by their codes and flags (request or answer) (checks already performed) */
+static int order_cmd_by_codefl( struct dict_object *o1, struct dict_object *o2 )
+{
+	uint8_t fl1, fl2;
+	int cmp = 0;
+	
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	cmp = ORDER_scalar( o1->data.cmd.cmd_code, o2->data.cmd.cmd_code );
+	if (cmp) 
+		return cmp;
+	
+	/* Same command code, we must compare the value of the 'R' flag */
+	fl1 = o1->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST;
+	fl2 = o2->data.cmd.cmd_flag_val & CMD_FLAG_REQUEST;
+	
+	/* We want requests first, so we reverse the operators here */
+	return ORDER_scalar(fl2, fl1);
+		
+}
+
+/* Compare two rule object by the AVP name that they refer (checks already performed) */
+static int order_rule_by_avpn ( struct dict_object *o1, struct dict_object *o2 )
+{
+	TRACE_ENTRY("%p %p", o1, o2);
+	
+	return strcmp( o1->data.rule.rule_avp->data.avp.avp_name, o2->data.rule.rule_avp->data.avp.avp_name );
+}
+
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+/*                                                                                                     */
+/*                                  Search  functions                                                  */
+/*                                                                                                     */
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+
+/* Functions used to search for objects in the lists, according to some criteria */
+
+/* On a general note, if result is not NULL, ENOENT is not returned but *result is NULL. */
+
+/* The following macros assume that "what", "ret", "result" (variables), and "end" (label) exist
+in the local context where they are called. They are meant to be called only from the functions that follow. */
+
+/* For searchs of type "xxx_OF_xxx": children's parent or default parent */
+#define SEARCH_childs_parent( type_of_child, default_parent ) {			\
+	struct dict_object *__child = (struct dict_object *) what;		\
+	CHECK_PARAMS_DO( verify_object(__child) && 				\
+		(__child->type == (type_of_child)), 				\
+		   {  ret = EINVAL; goto end;  }  );				\
+	ret = 0;								\
+	if (result)								\
+		*result = (__child->parent ? __child->parent :(default_parent));\
+}
+
+/* For search of strings in lists. isindex= 1 if the string is the ordering key of the list */
+#define SEARCH_string( str, sentinel, datafield, isindex ) {			\
+	char * __str = (char *) str;						\
+	int __cmp;								\
+	struct fd_list * __li;							\
+	ret = 0;								\
+	for  (__li = (sentinel); __li->next != (sentinel); __li = __li->next) {	\
+		__cmp = strcmp(__str, _O(__li->next->o)->data. datafield );	\
+		if (__cmp == 0) {						\
+			if (result)						\
+				*result = _O(__li->next->o);			\
+			goto end;						\
+		}								\
+		if ((isindex) && (__cmp < 0))					\
+			break;							\
+	}									\
+	if (result)								\
+		*result = NULL;							\
+	else									\
+		ret = ENOENT;							\
+}
+
+/* For search of octetstrings in lists (not \0 terminated). */
+#define SEARCH_ocstring( ostr, length, sentinel, osdatafield, isindex ) {	\
+	unsigned char * __ostr = (unsigned char *) ostr;			\
+	int __cmp;								\
+	size_t __len;								\
+	struct fd_list * __li;							\
+	ret = 0;								\
+	for  (__li = (sentinel); __li->next != (sentinel); __li = __li->next) {	\
+		__len = _O(__li->next->o)->data. osdatafield .len;		\
+		if ( __len > (length) )						\
+			__len = (length);					\
+		__cmp = memcmp(__ostr, 						\
+				_O(__li->next->o)->data. osdatafield .data, 	\
+				__len);						\
+		if (! __cmp) {							\
+			__cmp = ORDER_scalar( length,				\
+				_O(__li->next->o)->data. osdatafield .len); 	\
+		}								\
+		if (__cmp == 0) {						\
+			if (result)						\
+				*result = _O(__li->next->o);			\
+			goto end;						\
+		}								\
+		if ((isindex) && (__cmp < 0))					\
+			break;							\
+	}									\
+	if (result)								\
+		*result = NULL;							\
+	else									\
+		ret = ENOENT;							\
+}
+
+/* For search of AVP name in rule lists. */
+#define SEARCH_ruleavpname( str, sentinel ) {					\
+	char * __str = (char *) str;						\
+	int __cmp;								\
+	struct fd_list * __li;							\
+	ret = 0;								\
+	for  (__li = (sentinel); __li->next != (sentinel); __li = __li->next) {	\
+		__cmp = strcmp(__str, 						\
+		  _O(__li->next->o)->data.rule.rule_avp->data.avp.avp_name);\
+		if (__cmp == 0) {						\
+			if (result)						\
+				*result = _O(__li->next->o);			\
+			goto end;						\
+		}								\
+		if (__cmp < 0)							\
+			break;							\
+	}									\
+	if (result)								\
+		*result = NULL;							\
+	else									\
+		ret = ENOENT;							\
+}
+
+/* For search of scalars in lists. isindex= 1 if the value is the ordering key of the list */
+#define SEARCH_scalar( value, sentinel, datafield, isindex, defaultobj ) {	\
+	int __cmp;								\
+	struct fd_list * __li;							\
+	ret = 0;								\
+	if (  ((defaultobj) != NULL) 						\
+		   && (_O(defaultobj)->data. datafield  == value)) {		\
+		if (result)							\
+			*result = _O(defaultobj);				\
+		goto end;							\
+	}									\
+	for  (__li = (sentinel); __li->next != (sentinel); __li = __li->next) {	\
+		__cmp= ORDER_scalar(value, _O(__li->next->o)->data. datafield );\
+		if (__cmp == 0) {						\
+			if (result)						\
+				*result = _O(__li->next->o);			\
+			goto end;						\
+		}								\
+		if ((isindex) && (__cmp < 0))					\
+			break;							\
+	}									\
+	if (result)								\
+		*result = NULL;							\
+	else									\
+		ret = ENOENT;							\
+}
+
+/* For search of commands in lists by code and flag. R_flag_val = 0 or CMD_FLAG_REQUEST */
+#define SEARCH_codefl( value, R_flag_val, sentinel) {					\
+	int __cmp;								\
+	struct fd_list * __li;							\
+	ret = 0;								\
+	for  (	  __li = (sentinel);	 					\
+		  __li->next != (sentinel); 					\
+		  __li = __li->next) {						\
+		__cmp = ORDER_scalar(value, 					\
+				_O(__li->next->o)->data.cmd.cmd_code );		\
+		if (__cmp == 0) {						\
+			uint8_t __mask, __val;					\
+			__mask = _O(__li->next->o)->data.cmd.cmd_flag_mask;	\
+			__val  = _O(__li->next->o)->data.cmd.cmd_flag_val;	\
+			if ( ! (__mask & CMD_FLAG_REQUEST) )			\
+				continue;					\
+			if ( ( __val & CMD_FLAG_REQUEST ) != R_flag_val )	\
+				continue;					\
+			if (result)						\
+				*result = _O(__li->next->o);			\
+			goto end;						\
+		}								\
+		if (__cmp < 0)							\
+			break;							\
+	}									\
+	if (result)								\
+		*result = NULL;							\
+	else									\
+		ret = ENOENT;							\
+}
+
+static int search_vendor ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
+{
+	int ret = 0;
+	vendor_id_t id;
+	
+	TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
+	
+	switch (criteria) {
+		case VENDOR_BY_ID:
+			id = *(vendor_id_t *) what;
+			SEARCH_scalar( id, &dict->dict_vendors.list[0], vendor.vendor_id, 1, &dict->dict_vendors );
+			break;
+				
+		case VENDOR_BY_NAME:
+			/* "what" is a vendor name */
+			SEARCH_string( what, &dict->dict_vendors.list[0], vendor.vendor_name, 0);
+			break;
+			
+		case VENDOR_OF_APPLICATION:
+			/* "what" should be an application object */
+			SEARCH_childs_parent( DICT_APPLICATION, &dict->dict_vendors );
+			break;
+		
+		default:
+			/* Invalid criteria */
+			CHECK_PARAMS( criteria = 0 );
+	}
+end:
+	return ret;
+}
+
+static int search_application ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
+{
+	int ret = 0;
+	application_id_t id;
+	
+	TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
+	
+	switch (criteria) {
+		case APPLICATION_BY_ID:
+			id = *(application_id_t *) what;
+
+			SEARCH_scalar( id, &dict->dict_applications.list[0],  application.application_id, 1, &dict->dict_applications );
+			break;
+				
+		case APPLICATION_BY_NAME:
+			/* "what" is an application name */
+			SEARCH_string( what, &dict->dict_applications.list[0], application.application_name, 0);
+			break;
+			
+		case APPLICATION_OF_TYPE:
+			/* "what" should be a type object */
+			SEARCH_childs_parent( DICT_TYPE, &dict->dict_applications );
+			break;
+		
+		case APPLICATION_OF_COMMAND:
+			/* "what" should be a command object */
+			SEARCH_childs_parent( DICT_COMMAND, &dict->dict_applications );
+			break;
+		
+		default:
+			/* Invalid criteria */
+			CHECK_PARAMS( criteria = 0 );
+	}
+end:
+	return ret;
+}
+
+static int search_type ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
+{
+	int ret = 0;
+	
+	TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
+	
+	switch (criteria) {
+		case TYPE_BY_NAME:
+			/* "what" is a type name */
+			SEARCH_string( what, &dict->dict_types, type.type_name, 1);
+			break;
+			
+		case TYPE_OF_ENUMVAL:
+			/* "what" should be a type_enum object */
+			SEARCH_childs_parent( DICT_ENUMVAL, NULL );
+			break;
+		
+		case TYPE_OF_AVP:
+			/* "what" should be an avp object */
+			SEARCH_childs_parent( DICT_AVP, NULL );
+			break;
+		
+				
+		default:
+			/* Invalid criteria */
+			CHECK_PARAMS( criteria = 0 );
+	}
+end:
+	return ret;
+}
+
+static int search_enumval ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
+{
+	int ret = 0;
+	
+	TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
+	
+	switch (criteria) {
+		case ENUMVAL_BY_STRUCT:
+			{
+				struct dict_object * parent = NULL;
+				struct dict_enumval_request * _what = (struct dict_enumval_request *) what;
+				
+				CHECK_PARAMS(  _what  &&  ( _what->type_obj || _what->type_name )  );
+				
+				if (_what->type_obj != NULL) {
+					parent = _what->type_obj;
+					CHECK_PARAMS(  verify_object(parent)  &&  (parent->type == DICT_TYPE)  );
+				} else {
+					/* We received only the type name, we must find it first */
+					CHECK_FCT_DO( search_type( dict, TYPE_BY_NAME, _what->type_name, &parent ),
+							CHECK_PARAMS( 0 ) );
+				}
+				
+				/* From here the "parent" object is valid */
+				
+				if ( _what->search.enum_name != NULL ) {
+					/* We are looking for this string */
+					SEARCH_string(  _what->search.enum_name, &parent->list[1], enumval.enum_name, 1 );
+				} else {
+					/* We are looking for the value in enum_value */
+					switch (parent->data.type.type_base) {
+						case AVP_TYPE_OCTETSTRING:
+							SEARCH_ocstring( _what->search.enum_value.os.data, 
+									 _what->search.enum_value.os.len, 
+									 &parent->list[2], 
+									 enumval.enum_value.os , 
+									 1 );
+							break;
+
+						case AVP_TYPE_INTEGER32:
+							SEARCH_scalar(	_what->search.enum_value.i32,
+									&parent->list[2],
+									enumval.enum_value.i32,
+									1,
+									(struct dict_object *)NULL);
+							break;
+							
+						case AVP_TYPE_INTEGER64:
+							SEARCH_scalar(	_what->search.enum_value.i64,
+									&parent->list[2],
+									enumval.enum_value.i64,
+									1,
+									(struct dict_object *)NULL);
+							break;
+							
+						case AVP_TYPE_UNSIGNED32:
+							SEARCH_scalar(	_what->search.enum_value.u32,
+									&parent->list[2],
+									enumval.enum_value.u32,
+									1,
+									(struct dict_object *)NULL);
+							break;
+							
+						case AVP_TYPE_UNSIGNED64:
+							SEARCH_scalar(	_what->search.enum_value.u64,
+									&parent->list[2],
+									enumval.enum_value.u64,
+									1,
+									(struct dict_object *)NULL);
+							break;
+							
+						case AVP_TYPE_FLOAT32:
+							SEARCH_scalar(	_what->search.enum_value.f32,
+									&parent->list[2],
+									enumval.enum_value.f32,
+									1,
+									(struct dict_object *)NULL);
+							break;
+							
+						case AVP_TYPE_FLOAT64:
+							SEARCH_scalar(	_what->search.enum_value.f64,
+									&parent->list[2],
+									enumval.enum_value.f64,
+									1,
+									(struct dict_object *)NULL);
+							break;
+							
+						default:
+							/* Invalid parent type basetype */
+							CHECK_PARAMS( parent = NULL );
+					}
+				}
+				
+			}
+			break;
+		
+				
+		default:
+			/* Invalid criteria */
+			CHECK_PARAMS( criteria = 0 );
+	}
+end:
+	return ret;
+}
+
+static int search_avp ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
+{
+	int ret = 0;
+	
+	TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
+	
+	switch (criteria) {
+		case AVP_BY_CODE:
+			{
+				avp_code_t code;
+				code = *(avp_code_t *) what;
+
+				SEARCH_scalar( code, &dict->dict_vendors.list[1],  avp.avp_code, 1, (struct dict_object *)NULL );
+			}
+			break;
+				
+		case AVP_BY_NAME:
+			/* "what" is the AVP name, vendor 0 */
+			SEARCH_string( what, &dict->dict_vendors.list[2], avp.avp_name, 1);
+			break;
+			
+		case AVP_BY_CODE_AND_VENDOR:
+		case AVP_BY_NAME_AND_VENDOR:
+			{
+				struct dict_avp_request * _what = (struct dict_avp_request *) what;
+				struct dict_object * vendor = NULL;
+				
+				CHECK_PARAMS( (criteria != AVP_BY_NAME_AND_VENDOR) || _what->avp_name  );
+				
+				/* Now look for the vendor first */
+				CHECK_FCT( search_vendor( dict, VENDOR_BY_ID, &_what->avp_vendor, &vendor ) );
+				if (vendor == NULL) {
+					if (result)
+						*result = NULL;
+					else
+						ret = ENOENT;
+					goto end;
+				}
+				
+				/* We now have our vendor = head of the appropriate avp list */
+				if (criteria == AVP_BY_NAME_AND_VENDOR) {
+					SEARCH_string( _what->avp_name, &vendor->list[2], avp.avp_name, 1);
+				} else {
+					/* AVP_BY_CODE_AND_VENDOR */
+					SEARCH_scalar( _what->avp_code, &vendor->list[1],  avp.avp_code, 1, (struct dict_object *)NULL );
+				}
+			}
+			break;
+		
+		default:
+			/* Invalid criteria */
+			CHECK_PARAMS( criteria = 0 );
+	}
+end:
+	return ret;
+}
+
+static int search_cmd ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
+{
+	int ret = 0;
+	
+	TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
+	
+	switch (criteria) {
+		case CMD_BY_NAME:
+			/* "what" is a command name */
+			SEARCH_string( what, &dict->dict_cmd_name, cmd.cmd_name, 1);
+			break;
+			
+		case CMD_BY_CODE_R:
+		case CMD_BY_CODE_A:
+			{
+				command_code_t code;
+				uint8_t searchfl = 0;
+				
+				/* The command code that we are searching */
+				code = *(command_code_t *) what;
+				
+				/* The flag (request or answer) of the command we are searching */
+				if (criteria == CMD_BY_CODE_R) {
+					searchfl = CMD_FLAG_REQUEST;
+				}
+				
+				/* perform the search */
+				SEARCH_codefl( code, searchfl, &dict->dict_cmd_code );
+			}
+			break;
+				
+		case CMD_ANSWER:
+			{
+				/* "what" is a command object of type "request" */
+				struct dict_object * req = (struct dict_object *) what;
+				struct dict_object * ans = NULL;
+				
+				CHECK_PARAMS( verify_object(req) 
+						&& (req->type == DICT_COMMAND)
+						&& (req->data.cmd.cmd_flag_mask & CMD_FLAG_REQUEST)
+						&& (req->data.cmd.cmd_flag_val  & CMD_FLAG_REQUEST) );
+				
+				/* The answer is supposed to be the next element in the list, if it exists */
+				ans = req->list[1].next->o;
+				if ( ans == NULL ) {
+					TRACE_DEBUG( FULL, "the request was the last element in the list" );
+					ret = ENOENT;
+					goto end;
+				}
+				
+				/* Now check that the ans element is really the correct one */
+				if (  (ans->data.cmd.cmd_code != req->data.cmd.cmd_code)
+				   || (!(ans->data.cmd.cmd_flag_mask & CMD_FLAG_REQUEST))
+				   || (  ans->data.cmd.cmd_flag_val  & CMD_FLAG_REQUEST ) ) {
+					TRACE_DEBUG( FULL, "the answer does not follow the request in the list" );
+					ret = ENOENT;
+					goto end;
+				}
+				
+				if (result)
+					*result = ans;
+				ret = 0;
+			}						
+			break;
+			
+		default:
+			/* Invalid criteria */
+			CHECK_PARAMS( criteria = 0 );
+	}
+end:
+	return ret;
+}
+
+static int search_rule ( struct dictionary * dict, int criteria, void * what, struct dict_object **result )
+{
+	int ret = 0;
+	
+	TRACE_ENTRY("%p %d %p %p", dict, criteria, what, result);
+	
+	switch (criteria) {
+		case RULE_BY_AVP_AND_PARENT:
+			{
+				struct dict_object * parent = NULL;
+				struct dict_object * avp = NULL;
+				struct dict_rule_request * _what = (struct dict_rule_request *) what;
+				
+				CHECK_PARAMS( _what 
+						&& (parent = _what->rule_parent)
+						&& (avp    = _what->rule_avp   ) );
+				
+				CHECK_PARAMS( verify_object(parent) 
+						&& ((parent->type == DICT_COMMAND) 
+						 || ((parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED))) );
+				
+				CHECK_PARAMS( verify_object(avp) && (avp->type == DICT_AVP) );
+				
+				/* Perform the search */
+				SEARCH_ruleavpname( avp->data.avp.avp_name, &parent->list[2]);
+				
+			}
+			break;
+			
+		default:
+			/* Invalid criteria */
+			CHECK_PARAMS( criteria = 0 );
+	}
+end:
+	return ret;
+}
+
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+/*                                                                                                     */
+/*                                  Dump / debug functions                                             */
+/*                                                                                                     */
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+/* The following functions are used to debug the module, and allow to print out the content of the dictionary */
+static void dump_vendor_data ( void * data )
+{
+	struct dict_vendor_data * vendor = (struct dict_vendor_data *)data;
+	
+	fd_log_debug("data: %-6u \"%s\"", vendor->vendor_id, vendor->vendor_name);
+}
+static void dump_application_data ( void * data )
+{
+	struct dict_application_data * appli = (struct dict_application_data *) data;
+	fd_log_debug("data: %-6u \"%s\"", appli->application_id, appli->application_name);
+}
+static void dump_type_data ( void * data )
+{
+	struct dict_type_data * type = ( struct dict_type_data * ) data;
+	
+	fd_log_debug("data: %-12s \"%s\"", 
+			type_base_name[type->type_base], 
+			type->type_name);
+}
+static void dump_enumval_data ( struct dict_enumval_data * enumval, enum dict_avp_basetype type )
+{
+	const int LEN_MAX = 20;
+	fd_log_debug("data: (%-12s) \"%s\" -> ", type_base_name[type], enumval->enum_name);
+	switch (type) {
+		case AVP_TYPE_OCTETSTRING:
+			{
+				int i, n=LEN_MAX;
+				if (enumval->enum_value.os.len < LEN_MAX)
+					n = enumval->enum_value.os.len;
+				for (i=0; i < n; i++)
+					fd_log_debug("0x%02.2X/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i]));
+				if (n == LEN_MAX)
+					fd_log_debug("...");
+			}
+			break;
+		
+		case AVP_TYPE_INTEGER32:
+			fd_log_debug("%i", enumval->enum_value.i32);
+			break;
+
+		case AVP_TYPE_INTEGER64:
+			fd_log_debug("%lli", enumval->enum_value.i64);
+			break;
+
+		case AVP_TYPE_UNSIGNED32:
+			fd_log_debug("%u", enumval->enum_value.u32);
+			break;
+
+		case AVP_TYPE_UNSIGNED64:
+			fd_log_debug("%llu", enumval->enum_value.u64);
+			break;
+
+		case AVP_TYPE_FLOAT32:
+			fd_log_debug("%f", enumval->enum_value.f32);
+			break;
+
+		case AVP_TYPE_FLOAT64:
+			fd_log_debug("%g", enumval->enum_value.f64);
+			break;
+		
+		default:
+			fd_log_debug("??? (ERROR unknown type %d)", type);
+	}
+}
+static void dump_avp_data ( void * data )
+{
+	struct dict_avp_data * avp = (struct dict_avp_data * ) data;
+	fd_log_debug("data: v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %-6u \"%s\"", 
+			DUMP_AVPFL_val(avp->avp_flag_val), 
+			DUMP_AVPFL_val(avp->avp_flag_mask), 
+			type_base_name[avp->avp_basetype], 
+			avp->avp_code, 
+			avp->avp_name );
+}
+static void dump_command_data ( void * data )
+{
+	struct dict_cmd_data * cmd = (struct dict_cmd_data *) data;
+	fd_log_debug("data: v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %-6u \"%s\"", 
+			DUMP_CMDFL_val(cmd->cmd_flag_val), DUMP_CMDFL_val(cmd->cmd_flag_mask), cmd->cmd_code, cmd->cmd_name);
+}
+static void dump_rule_data ( void * data )
+{
+	struct dict_rule_data * rule = (struct dict_rule_data * )data;
+	fd_log_debug("data: pos:%d ord:%d m/M:%2d/%2d avp:\"%s\"", 
+			rule->rule_position, 
+			rule->rule_order, 
+			rule->rule_min, 
+			rule->rule_max,
+			rule->rule_avp->data.avp.avp_name);
+}
+
+static void dump_object ( struct dict_object * obj, int parents, int depth, int indent );
+
+static void dump_list ( struct fd_list * sentinel, int parents, int depth, int indent )
+{
+	struct fd_list * li = sentinel;
+	/* We don't lock here, the caller must have taken the dictionary lock for reading already */
+	while (li->next != sentinel)
+	{
+		li = li->next;
+		dump_object( _O(li->o), parents, depth, indent );
+	}
+}
+
+static void dump_object ( struct dict_object * obj, int parents, int depth, int indent )
+{
+	if (obj == NULL)
+		return;
+	
+	if (parents)
+		dump_object (obj->parent, parents-1, 0, indent + 1 );
+	
+	fd_log_debug("%*s@%p: %s%s (p:%-9p) ", 
+			indent,
+			"",
+			obj, 
+			verify_object(obj) ? "" : "INVALID ", 
+			_OBINFO(obj).name, 
+			obj->parent);
+	
+	if (obj->type == DICT_ENUMVAL)
+		dump_enumval_data ( &obj->data.enumval, obj->parent->data.type.type_base );
+	else
+		_OBINFO(obj).dump_data(&obj->data);
+	
+	fd_log_debug("\n");
+	
+	if (depth) {
+		int i;
+		for (i=0; i<NB_LISTS_PER_OBJ; i++) {
+			if ((obj->list[i].o == NULL) && (obj->list[i].next != &obj->list[i])) {
+				fd_log_debug("%*s>%p: list[%d]:\n", indent, "", obj, i);
+				dump_list(&obj->list[i], parents, depth - 1, indent + 2);
+			}
+		}
+	}
+}
+
+void fd_dict_dump_object(struct dict_object * obj)
+{
+	fd_log_debug("Dictionary object %p dump:\n", obj);
+	dump_object( obj, 1, 2, 2 );
+}
+
+void fd_dict_dump(struct dictionary * dict)
+{
+	int i;
+	
+	CHECK_PARAMS_DO(dict && (dict->dict_eyec == DICT_EYECATCHER), return);
+	
+	CHECK_POSIX_DO(  pthread_rwlock_rdlock( &dict->dict_lock ), /* ignore */  );
+	
+	fd_log_debug("######################################################\n");
+	fd_log_debug("###### Dumping vendors, AVPs and related rules #######\n");
+	
+	dump_object( &dict->dict_vendors, 0, 3, 0 );
+	
+	fd_log_debug("###### Dumping applications #######\n");
+
+	dump_object( &dict->dict_applications, 0, 1, 0 );
+	
+	fd_log_debug("###### Dumping types #######\n");
+
+	dump_list( &dict->dict_types, 0, 2, 0 );
+	
+	fd_log_debug("###### Dumping commands per name #######\n");
+
+	dump_list( &dict->dict_cmd_name, 0, 2, 0 );
+	
+	fd_log_debug("###### Dumping commands per code and flags #######\n");
+
+	dump_list( &dict->dict_cmd_code, 0, 0, 0 );
+	
+	fd_log_debug("###### Statistics #######\n");
+
+	for (i=1; i<=DICT_TYPE_MAX; i++)
+		fd_log_debug(" %5d objects of type %s\n", dict->dict_count[i], dict_obj_info[i].name);
+	
+	fd_log_debug("######################################################\n");
+	
+	/* Free the rwlock */
+	CHECK_POSIX_DO(  pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */  );
+}
+
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+/*                                                                                                     */
+/*                                  Exported functions                                                 */
+/*                                                                                                     */
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+
+/* These are the functions exported outside libfreediameter. */
+
+/* Get the data associated to an object */
+int fd_dict_gettype ( struct dict_object * object, enum dict_object_type * type)
+{
+	TRACE_ENTRY("%p %p", object, type);
+	
+	CHECK_PARAMS( type && verify_object(object) );
+	
+	/* Copy the value and return */
+	*type = object->type;
+	return 0;
+}
+
+int fd_dict_getdict ( struct dict_object * object, struct dictionary ** dict)
+{
+	TRACE_ENTRY("%p %p", object, dict);
+	
+	CHECK_PARAMS( dict && verify_object(object) );
+	
+	/* Copy the value and return */
+	*dict = object->dico;
+	return 0;
+}
+
+
+/* Get the data associated to an object */
+int fd_dict_getval ( struct dict_object * object, void * val)
+{
+	TRACE_ENTRY("%p %p", object, val);
+	
+	CHECK_PARAMS( val && verify_object(object) );
+	
+	/* Copy the value and return */
+	memcpy(val, &object->data, _OBINFO(object).datasize);;
+	return 0;
+}
+
+/* Add a new object in the dictionary */
+int fd_dict_new ( struct dictionary * dict, enum dict_object_type type, void * data, struct dict_object * parent, struct dict_object **ref )
+{
+	int ret = 0;
+	struct dict_object * new = NULL;
+	struct dict_object * vendor = NULL;
+	
+	TRACE_ENTRY("%p %d(%s) %p %p %p", dict, type, dict_obj_info[CHECK_TYPE(type) ? type : 0].name, data, parent, ref);
+	
+	/* Check parameters */
+	CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && CHECK_TYPE(type) && data  );
+	
+	/* Check the "parent" parameter */
+	switch (dict_obj_info[type].parent) {
+		case 0:	/* parent is forbidden */
+			CHECK_PARAMS( parent == NULL );
+		
+		case 1:	/* parent is optional */
+			if (parent == NULL)
+				break;
+		
+		case 2: /* parent is mandatory */
+			CHECK_PARAMS(  verify_object(parent)  );
+			
+			if (type == DICT_RULE ) { /* Special case : grouped AVP or Command parents are allowed */
+				CHECK_PARAMS( (parent->type == DICT_COMMAND ) 
+						|| ( (parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED ) ) );
+			} else {
+				CHECK_PARAMS( parent->type == dict_obj_info[type].parenttype );
+			}
+	}
+	
+	/* For AVP object, we must also check that the "vendor" referenced exists */
+	if (type == DICT_AVP) {
+		CHECK_FCT_DO(  fd_dict_search( dict, DICT_VENDOR, VENDOR_BY_ID, &(((struct dict_avp_data *)data)->avp_vendor), (void*)&vendor, ENOENT ),
+				CHECK_PARAMS( vendor = NULL )  );
+		
+		/* Also check if a parent is provided, that the type are the same */
+		if (parent) {
+			CHECK_PARAMS(  parent->data.type.type_base == ((struct dict_avp_data *)data)->avp_basetype  );
+		}
+	}
+	
+	/* For RULE object, we must also check that the "avp" referenced exists */
+	if (type == DICT_RULE) {
+		CHECK_PARAMS(  verify_object(((struct dict_rule_data *)data)->rule_avp)  );
+		CHECK_PARAMS(  ((struct dict_rule_data *)data)->rule_avp->type == DICT_AVP  );
+	}
+	
+	/* For COMMAND object, check that the 'R' flag is fixed */
+	if (type == DICT_COMMAND) {
+		CHECK_PARAMS( ((struct dict_cmd_data *)data)->cmd_flag_mask & CMD_FLAG_REQUEST   );
+	}
+	
+	/* Parameters are valid, create the new object */
+	CHECK_MALLOC(  new = malloc(sizeof(struct dict_object))  );
+	
+	/* Initialize the data of the new object */
+	init_object(new, type);
+	init_object_data(&new->data, data, type);
+	new->dico = dict;
+	new->parent = parent;
+	
+	/* We will change the dictionary => acquire the write lock */
+	CHECK_POSIX_DO(  ret = pthread_rwlock_wrlock(&dict->dict_lock),  goto error_free  );
+	
+	/* Now link the object -- this also checks that no object with same keys already exists */
+	switch (type) {
+		case DICT_VENDOR:
+			/* A vendor object is linked in the g_dict_vendors.list[0], by their id */
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &dict->dict_vendors.list[0], &new->list[0], (int (*)(void*, void *))order_vendor_by_id, (void **)ref ),
+					goto error_unlock  );
+			break;
+		
+		case DICT_APPLICATION:
+			/* An application object is linked in the g_dict_applciations.list[0], by their id */
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &dict->dict_applications.list[0], &new->list[0], (int (*)(void*, void *))order_appli_by_id, (void **)ref ),
+					goto error_unlock  );
+			break;
+		
+		case DICT_TYPE:
+			/* A type object is linked in g_list_types by its name */
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &dict->dict_types, &new->list[0], (int (*)(void*, void *))order_type_by_name, (void **)ref ),
+					goto error_unlock  );
+			break;
+		
+		case DICT_ENUMVAL:
+			/* A type_enum object is linked in it's parent 'type' object lists 1 and 2 by its name and values */
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &parent->list[1], &new->list[0], (int (*)(void*, void *))order_enum_by_name, (void **)ref ),
+					goto error_unlock  );
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &parent->list[2], &new->list[1], (int (*)(void*, void *))order_enum_by_val, (void **)ref ),
+					{ fd_list_unlink(&new->list[0]); goto error_unlock; }  );
+			break;
+		
+		case DICT_AVP:
+			/* An avp object is linked in lists 1 and 2 of its vendor, by code and name */
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &vendor->list[1], &new->list[0], (int (*)(void*, void *))order_avp_by_code, (void **)ref ),
+					goto error_unlock  );
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &vendor->list[2], &new->list[1], (int (*)(void*, void *))order_avp_by_name, (void **)ref ),
+					{ fd_list_unlink(&new->list[0]); goto error_unlock; }  );
+			break;
+			
+		case DICT_COMMAND:
+			/* A command object is linked in g_list_cmd_name and g_list_cmd_code by its name and code */
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &dict->dict_cmd_code, &new->list[1], (int (*)(void*, void *))order_cmd_by_codefl, (void **)ref ),
+					goto error_unlock  );
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &dict->dict_cmd_name, &new->list[0], (int (*)(void*, void *))order_cmd_by_name, (void **)ref ),
+					{ fd_list_unlink(&new->list[1]); goto error_unlock; }  );
+			break;
+		
+		case DICT_RULE:
+			/* A rule object is linked in list[2] of its parent command or AVP by the name of the AVP it refers */
+			CHECK_FCT_DO(  ret = fd_list_insert_ordered ( &parent->list[2], &new->list[0], (int (*)(void*, void *))order_rule_by_avpn, (void **)ref ),
+					goto error_unlock  );
+			break;
+			
+		default:
+			ASSERT(0);
+	}
+	
+	/* A new object has been created, increment the global counter */
+	dict->dict_count[type]++;
+	
+	/* Unlock the dictionary */
+	CHECK_POSIX_DO(  ret = pthread_rwlock_unlock(&dict->dict_lock),  goto error_free  );
+	
+	/* Save the pointer to the new object */
+	if (ref)
+		*ref = new;
+	
+	return 0;
+	
+error_unlock:
+	CHECK_POSIX_DO(  pthread_rwlock_unlock(&dict->dict_lock),  /* continue */  );
+error_free:
+	free(new);
+	return ret;
+}
+
+int fd_dict_search ( struct dictionary * dict, enum dict_object_type type, int criteria, void * what, struct dict_object **result, int retval )
+{
+	int ret = 0;
+	
+	TRACE_ENTRY("%p %d(%s) %d %p %p %d", dict, type, dict_obj_info[CHECK_TYPE(type) ? type : 0].name, criteria, what, result, retval);
+	
+	/* Check param */
+	CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && CHECK_TYPE(type) );
+	
+	/* Lock the dictionary for reading */
+	CHECK_POSIX(  pthread_rwlock_rdlock(&dict->dict_lock)  );
+	
+	/* Now call the type-specific search function */
+	ret = dict_obj_info[type].search_fct (dict, criteria, what, result);
+	
+	/* Unlock */
+	CHECK_POSIX(  pthread_rwlock_unlock(&dict->dict_lock)  );
+	
+	/* Update the return value as needed */
+	if ((result != NULL) && (*result == NULL))
+		ret = retval;
+	
+	return ret;
+}
+
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+/*                                                                                                     */
+/*                                  The init/fini functions                                            */
+/*                                                                                                     */
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+
+/* Initialize the dictionary */
+int fd_dict_init ( struct dictionary ** dict)
+{
+	struct dictionary * new = NULL;
+	
+	TRACE_ENTRY("");
+	
+	/* Sanity checks */
+	ASSERT( (sizeof(type_base_name) / sizeof(type_base_name[0])) == (AVP_TYPE_MAX + 1) );
+	ASSERT( (sizeof(dict_obj_info)  / sizeof(dict_obj_info[0]))  == (DICT_TYPE_MAX + 1) );
+	CHECK_PARAMS(dict);
+	
+	/* Allocate the memory for the dictionary */
+	CHECK_MALLOC( new = malloc(sizeof(struct dictionary)) );
+	memset(new, 0, sizeof(struct dictionary));
+	
+	new->dict_eyec = DICT_EYECATCHER;
+	
+	/* Initialize the lock for the dictionary */
+	CHECK_POSIX(  pthread_rwlock_init(&new->dict_lock, NULL)  );
+	
+	/* Initialize the sentinel for vendors and AVP lists */
+	init_object( &new->dict_vendors, DICT_VENDOR );
+	new->dict_vendors.data.vendor.vendor_name = "(no vendor)";
+	new->dict_vendors.list[0].o = NULL; /* overwrite since element is also sentinel for this list. */
+	
+	
+	/* Initialize the sentinel for applciations */
+	init_object( &new->dict_applications, DICT_APPLICATION );
+	new->dict_applications.data.application.application_name = "Diameter Common Messages";
+	new->dict_applications.list[0].o = NULL; /* overwrite since since element is also sentinel for this list. */
+			
+	/* Initialize the sentinel for types */
+	fd_list_init ( &new->dict_types, NULL );
+	
+	/* Initialize the sentinels for commands */
+	fd_list_init ( &new->dict_cmd_name, NULL );
+	fd_list_init ( &new->dict_cmd_code, NULL );
+	
+	/* Initialize the error command object */
+	init_object( &new->dict_cmd_error, DICT_COMMAND );
+	new->dict_cmd_error.data.cmd.cmd_name="(generic error format)";
+	new->dict_cmd_error.data.cmd.cmd_flag_mask=CMD_FLAG_ERROR | CMD_FLAG_REQUEST | CMD_FLAG_RETRANSMIT;
+	new->dict_cmd_error.data.cmd.cmd_flag_val =CMD_FLAG_ERROR;
+	
+	*dict = new;
+	
+	/* Done */
+	return 0;
+}
+
+/* Destroy a dictionary */
+int fd_dict_fini ( struct dictionary ** dict)
+{
+	int i;
+	
+	TRACE_ENTRY("");
+	CHECK_PARAMS( dict && *dict && ((*dict)->dict_eyec == DICT_EYECATCHER) );
+	
+	/* Acquire the write lock to make sure no other operation is ongoing */
+	CHECK_POSIX(  pthread_rwlock_wrlock(&(*dict)->dict_lock)  );
+	
+	/* Empty all the lists, free the elements */
+	destroy_list ( &(*dict)->dict_cmd_error.list[2] );
+	destroy_list ( &(*dict)->dict_cmd_code );
+	destroy_list ( &(*dict)->dict_cmd_name );
+	destroy_list ( &(*dict)->dict_types );
+	for (i=0; i< NB_LISTS_PER_OBJ; i++) {
+		destroy_list ( &(*dict)->dict_applications.list[i] );
+		destroy_list ( &(*dict)->dict_vendors.list[i] );
+	}
+	
+	/* Dictionary is empty, now destroy the lock */
+	CHECK_POSIX(  pthread_rwlock_unlock(&(*dict)->dict_lock)  );
+	CHECK_POSIX(  pthread_rwlock_destroy(&(*dict)->dict_lock)  );
+	
+	free(*dict);
+	*dict = NULL;
+	
+	return 0;
+}
+
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+/*                                                                                                     */
+/*                                  Other functions                                                    */
+/*                                                                                                     */
+/*******************************************************************************************************/
+/*******************************************************************************************************/
+
+/* Iterate a callback on the rules for an object */
+int fd_dict_iterate_rules ( struct dict_object *parent, void * data, int (*cb)(void *, struct dict_rule_data *) )
+{
+	int ret = 0;
+	struct fd_list * li;
+	
+	TRACE_ENTRY("%p %p %p", parent, data, cb);
+	
+	/* Check parameters */
+	CHECK_PARAMS(  verify_object(parent)  );
+	CHECK_PARAMS(  (parent->type == DICT_COMMAND) 
+			|| ((parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED)) );
+	TRACE_DEBUG (FULL, "Iterating on rules of %s: '%s'.", 
+			_OBINFO(parent).name, 
+			parent->type == DICT_COMMAND ? 
+				  parent->data.cmd.cmd_name
+				: parent->data.avp.avp_name);
+	
+	/* Acquire the read lock  */
+	CHECK_POSIX(  pthread_rwlock_rdlock(&parent->dico->dict_lock)  );
+	
+	/* go through the list and call the cb on each rule data */
+	for (li = &(parent->list[2]); li->next != &(parent->list[2]); li = li->next) {
+		ret = (*cb)(data, &(_O(li->next->o)->data.rule));
+		if (ret != 0)
+			break;
+	}
+		
+	/* Release the lock */
+	CHECK_POSIX(  pthread_rwlock_unlock(&parent->dico->dict_lock)  );
+	
+	return ret;
+}
+
+/* Create the list of vendors. Returns a 0-terminated array, that must be freed after use. Returns NULL on error. */
+uint32_t * fd_dict_get_vendorid_list(struct dictionary * dict)
+{
+	uint32_t * ret = NULL;
+	int i = 0;
+	struct fd_list * li;
+	
+	TRACE_ENTRY();
+	
+	/* Acquire the read lock */
+	CHECK_POSIX_DO(  pthread_rwlock_rdlock(&dict->dict_lock), return NULL  );
+	
+	/* Allocate an array to contain all the elements */
+	CHECK_MALLOC_DO( ret = calloc( dict->dict_count[DICT_VENDOR] + 1, sizeof(uint32_t) ), goto out );
+	
+	/* Copy the vendors IDs */
+	for (li = dict->dict_vendors.list[0].next; li != &(dict->dict_vendors.list[0]); li = li->next) {
+		ret[i] = _O(li->o)->data.vendor.vendor_id;
+		i++;
+		ASSERT( i <= dict->dict_count[DICT_VENDOR] );
+	}
+out:	
+	/* Release the lock */
+	CHECK_POSIX_DO(  pthread_rwlock_unlock(&dict->dict_lock), return NULL  );
+	
+	return ret;
+}
+
+/* Return the location of the cb list for an object, after checking its type */
+int fd_dict_disp_cb(enum dict_object_type type, struct dict_object *obj, struct fd_list ** cb_list)
+{
+	TRACE_ENTRY("%d %p %p", type, obj, cb_list);
+	CHECK_PARAMS( verify_object(obj) );
+	CHECK_PARAMS( _OBINFO(obj).type == type );
+	CHECK_PARAMS( cb_list );
+	*cb_list = &obj->disp_cbs;
+	return 0;
+}
+
+int fd_dict_get_error_cmd(struct dictionary * dict, struct dict_object **obj)
+{
+	TRACE_ENTRY("%p %p", dict, obj);
+	CHECK_PARAMS( dict && (dict->dict_eyec == DICT_EYECATCHER) && obj );
+	*obj = &dict->dict_cmd_error;
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfreediameter/init.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,53 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#include "libfd.h"
+
+int fd_lib_init(void)
+{
+	int ret = 0;
+	
+	/* Create the thread key that contains thread name for debug messages */
+	ret = pthread_key_create(&fd_log_thname, free);
+	if (ret != 0) {
+		fprintf(stderr, "Error initializing the libfreediameter library: %s\n", strerror(ret) );
+		return ret;
+	}
+	
+	/* Initialize the end-to-end id counter with random value as described in RFC3588 */
+	fd_msg_eteid_init();
+	
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfreediameter/libfd.h	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,50 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+/* This file contains the definitions for internal use in the libfreediameter library */
+
+#ifndef _LIBFD_H
+#define _LIBFD_H
+
+#include <freediameter/freediameter-host.h>
+#include <freediameter/libfreediameter.h>
+
+/* Internal to the library */
+extern const char * type_base_name[];
+void fd_msg_eteid_init(void);
+
+
+
+#endif /* _LIBFD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfreediameter/lists.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,273 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#include "libfd.h"
+
+/* Initialize a list element */
+void fd_list_init ( struct fd_list * list, void * obj )
+{
+	memset(list, 0, sizeof(struct fd_list));
+	list->next = list;
+	list->prev = list;
+	list->head = list;
+	list->o    = obj;
+}
+
+#define CHECK_SINGLE( li ) {			\
+	ASSERT( FD_LIST(li)->next == (li) );	\
+	ASSERT( FD_LIST(li)->prev == (li) );	\
+	ASSERT( FD_LIST(li)->head == (li) );	\
+}
+
+/* insert after a reference, checks done */
+static void list_insert_after( struct fd_list * ref, struct fd_list * item )
+{
+	item->prev = ref;
+	item->next = ref->next;
+	item->head = ref->head;
+	ref->next->prev = item;
+	ref->next = item;
+}
+
+/* insert after a reference */
+void fd_list_insert_after  ( struct fd_list * ref, struct fd_list * item )
+{
+	ASSERT(item != NULL);
+	ASSERT(ref != NULL);
+	CHECK_SINGLE ( item );
+	ASSERT(ref->head != item);
+	list_insert_after(ref, item);
+}
+
+/* insert before a reference, checks done */
+static void list_insert_before ( struct fd_list * ref, struct fd_list * item )
+{
+	item->prev = ref->prev;
+	item->next = ref;
+	item->head = ref->head;
+	ref->prev->next = item;
+	ref->prev = item;
+}
+
+/* insert before a reference */
+void fd_list_insert_before ( struct fd_list * ref, struct fd_list * item )
+{
+	ASSERT(item != NULL);
+	ASSERT(ref != NULL);
+	CHECK_SINGLE ( item );
+	ASSERT(ref->head != item);
+	list_insert_before(ref, item);
+}
+
+/* Insert an item in an ordered list -- ordering function provided. If duplicate object found, it is returned in ref_duplicate */
+int fd_list_insert_ordered( struct fd_list * head, struct fd_list * item, int (*cmp_fct)(void *, void *), void ** ref_duplicate)
+{
+	struct fd_list * ptr = head;
+	int cmp;
+	
+	/* Some debug sanity checks */
+	ASSERT(head != NULL);
+	ASSERT(item != NULL);
+	ASSERT(cmp_fct != NULL);
+	ASSERT(head->head == head);
+	CHECK_SINGLE ( item );
+	
+	/* loop in the list */
+	while (ptr->next != head)
+	{
+		/* Compare the object to insert with the next object in list */
+		cmp = cmp_fct( item->o, ptr->next->o );
+		if (!cmp) {
+			/* An element with the same key already exists */
+			if (ref_duplicate != NULL)
+				*ref_duplicate = ptr->next->o;
+			return EEXIST;
+		}
+		
+		if (cmp < 0)
+			break; /* We must insert the element here */
+		
+		ptr = ptr->next;
+	}
+	
+	/* Now insert the element between ptr and ptr->next */
+	list_insert_after( ptr, item );
+	
+	/* Ok */
+	return 0;
+}
+	
+/* Unlink an object */
+void fd_list_unlink ( struct fd_list * item )
+{
+	ASSERT(item != NULL);
+	if (item->head == item)
+		return;
+	/* unlink */
+	item->next->prev = item->prev;
+	item->prev->next = item->next;
+	/* sanitize */
+	item->next = item;
+	item->prev = item;
+	item->head = item;
+}
+
+
+/********************************************************************************************************/
+/* Hash function -- credits to Austin Appleby, thank you ^^ */
+/* See http://murmurhash.googlepages.com for more information on this function */
+
+/* the strings are NOT always aligned properly (ex: received in RADIUS message), so we use the aligned MurmurHash2 function as needed */
+#define _HASH_MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+uint32_t fd_hash ( char * string, size_t len )
+{
+	uint32_t hash = len;
+	char * data = string;
+	
+	const unsigned int m = 0x5bd1e995;
+	const int r = 24;
+	int align = (long)string & 3;
+	
+	if (!align || (len < 4)) {
+		
+		/* In case data is aligned, MurmurHash2 function */
+		while(len >= 4)
+		{
+			/* Mix 4 bytes at a time into the hash */
+			uint32_t k = *(uint32_t *)data;	/* We don't care about the byte order */
+
+			_HASH_MIX(hash, k, m);
+
+			data += 4;
+			len -= 4;
+		}
+
+		/* Handle the last few bytes of the input */
+		switch(len) {
+			case 3: hash ^= data[2] << 16;
+			case 2: hash ^= data[1] << 8;
+			case 1: hash ^= data[0];
+	        		hash *= m;
+		}
+		
+	} else {
+		/* Unaligned data, use alignment-safe slower version */
+		
+		/* Pre-load the temp registers */
+		uint32_t t = 0, d = 0;
+		switch(align)
+		{
+			case 1: t |= data[2] << 16;
+			case 2: t |= data[1] << 8;
+			case 3: t |= data[0];
+		}
+		t <<= (8 * align);
+
+		data += 4-align;
+		len -= 4-align;
+		
+		/* From this point, "data" can be read by chunks of 4 bytes */
+		
+		int sl = 8 * (4-align);
+		int sr = 8 * align;
+
+		/* Mix */
+		while(len >= 4)
+		{
+			uint32_t k;
+			
+			d = *(unsigned int *)data;
+			k = (t >> sr) | (d << sl);
+
+			_HASH_MIX(hash, k, m);
+
+			t = d;
+
+			data += 4;
+			len -= 4;
+		}
+
+		/* Handle leftover data in temp registers */
+		d = 0;
+		if(len >= align)
+		{
+			uint32_t k;
+			
+			switch(align)
+			{
+			case 3: d |= data[2] << 16;
+			case 2: d |= data[1] << 8;
+			case 1: d |= data[0];
+			}
+
+			k = (t >> sr) | (d << sl);
+			_HASH_MIX(hash, k, m);
+
+			data += align;
+			len -= align;
+
+			/* Handle tail bytes */
+
+			switch(len)
+			{
+			case 3: hash ^= data[2] << 16;
+			case 2: hash ^= data[1] << 8;
+			case 1: hash ^= data[0];
+					hash *= m;
+			};
+		}
+		else
+		{
+			switch(len)
+			{
+			case 3: d |= data[2] << 16;
+			case 2: d |= data[1] << 8;
+			case 1: d |= data[0];
+			case 0: hash ^= (t >> sr) | (d << sl);
+					hash *= m;
+			}
+		}
+
+
+	}
+
+	/* Do a few final mixes of the hash to ensure the last few
+	   bytes are well-incorporated. */
+	hash ^= hash >> 13;
+	hash *= m;
+	hash ^= hash >> 15;
+
+	return hash;
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfreediameter/log.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,107 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+#include "libfd.h"
+
+#include <stdarg.h>
+
+pthread_mutex_t fd_log_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_key_t	fd_log_thname;
+
+/* Log a debug message */
+void fd_log_debug ( char * format, ... )
+{
+	va_list ap;
+	
+	(void)pthread_mutex_lock(&fd_log_lock);
+	
+	pthread_cleanup_push(fd_cleanup_mutex, &fd_log_lock);
+	
+	va_start(ap, format);
+	vfprintf( stdout, format, ap);
+	va_end(ap);
+	fflush(stdout);
+
+	pthread_cleanup_pop(0);
+	
+	(void)pthread_mutex_unlock(&fd_log_lock);
+}
+
+/* Function to set the thread's friendly name */
+void fd_log_threadname ( char * name )
+{
+	void * val = NULL;
+	
+	TRACE_ENTRY("%p(%s)", name, name?:"/");
+	
+	/* First, check if a value is already assigned to the current thread */
+	val = pthread_getspecific(fd_log_thname);
+	if (val != NULL) {
+		TRACE_DEBUG(FULL, "Freeing old thread name: %s", val);
+		free(val);
+	}
+	
+	/* Now create the new string */
+	if (name == NULL) {
+		CHECK_POSIX_DO( pthread_setspecific(fd_log_thname, NULL), /* continue */);
+		return;
+	}
+	
+	CHECK_MALLOC_DO( val = strdup(name), return );
+	
+	CHECK_POSIX_DO( pthread_setspecific(fd_log_thname, val), /* continue */);
+	return;
+}
+
+/* Write current time into a buffer */
+char * fd_log_time ( char * buf, size_t len )
+{
+	int ret;
+	size_t offset = 0;
+	struct timespec tp;
+	struct tm tm;
+	
+	/* Get current time */
+	ret = clock_gettime(CLOCK_REALTIME, &tp);
+	if (ret != 0) {
+		snprintf(buf, len, "%s", strerror(ret));
+		return buf;
+	}
+	
+	offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &tp.tv_sec , &tm ));
+	offset += snprintf(buf + offset, len - offset, ".%6.6ld", tp.tv_nsec / 1000);
+
+	return buf;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfreediameter/messages.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,2139 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+/* Messages module.
+ * 
+ * This module allows to manipulate the msg and avp structures that represents a Diameter message in memory.
+ */
+
+#include "libfd.h"
+
+#include <sys/param.h>
+
+/* Type of object */
+enum msg_objtype {
+	MSG_MSG = 1, 
+	MSG_AVP
+};
+
+/* Chaining of elements as a free hierarchy */
+struct msg_avp_chain {
+	struct fd_list		chaining;	/* Chaining information at this level. */
+	struct fd_list		children;	/* sentinel for the children of this object */
+	enum msg_objtype 	type;		/* Type of this object, _MSG_MSG or _MSG_AVP */
+};
+
+/* Return the chain information from an AVP or MSG. Since it's the first field, we just cast */
+#define _C(_x) ((struct msg_avp_chain *)(_x))
+
+/* Some details about chaining:
+ *
+ *  A message is made of a header ( msg ) and 0 or more AVPs ( avp ).
+ * The structure is a kind of tree, where some AVPs (grouped AVPs) can contain other AVPs.
+ * Exemple:
+ * msg
+ *  |-avp
+ *  |-gavp
+ *  |   |-avp
+ *  |   |-avp
+ *  |   \-avp
+ *  |-avp
+ *  \-avp
+ *
+ * Each item (msg or avp) structure begins with a msg_avp_chain structure.
+ * The element at the top of the hierarchy (msg in our example) has all the fields of its "chaining" equal to the same value.
+ *
+ * All elements at the same level are linked by their "chaining" list.
+ * The "children" list is the sentinel for the lists of children of this element.
+ */
+
+/* The following definitions are used to recognize objects in memory. */
+#define MSG_MSG_EYEC	(0x11355463)
+#define MSG_AVP_EYEC	(0x11355467)
+
+/* The following structure represents an AVP instance. */
+struct avp {
+	struct msg_avp_chain	 avp_chain;		/* Chaining information of this AVP */
+	int			 avp_eyec;		/* Must be equal to MSG_AVP_EYEC */
+	struct dict_object	*avp_model;		/* If not NULL, pointer to the dictionary object of this avp */
+	struct avp_hdr		 avp_public;		/* AVP data that can be managed by other modules */
+	
+	uint8_t			*avp_source;		/* If the message was parsed from a buffer, pointer to the AVP data start in the buffer. */
+	uint8_t			*avp_rawdata;		/* when the data can not be interpreted, the raw data is copied here. The header is not part of it. */
+	size_t			 avp_rawlen;		/* The length of the raw buffer. */
+	union avp_value		 avp_storage;		/* To avoid many alloc/free, store the integer values here and set avp_public.avp_data to &storage */
+	int			 avp_mustfreeos;	/* 1 if an octetstring is malloc'd in avp_storage and must be freed. */
+};
+
+/* Macro to compute the AVP header size */
+#define AVPHDRSZ_NOVEND	8
+#define AVPHDRSZ_VENDOR	12
+#define GETAVPHDRSZ( _flag ) ((_flag & AVP_FLAG_VENDOR) ? AVPHDRSZ_VENDOR : AVPHDRSZ_NOVEND)
+
+/* Macro to cast a msg_avp_t */
+#define _A(_x) ((struct avp *)(_x))
+/* Check the type and eyecatcher */
+#define CHECK_AVP(_x) ((_C(_x)->type == MSG_AVP) && (_A(_x)->avp_eyec == MSG_AVP_EYEC))
+
+/* The following structure represents an instance of a message (command and children AVPs). */
+struct msg {
+	struct msg_avp_chain	 msg_chain;		/* List of the AVPs in the message */
+	int			 msg_eyec;		/* Must be equal to MSG_MSG_EYEC */
+	struct dict_object	*msg_model;		/* If not NULL, pointer to the dictionary object of this message */
+	struct msg_hdr		 msg_public;		/* Message data that can be managed by extensions. */
+	
+	uint8_t			*msg_rawbuffer;		/* data buffer that was received, saved during fd_msg_parse_buffer and freed in fd_msg_parse_dict */
+	int			 msg_routable;		/* Is this a routable message? (0: undef, 1: routable, 2: non routable) */
+	struct msg		*msg_query;		/* the associated query if the message is a received answer */
+	struct fd_list		*msg_rtlist;		/* Routing list for the query */
+	struct {
+			void (*fct)(void *, struct msg **);
+			void * data;
+		}		 msg_cb;		/* Callback to be called when an answer is received, if not NULL */
+	char *			 msg_src_id;		/* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */
+	uint32_t		 msg_src_hash;		/* Hash of the msg_src_id value */
+};
+
+/* Macro to compute the message header size */
+#define GETMSGHDRSZ() 	20
+
+/* Macro to cast a msg_avp_t */
+#define _M(_x) ((struct msg *)(_x))
+/* Check the type and eyecatcher */
+#define CHECK_MSG(_x) ((_C(_x)->type == MSG_MSG) && (_M(_x)->msg_eyec == MSG_MSG_EYEC))
+
+#define VALIDATE_OBJ(_x) ( (CHECK_MSG(_x)) || (CHECK_AVP(_x)) )
+
+
+/* Macro to validate a MSGFL_ value */
+#define CHECK_MSGFL(_fl) ( ((_fl) & (- (MSGFL_MAX << 1) )) == 0 )
+
+
+/* initial sizes of AVP from their types, in bytes. */
+static int avp_value_sizes[] = { 
+	 0,	/* AVP_TYPE_GROUPED: size is dynamic */
+	 0,	/* AVP_TYPE_OCTETSTRING: size is dynamic */
+	 4,	/* AVP_TYPE_INTEGER32: size is 32 bits */
+	 8,	/* AVP_TYPE_INTEGER64: size is 64 bits */
+	 4,	/* AVP_TYPE_UNSIGNED32: size is 32 bits */
+	 8,	/* AVP_TYPE_UNSIGNED64: size is 64 bits */
+	 4,	/* AVP_TYPE_FLOAT32: size is 32 bits */
+	 8	/* AVP_TYPE_FLOAT64: size is 64 bits */
+};
+#define CHECK_BASETYPE( _type ) ( ((_type) <= AVP_TYPE_MAX) && ((_type) >= 0) )
+#define GETINITIALSIZE( _type, _vend ) (avp_value_sizes[ CHECK_BASETYPE(_type) ? (_type) : 0] + GETAVPHDRSZ(_vend))
+
+/* Forward declaration */
+static int parsedict_do_msg(struct dictionary * dict, struct msg * msg, int only_hdr);
+
+/***************************************************************************************************************/
+/* Creating objects */
+
+/* Initialize a msg_avp_chain structure */
+static void init_chain(struct msg_avp_chain * chain, int type)
+{
+	fd_list_init( &chain->chaining, (void *)chain);
+	fd_list_init( &chain->children, (void *)chain);
+	chain->type = type;
+}
+
+/* Initialize a new AVP object */
+static void init_avp ( struct avp * avp )
+{
+	TRACE_ENTRY("%p", avp);
+	
+	memset(avp, 0, sizeof(struct avp));
+	init_chain( &avp->avp_chain, MSG_AVP);
+	avp->avp_eyec = MSG_AVP_EYEC;
+}
+	
+/* Initialize a new MSG object */
+static void init_msg ( struct msg * msg )
+{
+	TRACE_ENTRY("%p", msg);
+	
+	memset(msg, 0, sizeof(struct msg));
+	init_chain( &msg->msg_chain, MSG_MSG);
+	msg->msg_eyec = MSG_MSG_EYEC;
+}
+
+
+/* Create a new AVP instance */
+int fd_msg_avp_new ( struct dict_object * model, int flags, struct avp ** avp )
+{
+	struct avp *new = NULL;
+	
+	TRACE_ENTRY("%p %x %p", model, flags, avp);
+	
+	/* Check the parameters */
+	CHECK_PARAMS(  avp && CHECK_MSGFL(flags)  );
+	
+	if (model) {
+		enum dict_object_type 	 dicttype;
+		CHECK_PARAMS( (fd_dict_gettype(model, &dicttype) == 0) && (dicttype == DICT_AVP) );
+	}
+	
+	/* Create a new object */
+	CHECK_MALLOC(  new = malloc (sizeof(struct avp))  );
+	
+	/* Initialize the fields */
+	init_avp(new);
+	
+	if (model) {
+		struct dict_avp_data dictdata;
+		
+		CHECK_FCT(  fd_dict_getval(model, &dictdata)  );
+	
+		new->avp_model = model;
+		new->avp_public.avp_code    = dictdata.avp_code;
+		new->avp_public.avp_flags   = dictdata.avp_flag_val;
+		new->avp_public.avp_len = GETINITIALSIZE(dictdata.avp_basetype, dictdata.avp_flag_val );
+		new->avp_public.avp_vendor  = dictdata.avp_vendor;
+	}
+	
+	/* The new object is ready, return */
+	*avp = new;
+	return 0;
+}
+
+/* Create a new message instance */
+int fd_msg_new ( struct dict_object * model, int flags, struct msg ** msg )
+{
+	struct msg * new = NULL;
+	
+	TRACE_ENTRY("%p %x %p", model, flags, msg);
+	
+	/* Check the parameters */
+	CHECK_PARAMS(  msg && CHECK_MSGFL(flags)  );
+	
+	if (model) {
+		enum dict_object_type 	 dicttype;
+		CHECK_PARAMS( (fd_dict_gettype(model, &dicttype) == 0) && (dicttype == DICT_COMMAND) );
+	}
+	
+	/* Create a new object */
+	CHECK_MALLOC(  new = malloc (sizeof(struct msg))  );
+	
+	/* Initialize the fields */
+	init_msg(new);
+	new->msg_public.msg_version	= DIAMETER_VERSION;
+	new->msg_public.msg_length	= GETMSGHDRSZ(); /* This will be updated later */
+
+	if (model) {
+		struct dictionary 	*dict;
+		struct dict_cmd_data     dictdata;
+		struct dict_object     	*dictappl;
+		
+		CHECK_FCT( fd_dict_getdict(model, &dict) );
+		CHECK_FCT( fd_dict_getval(model, &dictdata)  );
+		
+		new->msg_model = model;
+		new->msg_public.msg_flags	= dictdata.cmd_flag_val;
+		new->msg_public.msg_code	= dictdata.cmd_code;
+
+		/* Initialize application from the parent, if any */
+		CHECK_FCT(  fd_dict_search( dict, DICT_APPLICATION, APPLICATION_OF_COMMAND, model, &dictappl, 0)  );
+		if (dictappl != NULL) {
+			struct dict_application_data appdata;
+			CHECK_FCT(  fd_dict_getval(dictappl, &appdata)  );
+			new->msg_public.msg_appl = appdata.application_id;
+		}
+	}
+	
+	if (flags & MSGFL_ALLOC_ETEID) {
+		new->msg_public.msg_eteid = fd_msg_eteid_get();
+	}
+	
+	/* The new object is ready, return */
+	*msg = new;
+	return 0;
+}	
+
+/* Create answer from a request */
+int fd_msg_new_answer_from_req ( struct dictionary * dict, struct msg ** msg, int flags )
+{
+	struct dict_object * model = NULL;
+	struct msg *qry, *ans;
+	
+	TRACE_ENTRY("%p %x", msg, flags);
+	
+	/* Check the parameters */
+	CHECK_PARAMS(  msg );
+	qry = *msg;
+	CHECK_PARAMS( CHECK_MSG(qry) && (qry->msg_public.msg_flags & CMD_FLAG_REQUEST) );
+	
+	/* Find the model for the answer */
+	if (flags & MSGFL_ANSW_ERROR) {
+		/* The model is the generic error format */
+		CHECK_FCT( fd_dict_get_error_cmd(dict, &model) );
+	} else {
+		/* The model is the answer corresponding to the query. It supposes that these are defined in the dictionary */
+		CHECK_FCT_DO(  parsedict_do_msg( dict, qry, 1), /* continue */  );
+		if (qry->msg_model) {
+			CHECK_FCT(  fd_dict_search ( dict, DICT_COMMAND, CMD_ANSWER, qry->msg_model, &model, EINVAL )  );
+		}
+	}
+	
+	/* Create the answer */
+	CHECK_FCT(  fd_msg_new( model, flags, &ans )  );
+	
+	/* Set informations in the answer as in the query */
+	ans->msg_public.msg_code = qry->msg_public.msg_code; /* useful for MSGFL_ANSW_ERROR */
+	ans->msg_public.msg_appl = qry->msg_public.msg_appl;
+	ans->msg_public.msg_eteid = qry->msg_public.msg_eteid;
+	ans->msg_public.msg_hbhid = qry->msg_public.msg_hbhid;
+	
+	/* associate with query */
+	 /* may do  CHECK_FCT(  msg_answ_associate( *msg, (msg_t *)qry )  ); but this is quicker */
+	ans->msg_query = qry;
+	
+	/* Done */
+	*msg = ans;
+	return 0;
+}
+
+/***************************************************************************************************************/
+
+/* Explore a message */
+int fd_msg_browse_internal ( msg_or_avp * reference, enum msg_brw_dir dir, msg_or_avp ** found, int * depth )
+{
+	struct msg_avp_chain *result = NULL;
+	int diff = 0;
+	struct fd_list *li = NULL;
+	
+	TRACE_ENTRY("%p %d %p %p", reference, dir, found, depth);
+	
+	/* Initialize the "found" result if any */
+	if (found)
+		*found = NULL;
+	
+	/* Check the parameters */
+	CHECK_PARAMS(  VALIDATE_OBJ(reference)  );
+	
+	TRACE_DEBUG(FCTS, "chaining(%p): nxt:%p prv:%p hea:%p top:%p", 
+			&_C(reference)->chaining,
+			_C(reference)->chaining.next,
+			_C(reference)->chaining.prev,
+			_C(reference)->chaining.head,
+			_C(reference)->chaining.o);
+	TRACE_DEBUG(FCTS, "children(%p): nxt:%p prv:%p hea:%p top:%p", 
+			&_C(reference)->children,
+			_C(reference)->children.next,
+			_C(reference)->children.prev,
+			_C(reference)->children.head,
+			_C(reference)->children.o);
+
+	/* Now search */
+	switch (dir) {
+		case MSG_BRW_NEXT:
+			/* Check the reference is an AVP */
+			CHECK_PARAMS(  _C(reference)->type == MSG_AVP  );
+
+			li = &_C(reference)->chaining;
+			
+			/* Check if the next element is not the sentinel ( ==> the parent) */
+			if (li->next != li->head)
+				result = _C(li->next->o);
+			break;
+
+		case MSG_BRW_PREV:
+			/* Check the reference is an AVP */
+			CHECK_PARAMS(  _C(reference)->type == MSG_AVP  );
+
+			li = &_C(reference)->chaining;
+			
+			/* Check if the prev element is not the sentinel ( ==> the parent) */
+			if (li->prev != li->head)
+				result = _C(li->prev->o);
+			break;
+
+		case MSG_BRW_FIRST_CHILD:
+			li = &_C(reference)->children;
+			if (! FD_IS_LIST_EMPTY(li)) {
+				result = _C(li->next->o);
+				diff = 1;
+			}
+			break;
+
+		case MSG_BRW_LAST_CHILD:
+			li = &_C(reference)->children;
+			if (! FD_IS_LIST_EMPTY(li)) {
+				result = _C(li->prev->o);
+				diff = 1;
+			}
+			break;
+
+		case MSG_BRW_PARENT:
+			/* If the object is not chained, it has no parent */
+			li = &_C(reference)->chaining;
+			if (li != li->head) {
+				/* The sentinel is the parent's children list */
+				result = _C(li->head->o);
+				diff = -1;
+			}
+			break;
+
+		case MSG_BRW_WALK:
+			/* First, try to find a child */
+			li = &_C(reference)->children;
+			if ( ! FD_IS_LIST_EMPTY(li) ) {
+				result = _C(li->next->o);
+				diff = 1;
+				break;
+			}
+			
+			/* Then try to find a "next" at this level or one of the parent's */
+			li = &_C(reference)->chaining;
+			do {
+				/* If this element has a "next" element, return it */
+				if (li->next != li->head) {
+					result = _C(li->next->o);
+					break;
+				}
+				/* otherwise, check if we have a parent */
+				if (li == li->head) {
+					/* no parent */
+					break;
+				}
+				/* Go to the parent's chaining information and loop */
+				diff -= 1;
+				li = &_C(li->head->o)->chaining;
+			} while (1); 
+			break;
+			
+		default:
+			/* Other directions are invalid */
+			CHECK_PARAMS( dir = 0 );
+	}
+	
+	/* Save the found object, if any */
+	if (found && result)
+		*found = (void *)result;
+	
+	/* Modify the depth according to the walk direction */
+	if (depth && diff)
+		(*depth) += diff;
+	
+	/* Return ENOENT if found was NULL */
+	if ((!found) && (!result))
+		return ENOENT;
+	else
+		return 0;
+}
+
+/* Add an AVP into a tree */
+int fd_msg_avp_add ( msg_or_avp * reference, enum msg_brw_dir dir, struct avp *avp)
+{
+	TRACE_ENTRY("%p %d %p", reference, dir, avp);
+	
+	/* Check the parameters */
+	CHECK_PARAMS(  VALIDATE_OBJ(reference)  &&  CHECK_AVP(avp)  &&  FD_IS_LIST_EMPTY(&avp->avp_chain.chaining)  );
+	
+	/* Now insert */
+	switch (dir) {
+		case MSG_BRW_NEXT:
+			/* Check the reference is an AVP -- we do not chain AVPs at same level as msgs. */
+			CHECK_PARAMS(  _C(reference)->type == MSG_AVP  );
+			
+			/* Insert the new avp after the reference */
+			fd_list_insert_after( &_A(reference)->avp_chain.chaining, &avp->avp_chain.chaining );
+			break;
+
+		case MSG_BRW_PREV:
+			/* Check the reference is an AVP */
+			CHECK_PARAMS(  _C(reference)->type == MSG_AVP  );
+			
+			/* Insert the new avp before the reference */
+			fd_list_insert_before( &_A(reference)->avp_chain.chaining, &avp->avp_chain.chaining );
+			break;
+
+		case MSG_BRW_FIRST_CHILD:
+			/* Insert the new avp after the children sentinel */
+			fd_list_insert_after( &_C(reference)->children, &avp->avp_chain.chaining );
+			break;
+
+		case MSG_BRW_LAST_CHILD:
+			/* Insert the new avp before the children sentinel */
+			fd_list_insert_before( &_C(reference)->children, &avp->avp_chain.chaining );
+			break;
+
+		default:
+			/* Other directions are invalid */
+			CHECK_PARAMS( dir = 0 );
+	}
+			
+	return 0;
+}
+
+/* Search a given AVP model in a message */
+int fd_msg_search_avp ( struct msg * msg, struct dict_object * what, struct avp ** avp )
+{
+	struct avp * nextavp;
+	struct dict_avp_data 	dictdata;
+	enum dict_object_type 	dicttype;
+	
+	TRACE_ENTRY("%p %p %p", msg, what, avp);
+	
+	CHECK_PARAMS( CHECK_MSG(msg) && what );
+	
+	CHECK_PARAMS( (fd_dict_gettype(what, &dicttype) == 0) && (dicttype == DICT_AVP) );
+	CHECK_FCT(  fd_dict_getval(what, &dictdata)  );
+	
+	/* Loop on all top AVPs */
+	CHECK_FCT(  fd_msg_browse(msg, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL)  );
+	while (nextavp) {
+		
+		if ( (nextavp->avp_public.avp_code   == dictdata.avp_code)
+		  && (nextavp->avp_public.avp_vendor == dictdata.avp_vendor) ) /* always 0 if no V flag */
+			break;
+		
+		/* Otherwise move to next AVP in the message */
+		CHECK_FCT( fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL) );
+	}
+	
+	if (avp)
+		*avp = nextavp;
+	
+	if (avp && nextavp) {
+		struct dictionary * dict;
+		CHECK_FCT( fd_dict_getdict( what, &dict) );
+		CHECK_FCT_DO( fd_msg_parse_dict( nextavp, dict ), /* nothing */ );
+	}
+	
+	if (avp || nextavp)
+		return 0;
+	else
+		return ENOENT;
+}
+
+
+/***************************************************************************************************************/
+/* Deleting objects */
+
+/* Destroy and free an AVP or message */
+static int destroy_obj (struct msg_avp_chain * obj )
+{
+	TRACE_ENTRY("%p", obj);
+	
+	/* Check the parameter is a valid object */
+	CHECK_PARAMS(  VALIDATE_OBJ(obj) && FD_IS_LIST_EMPTY( &obj->children ) );
+
+	/* Unlink this object if needed */
+	fd_list_unlink( &obj->chaining );
+	
+	/* Free the octetstring if needed */
+	if ((obj->type == MSG_AVP) && (_A(obj)->avp_mustfreeos == 1)) {
+		free(_A(obj)->avp_storage.os.data);
+	}
+	/* Free the rawdata if needed */
+	if ((obj->type == MSG_AVP) && (_A(obj)->avp_rawdata != NULL)) {
+		free(_A(obj)->avp_rawdata);
+	}
+	if ((obj->type == MSG_MSG) && (_M(obj)->msg_rawbuffer != NULL)) {
+		free(_M(obj)->msg_rawbuffer);
+	}
+	
+	if ((obj->type == MSG_MSG) && (_M(obj)->msg_src_id != NULL)) {
+		free(_M(obj)->msg_src_id);
+	}
+	
+	if ((obj->type == MSG_MSG) && (_M(obj)->msg_rtlist != NULL)) {
+		while (! FD_IS_LIST_EMPTY(_M(obj)->msg_rtlist) ) {
+			struct fd_list * li = _M(obj)->msg_rtlist->next;
+			fd_list_unlink(li);
+			free(li);
+		}
+
+		free(_M(obj)->msg_rtlist);
+	}
+	
+	/* free the object */
+	free(obj);
+	
+	return 0;
+}
+
+/* Destroy an object and all its children */
+static void destroy_tree(struct msg_avp_chain * obj)
+{
+	struct fd_list *rem;
+	
+	TRACE_ENTRY("%p", obj);
+	
+	/* Destroy any subtree */
+	while ( (rem = obj->children.next) != &obj->children)
+		destroy_tree(_C(rem->o));
+	
+	/* Then unlink and destroy the object */
+	CHECK_FCT_DO(  destroy_obj(obj),  /* nothing */  );
+}
+
+/* Free an object and its tree */
+int fd_msg_free ( msg_or_avp * object )
+{
+	TRACE_ENTRY("%p", object);
+	
+	if (CHECK_MSG(object)) {
+		if (_M(object)->msg_query) {
+			CHECK_FCT(  fd_msg_free( _M(object)->msg_query )  );
+			_M(object)->msg_query = NULL;
+		}
+	}
+	
+	destroy_tree(_C(object));
+	return 0;
+}
+
+
+/***************************************************************************************************************/
+/* Debug functions: dumping */
+
+/* indent inside an object */
+#define INOBJHDR 	"%*s   "
+#define INOBJHDRVAL 	indent<0 ? 1 : indent, indent<0 ? "-" : "|"
+
+/* Dump a msg_t object */
+static void obj_dump_msg (struct msg * msg, int indent )
+{
+	int ret = 0;
+	
+	fd_log_debug("%*sMSG: %p\n", INOBJHDRVAL, msg);
+	
+	if (!CHECK_MSG(msg)) {
+		fd_log_debug(INOBJHDR "INVALID!\n", INOBJHDRVAL);
+		return;
+	}
+	
+	if (!msg->msg_model) {
+		
+		fd_log_debug(INOBJHDR "(no model)\n", INOBJHDRVAL);
+		
+	} else {
+		
+		enum dict_object_type dicttype;
+		struct dict_cmd_data  dictdata;
+		ret = fd_dict_gettype(msg->msg_model, &dicttype);
+		if (ret || (dicttype != DICT_COMMAND)) {
+			fd_log_debug(INOBJHDR "(invalid model: %d %d)\n", INOBJHDRVAL, ret, dicttype);
+			goto public;
+		}
+		ret = fd_dict_getval(msg->msg_model, &dictdata);
+		if (ret != 0) {
+			fd_log_debug(INOBJHDR "(error getting model data: %s)\n", INOBJHDRVAL, strerror(ret));
+			goto public;
+		}
+		fd_log_debug(INOBJHDR "model : v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %u \"%s\"\n", INOBJHDRVAL, 
+			DUMP_CMDFL_val(dictdata.cmd_flag_val), DUMP_CMDFL_val(dictdata.cmd_flag_mask), dictdata.cmd_code, dictdata.cmd_name);
+	}
+public:	
+	fd_log_debug(INOBJHDR "public: V:%d L:%d fl:" DUMP_CMDFL_str " CC:%u A:%d hi:%x ei:%x\n", INOBJHDRVAL, 
+		msg->msg_public.msg_version,
+		msg->msg_public.msg_length,
+		DUMP_CMDFL_val(msg->msg_public.msg_flags),
+		msg->msg_public.msg_code,
+		msg->msg_public.msg_appl,
+		msg->msg_public.msg_hbhid,
+		msg->msg_public.msg_eteid
+		);
+	fd_log_debug(INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p h:%x src:%s\n", 
+			INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.fct, msg->msg_cb.data, msg->msg_query, msg->msg_src_hash, msg->msg_src_id?:"(nil)");
+}
+
+#define DUMP_VALUE(_format, _parms...)   fd_log_debug(INOBJHDR "value : t:'%s' v:'" _format "'\n", INOBJHDRVAL, typename, ## _parms);
+/* Dump an AVP value that is not a constant */
+static void dump_basic_type(union avp_value * value, enum dict_avp_basetype type, const char * typename, int indent)
+{
+	switch (type) {
+		case AVP_TYPE_GROUPED:
+			DUMP_VALUE("%s", "error: grouped AVP with a value!");
+			break;
+			
+		case AVP_TYPE_OCTETSTRING:
+			{
+				/* Dump only up to 16 bytes of the buffer */
+				unsigned char buf[8];
+				memset(buf, 0, sizeof(buf));
+				memcpy(buf, value->os.data, value->os.len < sizeof(buf) ? value->os.len : sizeof(buf) );
+				DUMP_VALUE("l:%d, v:%02.2X %02.2X %02.2X %02.2X  %02.2X %02.2X %02.2X %02.2X  ... ('%-*.*s')", 
+						value->os.len,
+						buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], 
+						value->os.len, value->os.len, value->os.data
+						);
+			}
+			break;
+		
+		case AVP_TYPE_INTEGER32:
+			DUMP_VALUE("%i",value->i32);
+			break;
+
+		case AVP_TYPE_INTEGER64:
+			DUMP_VALUE("%lli (0x%llx)",value->i64,value->i64);
+			break;
+
+		case AVP_TYPE_UNSIGNED32:
+			DUMP_VALUE("%u",value->u32);
+			break;
+
+		case AVP_TYPE_UNSIGNED64:
+			DUMP_VALUE("%llu",value->u64);
+			break;
+
+		case AVP_TYPE_FLOAT32:
+			DUMP_VALUE("%f",value->f32);
+			break;
+
+		case AVP_TYPE_FLOAT64:
+			DUMP_VALUE("%g",value->f64);
+			break;
+		
+		default:
+			DUMP_VALUE("%s %d", "error: invalid type :", type);
+	}
+}
+
+/* Dump an AVP value that is a constant */
+#define DUMP_CONST(_format, _parms...)   fd_log_debug(INOBJHDR "value : t:'%s' v:'%s' ( " _format " )\n", INOBJHDRVAL, typename, value->enum_name, ## _parms);
+static void dump_constant_type(struct dict_enumval_data * value, enum dict_avp_basetype type, char * typename, int indent)
+{
+	switch (type) {
+		case AVP_TYPE_GROUPED:
+			DUMP_CONST("%s", "error: grouped AVP with a constant value!");
+			break;
+		case AVP_TYPE_OCTETSTRING:
+			DUMP_CONST("%s", "value skipped");
+			break;
+		
+		case AVP_TYPE_INTEGER32:
+			DUMP_CONST("%i",value->enum_value.i32);
+			break;
+
+		case AVP_TYPE_INTEGER64:
+			DUMP_CONST("%li",value->enum_value.i64);
+			break;
+
+		case AVP_TYPE_UNSIGNED32:
+			DUMP_CONST("%u",value->enum_value.u32);
+			break;
+
+		case AVP_TYPE_UNSIGNED64:
+			DUMP_CONST("%lu",value->enum_value.u64);
+			break;
+
+		case AVP_TYPE_FLOAT32:
+			DUMP_CONST("%f",value->enum_value.f32);
+			break;
+
+		case AVP_TYPE_FLOAT64:
+			DUMP_CONST("%g",value->enum_value.f64);
+			break;
+		
+		default:
+			DUMP_CONST("%s %d", "error: invalid type :", type);
+	}
+}
+
+/* Dump an avp object */
+static void obj_dump_avp ( struct avp * avp, int indent )
+{
+	int ret = 0;
+	enum dict_avp_basetype type = -1;
+	
+	if (!CHECK_AVP(avp)) {
+		fd_log_debug(INOBJHDR "INVALID!\n", INOBJHDRVAL);
+		return;
+	}
+	
+	if (!avp->avp_model) {
+		
+		fd_log_debug(INOBJHDR "(no model)\n", INOBJHDRVAL);
+		
+	} else {
+		
+		enum dict_object_type dicttype;
+		struct dict_avp_data dictdata;
+		ret = fd_dict_gettype(avp->avp_model, &dicttype);
+		if (ret || (dicttype != DICT_AVP)) {
+			fd_log_debug(INOBJHDR "(invalid model: %d %d)\n", INOBJHDRVAL, ret, dicttype);
+			goto public;
+		}
+		ret = fd_dict_getval(avp->avp_model, &dictdata);
+		if (ret != 0) {
+			fd_log_debug(INOBJHDR "(error getting model data: %s)\n", INOBJHDRVAL, strerror(ret));
+			goto public;
+		}
+		fd_log_debug(INOBJHDR "model : v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %u \"%s\"\n", INOBJHDRVAL, 
+			DUMP_AVPFL_val(dictdata.avp_flag_val), 
+			DUMP_AVPFL_val(dictdata.avp_flag_mask), 
+			type_base_name[dictdata.avp_basetype], 
+			dictdata.avp_code, 
+			dictdata.avp_name );
+		type = dictdata.avp_basetype;
+	}
+public:	
+	fd_log_debug(INOBJHDR "public: C:%u fl:" DUMP_AVPFL_str " L:%d V:%u  data:@%p\n", INOBJHDRVAL, 
+		avp->avp_public.avp_code,
+		DUMP_AVPFL_val(avp->avp_public.avp_flags),
+		avp->avp_public.avp_len,
+		avp->avp_public.avp_vendor,
+		avp->avp_public.avp_value
+		);
+	/* Dump the value if set */
+	if (avp->avp_public.avp_value) {
+		if (!avp->avp_model) {
+			fd_log_debug(INOBJHDR "(data set but no model: ERROR)\n", INOBJHDRVAL);
+		} else {
+			/* Try and find a constant name for this value */
+			struct dictionary * dict = NULL;
+			struct dict_object * avp_type = NULL;
+			struct dict_object * avp_constant = NULL;
+			struct dict_type_data type_data;
+			struct dict_enumval_request  request;
+			ret = fd_dict_getdict(avp->avp_model, & dict);
+			if (ret != 0) {
+				dump_basic_type(avp->avp_public.avp_value, type, type_base_name[type], indent);
+				goto end;
+			}
+			ret = fd_dict_search(dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &avp_type, ENOENT);
+			if (ret != 0) {
+				dump_basic_type(avp->avp_public.avp_value, type, type_base_name[type], indent);
+				goto end;
+			}
+			ret = fd_dict_getval(avp_type, &type_data);
+			if (ret != 0) {
+				dump_basic_type(avp->avp_public.avp_value, type, "(error getting type data)", indent);
+				goto end;
+			}
+			if (type_data.type_base != type) {
+				dump_basic_type(avp->avp_public.avp_value, type, "(mismatching type information!)", indent);
+				goto end;
+			}
+			/* Create a query for a constant */
+			memset(&request, 0, sizeof(request));
+			request.type_obj = avp_type;
+			memcpy(&request.search.enum_value, avp->avp_public.avp_value, sizeof(union avp_value));
+			ret = fd_dict_search(dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &avp_constant, ENOENT);
+			if (ret != 0)  {
+				dump_basic_type(avp->avp_public.avp_value, type, type_data.type_name, indent);
+				goto end;
+			}
+			/* get the constant's information; we re-use request.search field */
+			ret = fd_dict_getval(avp_constant, &request.search);
+			if (ret != 0) {
+				dump_basic_type(avp->avp_public.avp_value, type, "(error getting constant data)", indent);
+				goto end;
+			}
+			dump_constant_type(&request.search, type, type_data.type_name, indent);
+		}
+	}
+end:	
+	fd_log_debug(INOBJHDR "intern: src:%p mf:%d raw:%p(%d)\n", INOBJHDRVAL, avp->avp_source, avp->avp_mustfreeos, avp->avp_rawdata, avp->avp_rawlen);
+}
+
+/* Dump a single object content */
+static void msg_dump_intern ( int level, msg_or_avp * obj, int indent )
+{
+	/* Log only if we are at least at level */
+	if ( ! TRACE_BOOL(level) )
+		return;
+	
+	/* Check the object */
+	if (!VALIDATE_OBJ(obj)) {
+		fd_log_debug( ">>> invalid object (%p)!.\n", obj);
+		return;
+	}
+	
+	/* Dump the object */
+	switch (_C(obj)->type) {
+		case MSG_AVP:
+			obj_dump_avp ( _A(obj), indent );
+			break;
+		
+		case MSG_MSG:
+			obj_dump_msg ( _M(obj), indent );
+			break;
+		
+		default:
+			ASSERT(0);
+	}
+}
+
+/* Dump a message content -- for debug mostly */
+void fd_msg_dump_walk ( int level, msg_or_avp *obj )
+{
+	msg_or_avp * ref = obj;
+	int indent = 1;
+	
+	TRACE_DEBUG(level, "------ Dumping object %p (w)-------", obj);
+	do {
+		msg_dump_intern ( level, ref, indent );
+		
+		/* Now find the next object */
+		CHECK_FCT_DO(  fd_msg_browse ( ref, MSG_BRW_WALK, &ref, &indent ), break  );
+		
+		/* dump next object */
+	} while (ref);
+	
+	TRACE_DEBUG(level, "------ /end of object %p -------", obj);
+}
+
+/* Dump a single object content -- for debug mostly */
+void fd_msg_dump_one ( int level, msg_or_avp * obj )
+{
+	TRACE_DEBUG(level, "------ Dumping object %p (s)-------", obj);
+	msg_dump_intern ( level, obj, 1 );
+	TRACE_DEBUG(level, "------ /end of object %p -------", obj);
+}
+
+
+/***************************************************************************************************************/
+/* Simple meta-data management */
+
+/* Retrieve the model of an object */
+int fd_msg_model ( msg_or_avp * reference, struct dict_object ** model )
+{
+	TRACE_ENTRY("%p %p", reference, model);
+	
+	/* Check the parameters */
+	CHECK_PARAMS(  model && VALIDATE_OBJ(reference)  );
+	
+	/* copy the model reference */
+	switch (_C(reference)->type) {
+		case MSG_AVP:
+			*model = _A(reference)->avp_model;
+			break;
+		
+		case MSG_MSG:
+			*model = _M(reference)->msg_model;
+			break;
+		
+		default:
+			CHECK_PARAMS(0);
+	}
+	
+	return 0;
+}
+
+/* Retrieve the address of the msg_public field of a message */
+int fd_msg_hdr ( struct msg *msg, struct msg_hdr **pdata )
+{
+	TRACE_ENTRY("%p %p", msg, pdata);
+	CHECK_PARAMS(  CHECK_MSG(msg) && pdata  );
+	
+	*pdata = &msg->msg_public;
+	return 0;
+}
+
+/* Retrieve the address of the avp_public field of an avp */
+int fd_msg_avp_hdr ( struct avp *avp, struct avp_hdr **pdata )
+{
+	TRACE_ENTRY("%p %p", avp, pdata);
+	CHECK_PARAMS(  CHECK_AVP(avp) && pdata  );
+	
+	*pdata = &avp->avp_public;
+	return 0;
+}
+
+/* Associate answers and queries */
+int fd_msg_answ_associate( struct msg * answer, struct msg * query )
+{
+	TRACE_ENTRY( "%p %p", answer, query );
+	
+	CHECK_PARAMS(  CHECK_MSG(answer) && CHECK_MSG(query) && (answer->msg_query == NULL )  );
+	
+	answer->msg_query = query;
+	
+	return 0;
+}	
+
+int fd_msg_answ_getq( struct msg * answer, struct msg ** query )
+{
+	TRACE_ENTRY( "%p %p", answer, query );
+	
+	CHECK_PARAMS(  CHECK_MSG(answer) && query  );
+	
+	*query = answer->msg_query;
+	
+	return 0;
+}	
+
+int fd_msg_answ_detach( struct msg * answer )
+{
+	TRACE_ENTRY( "%p", answer );
+	
+	CHECK_PARAMS(  CHECK_MSG(answer) );
+	
+	answer->msg_query = NULL;
+	
+	return 0;
+}
+
+/* Associate / get answer callbacks */
+int fd_msg_anscb_associate( struct msg * msg, void ( *anscb)(void *, struct msg **), void  * data )
+{
+	TRACE_ENTRY("%p %p %p", msg, anscb, data);
+	
+	/* Check the parameters */
+	CHECK_PARAMS( CHECK_MSG(msg) && anscb );
+	CHECK_PARAMS( ! (msg->msg_public.msg_flags & CMD_FLAG_REQUEST) );
+	CHECK_PARAMS( msg->msg_cb.fct == NULL ); /* No cb is already registered */
+	
+	/* Associate callback and data with the message, if any */
+	msg->msg_cb.fct = anscb;
+	msg->msg_cb.data = data;
+	
+	return 0;
+}	
+
+int fd_msg_anscb_get( struct msg * msg, void (**anscb)(void *, struct msg **), void ** data )
+{
+	TRACE_ENTRY("%p %p %p", msg, anscb, data);
+	
+	/* Check the parameters */
+	CHECK_PARAMS( CHECK_MSG(msg) && anscb && data );
+	
+	/* Copy the result */
+	*anscb = msg->msg_cb.fct;
+	*data  = msg->msg_cb.data;
+	
+	return 0;
+}	
+
+/* Associate routing lists */
+int fd_msg_rt_associate( struct msg * msg, struct fd_list ** list )
+{
+	TRACE_ENTRY( "%p %p", msg, list );
+	
+	CHECK_PARAMS(  CHECK_MSG(msg) && list  );
+	
+	msg->msg_rtlist = *list;
+	*list = NULL;
+	
+	return 0;
+}
+
+int fd_msg_rt_get( struct msg * msg, struct fd_list ** list )
+{
+	TRACE_ENTRY( "%p %p", msg, list );
+	
+	CHECK_PARAMS(  CHECK_MSG(msg) && list  );
+	
+	*list = msg->msg_rtlist;
+	msg->msg_rtlist = NULL;
+	
+	return 0;
+}	
+
+/* Find if a message is routable */
+int fd_msg_is_routable ( struct msg * msg )
+{
+	TRACE_ENTRY("%p", msg);
+	
+	CHECK_PARAMS_DO(  CHECK_MSG(msg),  return 0 /* pretend the message is not routable */ );
+	
+	if ( ! msg->msg_routable ) {
+		/* To define if a message is routable, we rely on the "PXY" command flag yet. */
+		msg->msg_routable = (msg->msg_public.msg_flags & CMD_FLAG_PROXIABLE) ? 1 : 2;
+		
+		/* Note : the 'real' criteria according to the Diameter I-D is that the message is 
+		 routable if and only if the "Destination-Realm" AVP is required by the command ABNF.
+		 We could make a test for this here, but it's more computational work and our test
+		 seems accurate (until proven otherwise...) */
+	}
+	
+	return (msg->msg_routable == 1) ? 1 : 0;
+}
+
+/* Associate source peer */
+int fd_msg_source_set( struct msg * msg, char * diamid, uint32_t hash, int add_rr, struct dictionary * dict )
+{
+	TRACE_ENTRY( "%p %p %x %d %p", msg, diamid, hash, add_rr, dict);
+	
+	/* Check we received a valid message */
+	CHECK_PARAMS( CHECK_MSG(msg) && dict );
+	
+	/* Cleanup any previous source */
+	free(msg->msg_src_id); msg->msg_src_id = NULL;
+	
+	/* If the request is to cleanup the source, we are done */
+	if (diamid == NULL) {
+		msg->msg_src_hash = 0;
+		return 0;
+	}
+	
+	/* Otherwise save the new informations */
+	CHECK_MALLOC( msg->msg_src_id = strdup(diamid) );
+	msg->msg_src_hash = hash;
+	
+	if (add_rr) {
+		struct dict_object 	*avp_rr_model;
+		avp_code_t 		 code = AC_ROUTE_RECORD;
+		struct avp 		*avp;
+		union avp_value		 val;
+		
+		/* Find the model for Route-Record in the dictionary */
+		CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE, &code, &avp_rr_model, ENOENT) );
+		
+		/* Create the AVP with this model */
+		CHECK_FCT( fd_msg_avp_new ( avp_rr_model, 0, &avp ) );
+		
+		/* Set the AVP value with the diameter id */
+		memset(&val, 0, sizeof(val));
+		val.os.data = (unsigned char *)diamid;
+		val.os.len  = strlen(diamid);
+		CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
+
+		/* Add the AVP in the message */
+		CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
+	}
+	
+	/* done */
+	return 0;
+}
+
+int fd_msg_source_get( struct msg * msg, char ** diamid, uint32_t *hash )
+{
+	TRACE_ENTRY( "%p %p %p", msg, diamid, hash);
+	
+	/* Check we received valid parameters */
+	CHECK_PARAMS( CHECK_MSG(msg) );
+	CHECK_PARAMS( diamid );
+	
+	/* Copy the informations */
+	*diamid = msg->msg_src_id;
+	if (hash)
+		*hash = msg->msg_src_hash;
+	
+	/* done */
+	return 0;
+}
+
+/******************* End-to-end counter *********************/
+uint32_t fd_eteid;
+pthread_mutex_t fd_eteid_lck = PTHREAD_MUTEX_INITIALIZER;
+
+void fd_msg_eteid_init(void)
+{
+	fd_eteid = ((uint32_t)time(NULL) << 20) | ((uint32_t)lrand48() & ( (1 << 20) - 1 ));
+}
+
+uint32_t fd_msg_eteid_get ( void )
+{
+	uint32_t ret;
+	
+	CHECK_POSIX_DO( pthread_mutex_lock(&fd_eteid_lck), /* continue */ );
+	
+	ret = fd_eteid ++;
+	
+	CHECK_POSIX_DO( pthread_mutex_unlock(&fd_eteid_lck), /* continue */ );
+	
+	return ret;
+}
+
+/***************************************************************************************************************/
+/* Manage AVPs values */
+
+/* Set the value of an AVP */
+int fd_msg_avp_setvalue ( struct avp *avp, union avp_value *value )
+{
+	enum dict_avp_basetype type = -1;
+	
+	TRACE_ENTRY("%p %p", avp, value);
+	
+	/* Check parameter */
+	CHECK_PARAMS(  CHECK_AVP(avp) && avp->avp_model  );
+	
+	/* Retrieve information from the AVP model */
+	{
+		enum dict_object_type dicttype;
+		struct dict_avp_data  dictdata;
+		
+		CHECK_PARAMS( (fd_dict_gettype(avp->avp_model, &dicttype) == 0) && (dicttype == DICT_AVP) );
+		CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
+		type = dictdata.avp_basetype;
+		CHECK_PARAMS(  type != AVP_TYPE_GROUPED  );
+	}
+	
+	/* First, clean any previous value */
+	if (avp->avp_mustfreeos != 0) {
+		free(avp->avp_storage.os.data);
+		avp->avp_mustfreeos = 0;
+	}
+	
+	memset(&avp->avp_storage, 0, sizeof(union avp_value));
+	
+	/* If the request was to delete a value: */
+	if (!value) {
+		avp->avp_public.avp_value = NULL;
+		return 0;
+	}
+	
+	/* Now we have to set the value */
+	memcpy(&avp->avp_storage, value, sizeof(union avp_value));
+	
+	/* Copy an octetstring if needed. */
+	if (type == AVP_TYPE_OCTETSTRING) {
+		CHECK_MALLOC(  avp->avp_storage.os.data = malloc(value->os.len)  );
+		avp->avp_mustfreeos = 1;
+		memcpy(avp->avp_storage.os.data, value->os.data, value->os.len);
+	}
+	
+	/* Set the data pointer of the public part */
+	avp->avp_public.avp_value = &avp->avp_storage;
+	
+	return 0;		
+}
+
+/* Set the value of an AVP, using formatted data */
+int fd_msg_avp_value_encode ( void *data, struct avp *avp )
+{
+	enum dict_avp_basetype type = -1;
+	struct dict_type_data type_data;
+	
+	TRACE_ENTRY("%p %p", data, avp);
+	
+	/* Check parameter */
+	CHECK_PARAMS(  CHECK_AVP(avp) && avp->avp_model  );
+	
+	/* Retrieve information from the AVP model and it's parent type */
+	{
+		enum dict_object_type dicttype;
+		struct dict_avp_data  dictdata;
+		struct dictionary   * dict;
+		struct dict_object  * parenttype = NULL;
+		
+		/* First check the base type of the AVP */
+		CHECK_PARAMS( (fd_dict_gettype(avp->avp_model, &dicttype) == 0) && (dicttype == DICT_AVP) );
+		CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
+		type = dictdata.avp_basetype;
+		CHECK_PARAMS(  type != AVP_TYPE_GROUPED  );
+		
+		/* Then retrieve information about the parent's type (= derived type) */
+		CHECK_FCT(  fd_dict_getdict( avp->avp_model, &dict )  );
+		CHECK_FCT(  fd_dict_search( dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &parenttype, EINVAL)  );
+		CHECK_FCT(  fd_dict_getval(parenttype, &type_data)  );
+		if (type_data.type_encode == NULL) {
+			TRACE_DEBUG(INFO, "This AVP type does not provide a callback to encode formatted data. ENOTSUP.");
+			return ENOTSUP;
+		}
+	}
+	
+	/* Ok, now we can encode the value */
+	
+	/* First, clean any previous value */
+	if (avp->avp_mustfreeos != 0) {
+		free(avp->avp_storage.os.data);
+		avp->avp_mustfreeos = 0;
+	}
+	avp->avp_public.avp_value = NULL;
+	memset(&avp->avp_storage, 0, sizeof(union avp_value));
+	
+	/* Now call the type's callback to encode the data */
+	CHECK_FCT(  (*type_data.type_encode)(data, &avp->avp_storage)  );
+	
+	/* If an octetstring has been allocated, let's mark it to be freed */
+	if (type == AVP_TYPE_OCTETSTRING)
+		avp->avp_mustfreeos = 1;
+	
+	/* Set the data pointer of the public part */
+	avp->avp_public.avp_value = &avp->avp_storage;
+	
+	return 0;		
+}
+
+/* Interpret the value of an AVP into formatted data */
+int fd_msg_avp_value_interpret ( struct avp *avp, void *data )
+{
+	struct dict_type_data type_data;
+	
+	TRACE_ENTRY("%p %p", avp, data);
+	
+	/* Check parameter */
+	CHECK_PARAMS(  CHECK_AVP(avp) && avp->avp_model && avp->avp_public.avp_value  );
+	
+	/* Retrieve information about the AVP parent type */
+	{
+		struct dictionary   * dict;
+		struct dict_object  * parenttype = NULL;
+		
+		CHECK_FCT(  fd_dict_getdict( avp->avp_model, &dict )  );
+		CHECK_FCT(  fd_dict_search( dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &parenttype, EINVAL)  );
+		CHECK_FCT(  fd_dict_getval(parenttype, &type_data)  );
+		if (type_data.type_interpret == NULL) {
+			TRACE_DEBUG(INFO, "This AVP type does not provide a callback to interpret value in formatted data. ENOTSUP.");
+			return ENOTSUP;
+		}
+	}
+	
+	/* Ok, now we can interpret the value */
+	
+	CHECK_FCT(  (*type_data.type_interpret)(avp->avp_public.avp_value, data)  );
+	
+	return 0;		
+}
+
+/***************************************************************************************************************/
+/* Creating a buffer from memory objects (bufferize a struct msg) */
+
+/* Following macros are used to store 32 and 64 bit fields into a buffer in network byte order */
+#define PUT_in_buf_32( _u32data, _bufptr ) {							\
+	*(uint32_t *)(_bufptr) = htonl((uint32_t)(_u32data));					\
+}
+#define PUT_in_buf_64( _u64data, _bufptr ) {							\
+	*(uint64_t *)(_bufptr) = htonll((uint64_t)(_u64data));					\
+}
+
+/* Write a message header in the buffer */
+static int bufferize_msg(unsigned char * buffer, size_t buflen, size_t * offset, struct msg * msg)
+{
+	TRACE_ENTRY("%p %d %p %p", buffer, buflen, offset, msg);
+	
+	if ((buflen - *offset) < GETMSGHDRSZ())
+		return ENOSPC;
+	
+	if (*offset & 0x3)
+		return EFAULT;	/* We are supposed to start on 32 bit boundaries */
+	
+	PUT_in_buf_32(msg->msg_public.msg_length, buffer + *offset);
+	buffer[*offset] = msg->msg_public.msg_version;
+	*offset += 4;
+	
+	PUT_in_buf_32(msg->msg_public.msg_code, buffer + *offset);
+	buffer[*offset] = msg->msg_public.msg_flags;
+	*offset += 4;
+	
+	PUT_in_buf_32(msg->msg_public.msg_appl, buffer + *offset);
+	*offset += 4;
+	
+	PUT_in_buf_32(msg->msg_public.msg_hbhid, buffer + *offset);
+	*offset += 4;
+	
+	PUT_in_buf_32(msg->msg_public.msg_eteid, buffer + *offset);
+	*offset += 4;
+	
+	return 0;
+}
+
+static int bufferize_chain(unsigned char * buffer, size_t buflen, size_t * offset, struct fd_list * list);
+
+/* Write an AVP in the buffer */
+static int bufferize_avp(unsigned char * buffer, size_t buflen, size_t * offset,  struct avp * avp)
+{
+	struct dict_avp_data dictdata;
+	
+	TRACE_ENTRY("%p %d %p %p", buffer, buflen, offset, avp);
+	
+	if ((buflen - *offset) < avp->avp_public.avp_len)
+		return ENOSPC;
+	
+	/* Write the header */
+	PUT_in_buf_32(avp->avp_public.avp_code, buffer + *offset);
+	*offset += 4;
+	
+	PUT_in_buf_32(avp->avp_public.avp_len, buffer + *offset);
+	buffer[*offset] = avp->avp_public.avp_flags;
+	*offset += 4;
+	
+	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+		PUT_in_buf_32(avp->avp_public.avp_vendor, buffer + *offset);
+		*offset += 4;
+	}
+	
+	/* Then we must write the AVP value */
+	
+	if (avp->avp_model == NULL) {
+		/* In the case where we don't know the type of AVP, just copy the raw data or source */
+		CHECK_PARAMS( avp->avp_source || avp->avp_rawdata );
+		
+		if ( avp->avp_source != NULL ) {
+			/* the message was not parsed completely */
+			size_t datalen = avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags);
+			memcpy(&buffer[*offset], avp->avp_source, datalen);
+			*offset += PAD4(datalen);
+		} else {
+			/* the content was stored in rawdata */
+			memcpy(&buffer[*offset], avp->avp_rawdata, avp->avp_rawlen);
+			*offset += PAD4(avp->avp_rawlen);
+		}
+		
+	} else {
+		/* The AVP is defined in the dictionary */
+		CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
+
+		CHECK_PARAMS( ( dictdata.avp_basetype == AVP_TYPE_GROUPED ) || avp->avp_public.avp_value );
+		
+		switch (dictdata.avp_basetype) {
+			case AVP_TYPE_GROUPED:
+				return bufferize_chain(buffer, buflen, offset, &avp->avp_chain.children);
+
+			case AVP_TYPE_OCTETSTRING:
+				memcpy(&buffer[*offset], avp->avp_public.avp_value->os.data, avp->avp_public.avp_value->os.len);
+				*offset += PAD4(avp->avp_public.avp_value->os.len);
+				break;
+
+			case AVP_TYPE_INTEGER32:
+				PUT_in_buf_32(avp->avp_public.avp_value->i32, buffer + *offset);
+				*offset += 4;
+				break;
+
+			case AVP_TYPE_INTEGER64:
+				PUT_in_buf_64(avp->avp_public.avp_value->i64, buffer + *offset);
+				*offset += 8;
+				break;
+
+			case AVP_TYPE_UNSIGNED32:
+				PUT_in_buf_32(avp->avp_public.avp_value->u32, buffer + *offset);
+				*offset += 4;
+				break;
+
+			case AVP_TYPE_UNSIGNED64:
+				PUT_in_buf_64(avp->avp_public.avp_value->u64, buffer + *offset);
+				*offset += 8;
+				break;
+
+			case AVP_TYPE_FLOAT32:
+				/* We read the f32 as "u32" here to avoid casting to uint make decimals go away. 
+				 The alternative would be something like "*(uint32_t *)(& f32)" but
+				 then the compiler complains about strict-aliasing rules. */
+				PUT_in_buf_32(avp->avp_public.avp_value->u32, buffer + *offset);
+				*offset += 4;
+				break;
+
+			case AVP_TYPE_FLOAT64:
+				/* Same remark as previously */
+				PUT_in_buf_64(avp->avp_public.avp_value->u64, buffer + *offset);
+				*offset += 8;
+				break;
+
+			default:
+				ASSERT(0);
+		}
+	}
+	return 0;
+}
+			
+/* Write a chain of AVPs in the buffer */
+static int bufferize_chain(unsigned char * buffer, size_t buflen, size_t * offset, struct fd_list * list)
+{
+	struct fd_list * avpch;
+	
+	TRACE_ENTRY("%p %d %p %p", buffer, buflen, offset, list);
+	
+	for (avpch = list->next; avpch != list; avpch = avpch->next) {
+		/* Bufferize the AVP */
+		CHECK_FCT( bufferize_avp(buffer, buflen, offset, _A(avpch->o))  );
+	}
+	return 0;
+}
+
+/* Create the message buffer, in network-byte order. We browse the tree twice, this could be probably improved if needed */
+int fd_msg_bufferize ( struct msg * msg, unsigned char ** buffer, size_t * len )
+{
+	int ret = 0;
+	unsigned char * buf = NULL;
+	size_t offset = 0;
+	
+	TRACE_ENTRY("%p %p %p", msg, buffer, len);
+	
+	/* Check the parameters */
+	CHECK_PARAMS(  buffer && CHECK_MSG(msg)  );
+	
+	/* Update the length. This also checks that all AVP have their values set */
+	CHECK_FCT(  fd_msg_update_length(msg)  );
+	
+	/* Now allocate a buffer to store the message */
+	CHECK_MALLOC(  buf = malloc(msg->msg_public.msg_length)  );
+	
+	/* Clear the memory, so that the padding is always 0 (should not matter) */
+	memset(buf, 0, msg->msg_public.msg_length);
+	
+	/* Write the message header in the buffer */
+	CHECK_FCT_DO( ret = bufferize_msg(buf, msg->msg_public.msg_length, &offset, msg), 
+		{
+			free(buf);
+			return ret;
+		}  );
+	
+	/* Write the list of AVPs */
+	CHECK_FCT_DO( ret = bufferize_chain(buf, msg->msg_public.msg_length, &offset, &msg->msg_chain.children),
+		{
+			free(buf);
+			return ret;
+		}  );
+	
+	ASSERT(offset == msg->msg_public.msg_length); /* or the msg_update_length is buggy */
+		
+	if (len) {
+		*len = offset;
+	}
+	
+	*buffer = buf;
+	return 0;
+}
+
+
+/***************************************************************************************************************/
+/* Parsing buffers and building AVP objects lists (not parsing the AVP values which requires dictionary knowledge) */
+
+/* Parse a buffer containing a supposed list of AVPs */
+static int parsebuf_list(unsigned char * buf, size_t buflen, struct fd_list * head)
+{
+	size_t offset = 0;
+	
+	TRACE_ENTRY("%p %d %p", buf, buflen, head);
+	
+	while (offset < buflen) {
+		struct avp * avp;
+		
+		if (buflen - offset <= AVPHDRSZ_NOVEND) {
+			TRACE_DEBUG(INFO, "truncated buffer: remaining only %d bytes", buflen - offset);
+			return EBADMSG;
+		}
+		
+		/* Create a new AVP object */
+		CHECK_MALLOC(  avp = malloc (sizeof(struct avp))  );
+		
+		init_avp(avp);
+		
+		/* Initialize the header */
+		avp->avp_public.avp_code    = ntohl(*(uint32_t *)(buf + offset));
+		avp->avp_public.avp_flags   = buf[offset + 4];
+		avp->avp_public.avp_len     = ((uint32_t)buf[offset+5]) << 16 |  ((uint32_t)buf[offset+6]) << 8 |  ((uint32_t)buf[offset+7]) ;
+		
+		offset += 8;
+		
+		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+			if (buflen - offset <= 4) {
+				TRACE_DEBUG(INFO, "truncated buffer: remaining only %d bytes for vendor and data", buflen - offset);
+				free(avp);
+				return EBADMSG;
+			}
+			avp->avp_public.avp_vendor  = ntohl(*(uint32_t *)(buf + offset));
+			offset += 4;
+		}
+		
+		/* Check there is enough remaining data in the buffer */
+		if (buflen - offset < avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags)) {
+			TRACE_DEBUG(INFO, "truncated buffer: remaining only %d bytes for data, and avp data size is %d", 
+					buflen - offset, 
+					avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags));
+			free(avp);
+			return EBADMSG;
+		}
+		
+		/* buf[offset] is now the beginning of the data */
+		avp->avp_source = &buf[offset];
+		
+		/* Now eat the data and eventual padding */
+		offset += PAD4(avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags));
+		
+		/* And insert this avp in the list, at the end */
+		fd_list_insert_before( head, &avp->avp_chain.chaining );
+	}
+	
+	return 0;
+}
+
+/* Create a message object from a buffer. Dictionary objects are not resolved, AVP contents are not interpreted, buffer is saved in msg */
+int fd_msg_parse_buffer ( unsigned char ** buffer, size_t buflen, struct msg ** msg )
+{
+	struct msg * new = NULL;
+	int ret = 0;
+	uint32_t msglen = 0;
+	unsigned char * buf;
+	
+	TRACE_ENTRY("%p %d %p", buffer, buflen, msg);
+	
+	CHECK_PARAMS(  buffer &&  *buffer  &&  msg  &&  (buflen >= GETMSGHDRSZ())  );
+	buf = *buffer;
+	*buffer = NULL;
+	
+	if ( buf[0] != DIAMETER_VERSION) {
+		TRACE_DEBUG(INFO, "Invalid version in message: %d (supported: %d)", buf[0], DIAMETER_VERSION);
+		free(buf);
+		return EBADMSG;
+	}
+	
+	msglen = ntohl(*(uint32_t *)buf) & 0x00ffffff;
+	if ( buflen < msglen ) {  
+		TRACE_DEBUG(INFO, "Truncated message (%d / %d)", buflen, msglen );
+		free(buf);
+		return EBADMSG; 
+	}
+	
+	/* Create a new object */
+	CHECK_MALLOC_DO( new = malloc (sizeof(struct msg)),  { free(buf); return ENOMEM; }  );
+	
+	/* Initialize the fields */
+	init_msg(new);
+	
+	/* Now read from the buffer */
+	new->msg_public.msg_version = buf[0];
+	new->msg_public.msg_length = msglen;
+
+	new->msg_public.msg_flags = buf[4];
+	new->msg_public.msg_code = ntohl(*(uint32_t *)(buf+4)) & 0x00ffffff;
+	
+	new->msg_public.msg_appl = ntohl(*(uint32_t *)(buf+8));
+	new->msg_public.msg_hbhid = ntohl(*(uint32_t *)(buf+12));
+	new->msg_public.msg_eteid = ntohl(*(uint32_t *)(buf+16));
+	
+	new->msg_rawbuffer = buf;
+	
+	/* Parse the AVP list */
+	CHECK_FCT_DO( ret = parsebuf_list(buf + GETMSGHDRSZ(), buflen - GETMSGHDRSZ(), &new->msg_chain.children), { destroy_tree(_C(new)); return ret; }  );
+	
+	*msg = new;
+	return 0;
+}
+
+		
+/***************************************************************************************************************/
+/* Parsing messages and AVP with dictionary information */
+
+/* Resolve dictionary objects of the cmd and avp instances, from their headers.
+ * When the model is found, the data is interpreted from the avp_source buffer and copied to avp_storage.
+ * When the model is not found, the data is copied as rawdata and saved (in case we FW the message).
+ * Therefore, after this function has been called, the source buffer can be freed.
+ * For command, if the dictionary model is not found, an error is returned.
+ */
+
+static int parsedict_do_chain(struct dictionary * dict, struct fd_list * head, int mandatory);
+
+/* Process an AVP. If we are not in recheck, the avp_source must be set. */
+static int parsedict_do_avp(struct dictionary * dict, struct avp * avp, int mandatory)
+{
+	struct dict_avp_data dictdata;
+	
+	TRACE_ENTRY("%p %p %d", dict, avp, mandatory);
+	
+	/* First check we received an AVP as input */
+	CHECK_PARAMS(  CHECK_AVP(avp) );
+	
+	if (avp->avp_model != NULL) {
+		/* the model has already been resolved. we do check it is still valid */
+
+		CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
+
+		if ( avp->avp_public.avp_code == dictdata.avp_code  ) {
+			/* Ok then just process the children if any */
+			return parsedict_do_chain(dict, &avp->avp_chain.children, mandatory && (avp->avp_public.avp_flags & AVP_FLAG_MANDATORY));
+		} else {
+			/* We just erase the old model */
+			avp->avp_model = NULL;
+		}
+	}
+	
+	/* Now try and resolve the model from the avp code and vendor */
+	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+		struct dict_avp_request avpreq;
+		avpreq.avp_vendor = avp->avp_public.avp_vendor;
+		avpreq.avp_code = avp->avp_public.avp_code;
+		CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE_AND_VENDOR, &avpreq, &avp->avp_model, 0));
+	} else {
+		/* no vendor */
+		CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE, &avp->avp_public.avp_code, &avp->avp_model, 0));
+	}
+	
+	/* First handle the case where we have not found this AVP in the dictionary */
+	if (!avp->avp_model) {
+		
+		if (mandatory && (avp->avp_public.avp_flags & AVP_FLAG_MANDATORY)) {
+			TRACE_DEBUG(INFO, "Unsupported mandatory AVP found:");
+			msg_dump_intern(INFO, avp, 2);
+			return ENOTSUP;
+		}
+		
+		if (avp->avp_source) {
+			/* we must copy the data from the source to the internal buffer area */
+			CHECK_PARAMS( !avp->avp_rawdata  );
+			
+			avp->avp_rawlen = avp->avp_public.avp_len - GETAVPHDRSZ( avp->avp_public.avp_flags );
+			
+			CHECK_MALLOC(  avp->avp_rawdata = malloc(avp->avp_rawlen)  );
+			
+			memcpy(avp->avp_rawdata, avp->avp_source, avp->avp_rawlen);
+			avp->avp_source = NULL;
+			
+			TRACE_DEBUG(FULL, "Unsupported optional AVP found, raw source data saved in avp_rawdata.");
+		}
+		
+		return 0;
+	}
+	
+	/* Ok we have resolved the object. Now we need to interpret its content. */
+	
+	CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
+	
+	if (avp->avp_rawdata) {
+		/* This happens if the dictionary object was defined after the first check */
+		avp->avp_source = avp->avp_rawdata;
+	}
+	
+	/* A bit of sanity here... */
+	ASSERT(CHECK_BASETYPE(dictdata.avp_basetype));
+	
+	/* Check the size is valid */
+	if ((avp_value_sizes[dictdata.avp_basetype] != 0) &&
+	    (avp->avp_public.avp_len - GETAVPHDRSZ( avp->avp_public.avp_flags ) != avp_value_sizes[dictdata.avp_basetype])) {
+		TRACE_DEBUG(INFO, "The AVP size is not suitable for the type. EBADMSG.");
+		return EBADMSG;
+	}
+	
+	/* Now get the value inside */
+	switch (dictdata.avp_basetype) {
+		case AVP_TYPE_GROUPED:
+			/* This is a grouped AVP, so let's parse the list of AVPs inside */
+			CHECK_FCT(  parsebuf_list(avp->avp_source, avp->avp_public.avp_len - GETAVPHDRSZ( avp->avp_public.avp_flags ), &avp->avp_chain.children)  );
+			
+			return parsedict_do_chain(dict, &avp->avp_chain.children, mandatory && (avp->avp_public.avp_flags & AVP_FLAG_MANDATORY));
+			
+		case AVP_TYPE_OCTETSTRING:
+			/* We just have to copy the string into the storage area */
+			CHECK_PARAMS( avp->avp_public.avp_len > GETAVPHDRSZ( avp->avp_public.avp_flags ) );
+			avp->avp_storage.os.len = avp->avp_public.avp_len - GETAVPHDRSZ( avp->avp_public.avp_flags );
+			CHECK_MALLOC(  avp->avp_storage.os.data = malloc(avp->avp_storage.os.len)  );
+			avp->avp_mustfreeos = 1;
+			memcpy(avp->avp_storage.os.data, avp->avp_source, avp->avp_storage.os.len);
+			break;
+		
+		case AVP_TYPE_INTEGER32:
+			avp->avp_storage.i32 = (int32_t)ntohl(*(uint32_t *)avp->avp_source);
+			break;
+	
+		case AVP_TYPE_INTEGER64:
+			avp->avp_storage.i64 = (int64_t)ntohll(*(uint64_t *)avp->avp_source);
+			break;
+	
+		case AVP_TYPE_UNSIGNED32:
+		case AVP_TYPE_FLOAT32: /* For float, we must not cast, or the value is changed. Instead we use implicit cast by changing the member of the union */
+			avp->avp_storage.u32 = (uint32_t)ntohl(*(uint32_t *)avp->avp_source);
+			break;
+	
+		case AVP_TYPE_UNSIGNED64:
+		case AVP_TYPE_FLOAT64: /* same as 32 bits */
+			avp->avp_storage.u64 = (uint64_t)ntohll(*(uint64_t *)avp->avp_source);
+			break;
+	
+	}
+	
+	/* The value is now set, so set the data pointer and return 0 */
+	avp->avp_public.avp_value = &avp->avp_storage;
+	return 0;
+}
+
+/* Process a list of AVPs */
+static int parsedict_do_chain(struct dictionary * dict, struct fd_list * head, int mandatory)
+{
+	struct fd_list * avpch;
+	
+	TRACE_ENTRY("%p %p %d", dict, head, mandatory);
+	
+	/* Sanity check */
+	ASSERT ( head == head->head );
+	
+	/* Now process the list */
+	for (avpch=head->next; avpch != head; avpch = avpch->next) {
+		CHECK_FCT(  parsedict_do_avp(dict, _A(avpch->o), mandatory)  );
+	}
+	
+	/* Done */
+	return 0;
+}
+
+/* Process a msg header. */
+static int parsedict_do_msg(struct dictionary * dict, struct msg * msg, int only_hdr)
+{
+	int ret = 0;
+	
+	TRACE_ENTRY("%p %p %d", dict, msg, only_hdr);
+	
+	CHECK_PARAMS(  CHECK_MSG(msg)  );
+	
+	/* Look for the model from the header */
+	CHECK_FCT( fd_dict_search ( dict, DICT_COMMAND, 
+			(msg->msg_public.msg_flags & CMD_FLAG_REQUEST) ? CMD_BY_CODE_R : CMD_BY_CODE_A,
+			&msg->msg_public.msg_code,
+			&msg->msg_model, ENOTSUP) );
+	
+	if (!only_hdr) {
+		/* Then process the children */
+		ret = parsedict_do_chain(dict, &msg->msg_chain.children, 1);
+
+		/* Free the raw buffer if any */
+		if ((ret == 0) && (msg->msg_rawbuffer != NULL)) {
+			free(msg->msg_rawbuffer);
+			msg->msg_rawbuffer=NULL;
+		}
+	}
+	
+	return ret;
+}
+
+int fd_msg_parse_dict ( msg_or_avp * object, struct dictionary * dict )
+{
+	TRACE_ENTRY("%p %p", dict, object);
+	
+	CHECK_PARAMS(  VALIDATE_OBJ(object)  );
+	
+	switch (_C(object)->type) {
+		case MSG_MSG:
+			return parsedict_do_msg(dict, _M(object), 0);
+		
+		case MSG_AVP:
+			return parsedict_do_avp(dict, _A(object), 0);
+		
+		default:
+			ASSERT(0);
+	}
+	return EINVAL;
+}
+
+/***************************************************************************************************************/
+/* Parsing messages and AVP for rules (ABNF) compliance */
+
+/* This function is used to get stats (first occurence position, last occurence position, number of occurences) 
+   of AVP instances of a given model in a chain of AVP */
+static void parserules_stat_avps( struct dict_object * model_avp, struct fd_list *list, int * count, int * firstpos, int * lastpos) 
+{
+	struct fd_list * li;
+	int curpos = 0; /* The current position in the list */
+	
+	TRACE_ENTRY("%p %p %p %p %p", model_avp, list, count, firstpos, lastpos);
+	
+	*count = 0;	/* number of instances found */
+	*firstpos = 0;	/* position of the first instance */
+	*lastpos = 0;	/* position of the last instance, starting from the end */
+	
+	for (li = list->next; li != list; li = li->next) {
+		/* Increment the current position counter */
+		curpos++;
+		
+		/* If we previously saved a "lastpos" information, increment it */
+		if (*lastpos != 0)
+			(*lastpos)++;
+		
+		/* Check the type of the next AVP. We can compare the references directly, it is safe. */
+		if (_A(li->o)->avp_model == model_avp) {
+			
+			/* This AVP is of the type we are searching */
+			(*count)++;
+			
+			/* If we don't have yet a "firstpos", save it */
+			if (*firstpos == 0)
+				*firstpos = curpos;
+			
+			/* Reset the lastpos */
+			(*lastpos) = 1;
+		}
+	}
+}
+
+/* We use this structure as parameter for the next function */
+struct parserules_data {
+	struct fd_list     * sentinel;  /* Sentinel of the list of children AVP */
+	struct dict_object * ruleavp;   /* If the rule conflicts, save the rule_avp here (we don't have direct access to the rule but it can be searched) */
+};
+
+/* Check that a list of AVPs is compliant with a given rule -- will be iterated on the list of rules */
+static int parserules_check_one_rule(void * data, struct dict_rule_data *rule)
+{
+	int ret = 0, count, first, last, min;
+	struct parserules_data * pr_data = (struct parserules_data *) data;
+	
+	TRACE_ENTRY("%p %p", data, rule);
+	
+	/* Get statistics of the AVP concerned by this rule in the message instance */
+	parserules_stat_avps( rule->rule_avp, pr_data->sentinel, &count, &first, &last);
+	
+	if (TRACE_BOOL(ANNOYING))
+	{
+		struct dict_avp_data avpdata;
+		ret = fd_dict_getval(rule->rule_avp, &avpdata);
+		
+		TRACE_DEBUG(ANNOYING, "Checking rule: p:%d(%d) m/M:%2d/%2d. Counted %d (first: %d, last:%d) of AVP '%s'", 
+					rule->rule_position,
+					rule->rule_order,
+					rule->rule_min,
+					rule->rule_max,
+					count, 
+					first, 
+					last,
+					(ret == 0) ? avpdata.avp_name : "???"
+				);
+	}
+	
+	/* Now check the rule is not conflicting */
+	ret = 0;
+	
+	/* Check the "min" value */
+	if ((min = rule->rule_min) == -1) {
+		if (rule->rule_position == RULE_OPTIONAL)
+			min = 0;
+		else
+			min = 1;
+	}
+	if (count < min) {
+		TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is < the rule min (%d).", count, min);
+		ret = EBADMSG;
+		goto end;
+	}
+	
+	/* Check the "max" value */
+	if ((rule->rule_max != -1) && (count > rule->rule_max)) {
+		TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is > the rule max (%d).", count, rule->rule_max);
+		ret = EBADMSG;
+		goto end;
+	}
+		
+	/* Check the position and order (if relevant) */
+	switch (rule->rule_position) {
+		case RULE_OPTIONAL:
+		case RULE_REQUIRED:
+			/* No special position constraints */
+			break;
+		
+		case RULE_FIXED_HEAD:
+			/* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *after* its fixed position */
+			if (first > rule->rule_order) {
+				TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_HEAD AVP appears first in (%d) position, the rule requires (%d).", first, rule->rule_order);
+				ret = EBADMSG;
+				goto end;
+			}
+			break;
+	
+		case RULE_FIXED_TAIL:
+			/* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *before* its fixed position */
+			if (last > rule->rule_order) {	/* We have a ">" here because we count in reverse order (i.e. from the end) */
+				TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_TAIL AVP appears last in (%d) position, the rule requires (%d).", last, rule->rule_order);
+				ret = EBADMSG;
+				goto end;
+			}
+			break;
+		
+		default:
+			/* What is this position ??? */
+			ASSERT(0);
+			ret = ENOTSUP;
+	}
+	
+	/* We've checked all the parameters */
+end:
+	if (ret == EBADMSG) {
+		pr_data->ruleavp = rule->rule_avp;
+	}
+
+	return ret;
+}
+
+/* Check the rules recursively */
+static int parserules_do ( struct dictionary * dict, msg_or_avp * object, struct dict_object ** conflict_rule, int mandatory)
+{
+	int ret = 0;
+	struct parserules_data data;
+	struct dict_object * model = NULL;
+	
+	TRACE_ENTRY("%p %p %p %d", dict, object, conflict_rule, mandatory);
+	
+	/* object has already been checked and dict-parsed when we are called. */
+	
+	/* First, handle the cases where there is no model */
+	{
+		if (CHECK_MSG(object)) {
+			if ( _M(object)->msg_public.msg_flags & CMD_FLAG_ERROR ) {
+				/* The case of error messages: the ABNF is different */
+				CHECK_FCT( fd_dict_get_error_cmd(dict, &model) );
+			} else {
+				model = _M(object)->msg_model;
+			}
+			/* Commands MUST be supported in the dictionary */
+			if (model == NULL) {
+				TRACE_DEBUG(INFO, "Message with no dictionary model. EBADMSG");
+				return EBADMSG;
+			}
+		}
+
+		/* AVP with the 'M' flag must also be recognized in the dictionary -- except inside an optional grouped AVP */
+		if (CHECK_AVP(object) && ((model = _A(object)->avp_model) == NULL)) {
+			if ( mandatory && (_A(object)->avp_public.avp_flags & AVP_FLAG_MANDATORY)) {
+				/* Return an error in this case */
+				TRACE_DEBUG(INFO, "Mandatory AVP with no dictionary model. EBADMSG");
+				return EBADMSG;
+			} else {
+				/* We don't know any rule for this object, so assume OK */
+				TRACE_DEBUG(FULL, "Unknown informational AVP, ignoring...");
+				return 0;
+			}
+		}
+	}
+	
+	/* At this point we know "model" is set and points to the object's model */
+	
+	/* If we are an AVP with no children, just return OK */
+	if (CHECK_AVP(object)) {
+		struct dict_avp_data	dictdata;
+		CHECK_FCT(  fd_dict_getval(model, &dictdata)  );
+		if (dictdata.avp_basetype != AVP_TYPE_GROUPED) {
+			/* This object has no children and no rules */
+			return 0;
+		}
+	}
+	
+	/* If this object has children, first check the rules for all its children */
+	{
+		int is_child_mand = 0;
+		struct fd_list * ch = NULL;
+		if (  CHECK_MSG(object) 
+		   || (mandatory && (_A(object)->avp_public.avp_flags & AVP_FLAG_MANDATORY)) )
+			is_child_mand = 1;
+		for (ch = _C(object)->children.next; ch != &_C(object)->children; ch = ch->next) {
+			CHECK_FCT(  parserules_do ( dict, _C(ch->o), conflict_rule, is_child_mand )  );
+		}
+	}
+
+	/* Now check all rules of this object */
+	data.sentinel = &_C(object)->children;
+	data.ruleavp  = NULL;
+	ret = fd_dict_iterate_rules ( model, &data, parserules_check_one_rule );
+	
+	/* Save the reference to the eventual conflicting rule; otherwise set to NULL */
+	if (conflict_rule && data.ruleavp) {
+		/* data.ruleavp contains the AVP, and model is the parent */
+		struct dict_object * rule = NULL;
+		struct dict_rule_request req = { model, data.ruleavp };
+		
+		CHECK_FCT_DO( fd_dict_search ( dict, DICT_RULE, RULE_BY_AVP_AND_PARENT, &req, &rule, ENOENT),  rule = NULL );
+		
+		*conflict_rule = rule;
+	}
+	
+	return ret;
+}
+
+int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct dict_object ** rule)
+{
+	TRACE_ENTRY("%p %p", object, rule);
+	
+	/* Resolve the dictionary objects when missing. This also validates the object. */
+	CHECK_FCT(  fd_msg_parse_dict ( object, dict )  );
+	
+	/* Call the recursive function */
+	return parserules_do ( dict, object, rule, 1 ) ;
+}
+
+/***************************************************************************************************************/
+
+/* Compute the lengh of an object and its subtree. */
+int fd_msg_update_length ( msg_or_avp * object )
+{
+	size_t sz = 0;
+	struct dict_object * model;
+	union {
+		struct dict_cmd_data   cmddata;
+		struct dict_avp_data   avpdata;
+	} dictdata;
+	
+	TRACE_ENTRY("%p", object);
+	
+	/* Get the model of the object. This also validates the object */
+	CHECK_FCT( fd_msg_model ( object, &model ) );
+	
+	/* Get the information of the model */
+	if (model) {
+		CHECK_FCT(  fd_dict_getval(model, &dictdata)  );
+	} else {
+		/* For unknown AVP, just don't change the size */
+		if (_C(object)->type == MSG_AVP)
+			return 0;
+	}
+	
+	/* Deal with easy cases: AVPs without children */
+	if ((_C(object)->type == MSG_AVP) && (dictdata.avpdata.avp_basetype != AVP_TYPE_GROUPED)) {
+		/* Sanity check */
+		ASSERT(FD_IS_LIST_EMPTY(&_A(object)->avp_chain.children));
+		
+		/* Now check that the data is set in the AVP */
+		CHECK_PARAMS(  _A(object)->avp_public.avp_value  );
+		
+		sz = GETAVPHDRSZ( _A(object)->avp_public.avp_flags );
+		
+		switch (dictdata.avpdata.avp_basetype) {
+			case AVP_TYPE_OCTETSTRING:
+				sz += _A(object)->avp_public.avp_value->os.len;
+				break;
+			
+			case AVP_TYPE_INTEGER32:
+			case AVP_TYPE_INTEGER64:
+			case AVP_TYPE_UNSIGNED32:
+			case AVP_TYPE_UNSIGNED64:
+			case AVP_TYPE_FLOAT32:
+			case AVP_TYPE_FLOAT64:
+				sz += avp_value_sizes[dictdata.avpdata.avp_basetype];
+				break;
+			
+			default:
+				/* Something went wrong... */
+				ASSERT(0);
+		}
+	}
+	else  /* message or grouped AVP */
+	{
+		struct fd_list * ch = NULL;
+		
+		/* First, compute the header size */
+		if (_C(object)->type == MSG_AVP) {
+			sz = GETAVPHDRSZ( _A(object)->avp_public.avp_flags );
+		} else {
+			sz = GETMSGHDRSZ( );
+		}
+		
+		/* Recurse in all children and update the sz information */
+		for (ch = _C(object)->children.next; ch != &_C(object)->children; ch = ch->next) {
+			CHECK_FCT(  fd_msg_update_length ( ch->o )  );
+			
+			/* Add the padded size to the parent */
+			sz += PAD4( _A(ch->o)->avp_public.avp_len );
+		}
+	}
+	
+	/* When we arrive here, the "sz" variable contains the size to write in the object */
+	if (_C(object)->type == MSG_AVP) 
+		_A(object)->avp_public.avp_len = sz;
+	else
+		_M(object)->msg_public.msg_length = sz;
+	
+	return 0;
+}
+
+/***************************************************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfreediameter/mqueues.c	Fri Aug 28 19:14:42 2009 +0900
@@ -0,0 +1,394 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2008, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* 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.								 *
+*********************************************************************************************************/
+
+/* Messages queues module.
+ *
+ * The threads that call these functions must be in the cancellation state PTHREAD_CANCEL_ENABLE and type PTHREAD_CANCEL_DEFERRED.
+ * This is the default state and type on thread creation.
+ *
+ * In order to destroy properly a queue, the application must:
+ *  -> shutdown any process that can add into the queue first.
+ *  -> pthread_cancel any thread that could be waiting on the queue.
+ *  -> consume any message that is in the queue, using meq_tryget.
+ *  -> then destroy the queue using meq_del.
+ */
+
+#include "libfd.h"
+
+/* Definition of a message queue object */
+struct mqueue {
+	int		eyec;	/* An eye catcher, also used to check a queue is valid. MQ_EYEC */
+	
+	pthread_mutex_t	mtx;	/* Mutex protecting this queue */
+	pthread_cond_t	cond;	/* condition variable of the list */
+	
+	struct fd_list	list;	/* sentinel for the list of messages */
+	int		count;	/* number of objects in the list */
+	int		thrs;	/* number of threads waiting for a new message (when count is 0) */
+	
+	uint16_t	high;	/* High level threshold (see libfreediameter.h for details) */
+	uint16_t	low;	/* Low level threshhold */
+	void 		*data;	/* Opaque pointer for threshold callbacks */
+	void		(*h_cb)(struct mqueue *, void **); /* The callbacks */
+	void		(*l_cb)(struct mqueue *, void **);
+	int 		highest;/* The highest count value for which h_cb has been called */
+};
+
+/* The eye catcher value */
+#define MQ_EYEC	0xe7ec1130
+
+/* Macro to check a pointer */
+#define CHECK_QUEUE( _queue ) (( (_queue) != NULL) && ( (_queue)->eyec == MQ_EYEC) )
+
+
+/* Create a new message queue */
+int fd_mq_new ( struct mqueue ** queue )
+{
+	struct mqueue * new;
+	
+	TRACE_ENTRY( "%p", queue );
+	
+	CHECK_PARAMS( queue );
+	
+	/* Create a new object */
+	CHECK_MALLOC( new = malloc (sizeof (struct mqueue) )  );
+	
+	/* Initialize the content */
+	memset(new, 0, sizeof(struct mqueue));
+	
+	new->eyec = MQ_EYEC;
+	CHECK_POSIX( pthread_mutex_init(&new->mtx, NULL) );
+	CHECK_POSIX( pthread_cond_init(&new->cond, NULL) );
+	
+	fd_list_init(&new->list, NULL);
+	
+	/* We're done */
+	*queue = new;
+	return 0;
+}
+
+/* Delete a message queue. It must be unused. */ 
+int fd_mq_del ( struct mqueue  ** queue )
+{
+	struct mqueue * q;
+	
+	TRACE_ENTRY( "%p", queue );
+
+	CHECK_PARAMS( queue && CHECK_QUEUE( *queue ) );
+	
+	q = *queue;
+	
+	CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
+	
+	if ((q->count != 0) || (q->thrs != 0) || (q->data != NULL)) {
+		TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %d, %p)", q->count, q->thrs, q->data);
+		CHECK_POSIX_DO(  pthread_mutex_unlock( &q->mtx ), /* no fallback */  );
+		return EINVAL;
+	}
+	
+	/* sanity check */
+	ASSERT(FD_IS_LIST_EMPTY(&q->list));
+	
+	/* Ok, now invalidate the queue */
+	q->eyec = 0xdead;
+	
+	/* And destroy it */
+	CHECK_POSIX(  pthread_mutex_unlock( &q->mtx )  );
+	
+	CHECK_POSIX(  pthread_cond_destroy( &q->cond )  );
+	
+	CHECK_POSIX(  pthread_mutex_destroy( &q->mtx )  );
+	
+	free(q);
+	*queue = NULL;
+	
+	return 0;
+}
+
+/* Get the length of the queue */
+int fd_mq_length ( struct mqueue * queue, int * length )
+{
+	TRACE_ENTRY( "%p %p", queue, length );
+	
+	/* Check the parameters */
+	CHECK_PARAMS( CHECK_QUEUE( queue ) && length );
+	
+	/* lock the queue */
+	CHECK_POSIX(  pthread_mutex_lock( &queue->mtx )  );
+	
+	/* Retrieve the count */
+	*length = queue->count;
+	
+	/* Unlock */
+	CHECK_POSIX(  pthread_mutex_unlock( &queue->mtx )  );
+	
+	/* Done */
+	return 0;
+}
+
+/* alternate version with no error checking */
+int fd_mq_length_noerr ( struct mqueue * queue )
+{
+	if ( !CHECK_QUEUE( queue ) )
+		return 0;
+	
+	return queue->count; /* Let's hope it's read atomically, since we are not locking... */
+}
+
+/* Set the thresholds of the queue */
+int fd_mq_setthrhd ( struct mqueue * queue, void * data, uint16_t high, void (*h_cb)(struct mqueue *, void **), uint16_t low, void (*l_cb)(struct mqueue *, void **) )
+{
+	TRACE_ENTRY( "%p %p %hu %p %hu %p", queue, data, high, h_cb, low, l_cb );
+	
+	/* Check the parameters */
+	CHECK_PARAMS( CHECK_QUEUE( queue ) && (high > low) && (queue->data == NULL) );
+	
+	/* lock the queue */
+	CHECK_POSIX(  pthread_mutex_lock( &queue->mtx )  );
+	
+	/* Save the values */
+	queue->high = high;
+	queue->low  = low;
+	queue->data = data;
+	queue->h_cb = h_cb;
+	queue->l_cb = l_cb;
+	
+	/* Unlock */
+	CHECK_POSIX(  pthread_mutex_unlock( &queue->mtx )  );
+	
+	/* Done */
+	return 0;
+}
+
+/* Post a new message in the queue */
+int fd_mq_post ( struct mqueue * queue, struct msg ** msg )
+{
+	struct fd_list * new;
+	int call_cb = 0;
+	
+	TRACE_ENTRY( "%p %p", queue, msg );
+	
+	/* Check the parameters */
+	CHECK_PARAMS( CHECK_QUEUE( queue ) && msg && *msg );
+	
+	/* Create a new list item */
+	CHECK_MALLOC(  new = malloc (sizeof (struct fd_list))  );
+	
+	fd_list_init(new, *msg);
+	*msg = NULL;
+	
+	/* lock the queue */
+	CHECK_POSIX(  pthread_mutex_lock( &queue->mtx )  );
+	
+	/* Add the new message at the end */
+	fd_list_insert_before( &queue->list, new);
+	queue->count++;
+	if (queue->high && ((queue->count % queue->high) == 0)) {
+		call_cb = 1;
+		queue->highest = queue->count;
+	}
+	
+	/* Signal if threads are asleep */
+	if (queue->thrs > 0) {
+		CHECK_POSIX(  pthread_cond_signal(&queue->cond)  );
+	}
+	
+	/* Unlock */
+	CHECK_POSIX(  pthread_mutex_unlock( &queue->mtx )  );
+	
+	/* Call high-watermark cb as needed */
+	if (call_cb && queue->h_cb)
+		(*queue->h_cb)(queue, &queue->data);
+	
+	/* Done */
+	return 0;
+}
+
+/* Pop the first message from the queue */
+static struct msg * mq_pop(struct mqueue * queue)
+{
+	struct msg * ret = NULL;
+	struct fd_list * li;
+	
+	ASSERT( ! FD_IS_LIST_EMPTY(&queue->list) );
+	
+	fd_list_unlink(li = queue->list.next);
+	queue->count--;
+	ret = (struct msg *)(li->o);
+	free(li);
+	
+	return ret;
+}
+
+/* Check if the low watermark callback must be called. */
+static int test_l_cb(struct mqueue * queue)
+{
+	if ((queue->high == 0) || (queue->low == 0) || (queue->l_cb == 0))
+		return 0;
+	
+	if (((queue->count % queue->high) == queue->low) && (queue->highest > queue->count)) {
+		queue->highest -= queue->high;
+		return 1;
+	}
+	
+	return 0;
+}
+
+/* Try poping a message */
+int fd_mq_tryget ( struct mqueue * queue, struct msg ** msg )
+{
+	int wouldblock = 0;
+	int call_cb = 0;
+	
+	TRACE_ENTRY( "%p %p", queue, msg );
+	
+	/* Check the parameters */
+	CHECK_PARAMS( CHECK_QUEUE( queue ) && msg );
+	
+	/* lock the queue */
+	CHECK_POSIX(  pthread_mutex_lock( &queue->mtx )  );
+	
+	/* Check queue status */
+	if (queue->count > 0) {
+		/* There are messages in the queue, so pick the first one */
+		*msg = mq_pop(queue);
+		call_cb = test_l_cb(queue);
+	} else {
+		wouldblock = 1;
+		*msg = NULL;
+	}
+		
+	/* Unlock */
+	CHECK_POSIX(  pthread_mutex_unlock( &queue->mtx )  );
+	
+	/* Call low watermark callback as needed */
+	if (call_cb)
+		(*queue->l_cb)(queue, &queue->data);
+	
+	/* Done */
+	return wouldblock ? EWOULDBLOCK : 0;
+}
+
+/* This handler is called when a thread is blocked on a queue, and cancelled */
+static void mq_cleanup(void * queue)
+{
+	struct mqueue * q = (struct mqueue *)queue;
+	TRACE_ENTRY( "%p", queue );
+	
+	/* Check the parameter */
+	if ( ! CHECK_QUEUE( q )) {
+		TRACE_DEBUG(INFO, "Invalid queue, skipping handler");
+		return;
+	}
+	
+	/* The thread has been cancelled, therefore it does not wait on the queue anymore */
+	q->thrs--;
+	
+	/* Now unlock the queue, and we're done */
+	CHECK_POSIX_DO(  pthread_mutex_unlock( &q->mtx ),  /* nothing */  );
+	
+	/* End of cleanup handler */
+	return;
+}
+
+/* The internal function for meq_timedget and meq_get */
+static int mq_tget ( struct mqueue * queue, struct msg ** msg, int istimed, const struct timespec *abstime)
+{
+	int timedout = 0;
+	int call_cb = 0;
+	
+	/* Check the parameters */
+	CHECK_PARAMS( CHECK_QUEUE( queue ) && msg && (abstime || !istimed) );
+	
+	/* Initialize the msg value */
+	*msg = NULL;
+	
+	/* lock the queue */
+	CHECK_POSIX(  pthread_mutex_lock( &queue->mtx )  );
+	
+awaken:
+	/* Check queue status */
+	if (queue->count > 0) {
+		/* There are messages in the queue, so pick the first one */
+		*msg = mq_pop(queue);
+		call_cb = test_l_cb(queue);
+	} else {
+		int ret = 0;
+		/* We have to wait for a new message */
+		queue->thrs++ ;
+		pthread_cleanup_push( mq_cleanup, queue);
+		if (istimed) {
+			ret = pthread_cond_timedwait( &queue->cond, &queue->mtx, abstime );
+		} else {
+			ret = pthread_cond_wait( &queue->cond, &queue->mtx );
+		}
+		pthread_cleanup_pop(0);
+		queue->thrs-- ;
+		if (ret == 0)
+			goto awaken;  /* test for spurious wake-ups */
+		
+		if (istimed && (ret == ETIMEDOUT)) {
+			timedout = 1;
+		} else {
+			/* Unexpected error condition (means we need to debug) */
+			ASSERT( ret == 0 /* never true */ );
+		}
+	}
+	
+	/* Unlock */
+	CHECK_POSIX(  pthread_mutex_unlock( &queue->mtx )  );
+	
+	/* Call low watermark callback as needed */
+	if (call_cb)
+		(*queue->l_cb)(queue, &queue->data);
+	
+	/* Done */
+	return timedout ? ETIMEDOUT : 0;
+}
+
+/* Get the next available message, block until there is one */
+int fd_mq_get ( struct mqueue * queue, struct msg ** msg )
+{
+	TRACE_ENTRY( "%p %p", queue, msg );
+	return mq_tget(queue, msg, 0, NULL);
+}
+
+/* Get the next available message, block until there is one, or the timeout expires */
+int fd_mq_timedget ( struct mqueue * queue, struct msg ** msg, const struct timespec *abstime )
+{
+	TRACE_ENTRY( "%p %p %p", queue, msg, abstime );
+	return mq_tget(queue, msg, 1, abstime);
+}
+
"Welcome to our mercurial repository"